一、SpringBoot默认的错误处理机制
1.1原理
可以参照ErrorMvcAutoConfiguration错误处理的自动配置,给容器中添加了一下组件:
@Bean
@ConditionalOnMissingBean(
value = {ErrorAttributes.class},
search = SearchStrategy.CURRENT
)
// 帮我们在页面定制错误信息
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
@Bean
@ConditionalOnMissingBean(
value = {ErrorController.class},
search = SearchStrategy.CURRENT
)
//处理 /error请求
// 产生HTML类型数据,产生json数据
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider<ErrorViewResolver> errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(), (List)errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
@Bean
//系统出现错误以后来到error请求进行处理
public ErrorMvcAutoConfiguration.ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorMvcAutoConfiguration.ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
@Bean
@ConditionalOnBean({DispatcherServlet.class})
@ConditionalOnMissingBean({ErrorViewResolver.class})
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
}
1.2步骤
一旦系统出现4××或5××之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),就会来到/error请求,就会被BasicErrorController处理
1)响应页面,去哪个页面是由 DefaultErrorViewResolver 得到的
二、定制错误响应
2.1定制HTML数据
2.1.1有模板引擎的情况下
error/状态码【将错误页面命名为 错误状态码.html放在模板引擎文件夹里面的error文件夹下】,当发生此状态码的错误就会来到 对应的页面。
我们可以使用4××或5××作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html)
页面能获取到的信息:
timestamp : 时间戳
status : 状态码
error : 错误提示
exception : 异常对象
message : 异常消息
errors : JSR303数据校验的错误在这里
如:
<h1>status:[[${status}]]</h1>
<h2>timestamp:[[${timestamp}]]</h2>
2.1.2没有模板引擎
模板引擎找不到这个错误页面,静态资源文件夹下找,只不过不会动态显示信息。
2.1.3以上都没有错误页面,就是默认来到springboot默认的错误提示页面。
2.2定制JSON数据
2.2.1浏览器服务器返回的都是json
2.2.2自适应
转发到 /error进行自适应响应效果处理
@ExceptionHandler(UserNotExistException.class)
public String handlerException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
map.put("code","user.no.exist");
map.put("message",e.getMessage());
//传入自己的错误状态码 否则就不会进入定制错误页面的解析流程
request.setAttribute("javax.servlet.error.status_code","400");
//转发到 /error
return "forward:/error";
}
2.2.3定制数据携带出去
出现错误以后,会来到/error请求,会被 BasicErrorController处理,响应出去可以获取的数据是由getErrorAttributes得到的(是AbstractErrorController(ErrorController)规定的方法);
1)、可以完全来编写一个ErrorController的实现类【或者编写AbstractErrorController】,放在容器中。 --麻烦
2)、页面上能用的数据,或者json返回能调用的数据都是通过errorAttributes.getErrorAttributes得到。 --使用
//给容器加入我们自定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
map.put("comapny","tchuhu");
//我们异常处理器携带的数据
Map<String, Object> ext =(Map<String, Object>) webRequest.getAttribute("ext", 0);
map.put("ext",ext);
return super.getErrorAttributes(webRequest, includeStackTrace);
}
}
效果:
<h1>status:[[${status}]]</h1>
<h2>timestamp:[[${timestamp}]]</h2>
<h2>exception:[[${exception}]]</h2>
<h2>message:[[${message}]]</h2>
<h2>ext:[[${ext.code}]]</h2>
<h2>ext:[[${ext.message}]]</h2>