- 一、错误处理机制
- 二、ErrorPageCustomizer
- 三、BasicErrorController
- 四、DefaultErrorViewResolver
- 五、如何定制错误响应页面
- 六、DefaultErrorAttributes(错误信息)
- 七、defaultErrorView(默认错误视图)
- 八、如何定制JSON数据
跳转到目录 当访问一个不存在
的页面,或者程序抛出异常时
- 浏览器返回一个默认的错误页面, 注意看浏览器发送请求的
请求头
: - 其他(Postman)客户端返回的是
json
数据,注意看请求头
原理:
查看org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
源码,
这里是springboot错误处理的自动配置信息
主要给容器中注册了以下组件:
- ErrorPageCustomizer 系统出现错误以后来到
error请求
进行处理;相当于(web.xml注册的错误页面规则) - BasicErrorController : 处理
/error
请求 - DefaultErrorViewResolver : 默认的错误视图解析器
- DefaultErrorAttributes : 错误信息
- defaultErrorView : 默认错误视图
跳转到目录
- 系统出现错误以后来到
error请求
进行处理;相当于(web.xml注册的错误页面规则) - 也就是说系统出现
4xx
或者5xx
的之类状态码的错误; ErrorPageCustomizer就会生效(定制错误的想赢规则), 就会来到/error请求
在ErrorMvcAutoConfiguration中找到ErrorPageCustomizer
@Bean
public ErrorMvcAutoConfiguration.ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorMvcAutoConfiguration.ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
进入ErrorPageCustomizer
private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
private final ServerProperties properties;
private final DispatcherServletPath dispatcherServletPath;
protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
this.properties = properties;
this.dispatcherServletPath = dispatcherServletPath;
}
//注册错误页面
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
errorPageRegistry.addErrorPages(new ErrorPage[]{errorPage});
}
public int getOrder() {
return 0;
}
}
进入getPath()方法 当请求出现错误后就会转发到/error; 然后这个error请求就会被BasicErrorController处理;
跳转到目录
- 处理
/error
请求
@Bean
@ConditionalOnMissingBean(
value = {ErrorController.class},
search = SearchStrategy.CURRENT
)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(), (List)errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
进入BasicErrorController类
@Controller
/**
* 使用配置文件中server.error.path配置
* 如果server.error.path没有配置使用error.path
* 如果error.path也没有配置就使用/error
*/
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {
这个类下面的方法 上面两个方法一个用于
浏览器请求响应html页面
,一个用于其他客户端请求响应json数据
- 处理浏览器请求的方法中,modelAndView存储到哪个页面的页面地址和页面内容数据
点进resolveErrorView
方法
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map model) {
Iterator var5 = this.errorViewResolvers.iterator();
ModelAndView modelAndView;
do {
if (!var5.hasNext()) {
return null;
}
//所有的ErrorViewResolver得到ModelAndView
ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
modelAndView = resolver.resolveErrorView(request, status, model);
} while(modelAndView == null);
return modelAndView;
}
ErrorViewResolver从哪里来的呢? 已经在容器中注册了一个DefaultErrorViewResolver
跳转到目录
- 响应错误页面, 去哪个页面是由
DefaultErrorViewResolver
解析得到的
@Configuration(
proxyBeanMethods = false
)
static class DefaultErrorViewResolverConfiguration {
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
}
//注册默认错误视图解析器
@Bean
@ConditionalOnBean({DispatcherServlet.class})
@ConditionalOnMissingBean({ErrorViewResolver.class})
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
}
}
进入DefaultErrorViewResolver然后调用ErrorViewResolver的resolveErrorView()
方法
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) {
//把状态码和model传过去获取视图
ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
//上面没有获取到视图就使用把状态吗替换再再找,以4开头的替换为4xx,5开头替换为5xx,见下文(如果定制错误响应)
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map model) {
//viewName传过来的是状态码,例:/error/404
String errorViewName = "error/" + viewName;
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
//模板引擎(thymeleaf)可以解析这个页面地址就用模板引擎解析
return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
}
如果模板引擎不可用,就调用resolveResource
方法获取视图 这里通过 getStaticLocations 可以发现在这里地方也可以获取视图
, 有模板引擎在templates
中获取
private ModelAndView resolveResource(String viewName, Map model) {
//获取的是静态资源文件夹
String[] var3 = this.resourceProperties.getStaticLocations();
int var4 = var3.length;
for(int var5 = 0; var5
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?