Spring boot 处理 error 的基本流程:
Controller -> 发生错误 -> BasicErrorController -> 根据 @RequestMapping(produces) 判断调用 errorHtml 或者 error 方法
然后:
errorHtml -> getErrorAttributes -> ErrorViewResolver -> 错误显示页面
error -> getErrorAttributes -> @ResponseBody (直接返回JSON)
如果想要定制一些东西,按照官方文档的建议可以:
1.继承 BasicErrorController 扩展处理一个新的 content type
2.自定义 ErrorAttributes 获得自己想要的结果集
3.实现 ErrorViewResolver 接口,自定义错误显示视图
Spring boot 默认使用 DefaultErrorViewResolver 作为 ErrorViewResolver 的实现,并配置了 4xx, 5xx 视图
一般的,并不需要扩展上面的内容,通常情况下,下面两种方式可以应对大部分场景
注意:如 404 等是通过 Servlet (DispatcherServlet.noHandlerFound) 的处理并返回 response ( response.sendError) ,并未到达 Controller 层,所以并不能捕获到。
1.捕获异常:
使用 @ControllerAdvice 与 @ExceptionHandler 捕获异常并处理(返回自定义json对象或是页面视图,将替代 ErrorAttributes、ErrorViewResolver)
2.直接提供相应错误显示视图一、使用@ControllerAdvice
此方式只会处理Controller异常,其它异常仍会用SpringBoot默认异常处理方式。@RestControllerAdvice返回json
/**
* 全局异常,类似spring处理
* @author WANGJS-PC
*
*/
@ControllerAdvice
public class GlobalDefaultExceptionHandler {
/**
* 处理 Exception 类型的异常
* 方法名为任意名,入参一般使用 Exception 异常类,方法返回值可自定义。
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String, Object> defaultExceptionHandler(Exception e) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", 500);
map.put("msg", e.getMessage());
return map;
}
二、
在templates下新建error文件夹,新建404,400等html,遇到此错误会自动跳转到此html。
默认会从templates、static、public下依次寻找。
三、继承BasicErrorController
也可以继承AbstractErrorController,仿照BasicErrorController重写此类。BasicErrorController是SpringBoot提供的一个处理异常的类。可以继承他扩展,也可以自己完全重写。
关键的两个方法:
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections
.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
可以根据状态码返回内容。重写此类注册到容器中(添加@Component或@Controller即可),二会失效,不会自动跳转html。
四、自定义异常处理路径 ErrorPageRegistry
/**
* 自定义异常处理路径 ErrorPageRegistry
*
* @return
*/
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/test/1234"));
configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST,
"/test/400"));
configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(
HttpStatus.INTERNAL_SERVER_ERROR,"/test/500"));
configurableEmbeddedServletContainer.addErrorPages(new ErrorPage(
java.lang.Throwable.class, "/test/500"));
}
};
}
注册这个bean(二也会失效),然后添加相应Controller即可。