摘要:本文主要介绍了Springboot里面如何自定义错误页面、异常数据、异常视图以及异常的源码分析。
自定义错误页面
当我们没有自定义错误页面时,Springboot会为我们自动配置一个异常页面。如果我们想自定义错误页面,则需要提供 /error 路径 ,不过在 Spring Boot 中,提供 /error 路径实际上是下下策,Spring Boot 本身在处理异常时,也是当所有条件都不满足时,才会去找 /error 路径。那么我们就先来看看,在 Spring Boot 中,如何自定义 error 页面,整体上来说,可以分为两种,一种是静态页面,另一种是动态页面。
静态页面
自定义静态异常页面,又分为两种,第一种 是使用 HTTP 响应码来命名页面,例如 404.html、405.html、500.html ….,另一种就是直接定义一个 4xx.html,表示400-499 的状态都显示这个异常页面,5xx.html 表示 500-599 的状态显示这个异常页面。默认是在classpath:/static/error/
路径下定义静态页面。
动态页面
动态的异常页面定义方式和静态的基本 一致,可以采用的页面模板有 jsp、freemarker、thymeleaf。动态异常页面,也支持 404.html 或者 4xx.html ,但是一般来说,由于动态异常页面可以直接展示异常详细信息,所以就没有必要挨个枚举错误了 ,直接定义 4xx.html(这里使用thymeleaf模板)或者 5xx.html 即可。
错误页面显示的优先级
那么自定义的错误页面也是有优先级的,精确 > 模糊,动态 > 静态。
自定义异常数据
我们首先来看一下ErrorMvcAutoConfiguration这个类,这里有一个方法叫errorAttributes,返回一个DefaultErrorAttributes
1 2 3 4 5
| @Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException()); }
|
该方法为我们创建了默认的异常数据,其生效的条件是@ConditionalOnMissingBean,即没有提供自定义的异常数据。而我们再看DefaultErrorAttributes类中获取异常信息的方法。
1 2 3 4 5 6 7 8 9
| @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map<String, Object> errorAttributes = new LinkedHashMap<>(); errorAttributes.put("timestamp", new Date()); addStatus(errorAttributes, webRequest); addErrorDetails(errorAttributes, webRequest, includeStackTrace); addPath(errorAttributes, webRequest); return errorAttributes; }
|
因此如果我们需要自定义异常数据,只需要继承这个DefaultErrorAttributes类,并重写getErrorAttributes方法即可。因此我们创建一个MyErrorAttribute类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.example.exception;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; import org.springframework.stereotype.Component; import org.springframework.web.context.request.WebRequest;
import java.util.Map;
@Component public class MyErrorAttribute extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace); errorAttributes.put("myerror", "这是我的异常类"); return errorAttributes; } }
|
然后我们在相应的错误页面上添加异常数据的显示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>My500</h1> <table border="1"> <tr> <td>path</td> <td th:text="${path}"></td> </tr> <tr> <td>timestamp</td> <td th:text="${timestamp}"></td> </tr> <tr> <td>message</td> <td th:text="${message}"></td> </tr> <tr> <td>status</td> <td th:text="${status}"></td> </tr> <tr> <td>myerror</td> <td th:text="${myerror}"></td> </tr> </table> </body> </html>
|
自定义异常视图
在ErrorMvcAutoConfiguration类中有一个名为conventionErrorViewResolver的方法定义了异常视图,并返回一个DefaultErrorViewResolver类,该类定义了默认的异常视图。
1 2 3 4 5 6
| @Bean @ConditionalOnBean(DispatcherServlet.class) @ConditionalOnMissingBean(ErrorViewResolver.class) DefaultErrorViewResolver conventionErrorViewResolver() { return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties); }
|
因此我们只需要继承自DefaultErrorViewResolver类即可自定义异常视图。因此我们创建一个MyErrorViewResolver类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package com.example.exception;
import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.autoconfigure.web.servlet.error.DefaultErrorViewResolver; import org.springframework.context.ApplicationContext; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest; import java.util.Map;
@Component public class MyErrorViewResolver extends DefaultErrorViewResolver {
public MyErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) { super(applicationContext, resourceProperties); }
@Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("my500"); modelAndView.addAllObjects(model); return modelAndView; } }
|
自定义完异常数据和异常视图后,我们来启动一下项目来看看效果