我们在开发中,碰到异常那就是家常便饭了。那么今天小编就给大家聊一聊 Spring Boot 对异常的处理。
在小编的上一篇文章:Spring Boot(十 二)-- @ControllerAdvice注解的使用 ,中已经介绍了 SpringMVC 中 @ControllerAdvice
注解是如何处理异常的,但是这种方式是 SpringMVC 中就有的功能,今天小编就说说 Spring Boot 中的异常处理方式。
通常情况我们在后端出现异常,Spring Boot 默认异常页面是:
通过这个页面,我们可以很清楚的看出来,我们这个程序应用没有提供一个明确的 /error 路径,如果开发者提供了 /error 路径,那么这个页面就不会展现出来。注意: 在 Spring Boot 中,提供 /error 路径实际是下下策, Spring Boot 在处理异常时,是在所有的条件都不满足时,才会找到 /error 路径。下面我们就看看在 Spring Boot 中,是如何定义 error 页面的。至于 提供 error 页面也是存在两种方式:一种是静态页面,一种是动态页面。
静态页面异常处理
自定义静态页面异常,也分两种:
- 第一种:使用 HTTP 响应码来命名的 HTML 页面。如:404.html、500.html
- 第二种:使用 HTTP 一类响应码的第一个数字为前缀,代表该类的异常处理。如:4xx.html,该页面代表 400~499 状态的异常都使用这个页面显示。
默认是在 classpath:/static/error/ 路径下定义相关页面:
启动项目,项目抛出 500 请求错误,就会自动展示 500.html 这个页面,如果发生 404 错误,则会展示 404.html 页面。如果异常页面存在的有 5xx.html ,也存在 500.html,那么抛出 500 错误时,优先展示具体的 500.html 页面。
如:
抛出异常的 Controller 代码如下:
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
int i = 1 / 0;
return "hello";
}
}
500错误页面,就是一个很简单的 html 页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>500</h1>
</body>
</html>
启动项目,访问 :http://localhost:8080/hello
动态页面异常处理
动态的异常页面定义方式和静态的基本一致,我们可以使用页面模板有: jsp、freemarker、thymeleaf 。这里小编使用的是 thymeleaf 页面模板,所以创建的动态页面异常是以 html 结尾的。动态页面异常处理,也支持具体的异常 如: 404.html ,也支持一类的异常 如:4xx.html。但是,一般情况来说,由于动态页面可以直接展示异常详细信息,所以没有必要挨个枚举错误了,直接定义 4xx.html 或者 5xx.html 即可。
注意
:动态页面模板,不需要开发者自己去定义控制器,直接定义异常页面即可, Spring Boot 中自带的异常处理会自动查找到异常页面。
5xx.html 页面的内容:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>templates: 5xx</h1>
<div th:text="${error}"></div>
<div th:text="${status}">status</div><br>
<div th:text="${path}">path</div><br>
<div th:text="${timestamp}">timestamp</div><br>
<div th:text="${message}">message</div><br>
</body>
</html>
启动项目,访问:http://localhost:8080/hello
注意:
如果静态异常页面、动态异常页面两种方式同时出现,那么该异常如何处理,例如:classpath:/static/error/500.html
、classpath:/static/error/5xx.html
、classpath:/templates/error/500.html
、classpath:/templates/error/5xx.html
,同时出现时,那么完整的错误页面查找的顺序如下:
项目出现500错误:
- 首先查找动态页面具体异常:
classpath:/templates/error/500.html
,- 如果没有,那么就去找静态中的 具体异常页面:
classpath:/static/error/500.html
,- 如果没有,那么去动态异常页面找:
classpath:/templates/error/5xx.html
,- 如果还没有,则去静态异常页面找:
classpath:/static/error/5xx.html
,- 如果以上四种都没有,则返回 Spring Boot 默认页面。
自定义异常数据
默认情况下,在Spring Boot 中,所有的异常数据其实就是上文所展示出来的5条数据,这5条数据定义在 org.springframework.boot.web.servlet.error.DefaultErrorAttributes
类中,具体定义在 getErrorAttributes
方法中 :
@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 类本身则是在 org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
异常自动配置类中定义的,如果开发者没有自己提供一个 ErrorAttributes 的实例的话,那么 Spring Boot 将自动提供一个ErrorAttributes 的实例,也就是 DefaultErrorAttributes 。
基于此 ,开发者自定义 ErrorAttributes 有两种方式 :
直接实现 ErrorAttributes 接口
继承 DefaultErrorAttributes(推荐),因为 DefaultErrorAttributes 中对异常数据的处理已经完成,开发者可以直接使用。
具体定义如下:
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
if ((Integer) map.get("status") == 500) {
map.put("message","服务器繁忙中,请稍后再访问....");
}
return map;
}
}
启动项目,访问:http://localhost:8080/hello
附加
:如果想要另外添加自己的异常信息,由于该方法中的 getErrorAttributes
方法中的 map 不是hasMap 所以不可以修改,那么我们可以在方法中自定义一个 map2 集合,然后读取 map 中的数据存取到 map2 中,然后想添加自己的异常就可以添加了,最后返回 map2。这里小编就不演示了,有兴趣的朋友可以试试。