009 错误处理

一 .概述

  在springboot之中,为我们的默认的错误处理进行了默认的配置,本此我们来看看错误处理的方式.


二 .错误处理的原理

  我们首先找到错误的动配置类之中.

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
// Load before the main WebMvcAutoConfiguration so that the error View is available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties(ResourceProperties.class)
public class ErrorMvcAutoConfiguration {

我们发现配置信息应该在ResourceProperties在中.

我们现在看看这个自动配置向容器之中添加了什么组件.

    @Bean
    @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
    public DefaultErrorAttributes errorAttributes() {
        return new DefaultErrorAttributes();
    }

添加了一个错误属性的组件.

@Bean
    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
        return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
                this.errorViewResolvers);
    }

添加了一个基本的错误处理器组件.

@Bean
    public ErrorPageCustomizer errorPageCustomizer() {
        return new ErrorPageCustomizer(this.serverProperties);
    }

添加一个错误页的组件.

  @Bean
    public static PreserveErrorControllerTargetClassPostProcessor preserveErrorControllerTargetClassPostProcessor() {
        return new PreserveErrorControllerTargetClassPostProcessor();
    }

添加了一个PostProcessor组件.

@Configuration
    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
        public DefaultErrorViewResolver conventionErrorViewResolver() {
            return new DefaultErrorViewResolver(this.applicationContext,
                    this.resourceProperties);
        }

    }

上面配置了一个错误视图解析器.

当我们的系统之中出现了异常,比如4XX或者5XX的时候,首先会找到一个错误的页面进行处理.

我们可以从下面看到就是去了/error错误的页面.

    @Value("${error.path:/error}")
    private String path = "/error";

然后就是错误处理器进行处理了.

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

我们发现这个错误处理器正好处理的就是/error的请求.

这样就会进行下面的两个处理方式.

@RequestMapping(produces = "text/html")
    public ModelAndView errorHtml(HttpServletRequest request,
            HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
                request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
    }

    @RequestMapping
    @ResponseBody
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request,
                isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = getStatus(request);
        return new ResponseEntity<Map<String, Object>>(body, status);
    }

其中,一个就是处理页面的错误,另外一个就是处理其他设备的请求错误.

那么,这些错误信息都存放在哪里了呢?

DefaultErrorAttributes这个组件帮助我们存放了错误的信息.


三.自定义错误信息

[1]页面请求

  springboot会帮助我们将浏览器的请求转换到4xx.html或者5xx.html页面之中,这个页面需要存在在error文件夹下面.

看下面的实验:

  我们在我们的templates的error里面定义两个页面,一个是4xx.html页面,另外一个就是5xx.html页面.

当我们使用浏览器访问的时候,就会根据错误跳转到不同的页面上.[这个需要视图解析器的支持].

通过这种方式,我们就能完成页面请求的显示了.

[2]在上面我们说到,我们将异常信息存放在DefaultErrorAttributes之中.

另外我们可以使用@ControllerAdvice中添加一个HandlerException进行处理,但是这种方式无法区分是页面请求,还是json请求.

我们就需要进行判断.

我们可以根据produces进行判断,或者我们使用请求转发到/error的请求路径上.

[3]如果需要自定义错误的信息,我们就向容器之中添加一个DefaultErrorAttributes就可以了.


四 .自定义的实例  

@Component
public class ExceptionHandlerConfig implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        // 在这里我们能够完成异常的解析工作,这是比较重要的.
        
        // 重定向到springboot为我们做的一个错误处理器.
        ModelAndView mv = new ModelAndView("forword:/error");
        return mv;
    }

}

我们首先定义一个异常解析器,这个异常解析器的核心就是需要将请求转发到/error之中,这样我们就能使用springboot的默认的错误处理机制.

@Component
public class ErrorAttributesEnhance extends DefaultErrorAttributes{

    @Override
    public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
         
        // 获取父类之中的错误的属性
         Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
         //然后我们可以对这个map进行处理,添加或者删除
         return errorAttributes;
    }
    
}

添加一个异常属性处理存储器,我们可以调用父类获取一些错误的信息,然后可以对这个map进行添加和删除属性.

原文地址:https://www.cnblogs.com/trekxu/p/9740078.html