• 16、springboot——错误处理原理+定制错误页面(1)


    一、springboot默认的处理机制

      1.浏览器返回一个错误的页面
      默认处理错误:返回一个错误的页面:
      包括错误类型、时间......
      2.其他客户端访问
      默认响应一个json数据

     

    原理:

    错误自动配置的类:ErrorMvcAutoConfiguration.java

     

     默认配置:

    @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
    )
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
        return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
    }
    
    @Bean
    public ErrorMvcAutoConfiguration.ErrorPageCustomizer errorPageCustomizer() {
        return new ErrorMvcAutoConfiguration.ErrorPageCustomizer(this.serverProperties, this.dispatcherServletPath);
    }
    
    @Bean
    @ConditionalOnBean({DispatcherServlet.class})
    @ConditionalOnMissingBean
    public DefaultErrorViewResolver conventionErrorViewResolver() {
        return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
    }

     1、DefaultErrorAttributes:

    在页面共享信息
    public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = new LinkedHashMap();
        errorAttributes.put("timestamp", new Date());
        errorAttributes.put("path", request.path());
        Throwable error = this.getError(request);
        HttpStatus errorStatus = this.determineHttpStatus(error);
        errorAttributes.put("status", errorStatus.value());
        errorAttributes.put("error", errorStatus.getReasonPhrase());
        errorAttributes.put("message", this.determineMessage(error));
        this.handleException(errorAttributes, this.determineException(error), includeStackTrace);
        return errorAttributes;
    }

    2、BasicErrorController:处理默认/error请求

    @Controller
    @RequestMapping({"${server.error.path:${error.path:/error}}"})
    public class BasicErrorController extends AbstractErrorController {
    
    @RequestMapping(
        produces = {"text/html"}//产生html类型数据,浏览器发送的请求来到这个方法处理
    )
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        
        //去哪个页面作为错误页面,包含页面地址和页面内容
        ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
        return modelAndView != null ? modelAndView : new ModelAndView("error", model);
    }
    
    @RequestMapping   //产生json数据,其他客户端来到这个方法处理;
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = this.getStatus(request);
        return new ResponseEntity(body, status);
    }
    ...
    }

    3、ErrorPageCustomizer:

    public class ErrorProperties {
    @Value("${error.path:/error}")
    private String path = "/error";
    public String getPath() {
        return this.path;
    }
    ...
    }

    4、DefaultErrorViewResolver:

    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        ModelAndView modelAndView = this.resolve(String.valueOf(status.value()), model);
        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<String, Object> model) {
        //默认springboot会找到某个页面   error/404
        String errorViewName = "error/" + viewName;
        //模板引擎可以解析页面地址就使用模板引擎解析
        TemplateAvailabilityProvider provider = 
                    this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
        //模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面
        return provider != null ? new ModelAndView(errorViewName, model) :
     this.resolveResource(errorViewName, model);
    }

    步骤:

    一但系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);
    就会来到/error请求,就会被BasicErrorController进行处理
    1)响应页面(resolveErrorView方法)去哪个页面是由DefaultErrorViewResolver解析得到的
    protected ModelAndView resolveErrorView(HttpServletRequest request, 
    HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
        //所有的ErrorViewResolver得到ModelAndView
        Iterator var5 = this.errorViewResolvers.iterator();
        ModelAndView modelAndView;
        do {
            if (!var5.hasNext()) {
                return null;
            }
            ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
            modelAndView = resolver.resolveErrorView(request, status, model);
        } while(modelAndView == null);
        return modelAndView;
    }

  • 相关阅读:
    BZOJ 3196 二逼平衡树
    BZOJ 4241 历史研究
    Problem 71:Ordered fractions
    矿工安全生产
    Codeforces 771C:Bear and Tree Jumps
    Problem 77:Prime summations
    Problem 69:Totient maximum
    关于Euclid算法
    团体程序设计天梯赛-练习集
    埃蒙的时空航道
  • 原文地址:https://www.cnblogs.com/lyh233/p/12527639.html
Copyright © 2020-2023  润新知