首页 > 编程语言 > 详细

springboot错误处理机制及自定义错误处理

时间:2020-03-13 17:37:10      阅读:111      评论:0      收藏:0      [点我收藏+]

springboot对于404,500等错误处理非常人性化,如果你是用浏览器访问的就返回一个页面,如果是客户端就会返回json数据,如下

{
    "timestamp": "2020-03-13T08:24:41.493+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/crud/aaa"
}

下面我们来简单的研究下原理,先看下错误处理器的自动配置类

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
// 可以看出这个配置类是在webmvc自动配置之前加载的,这里主要加载了下面两个组件
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {

  //将放回的错误信息封装进入默认的错误属性中
   @Bean
     @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
    public DefaultErrorAttributes errorAttributes() {
        return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
    }

      //处理错误信息的controller
  @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()));
  }
  
  //默认的错误页面定制器
  @Bean
  public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
  return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
  }
  //默认错误映射处理器
  @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);
  }

  }
}

而这个DefaultErrorAttributes类中,这个五个属性的添加正好和我们接收的json数据一一对应,错误信息就是封装到这里边的

public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {

    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = new LinkedHashMap();
        errorAttributes.put("timestamp", new Date());//timestamp
        this.addStatus(errorAttributes, webRequest);//status
        this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);//error,message
        this.addPath(errorAttributes, webRequest);//path
        return errorAttributes;
    }
}

我们再来看下BasicErrorController这个基础错误处理器

//处理所有的/error请求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
//如果请求头接受方式为text/html,就是浏览器发送的,返回modelAndView就是默认的错误页面
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    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) ? modelAndView : new ModelAndView("error", model);
    }

        //其余的请求方式呢,返回json数据
    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity<Map<String, Object>>(status);
        }
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        return new ResponseEntity<>(body, status);
    }
}

那么每当我们的请求发生错误或者异常时,是如何重定向到/error呢?DefaultErrorViewResolver 中

public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {

    private static final Map<Series, String> SERIES_VIEWS;

    static {
        Map<Series, String> views = new EnumMap<>(Series.class);
        views.put(Series.CLIENT_ERROR, "4xx");
        views.put(Series.SERVER_ERROR, "5xx");
        SERIES_VIEWS = Collections.unmodifiableMap(views);
    }
  private ModelAndView resolve(String viewName, Map<String, Object> model) {
    //默认SpringBoot可以去找到一个页面? error/404
    String errorViewName = "error/" + viewName;
    //模板引擎可以解析这个页面地址就用模板引擎解析
    TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
    if (provider != null) {
      //模板引擎可用的情况下返回到errorViewName指定的视图地址
      return new ModelAndView(errorViewName, model);
    }
    //模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html
    return resolveResource(errorViewName, model);
  }

}

这个就会去/error/4xx.html或者/error/5xx.html,都没有返回默认页面

 

springboot错误处理机制及自定义错误处理

原文:https://www.cnblogs.com/vegeta-xiao/p/12487620.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!