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 ... ...
随机推荐
- mysql-逗号分隔关联查询
牛逼plus 每天一个知识点 tableA id num 1 1001,1002 2 1002 tableB id num name 1 1001 A 2 1002 B 想要的结果: id name ...
- luogu 1344
首先题意就是裸的最小割啦 然后考虑如何统计边数 这里有一个trick: 我们设定一个大于$m$的阈值,对于每条边的边权我们乘这个阈值+1后跑最小割,得到的答案除以阈值就是真正的最小割,取模阈值后就是最 ...
- scala中变量常量字符串使用
1.注释 scala注释使用与java完全一样: 2.变量和常量 (1).常量:在程序执行中,其值不会改变的变量: 基本语法:var 变量名称:变量类型 = 变量初始值 var num1:Int = ...
- 英国延长 UKCA 标记截止日期
政府于 2022 年 11 月 14 日宣布,企业将有 2 年的时间来应用新的 UKCA 产品标记.在 2024 年 12 月 31 日之前,企业可以选择使用 UKCA 或 CE 标志,之后企业只能使 ...
- OO_Lab2总结博客
OO_Lab2 一.单元内容 本单元内容为规格化设计,即通过参考已经完成的JML描述实现一个社交网络相关功能. 本单元整体来说难度不大,但是却是我最惨的一次作业,所以本博客可能会主要谈一谈测试中的一些 ...
- C语言程序设计基础 实验3 函数
C语言程序设计基础 实验3 函数 一.实验目的 1. 理解函数的本质:模块化,实现代码复用 2. 掌握函数定义.声明.调用的语法 3. 理解并掌握函数的形参.实参,以及函数调用和返回的过程 4. ...
- connect及bind、listen、accept背后的三次握手
如图所示打上断点,分别找出connect() bind() listen() accpet()对应的函数 源码在上一次作业中已经分析过了 https://www.cnblogs.com/qwertyu ...
- ABP vNext微服务架构详细教程——镜像推送
1. Jenkins搭建 为实现容器化部署,我们需要将代码打包成镜像并推送至容器仓库,我们可以选择自建容器仓库或者使用公有云服务商提供的镜像仓库.这里我们使用阿里云提供的免费镜像仓库. 代码打包和镜像 ...
- PT的常用命令
归纳常用的PT命令,便于工作中应用. 1. 报时序的命令 report_timing -from A -to [get_clocks {clkA}] -delay_type min report_ ...
- Spring 常见问题 - 2
1. @Component, @Controller, @Repository, @Service 有何区别? @Component:这将 java 类标记为 bean.它是任何 Spring 管理组 ...