手撕SpringMVC异常
1.异常处理简介
SpringMVC通过HandlerExceptionResolver处理程序的异常,包括Handler映射、数据绑定以及处理器方法执行时发生的异常。
①HandlerExceptionResolver(接口) 源码注释:
* Interface to be implemented by objects that can resolve exceptions thrown during
* handler mapping or execution, in the typical case to error views. Implementors are
* typically registered as beans in the application context.
SpringMVC提供的HandlerExceptionResolver的实现类②DispatcherServlet默认装配,以及开发常用装配没有使用<mvc:annotation-drivern/>配置,则装配了以下三种异常解析器:AnnotationMehtodHandlerExceptionResolver (源码中显示已经过时)ResponseStatusExceptionResolverDefaultHandlerExceptionResolver使用了<mvc:annotation-drivern/>配置:ExceptionHandlerExceptionResolver2.ExceptionHandlerExceptionResolverResponseStatusExceptionResolverDefaultHandlerExceptionResolverTalk is cheap! show me your code!主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。
//这个也是能够处理运行时发生的异常,但是和ArithmeticException相比较,没有ArithmeticException近
@ExceptionHandler(Exception.class)
public String getEx(){
return "error";
}
//处理任何符合ArithmeticException的异常,一旦运行过程中又出现该类型异常,便会转到此处执行
@ExceptionHandler(ArithmeticException.class)
public String getEx(){
return "error";
}
@RequestMapping(value = "exceptionTest")
public String exceptionTest(){
int i = 10/0;
//如果代码正常执行,那么就会返回a.jsp ,但是还是出现了异常
return "a";
}
@ExceptionHandler注解定义的方法优先级问题:例如发生的是ArithmeticException,但是声明的异常有 RuntimeException 和 Exception,
此候会根据异常的最近 继承关系找到继承深度最浅的那个@ExceptionHandler 注解方法,即标记了 RuntimeException 的方法
此时还有一种情况,如果用户自定义了一个类,并使用@ControllerrAdvice注解,同时其内部定义了许多@ExceptionHandler注解方法,如下:@ControllerAdvice
public class MyHandlerException {
@ExceptionHandler(ArithmeticException.class)
public String testEx(){
return "error";
}
}
此时规则如下:ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话,会找 @ControllerAdvice 中的@ExceptionHandler 注解方法
3.ResponseStatusExceptionResolver
直接上代码理解:
①自定义一个异常,并采用@ResponseStatus注解修饰异常类
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public class MyException extends RuntimeException {
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
////////////// 测试代码
@RequestMapping(value = "exceptionTest")
public String exceptionTest(){
try {
int i = 10/0;
} catch (Exception e) {
throw new MyException();
}
return "a";
}
若在处理器方法中抛出了上述异常:
若ExceptionHandlerExceptionResolver 不解析述异常。由于触发的异常 UnauthorizedException 带有@ResponseStatus 注解。因此会被ResponseStatusExceptionResolver 解析到。最后响应HttpStatus.UNAUTHORIZED 代码给客户端。HttpStatus.UNAUTHORIZED 代表响应码401,无权限。 关于其他的响应码请参考 HttpStatus 枚举类型源码
实际出现异常然后如下图:
4.DefaultHandlerExceptionResolver
对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException 等
5.SimpleMappingExceptionResolver(这个异常处理器没有自动注册,需要手动配置)
如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常
<bean id="simpleMappingExceptionResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">error</prop>
</props>
</property>
</bean>
当发生ArithmeticException时就可以转到error页面,当然这个配置是properties类型,因此可以配置多个各种类型的异常以及异常对应的界面。
注意:当代码中也配置了异常处理方法,无论远近只要能处理,那么代码处理异常优先级高于配置文件,直接使用代码中的方式处理