spring boot默认异常处理机制精讲 以及如何自定义异常消息,页面
spring boot默认处理机制精讲 以及如何自定义异常消息,页面
SpringBoot默认的错误处理机制
默认效果:
1)、浏览器,返回一个默认的错误页面
2)、如果是其他客户端,默认响应一个json数据
原理
在spring boot中,关于错误的自动配置类是 ErrorMvcAutoConfiguration
这个自动配置类, 给容器中加入了这几个关键组件:
-
ErrorPageCustomizer:
这个类的作用是定制错误的响应规则。在它的的registerErrorPages方法里的getPath方法指定了处理错误默认发送的请求为/error请求 -
BasicErrorController:
这个类就是来处理/error请求的,它有如下两个方法:这个类就是来处理/error请求的,它有如下两个方法:
@RequestMapping(produces = "text/html") // 指定响应HTML数据
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) ? modelAndView : new ModelAndView("error", model);
}
@RequestMapping
@ResponseBody // 指定响应json数据
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);
}
spring boot 默认处理/error请求时,会根据响应头来判断发送请求的是浏览器还是app,然后响应HTML或者json数据。
浏览器这部分代码处理完请求之后返回了一个ModelAndView 指定响应的页面,这个页面回去resolveErrorView这个方法里面找。
protected ModelAndView resolveErrorView(HttpServletRequest request,
HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
这个方法遍历所有的ErrorViewResolver,从这里面找返回的页面。在没有指定的情况下,默认来到了第三个注入的组件
-
DefaultErrorViewResolver
这个组件的作用是指定浏览器响应的错误页面。这个组件的作用是指定浏览器响应的错误页面。
我们来看他是如何指定的:
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model) {
// 将状态码转换为视图名称
ModelAndView modelAndView = resolve(String.valueOf(status), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
可以看出,默认是将响应的状态码指定为视图名称,也就是说我们如果想自定义浏览器的错误响应页面,只需要在静态资源文件夹下创建4xx, 5xx等页面,当发生对应状态码异常时就会来到对应页面。
如何定制错误信息
定制浏览器错误页面
- 没有模板引擎的情况下
error/状态码 :将错误页面命名为 错误状态码.html 放在静态资源文件夹里面的 error文件夹下,发生此状态码的错误就会来到对应的页面。
ps:如果建立名为4xx.html的文件,当发生以4开头的状态码错误时,在没有被精确匹配的情况下,就会来到这个页面。 - 有模板引擎的情况下
当然要把错误状态码.html文件放在模板引擎文件夹下。
有模板引擎的优势在于:你可在错误页面获取一些讯息:- status:状态码
- timestamp:时间戳
- error:错误提示
- exception:异常对象
- message:异常消息
- errors:JSR303数据校验的错误都在这里
- 如果以上两个地方都没找到,就会来到默认一开始的页面。
定制json错误消息
假设我们现在有一个UserNotExistException
public class UserNotExistException extends RuntimeException {
private String id;
public String getId() {
return id;
}
public UserNotExistException(String id) {
super("用户不存在");
this.id = id;
}
}
我们可以利用springMvc的ControllerAdvice来定制这个异常的处理
@ControllerAdvice // 这是一个专门处理异常的Controller
public class ControllerExceptionHandler {
@ExceptionHandler(UserNotExistException.class) // 这个方法处理UserNotExistException异常
@ResponseBody // 已json的形式返回
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 指定响应的错误状态码为404,不指定默认是200
public Map<String, Object> handleUserNotExistException(UserNotExistException ex) {
Map<String, Object> result = new HashMap<>();
result.put("id", ex.getId());
result.put("message", ex.getMessage());
return result;
}
}
这么写,我们app端访问该异常时能够正确返回我们定制的json数据。
但是存在一个问题:浏览器出现该异常时返回的也是json数据,而不是我们定制的404.html页面,失去了spring boot默认的自适应效果。