avatar

SpringBoot自定义异常

摘要:本文主要介绍了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;

/**
* @author: WJZheng
* @date: 2020/3/17 01:06
* @description:
*/

@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;

/**
* @author: WJZheng
* @date: 2020/3/17 01:22
* @description:
*/
@Component
public class MyErrorViewResolver extends DefaultErrorViewResolver {
/**
* Create a new {@link DefaultErrorViewResolver} instance.
*
* @param applicationContext the source application context
* @param resourceProperties resource properties
*/
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;
}
}

自定义完异常数据和异常视图后,我们来启动一下项目来看看效果

Author: WJZheng
Link: https://wellenzheng.github.io/2020/03/17/SpringBoot%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BC%82%E5%B8%B8/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment