error601(HttpServletRequest request, HttpServletResponse response) throws AnotherException {
throw new AnotherException();
}
@ExceptionHandler(AnotherException.class)
String handleAnotherException(HttpServletRequest request, HttpServletResponse response, Model model)
throws IOException {
// 需要设置Status Code,否则响应结果会是200
response.setStatus(601);
model.addAllAttributes(errorAttributes.getErrorAttributes(new ServletRequestAttributes(request), true));
return "error/6xx";
}
总结:
1. 没有被HandlerExceptionResolverresolve到的异常会交给容器处理。已知的实现有(按照顺序):
- DefaultErrorAttributes,只负责把异常记录在Request attributes中,name是org.springframework.boot.autoconfigure.web.DefaultErrorAttributes.ERROR
- ExceptionHandlerExceptionResolver,根据@ExceptionHandler resolve
- ResponseStatusExceptionResolver,根据@ResponseStatus resolve
- DefaultHandlerExceptionResolver,负责处理Spring MVC标准异常
2. @ResponseStatus用来规定异常对应的Status Code,其他异常的Status Code由容器决定,在Tomcat里都认定为500(StandardHostValve#L317、StandardHostValve#L345)
3. @ExceptionHandler处理的异常不会经过BasicErrorController,需要自己决定如何返回页面,并且设置Status Code(如果不设置就是200)
4. BasicErrorController会尝试根据Status Code找error page,找不到的话就用Whitelabel error page
本章节代码在me.chanjar.boot.customstatuserrorpage,使用CustomStatusErrorPageExample运行。
利用ErrorViewResolver来定制错误页面
前面讲到BasicErrorController会根据Status Code来跳转对应的error页面,其实这个工作是由DefaultErrorViewResolver完成的。
实际上我们也可以提供自己的ErrorViewResolver来定制特定异常的error页面。
@Component
public class SomeExceptionErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
return new ModelAndView("custom-error-view-resolver/some-ex-error", model);
}
}
不过需要注意的是,无法通过ErrorViewResolver设定Status Code,Status Code由@ResponseStatus或者容器决定(Tomcat里一律是500)。
本章节代码在me.chanjar.boot.customerrorviewresolver,使用CustomErrorViewResolverExample运行。
@ExceptionHandler 和 @ControllerAdvice
前面的例子中已经有了对@ControllerAdvice和@ExceptionHandler的使用,这里只是在做一些补充说明:
- @ExceptionHandler配合@ControllerAdvice用时,能够应用到所有被@ControllerAdvice切到的Controller
- @ExceptionHandler在Controller里的时候,就只会对那个Controller生效
参考文档:
附录I
下表列出哪些特性是Spring Boot的,哪些是Spring MVC的:
Feature |
Spring Boot |
Spring MVC |
BasicErrorController |
Yes |
|
ErrorAttributes |
Yes |
|
ErrorViewResolver |
Yes |
|
@ControllerAdvice |
|
Yes |
@ExceptionHandler |
|
Yes |
@ResponseStatus |
|
Yes |
HandlerExceptionResolver |
|
Yes |