SpringBoot——定制错误页面及原理
更多内容,前往 IT-BLOG
一、SpringBoot 默认的错误处理机制
【1】浏览器返回的默认错误页面如下:

☞ 浏览器发送请求的请求头信息如下:text/html 会在后面的源码分析中说到。

【2】如果是其他客户端,默认则响应错误的 JSON字符串,如下所示:

☞ 其他客户端发送请求的请求头信息如下: " */* " 源码中解释。

二、原理分析
参照 ErrorMvcAutoConfiguration类:错误处理的自动配置类,以下4项为此类的重要信息。
【1】ErrorMvcAutoConfiguration.ErrorPageCustomizer:当系统出现 4xx或者 5xx之类的错误时,ErrorPageCustomizer就会生效(定制错误的响应规则),根据如下源码可知,将会来到 /error请求。
1 @Bean
2 public ErrorMvcAutoConfiguration.ErrorPageCustomizer errorPageCustomizer() {
3 return new ErrorMvcAutoConfiguration.ErrorPageCustomizer(this.serverProperties);
4 }
5
6 //进入ErrorPageCustomizer方法,发现registerErrorPages方法:注册一个错误也
7 private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
8 private final ServerProperties properties;
9
10 protected ErrorPageCustomizer(ServerProperties properties) {
11 this.properties = properties;
12 }
13
14 public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
15 ErrorPage errorPage = new ErrorPage(this.properties.getServletPrefix() +
16 this.properties.getError().getPath());
17 errorPageRegistry.addErrorPages(new ErrorPage[]{errorPage});
18 }
19 }
20
21 //进入this.properties.getError().getPath()方法,获取如下信息,得到/error请求。
22 @Value("${error.path:/error}")
23 private String path = "/error";//系统出现错误以后来到error请求进行处理;(web.xml注册的错误页面规则)
【2】BasicErrorController 处理 /error错误请求:注意:text/html 和 */*就是在此处生效。
1 @Bean
2 @ConditionalOnMissingBean(
3 value = {ErrorController.class},
4 search = SearchStrategy.CURRENT
5 )
6 public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
7 return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
8 }
9
10 //进入BasicErrorController对象,获取如下信息
11 @Controller
12 @RequestMapping({"${server.error.path:${error.path:/error}}"})
13 public class BasicErrorController extends AbstractErrorController {
14 private final ErrorProperties errorProperties;
15
16 public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
17 this(errorAttributes, errorProperties, Collections.emptyList());
18 }
19
20 @RequestMapping(
21 produces = {"text/html"}//产生html类型的数据;浏览器发送的请求来到这个方法处理
22 )
23 public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
24 HttpStatus status = this.getStatus(request);
25 Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
26 response.setStatus(status.value());
27
28 //去哪个页面作为错误页面;包含页面地址和页面内容
29 ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
30 return modelAndView != null?modelAndView:new ModelAndView("error", model);
31 }
32
33 @RequestMapping
34 @ResponseBody//产生json数据,其他客户端来到这个方法处理;
35 public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
36 Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
37 HttpStatus status = this.getStatus(request);
38 return new ResponseEntity(body, status);
39 }
40 }
☞ 如上代码中提到的错误页面解析代码,进入此方法: this.resolveErrorView(request, response, status, model);
1 protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
2 Iterator var5 = this.errorViewResolvers.iterator();
3 ModelAndView modelAndView;
4 do {
5 //从所有的ErrorViewResolver得到ModelAndView
6 if(!var5.hasNext()) {
7 return null;
8 }
9
10 ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
11 modelAndView = resolver.resolveErrorView(request, status, model);
12 } while(modelAndView == null);
13
14 return modelAndView;
15 }
【3】最终的响应页面是由 DefaultErrorViewResolver 解析得到的:最重要的信息是,SpringBoot 默认模板引擎的 /error目录下获取 ‘status’.xml 错误页面,也可以通过 4xx.xml来统配 404.xml和 400.xml等等,但是优先获取精准的页面。如果模板引擎中不存在,则会从静态页面中获取错误页面。否则返回系统默认错误页面。
1 @Bean
2 @ConditionalOnBean({DispatcherServlet.class})
3 @ConditionalOnMissingBean
4 public DefaultErrorViewResolver conventionErrorViewResolver() {
5 return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
6 }
7
8 //进入DefaultErrorViewResolver类中
9 public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
10 ModelAndView modelAndView = this.resolve(String.valueOf(status), model);
11 if(modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
12
13 //调用时viewname = status ***重要
14 modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
15 }
16
17 return modelAndView;
18 }
19
20 private ModelAndView resolve(String viewName, Map<String, Object> model) {
21
22 //默认SpringBoot可以去找到一个页面? error/404
23 String errorViewName = "error/" + viewName;
24
25 //模板引擎可以解析这个页面地址就用模板引擎解析
26 TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.
27 getProvider(errorViewName, this.applicationContext);
28
29 //模板引擎可用的情况下返回到errorViewName指定的视图地址,
30 //当模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html
31 return provider != null?new ModelAndView(errorViewName, model):this.resolveResource(errorViewName, model);
32 }
【4】DefaultErrorAttributes:在页面添加错误信息,供我们使用。
1 @Bean
2 @ConditionalOnMissingBean(
3 value = {ErrorAttributes.class},
4 search = SearchStrategy.CURRENT
5 )
6 public DefaultErrorAttributes errorAttributes() {
7 return new DefaultErrorAttributes();
8 }
9
10 //进入DefaultErrorAttributes类中,发现此方法给视图中添加了status状态等信息,供我们使用。
11 public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
12 Map<String, Object> errorAttributes = new LinkedHashMap();
13 errorAttributes.put("timestamp", new Date());
14 this.addStatus(errorAttributes, requestAttributes);
15 this.addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
16 this.addPath(errorAttributes, requestAttributes);
17 return errorAttributes;
18 }
三、定制错误 JSON数据
【1】自定义异常处理类,返回定制的 JSON数据。通过上述的分析,我们得知:①、可以完全编写一个 ErrorController的实现类,或者继承 AbstractErrorController的子类,放入容器中。②、也可以自定义异常处理类,返回 JSON数据。③、页面上的数据或 JSON返回的数据都是可以通过 errorAttributes.getErrorAttributes得到的。我们可以自定义属于自己的 ErrorAttributes。
1 //首先我们可以通过自定义异常处理,来确定返回的数据,但这个不够灵活,我们可以与③结合使用
2 /**
3 * @RequestMapping启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping
4 * 注解的方法上。
5 */
6 @ControllerAdvice
7 public class MyExceptionHandler {
8 @ResponseBody
9 @ExceptionHandler(UserNotExistException.class)
10 public Map<String,Object> handlerException(Exception e, HttpServletRequest request){
11 Map<String,Object> map = new HashMap<String,Object>();
12 request.setAttribute("javax.servlet.error.status_code","500");
13 map.put("code","user.notexist");
14 map.put("message",e.getMessage());
15 return map;
16 }
17 }
18
19 //③自定义ErrorAttributes,一定要加入容器
20 @Component
21 public class MyErrorAttributes extends DefaultErrorAttributes{
22 @Override
23 public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
24 //获取默认的配置,在此基础上添加自己的需求
25 Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
26 //自定义自己需要的属性
27 map.put("company","yintong");
28
29 //获取我们在异常处理类中添加的信息,
30 /*注意:当我们需要结合使用的时候异常处理必须return "forward:/error";将请求转发出去,不能直接返回map对象,
31 同时要去掉@responseBody注解,否则ErrorAttributes不生效*/
32 map.put("ext",requestAttributes.getAttribute("ext",requestAttributes.SCOPE_REQUEST));
33 return map;
34 }
35 }
【2】效果展示:


