SpringBoot入门---错误页面原理解析

springboot错误页面原理

以下会提到的重点类:

  • BasicErrorController 基础错误控制器

  • DefaultErrorViewResolver 默认错误视图解析器

  • DefaultErrorAttributes 默认错误属性类

  • ErrorPageCustomizer 错误页面定制器

ErrorMvcAutoConfiguration 错误mvc自动配置类

package org.springframework.boot.autoconfigure.web.servlet.error;

/**
 * {@link EnableAutoConfiguration Auto-configuration} 通过MVC错误控制器呈现错误
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({
    Servlet.class, DispatcherServlet.class })
// 在主WebMvcAutoConfiguration之前加载,以便可以使用错误视图
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({
    ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {
   

   // Web服务器的{@link ConfigurationProperties @ConfigurationProperties}(例如端口和路径设置)。
   private final ServerProperties serverProperties;

   // 构造器,需要传入ServerProperties
   public ErrorMvcAutoConfiguration(ServerProperties serverProperties) {
   
      this.serverProperties = serverProperties;
   }

   //  默认错误属性类。ErrorAttributes的默认实现。为错误视图提供错误信息等属性。
   @Bean
   @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
   public DefaultErrorAttributes errorAttributes() {
   
      return new DefaultErrorAttributes();
   }

   /*
       基本的全局错误Controller,呈现ErrorAttributes(在这里指DefaultErrorAttributes)。可以使用Spring MVC抽象(例如@ExceptionHandler)或添加Servlet(AbstractServletWebServerFactory#setErrorPages服务器错误页面)来处理更具体的错误。
   */
   @Bean
   @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
   public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
         ObjectProvider<ErrorViewResolver> errorViewResolvers) {
   
      return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
            errorViewResolvers.orderedStream().collect(Collectors.toList()));
   }

   // WebServerFactoryCustomizer,用于配置服务器的错误页面。
   @Bean
   public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
   
      return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
   }

   // BeanFactoryPostProcessor,以确保在使用AOP时保留ErrorController MVC bean的目标类。
   @Bean
   public static PreserveErrorControllerTargetClassPostProcessor preserveErrorControllerTargetClassPostProcessor() {
   
      return new PreserveErrorControllerTargetClassPostProcessor();
   }

   // 默认错误视图解析器配置
   @Configuration(proxyBeanMethods = false)
   static class DefaultErrorViewResolverConfiguration {
   

      // ioc容器
      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);
      }

   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
   @Conditional(ErrorTemplateMissingCondition.class)
   protected static class WhitelabelErrorViewConfiguration {
   

      private final StaticView defaultErrorView = new StaticView();

      @Bean(name = "error")
      @ConditionalOnMissingBean(name = "error")
      public View defaultErrorView() {
   
         return this.defaultErrorView;
      }

      // 如果用户添加@EnableWebMvc,则WebMvcAutoConfiguration中的bean名称视图解析器将消失,因此请重新添加它以避免失效。
      @Bean
      @ConditionalOnMissingBean
      public BeanNameViewResolver beanNameViewResolver() {
   
         BeanNameViewResolver resolver = new BeanNameViewResolver();
         resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
         return resolver;
      }

   }

   /**
    * SpringBootCondition 在未检测到错误模板视图时匹配
    * 缺少错误模板类
    */
   private static class ErrorTemplateMissingCondition extends SpringBootCondition {
   

      @Override
      public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
   
         ConditionMessage.Builder message = ConditionMessage.forCondition("ErrorTemplate Missing");
         TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(context.getClassLoader());
         TemplateAvailabilityProvider provider = providers.getProvider("error", context.getEnvironment(),
               context.getClassLoader(), context.getResourceLoader());
         if (provider != null) {
   
            return ConditionOutcome.noMatch(message.foundExactly("template from " + provider));
         }
         return ConditionOutcome.match(message.didNotFind("error template view").atAll());
      }

   }

   /**
    * 简单的View(视图)实现,可编写默认的HTML错误页面。
    * 如果没有找到错误模板视图、静态html的话,就会调用这个类,生成一段错误文本返回。
    */
   private static class StaticView implements View {
   

      private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html", StandardCharsets.UTF_8);

      private static final Log logger = LogFactory.getLog(StaticView.class);

      /* 
        在DispatcherServlet类中的render()方法中调用view.render(mv.getModelInternal(), request, response),然后跳转到这里。
        渲染简易文本错误视图。
      */
      @Override
      public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
            throws Exception {
   
         if (response.isCommitted()) {
   
            String message = getMessage(model);
            logger.error(message);
            return;
         }
         // 设置ContentType返回头
         response.setContentType(TEXT_HTML_UTF8.toString());
         StringBuilder builder = new StringBuilder();
         // 时间戳
         Date timestamp = (Date) model.get("timestamp");
         // 错误消息
         Object message = model.get("message");
         Object trace = model.get("trace");
         if (response.getContentType() == null) {
   
            response.setContentType(getContentType());
         }
         builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
               "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
               .append("<div id='created'>").append(timestamp).append("</div>")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值