SpringMVC中的异常处理程序
我想创建一个异常处理程序,它将拦截项目中的所有控制器。这可能吗?看起来我必须在每个控制器中放置一个处理程序方法。谢谢你的帮助。我有一个发送Json响应的spring控制器。因此,如果发生异常,我希望发送一个可以从一个位置控制的错误响应。定义异常处理程序的抽象类就可以了。然后让您的控制器继承它。(我在Spring3.1中找到了一种实现它的方法,这在回答的第二部分中有描述) 参见Spring参考的章节 除了使用SpringMVC中的异常处理程序,spring,spring-mvc,interceptor,custom-exceptions,Spring,Spring Mvc,Interceptor,Custom Exceptions,我想创建一个异常处理程序,它将拦截项目中的所有控制器。这可能吗?看起来我必须在每个控制器中放置一个处理程序方法。谢谢你的帮助。我有一个发送Json响应的spring控制器。因此,如果发生异常,我希望发送一个可以从一个位置控制的错误响应。定义异常处理程序的抽象类就可以了。然后让您的控制器继承它。(我在Spring3.1中找到了一种实现它的方法,这在回答的第二部分中有描述) 参见Spring参考的章节 除了使用@ExceptionHandler,还有更多的方法(请参阅) 您可以实现一个(使用ser
@ExceptionHandler
,还有更多的方法(请参阅)
- 您可以实现一个(使用servlet而不是portlet包),它是某种全局@ExceptionHandler
- 如果没有特定的异常逻辑,但只有特定的视图,则可以使用,这至少是
的一个实现,其中可以指定异常名称模式和抛出异常时显示的视图(jsp)。例如:HandlerExceptionResolver
当请求由Spring3.x控制器方法处理时,此方法(由<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:defaultErrorView="uncaughtException"> <property name="exceptionMappings"> <props> <prop key=".DataAccessException">dataAccessFailure</prop> <prop key=".TypeMismatchException">resourceNotFound</prop> <prop key=".AccessDeniedException">accessDenied</prop> </props> </property> </bean>
表示)是org.springframework.web.Method.HandlerMethod
参数handler
使用ExceptionHandlerExceptionResolver
(handler
)获取控制器类,并在其中扫描带有HandlerMethod
注释的方法。如果此方法之一与异常(@ExceptionHandler
)匹配,则会调用此方法以处理异常。(elseex
返回,以表示此异常解析程序不承担任何责任) 第一个想法是实现自己的null
,其行为类似于HandlerExceptionResolver
,但它不应该在控制器类中搜索ExceptionHandlerExceptionResolver
,而应该在一个特殊的bean中搜索它们。缺点是,必须(复制(或子类@ExceptionHandler
)并且必须)手动配置所有nice消息转换器、参数解析器和返回值处理程序(真实的且只有ExceptionHandlerExceptionResolver
的配置由spring自动完成)。所以我想出了另一个主意: 实现一个简单的ExceptionHandlerExceptionResolver
,它将异常“转发”到(已配置的)HandlerExceptionResolver
,但使用一个修改的ExceptionHandlerExceptionResolver
,该处理程序指向包含全局异常处理程序的bean(我称它们为全局,因为它们对所有控制器都起作用) 这就是实现:处理程序
GlobalMethodHandlerExeptionResolver
以及全局处理程序的示例:import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; import org.springframework.util.StringUtils; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; public class GlobalMethodHandlerExeptionResolver implements HandlerExceptionResolver, Ordered { @Override public int getOrder() { return -1; // } private ExceptionHandlerExceptionResolver realExceptionResolver; private List<GlobalMethodExceptionResolverContainer> containers; @Autowired public GlobalMethodHandlerExeptionResolver( ExceptionHandlerExceptionResolver realExceptionResolver, List<GlobalMethodExceptionResolverContainer> containers) { this.realExceptionResolver = realExceptionResolver; this.containers = containers; } @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { for (GlobalMethodExceptionResolverContainer container : this.containers) { ModelAndView result = this.realExceptionResolver.resolveException( request, response, handlerMethodPointingGlobalExceptionContainerBean(container), ex); if (result != null) return result; } // we feel not responsible return null; } protected HandlerMethod handlerMethodPointingGlobalExceptionContainerBean( GlobalMethodExceptionResolverContainer container) { try { return new HandlerMethod(container, GlobalMethodExceptionResolverContainer.class. getMethod("fakeHanderMethod")); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException(e); } } }
@Component public class JsonGlobalExceptionResolver implements GlobalMethodExceptionResolverContainer { @Override public void fakeHanderMethod() { } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public ValidationErrorDto handleMethodArgumentNotValidException( MethodArgumentNotValidException validationException, Locale locale) { ... /* map validationException.getBindingResult().getFieldErrors() * to ValidationErrorDto (custom class) */ return validationErrorDto; } }
顺便说一句:您不需要注册
,因为spring会自动为异常解析器注册实现GlobalMethodHandlerExeptionResolver
的所有bean。所以一个简单的HandlerExceptionResolver
就足够了。因为Spring3.2可以使用注释。 您可以在@ControllerAdvice类中声明一个方法 在这种情况下,它处理来自all控制器的@RequestMapping方法的异常@ControllerAdvice public class MyGlobalExceptionHandler { @ExceptionHandler(value=IOException.class) public @ResponseBody String iOExceptionHandler(Exception ex){ // // } // other exception handler methods // ... }
你到底想让处理者做什么?@Bozho-问题被更新了。我明白了。我们也遇到了同样的问题,并选择扩展一个定义处理程序的基类(正如gouki所建议的那样),这是一个很好的答案。可以用注释来完成吗?我们有返回Json响应而不是视图的控制器。@fastcodejava:我想没有标准注释。无论如何,你可以自己构建。在最新的Spring参考中,“处理异常”一章是17.11。如果您仍然感兴趣,请参阅@fastcodejava:我找到了一种方法,可以让
方法负责控制器。-请看我的扩展答案。我使用了@ControllerAdvice。它确实会处理异常并返回指定的错误页面,但问题是日志中没有保存任何内容。您能告诉我如何为此启用日志记录吗?在抽象类中定义ExceptionHandler在我的情况下不起作用(Spring 4.1.4)。@ExceptionHandler
@Component public class JsonGlobalExceptionResolver implements GlobalMethodExceptionResolverContainer { @Override public void fakeHanderMethod() { } @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public ValidationErrorDto handleMethodArgumentNotValidException( MethodArgumentNotValidException validationException, Locale locale) { ... /* map validationException.getBindingResult().getFieldErrors() * to ValidationErrorDto (custom class) */ return validationErrorDto; } }
@ControllerAdvice public class MyGlobalExceptionHandler { @ExceptionHandler(value=IOException.class) public @ResponseBody String iOExceptionHandler(Exception ex){ // // } // other exception handler methods // ... }