14、SpringBoot-CRUD错误处理机制(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; }