----关注公众号,获取更多内容----
SpringBoot——定制错误页面及原理的更多相关文章
- springboot 定制错误页面
项目中经常遇到的异常情况 400-Bad Request 401-Unauthorized If the request already included Authorization credenti ...
- SpringBoot定制错误页面
(1)有模板引擎的情况下,例如404错误,将会在thymeleaf的templates的error下寻找404.html,如果找不到再寻找4xx.html *所有4开头的错误状态码如果找不到特定的ht ...
- SpringBoot定制错误的Json数据
(1)自定义异常处理&返回定制Json数据 @ControllerAdvice public class MyExceptionHandler { @ResponseBody @Excepti ...
- SpringBoot自定义错误页面,SpringBoot 404、500错误提示页面
SpringBoot自定义错误页面,SpringBoot 404.500错误提示页面 SpringBoot 4xx.html.5xx.html错误提示页面 ====================== ...
- springboot自定义错误页面
springboot自定义错误页面 1.加入配置: @Bean public EmbeddedServletContainerCustomizer containerCustomizer() { re ...
- 【Laravel5】 定制错误页面
laravel5 所有异常错误都由类 App\Exceptions\Handler 处理,该类包含两个方法: report 和 render . 这里我们只看 render ...
- Spring boot错误处理以及定制错误页面
如果是浏览器访问,返回错误页面 注意浏览器发送请求的请求头: 注意区别其他客户端哦比如 postman 如果是其他客户端,返回一个Json数据 原理可以参照ErrorMvcAutoConfigura ...
- springboot系列六、springboot配置错误页面及全局异常
一.spring1.x中处理方式 @Bean public EmbeddedServletContainerCustomizer containerCustomizer() { return new ...
- Springboot - 自定义错误页面
Springboot 没找到页面或内部错误时,会访问默认错误页面.这节我们来自定义错误页面. 自定义错误页面 1.在resources 目录下面再建一个 resources 文件夹,里面建一个 err ...
- apache定制错误页面
编辑配置文件,错误页面定制支持三种形式: 1. 普通文本 2. 本地跳转 3. 外部跳转 [root@ken-node2 ~]# vim /etc/httpd/conf/httpd.conf ... ...
随机推荐
- bzoj 4573
LCT神题... 首先暴力的做法就是每次在一个区间上link,然后暴力查询,时间复杂度$O(爆炸)$ 但是我们可以发现的是,每棵树之间互不影响! 因此我们可以考虑离线之后分别统计每棵树 但是这样做其实 ...
- 百度地图api高亮显示指定区域,其余遮罩
先放一张最后的效果图 主要功能:只显示天府新区(双流区+龙泉驿区)这一块,其他的地方就用半透明的遮罩层盖住,然后用Markers标注出每个项目的所在地点,当鼠标悬浮在标注点的时候就显示出项目名称. h ...
- 如何使用autotools/automake自动生成Makefile文件
前言: Linux下编程时,为了方便编译,往往使用Makefile文件自动完成编译,但是Makefile文件本身的书写十分复杂,规则很多.好在Linux为我们提供了自动生成功能完善的Makefile文 ...
- vue 封装时间格式化和number精确度
//format.js 公用js /** * Parse the time to string * @param {(Object|string|number)} time * @param {str ...
- 西瓜书3.4 解题报告(python 多分类学习 十折交叉法)
偷懒找了UCI上最小的一个数据集,数据大约是集装箱起重机的转动速度.角度,判断其力量大小(我不懂起重机啊啊啊) 虽然不懂但并不妨碍写代码分类,显然标记就是力量,分为0.3.0.5.0.7三种.具体的模 ...
- C和C++内存分配语法补充
NOTE: 动态内存分配:需要加载头文件<stdlib.h>malloc(m):开辟m字节长度的地址空间,并返回首地址sizeof(x):计算变量x的长度free(p):释放指针p所指的存 ...
- Java Fastjson Unserialize WriteUp
Java Fastjson Unserialize 题目地址: https://ctf.bugku.com/challenges/detail/id/339.html 1. 查看网页源代码 <s ...
- SpingBoot面试大汇总
1.什么是SpringBoot? 1)用来优化Spring应用的初始搭建以及开发过程,使用特定的方式来配置(properties和yml文件) 2)嵌入式的内置服务器tomcat无需部署war文件简化 ...
- spring-security-oauth2使用遇到的坑
异常信息为 2021-08-22 14:24:11.086 WARN 17812 --- [ main] ConfigServletWebServerApplicationContext : Exce ...
- DPDK在虚拟机上运行时,报错: Ethdev port_id=0 requested Rx offloads 0xe doesn't match Rx offloads capabilities 0x82a1d in rte_eth_dev_configure()
这个错误是因为RX_OFFLOAD与TX_OFFLOAD可能不支持IPV4_CKSUM的检验 解决办法: 1,在配置中注释掉 DEV_RX_OFFLOAD_CHECKSUM 2,在代码中关闭 DEV_ ...