HandlerExceptionResolver
• Spring MVC通过HandlerExceptionResolver处理程序的异常,包括Handler 映射、数据绑定以及目标方法执行时发生的异常。
• SpringMVC提供的HandlerExceptionResolver的实现类
• DispatcherServlet默认装配的HandlerExceptionResolver:
– 没有使用<mvc:annotation-driven/> 配置:
– 使用了<mvc:annotation-driven/> 配置:
ExceptionHandlerExceptionResolver
- 主要处理Handler 中用@ExceptionHandler注解定义的方法。
- @ExceptionHandler注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有RuntimeException和Exception,此时会根据异常的最近继承关系找到继承深度最浅的那个@ExceptionHandler注解方法,即标记了RuntimeException的方法
- ExceptionHandlerMethodResolver内部若找不到@ExceptionHandler注解的话,会找@ControllerAdvice中的@ExceptionHandler注解方法
@ExceptionHandler({ RuntimeException.class })
public ModelAndView handleArithmeticException2(Exception ex) {
System.out.println("[出异常了]: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
/**
* 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象
* 2. @ExceptionHandler方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值
* 3. @ExceptionHandler 方法标记的异常有优先级的问题.
* 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常, 则将去 @ControllerAdvice
* 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.
*/
@ExceptionHandler({ ArithmeticException.class })
public ModelAndView handleArithmeticException(Exception ex) {
System.out.println("出异常了: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
@RequestMapping("/testExceptionHandlerExceptionResolver")
public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i) {
System.out.println("result: " + (10 / i));
return "success";
}
@ControllerAdvice
public class HandlerException {
@ExceptionHandler({ ArithmeticException.class })
public ModelAndView handleArithmeticException(Exception ex) {
System.out.println("出异常了: " + ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
}
ResponseStatusExceptionResolver
• 在异常及异常父类中找到@ResponseStatus注解,然后使用这个注解的属性进行处理。
• 定义一个@ResponseStatus注解修饰的异常类
• 若在处理器方法中抛出了上述异常:
若ExceptionHandlerExceptionResolver不解析述异常。由于触发的异常UserNameNotMatchPasswordException带有@ResponseStatus注解。因此会被ResponseStatusExceptionResolver解析到。最后响应HttpStatus.UNAUTHORIZED代码给客户端。HttpStatus.UNAUTHORIZED代表响应码401,无权限。关于其他的响应码请参考HttpStatus枚举类型源码。
目标方法:
@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i) {
if (i == 13) {
throw new UserNameNotMatchPasswordException();
}
System.out.println("testResponseStatusExceptionResolver...");
return "success";
}
若请求参数为13,则抛出自定义异常UserNameNotMatchPasswordException
@ResponseStatus(value=HttpStatus.UNAUTHORIZED, reason="用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException {
/**
* @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = 1L;
}
请求http://localhost:8081/testResponseStatusExceptionResolver?i=13 测试结果:
如果@ResponseStatus 标注在目标方法上,参数为13则抛出UserNameNotMatchPasswordException,正常情况不为13的话 结果如下:
DefaultHandlerExceptionResolver
@Override
@SuppressWarnings("deprecation")
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
try {
// 处理 404 (Not Found) 异常
if (ex instanceof org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) ex,
request, response, handler);
}
// 处理请求方式不支持 异常
else if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
response, handler);
}
//这个网上说 如果发送的ajax请求类型为'application/x-www-form-urlencoded;charset=UTF-8',但是Spring MVC使用的是‘application/json’,所以需要在ajax请求中改成'Content-Type' : 'application/json;charset=utf-8',
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
handler);
}
else if (ex instanceof HttpMediaTypeNotAcceptableException) {
return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, request, response,
handler);
}
else if (ex instanceof MissingPathVariableException) {
return handleMissingPathVariable((MissingPathVariableException) ex, request,
response, handler);
}
else if (ex instanceof MissingServletRequestParameterException) {
return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request,
response, handler);
}
else if (ex instanceof ServletRequestBindingException) {
return handleServletRequestBindingException((ServletRequestBindingException) ex, request, response,
handler);
}
else if (ex instanceof ConversionNotSupportedException) {
return handleConversionNotSupported((ConversionNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof TypeMismatchException) {
return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotReadableException) {
return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotWritableException) {
return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
}
else if (ex instanceof MethodArgumentNotValidException) {
return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response,
handler);
}
else if (ex instanceof MissingServletRequestPartException) {
return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request,
response, handler);
}
else if (ex instanceof BindException) {
return handleBindException((BindException) ex, request, response, handler);
}
else if (ex instanceof NoHandlerFoundException) {
return handleNoHandlerFoundException((NoHandlerFoundException) ex, request, response, handler);
}
else if (ex instanceof AsyncRequestTimeoutException) {
return handleAsyncRequestTimeoutException(
(AsyncRequestTimeoutException) ex, request, response, handler);
}
}
catch (Exception handlerException) {
if (logger.isWarnEnabled()) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
}
}
return null;
}
/**
*
* @Title: testDefaultHandlerExceptionResolver
* @Description: 测试 DefaultHandlerExceptionResolver 异常
* 如果请求方式为 GET 方式,则抛出DefaultHandlerExceptionResolver 异常
* @param: @return
* @return: String
* @throws
*/
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)
public String testDefaultHandlerExceptionResolver(){
System.out.println("testDefaultHandlerExceptionResolver...");
return "success";
}
SimpleMappingExceptionResolver
/**
*
* @Title: testSimpleMappingExceptionResolver
* @Description: 测试SimpleMappingExceptionResolver 异常
* 如果数组下标越界,则抛出异常
* @param: @param i
* @param: @return
* @return: String
* @throws
*/
@RequestMapping("/testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
String [] vals = new String[10];
System.out.println(vals[i]);
return "success";
}
需在xml中配置异常处理
<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>
出现异常跳转到error.jsp页面
<h4>error Page</h4>
${exception }
发送请求http://localhost:8081/testSimpleMappingExceptionResolver?i=14 此时触发异常
<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
</props>
</property>
</bean>