Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
其中HandlerExceptionResolver的实现类如下图所示:
注意:AnnotationMethodHandlerExceptionResolver是过时的。
DispatcherServlet 默认装配的 HandlerExceptionResolver 包含如下子类:
- 未配置<mvc:annotation-driven/>时:
- 配置了<mvc:annotation-driven/>时:
所以一般我们在使用HandlerExceptionResolver 处理异常时,需要配置<mvc:annotation-driven/>。
1. ExceptionHandlerExceptionResolver
1.1 @ExceptionHandler 注解
1.1.1 示例
ExceptionHandlerExceptionResolver主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
下面简单演示一下@ExceptionHandler 注解的使用。
1.在控制器类中编写定义如下两个方法,具体代码如下所示:
1 | /** |
2.当我们在请求测试传入的参数为0时,这时testExceptionHandlerExceptionResolver方法会发生除0异常并将异常交由@ExceptionHandler作用的handleArithmeticException进行处理。运行的结果如下图所示:
1.1.2 @ExceptionHandler 注解定义的方法优先级问题
例如发生的是NullPointerException,但是声明的异常有RuntimeException 和 Exception,此时会根据异常的最近继承关系找到继承深度最浅的那个@ExceptionHandler注解方法,即标记了 RuntimeException 的方法。
比如在上述的示例中,我在控制器中添加了另一个异常处理的方法,具体代码如下所示:
1 | ({RuntimeException.class}) |
如果请求发生了除0异常时,该异常会由handleException处理而不是handleArithmeticException。运行结果如下所示:
1.2 @ControllerAdvice 注解
我们若在控制器类中使用@ExceptionHandler定义的方法来处理异常,其只适用于处理当前控制器类方法所发生的异常,SpringMVC还支持全局的异常处理类。
ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,也就是在当前的控制器类中找不到@ExceptionHandler 注解作用的异常处理方法的话,则会找@ControllerAdvice标注的类中的@ExceptionHandler 注解方法。
基于上述示例,将控制器类中的异常处理方法注释掉。并编写一个异常处理类,具体代码如下:
1 |
|
请求响应测试后,运行输出结果如下所示:
1 | ExceptionHandleTest:出异常了:java.lang.ArithmeticException: / by zero |
2. ResponseStatusExceptionResolver
我们也可以使用ResponseStatusExceptionResolver来解析自定义的异常类。
比如现在定义了如下一个异常类:
1 | /** |
我们在若在处理器方法中抛出了上述异常,代码如下:
1 | "/testResponseStatusExceptionResolver") ( |
当请求参数传入的id值为13且ExceptionHandlerExceptionResolver 不解析述异常时,由于触发的异常 IDNotMatchException 带有@ResponseStatus注解。因此会ResponseStatusExceptionResolver 解析到。最后响应HttpStatus.UNAUTHORIZED 码给客户端。HttpStatus.UNAUTHORIZED 代表响应码401,无权限。
出错的运行结果如下图所示:
3. DefaultHandlerExceptionResolver
DefaultHandlerExceptionResolver可以对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等。
4. SimpleMappingExceptionResolver
如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。
下面演示一下该类的使用。
1.首先需要在MVC配置文件中进行如下配置:
1 | <!-- 配置使用SimpleMappingExceptionResolver来映射异常 --> |
注意:<property name=”exceptionAttribute” value=”ex”></property>中的value的值默认为exception,SimpleMappingExceptionResolver有进行如下定义:
当我们没有配置exceptionAttribute时,我们依然可以在JSP页面通过${requestScope.exception}来获取异常数据。
2.在控制器类中编写如下目标方法:
1 | "/testSimpleMappingExceptionResolver") ( |
3.当请求传入的i值为15时,其运行结果如下图所示:
不同于使用@ExceptionHandler注解需要返回包含异常信息的ModelAndView对象才能将错误信息显示在页面上那么繁琐,显然使用SimpleMappingExceptionResolver更为方便一点。