您当前的位置: 首页 >  spring

white camel

暂无认证

  • 1浏览

    0关注

    442博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

SpringBoot——错误处理机制 & 定制错误页面 (源码分析)

white camel 发布时间:2020-04-23 19:45:55 ,浏览量:1

目录
  • 一、错误处理机制
  • 二、ErrorPageCustomizer
  • 三、BasicErrorController
  • 四、DefaultErrorViewResolver
  • 五、如何定制错误响应页面
  • 六、DefaultErrorAttributes(错误信息)
  • 七、defaultErrorView(默认错误视图)
  • 八、如何定制JSON数据

在这里插入图片描述

一、错误处理机制

跳转到目录 当访问一个不存在的页面,或者程序抛出异常时

1、默认效果
  • 浏览器返回一个默认的错误页面, 注意看浏览器发送请求的请求头: 在这里插入图片描述
  • 其他(Postman)客户端返回的是json数据,注意看请求头 在这里插入图片描述

原理:

查看org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration源码,

这里是springboot错误处理的自动配置信息

主要给容器中注册了以下组件:

  • ErrorPageCustomizer 系统出现错误以后来到error请求进行处理;相当于(web.xml注册的错误页面规则)
  • BasicErrorController : 处理/error请求
  • DefaultErrorViewResolver : 默认的错误视图解析器
  • DefaultErrorAttributes : 错误信息
  • defaultErrorView : 默认错误视图
二、ErrorPageCustomizer

跳转到目录

  • 系统出现错误以后来到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处理;

三、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

跳转到目录

  • 响应错误页面, 去哪个页面是由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             
关注
打赏
1661428283
查看更多评论
0.0400s