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 ... ...
随机推荐
- CCF 202006-2 稀疏向量
#include <iostream> #include <bits/stdc++.h> #include <string> using namespace std ...
- 装机DEBUG大全
显示器 分屏没声音?去声音设置 (前提是HDMI连接 分屏能够传输音频 再去调整应用的音频
- bzoj 3106
好久没写oi系列的题解了 要不是为了大作业我才不会回来学这些奇怪的东西呢 本题对抗搜索就好啦 首先要分析一点,就是由于我们的黑棋每次走两步,白棋只走一步而且是白棋先走,所以除非白棋第一步吃掉黑棋,否则 ...
- Spring面试题大汇总
1.Spring的IOC和AOP机制? 我们在使用spring框架其实就是为了实现IOC,依赖注入,和AOP,面向切面编程,主要有两种设计模式工厂模式和代理模式,IOC就是典型的工厂模式,通过sess ...
- ARP协议 路由器原理
ARP协议 路由器原理 1 广播与广播域 广播:将广播地址作为目的地址的数据帧 广播域:网络中能够接收到同一个广播所有节点的集合(在这里广播域越小越好) 交换机控制不了广播 路由器可以控制广播 ...
- Verilog中端口的连接规则
摘自于(15条消息) Verilog中端口应该设置为wire形还是reg形_CLL_caicai的博客-CSDN博客, 以及(15条消息) Verilog端口连接规则_「已注销」的博客-CSDN博客_ ...
- HTML悬浮div
需求,html底部为地图,上层是各个div HTML<body> //地图 <div id='map' id="demo1"></div> &l ...
- 解决SVN不显示绿色小对勾
https://blog.csdn.net/qq_34338527/article/details/108534652
- jq的用法
选择页面中的元素,得到jQuery实例对象 ID选择器$("#save") 类选择器$(".class") 标签选择器$("div") 复合 ...
- mmdetection RPNHead--_init_layers()
RPNHead类包含的函数: (1)_init_():初始化函数 (2)_init_layers():设置Head中的卷积层 (3)forward_single():单尺度特征图的前向传播 (4)lo ...