科技创新的评价机制的作用,南京seo公司哪家好,济南做网站的公司有哪些,莱芜地板街50一次SpringBoot错误处理----源码解析 文章目录 1、默认机制2、使用ExceptionHandler标识一个方法#xff0c;处理用Controller标注的该类发生的指定错误1#xff09;.局部错误处理部分源码2#xff09;.测试 3、 创建一个全局错误处理类集中处理错误#xff0c;使用Controller…SpringBoot错误处理----源码解析 文章目录 1、默认机制2、使用ExceptionHandler标识一个方法处理用Controller标注的该类发生的指定错误1.局部错误处理部分源码2.测试 3、 创建一个全局错误处理类集中处理错误使用ControllerAdvice注解标注1.全局错误处理部分源码3.测试 4、SpringMVC错误处理未能处理上述处理不存在1、SpringBoot中自动配置的错误处理机制基于ErrorMvcAutoConfiguration自动配置实现2、 BasicErrorController组件规则如下 5、自定义错误响应6、测试1、在项目的resources/templates/目录下创建一个error文件夹放入4xx.html、5xx.html2、在项目的resources/templates/error文件夹中再放入404.html、500.html3、浏览器先后测试上述情况 1、默认机制
SpringBoot错误处理的自动配置都在ErrorMvcAutoConfiguration中两大核心机制 1.SpringBoot会自适应处理错误响应页面或JSON数据 2.SpringMVC的错误处理机制依然保留MVC处理不了才会交给SpringBoot进行处理。 图片来自尚硅谷
2、使用ExceptionHandler标识一个方法处理用Controller标注的该类发生的指定错误
默认只能处理这个类的该指定错误
// ExceptionHandler源码
Target({ElementType.METHOD}) // 指定了该注解仅能用于方法
Retention(RetentionPolicy.RUNTIME) //指定了注解会在运行时保留这允许通过反射在运行时获取对注解的访问
Documented //注解应该被包含在生成的 JavaDoc 文档中
Reflective({ExceptionHandlerReflectiveProcessor.class})
public interface ExceptionHandler {Class? extends Throwable[] value() default {}; //它定义了一个名为 value 的属性其类型是一个 Class 数组这个数组的元素必须是 Throwable 类或其子类。通过使用这个注解时可以为 value 属性提供一个 Throwable 类型的数组
}1.局部错误处理部分源码
Controller //适配服务端渲染 前后不分离模式开始
public class WelcomeController {//来到首页GetMapping(/)public String index(){int i10/0; //制造错误return index;}ResponseBody //返回的字符串应该直接作为 HTTP 响应体的内容而不是作为视图名称解析。通常用于返回 JSON 或纯文本等非HTML内容ExceptionHandler(Exception.class) //传递到value数组中public String handleException(Exception e){return Ohho~~~原因e.getMessage();}}2.测试 1.启动项目浏览器访问http://localhost:8080/ 2.测试结果成功处理错误
3、 创建一个全局错误处理类集中处理错误使用ControllerAdvice注解标注
这个类是集中处理所有Controller 发生的错误
//ControllerAdvice源码
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Component //标记类为一个 Spring 组件
public interface ControllerAdvice {AliasFor(annotation Component.class,attribute value)String name() default ;AliasFor(basePackages)String[] value() default {};AliasFor(value)String[] basePackages() default {};Class?[] basePackageClasses() default {};Class?[] assignableTypes() default {};Class? extends Annotation[] annotations() default {};
}1.全局错误处理部分源码
ControllerAdvice //这个类是集中处理所有Controller发生的错误
public class GlobalExceptionHandler {ResponseBodyExceptionHandler(Exception.class)public String handleException(Exception e){return Ohho~~~统一处理所有错误原因e.getMessage();}
}###2.再创建一个类使用Controller注解标注
Controller
public class HelloController {GetMapping(/haha)public String haha(){int i 10/0; //制造错误return index;}
}3.测试
1.启动项目浏览器访问http://localhost:8080/2.测试结果成功处理错误就近原则执行的是Controller类中标注了ExceptionHandler方法的处理 3.浏览器访问http://localhost:8080/haha全局错误处理类进行处理
4、SpringMVC错误处理未能处理上述处理不存在
第一阶段的处理未解决错误转发到/error执行后续处理图中第一阶段失效第二阶段处理以下测试过程中注释掉上文中的全局和局部处理代码
1、SpringBoot中自动配置的错误处理机制基于ErrorMvcAutoConfiguration自动配置实现
在ErrorMvcAutoConfiguration自动装配类中SpringBoot在底层写好一个 BasicErrorController的组件专门处理/error这个请求部分源码如下
AutoConfiguration(before WebMvcAutoConfiguration.class) //指定了该自动配置类在 WebMvcAutoConfiguration 之前进行配置
ConditionalOnWebApplication(type Type.SERVLET) //只有在当前应用是一个 Servlet Web 应用时这个自动配置才会生效
ConditionalOnClass({ Servlet.class, DispatcherServlet.class }) //只有当类路径中存在 Servlet 和 DispatcherServlet 时这个自动配置才会生效
EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class }) //启用指定类的配置属性绑定
public class ErrorMvcAutoConfiguration {private final ServerProperties serverProperties; //注入了 ServerProperties 实例。这样的构造方法注入是为了获取应用程序的服务器配置public ErrorMvcAutoConfiguration(ServerProperties serverProperties) {this.serverProperties serverProperties; //注入 ServerProperties 实例}//容器中不存在 ErrorAttributes 类型的 Bean 时才会创建并注册当前方法所返回的 BeanBeanConditionalOnMissingBean(value ErrorAttributes.class, search SearchStrategy.CURRENT)public DefaultErrorAttributes errorAttributes() {return new DefaultErrorAttributes();}//在容器中不存在 ErrorController 类型的 Bean 时才会创建并注册当前方法所返回的 BeanBeanConditionalOnMissingBean(value ErrorController.class, search SearchStrategy.CURRENT)public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,ObjectProviderErrorViewResolver errorViewResolvers) {return new BasicErrorController(errorAttributes, this.serverProperties.getError(),errorViewResolvers.orderedStream().toList());}...
}2、 BasicErrorController组件
SpringBoot中默认的server.error.path/error即该类就是处理/error请求的根据不同类型的请求如果产生 HTML 内容的请求匹配public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) 这个方法否则其他请求类型匹配public ResponseEntityMapString, Object error(HttpServletRequest request)方法。分别进行处理。只会匹配其中一个Spring MVC会尝试匹配与请求路径最匹配的RequestMapping
1.部分源码
Controller
RequestMapping(${server.error.path:${error.path:/error}})
public class BasicErrorController extends AbstractErrorController {private final ErrorProperties errorProperties;/*** Create a new {link BasicErrorController} instance.* param errorAttributes the error attributes* param errorProperties configuration properties*/public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {this(errorAttributes, errorProperties, Collections.emptyList());}/*** Create a new {link BasicErrorController} instance.* param errorAttributes the error attributes* param errorProperties configuration properties* param errorViewResolvers error view resolvers*/public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties,ListErrorViewResolver errorViewResolvers) {super(errorAttributes, errorViewResolvers);Assert.notNull(errorProperties, ErrorProperties must not be null);this.errorProperties errorProperties;}RequestMapping(produces MediaType.TEXT_HTML_VALUE) //请求类型为HTML 文本public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status getStatus(request);MapString, Object model Collections.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView resolveErrorView(request, response, status, model);return (modelAndView ! null) ? modelAndView : new ModelAndView(error, model);}RequestMappingpublic ResponseEntityMapString, Object error(HttpServletRequest request) {HttpStatus status getStatus(request);if (status HttpStatus.NO_CONTENT) {return new ResponseEntity(status);}MapString, Object body getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));return new ResponseEntity(body, status);}...
}2.匹配成功之后错误页面解析的核心代码 //1、解析错误的自定义视图地址
ModelAndView modelAndView resolveErrorView(request, response, status, model);
//2、如果解析不到错误页面的地址默认的错误页就是 error
return (modelAndView ! null) ? modelAndView : new ModelAndView(error, model);3.在ErrorMvcAutoConfiguration自动装配类中SpringBoot在底层写好一个 DefaultErrorViewResolver的组件注入到了容器中 Configuration(proxyBeanMethods false)EnableConfigurationProperties({ WebProperties.class, WebMvcProperties.class })static class DefaultErrorViewResolverConfiguration {private final ApplicationContext applicationContext;private final Resources resources;DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext, WebProperties webProperties) {this.applicationContext applicationContext;this.resources webProperties.getResources();}BeanConditionalOnBean(DispatcherServlet.class)ConditionalOnMissingBean(ErrorViewResolver.class)DefaultErrorViewResolver conventionErrorViewResolver() {return new DefaultErrorViewResolver(this.applicationContext, this.resources);}}4.在DefaultErrorViewResolver中定义了错误页的默认规则功能如下 如果在类路径下查看是否存在 error/错误码 的页面存在就返回该视图否则去4个CLASSPATH_RESOURCE_LOCATIONS路径下查看是否写了 error/错误码.html 的页面存在则返回该视图都不存在则modelAndViewnull;则判断是否有 error/4xx 或者 error/5xx 的页面存在则返回该视图否则去4个CLASSPATH_RESOURCE_LOCATIONS路径下查看是否写了 error/4xx.html 或者 error/5xx.html 的页面存在则返回该视图 public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {...private static final MapSeries, String SERIES_VIEWS;static {MapSeries, String views new EnumMap(Series.class);views.put(Series.CLIENT_ERROR, 4xx);views.put(Series.SERVER_ERROR, 5xx);SERIES_VIEWS Collections.unmodifiableMap(views);}// 查看是否存在 error/错误码 的页面存在就返回该视图// 不存在则判断是否有 error/4xx 或者 error/5xx 的页面存在则返回该视图Overridepublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, MapString, Object model) {ModelAndView modelAndView resolve(String.valueOf(status.value()), model);if (modelAndView null SERIES_VIEWS.containsKey(status.series())) {modelAndView resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;}// 在类路径下查看是否存在 error/错误码 的模板引擎存在就返回该视图// 否则去下面的4个CLASSPATH_RESOURCE_LOCATIONS路径下查看是否写了 error/错误码.html 的页面存在则返回该视图private ModelAndView resolve(String viewName, MapString, Object model) {String errorViewName error/ viewName;TemplateAvailabilityProvider provider this.templateAvailabilityProviders.getProvider(errorViewName,this.applicationContext);if (provider ! null) {return new ModelAndView(errorViewName, model);}return resolveResource(errorViewName, model);}//去下面的4个CLASSPATH_RESOURCE_LOCATIONS路径下查看是否写了 error/错误码.html 的页面存在则返回该视图//this.resources.getStaticLocations()//private static final String[] CLASSPATH_RESOURCE_LOCATIONS { classpath:/META-INF/resources/,// classpath:/resources/, classpath:/static/, classpath:/public/ };private ModelAndView resolveResource(String viewName, MapString, Object model) {for (String location : this.resources.getStaticLocations()) {try {Resource resource this.applicationContext.getResource(location);resource resource.createRelative(viewName .html);if (resource.exists()) {return new ModelAndView(new HtmlResourceView(resource), model);}}catch (Exception ex) {}}return null;}...
}5.在ErrorMvcAutoConfiguration自动装配类中向容器中放入了一个默认名为error的视图提供了默认的白页功能如果上述都无法处理 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();// 注入了error视图Bean(name error)ConditionalOnMissingBean(name error)public View defaultErrorView() {return this.defaultErrorView;}// If the user adds EnableWebMvc then the bean name view resolver from// WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.BeanConditionalOnMissingBeanpublic BeanNameViewResolver beanNameViewResolver() {BeanNameViewResolver resolver new BeanNameViewResolver();resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);return resolver;}}默认的白页源码就在类ErrorMvcAutoConfiguration中定义的 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);Overridepublic void render(MapString, ? model, HttpServletRequest request, HttpServletResponse response)throws Exception {if (response.isCommitted()) {String message getMessage(model);logger.error(message);return;}response.setContentType(TEXT_HTML_UTF8.toString());StringBuilder builder new StringBuilder();Object timestamp model.get(timestamp);Object message model.get(message);Object trace model.get(trace);if (response.getContentType() null) {response.setContentType(getContentType());}builder.append(htmlbodyh1Whitelabel Error Page/h1).append(pThis application has no explicit mapping for /error, so you are seeing this as a fallback./p).append(div idcreated).append(timestamp).append(/div).append(divThere was an unexpected error (type).append(htmlEscape(model.get(error))).append(, status).append(htmlEscape(model.get(status))).append()./div);if (message ! null) {builder.append(div).append(htmlEscape(message)).append(/div);}if (trace ! null) {builder.append(div stylewhite-space:pre-wrap;).append(htmlEscape(trace)).append(/div);}builder.append(/body/html);response.getWriter().append(builder.toString());}private String htmlEscape(Object input) {return (input ! null) ? HtmlUtils.htmlEscape(input.toString()) : null;}private String getMessage(MapString, ? model) {Object path model.get(path);String message Cannot render error page for request [ path ];if (model.get(message) ! null) {message and exception [ model.get(message) ];}message as the response has already been committed.;message As a result, the response may have the wrong status code.;return message;}Overridepublic String getContentType() {return text/html;}}6.在ErrorMvcAutoConfiguration自动装配类中封装了JSON格式的错误信息(初始化了错误的类型、错误的状态码、路径、栈信息、时间戳等信息) Bean
ConditionalOnMissingBean(value ErrorAttributes.class, search SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {return new DefaultErrorAttributes();
}规则如下 1.解析一个错误页 如果发生了500、404、503、403 这些错误 如果有模板引擎默认在 classpath:/templates/error/精确码.html 如果没有模板引擎在静态资源文件夹下找 精确码.html 如果匹配不到精确码.html这些精确的错误页就去找5xx.html4xx.html模糊匹配 如果有模板引擎默认在 classpath:/templates/error/5xx.html 如果没有模板引擎在静态资源文件夹下找 5xx.html 2.如果模板引擎路径templates下有 error.html页面就直接渲染
5、自定义错误响应
1) 自定义json响应使用文章第2和第3部分介绍的使用注解进行统一的异常处理
2自定义页面响应根据第4部分介绍的规则在对应的项目路径classpath:/METAINF/resources/,classpath:/resources/,classpath:/static/, classpath:/public/或者模板引擎目录下定义错误页面即可。
6、测试
1、在项目的resources/templates/目录下创建一个error文件夹放入4xx.html、5xx.html
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body4xx.html
/body
/html!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
5xx.html
/body
/html2、在项目的resources/templates/error文件夹中再放入404.html、500.html
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
404.html
/body
/html!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body
500.html
/body
/html3、浏览器先后测试上述情况
1.访问一个不存在的路径2.制造除0错误。