SpringBoot全局异常处理

开课吧开课吧锤锤2021-08-16 11:34

我们知道SpringBoot已经提供了一套默认的异常处理机制,但是SpringBoot提供的默认异常处理机制却并不一定适合我们实际的业务场景,因此,我们通常会根据自身的需要对SpringBoot全局异常进行统一定制,例如定制错误页面,定制错误数据等。  

SpringBoot全局异常处理

定制错误页面  

我们可以通过以下3种方式定制SpringBoot错误页面:  

自定义error.html  

自定义动态错误页面  

自定义静态错误页面  

自定义error.html  

我们可以直接在模板引擎文件夹(/resources/templates)下创建error.html,覆盖SpringBoot默认的错误视图页面(WhitelabelErrorPage)。  

示例1  

1.在spring-boot-adminex的模板引擎文件夹(classpath:/resources/templates)下,创建一个error.html,代码如下。  

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>自定义 error.html</title>
</head>
<body>
<h1>自定义 error.html</h1>
<p>status:<span th:text="${status}"></span></p>
<p>error:<span th:text="${error}"></span></p>
<p>timestamp:<span th:text="${timestamp}"></span></p>
<p>message:<span th:text="${message}"></span></p>
<p>path:<span th:text="${path}"></span></p>
</body>
</html>

2.启动SpringBoot,在完成登陆跳转到主页后,使用浏览器地访问“http://localhost:8080/111”,结果如下图。  

SpringBoot全局异常处理

由图可以看出,SpringBoot使用了我们自定义的error.html覆盖了默认的错误视图页面(WhitelabelErrorPage)。  

自定义动态错误页面  

如果SprngBoot项目使用了模板引擎,当程序发生异常时,SpringBoot的默认错误视图解析器(DefaultErrorViewResolver)就会解析模板引擎文件夹(resources/templates/)下error目录中的错误视图页面。  

精确匹配  

我们可以根据错误状态码(例如404、500、400等等)的不同,分别创建不同的动态错误页面(例如404.html、500.html、400.html等等),并将它们存放在模板引擎文件夹下的error目录中。当发生异常时,SpringBoot会根据其错误状态码精确匹配到对应的错误页面上。  

示例2  

1.在spring-boot-adminex的模板引擎文件夹下error目录中,创建一个名为404.html的错误页面,代码如下。  

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>自定义动态错误页面 404.html</h1>
<p>status:<span th:text="${status}"></span></p>
<p>error:<span th:text="${error}"></span></p>
<p>timestamp:<span th:text="${timestamp}"></span></p>
<p>message:<span th:text="${message}"></span></p>
<p>path:<span th:text="${path}"></span></p>
</body>
</html>

2.启动SpringBoot,在完成登陆跳转到主页后,在浏览器地址栏输入“http://localhost:8080/111”,结果如下图。  

SpringBoot全局异常处理

模糊匹配  

我们还可以使用4xx.html和5xx.html作为动态错误页面的文件名,并将它们存放在模板引擎文件夹下的error目录中,来模糊匹配对应类型的所有错误,例如404、400等错误状态码以“4”开头的所有异常,都会解析到动态错误页面4xx.html上。  

示例3  

在spring-boot-adminex的模板引擎文件夹下error目录中,创建一个名为4xx.html的错误页面,代码如下。  

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>自定义动态错误页面 4xx.html</h1>
<p>status:<span th:text="${status}"></span></p>
<p>error:<span th:text="${error}"></span></p>
<p>timestamp:<span th:text="${timestamp}"></span></p>
<p>message:<span th:text="${message}"></span></p>
<p>path:<span th:text="${path}"></span></p>
</body>
</html>

2.启动SpringBoot,在完成登陆跳转到主页后,使用浏览器访问“http://localhost:8080/111”,结果如下图。  

SpringBoot全局异常处理

自定义静态错误页面  

若SprngBoot项目没有使用模板引擎,当程序发生异常时,SpringBoot的默认错误视图解析器(DefaultErrorViewResolver)则会解析静态资源文件夹下error目录中的静态错误页面。  

精确匹配  

我们可以根据错误状态码(例如404、500、400等等)的不同,分别创建不同的静态错误页面(例如404.html、500.html、400.html等等),并将它们存放在静态资源文件夹下的error目录中。当发生异常时,SpringBoot会根据错误状态码精确匹配到对应的错误页面上。  

示例4  

1.在spring-boot-adminex的静态资源文件夹src/recources/static下的error目录中,创建一个名为404.html的静态错误页面,代码如下。  

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>自定义静态错误页面 404.html</h1>
<p>status:<span th:text="${status}"></span></p>
<p>error:<span th:text="${error}"></span></p>
<p>timestamp:<span th:text="${timestamp}"></span></p>
<p>message:<span th:text="${message}"></span></p>
<p>path:<span th:text="${path}"></span></p>
</body>
</html>

2.启动SpringBoot,在完成登陆跳转到主页后,使用浏览器访问“http://localhost:8080/111”,结果如下图。  

SpringBoot全局异常处理

由于该错误页为静态页面,无法识别Thymeleaf表达式,因此无法展示与错误相关的错误信息。  

模糊匹配  

我们还可以使用4xx.html和5xx.html作为静态错误页面的文件名,并将它们存放在静态资源文件夹下的error目录中,来模糊匹配对应类型的所有错误,例如404、400等错误状态码以“4”开头的所有错误,都会解析到静态错误页面4xx.html上。  

示例5 

在spring-boot-adminex的模板引擎文件夹下的error目录中,创建一个名为4xx.html的错误页面,代码如下。  

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>自定义静态错误页面 4xx.html</h1>
<p>status:<span th:text="${status}"></span></p>
<p>error:<span th:text="${error}"></span></p>
<p>timestamp:<span th:text="${timestamp}"></span></p>
<p>message:<span th:text="${message}"></span></p>
<p>path:<span th:text="${path}"></span></p>
</body>
</html>

2.启动SpringBoot,在完成登陆跳转到主页后,使用浏览器访问“http://localhost:8080/111”,结果如下图。  

SpringBoot全局异常处理

错误页面优先级  

以上5种方式均可以定制SpringBoot错误页面,且它们的优先级顺序为:自定义动态错误页面(精确匹配)>自定义静态错误页面(精确匹配)>自定义动态错误页面(模糊匹配)>自定义静态错误页面(模糊匹配)>自定义error.html。  

当遇到错误时,SpringBoot会按照优先级由高到低,依次查找解析错误页,一旦找到可用的错误页面,则直接返回客户端展示。  

定制错误数据  

我们知道,SpringBoot提供了一套默认的异常处理机制,其主要流程如下:  

1、发生异常时,将请求转发到“/error”,交由BasicErrorController(SpringBoot默认的Error控制器)进行处理;  

2、BasicErrorController根据客户端的不同,自动适配返回的响应形式,浏览器客户端返回错误页面,机器客户端返回JSON数据。  

3、BasicErrorController处理异常时,会调用DefaultErrorAttributes(默认的错误属性处理工具)的getErrorAttributes()方法获取错误数据。  

我们还可以定制SpringBoot的错误数据,具体步骤如下。  

自定义异常处理类,将请求转发到“/error”,交由SpringBoot底层(BasicErrorController)进行处理,自动适配浏览器客户端和机器客户端。  

通过继承DefaultErrorAttributes来定义一个错误属性处理工具,并在原来的基础上添加自定义的错误数据。  

1.自定义异常处理类  

被@ControllerAdvice注解的类可以用来实现全局异常处理,这是SpringMVC中提供的功能,在SpringBoot中可以直接使用。  

1)在net.kaikeba.net.exception包内,创建一个名为UserNotExistException的异常类,代码如下。  

package net.kaikeba.www.exception;
/**
* 自定义异常
*/
public class UserNotExistException extends RuntimeException {
    public UserNotExistException() {
        super("用户不存在!");
    }
}

2)在IndexController添加以下方法,触发UserNotExistException异常,代码如下。  

@Controller
public class IndexController {
    ......
    @GetMapping(value = {"/testException"})
    public String testException(String user) {
        if ("user".equals(user)) {
            throw new UserNotExistException();
        }
        //跳转到登录页 login.html
        return "login";
    }
}

3)在net.kaikeba.www.controller中,创建一个名为MyExceptionHandler异常处理类,代码如下。  

package net.kaikeba.www.controller;
import net.kaikeba.www.exception.UserNotExistException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(UserNotExistException.class)
    public String handleException(Exception e, HttpServletRequest request) {
        Map<String, Object> map = new HashMap<>();
        //向 request 对象传入错误状态码
        request.setAttribute("javax.servlet.error.status_code",500);
        //根据当前处理的异常,自定义的错误数据
        map.put("code", "user.notexist");
        map.put("message", e.getMessage());
        //将自定的错误数据传入 request 域中
        request.setAttribute("ext",map);
        return "forward:/error";
    }
}

2.自定义错误属性处理工具  

1)在net.kaikeba.www.componet包内,创建一个错误属性处理工具类MyErrorAttributes(继承DefaultErrorAttributes),通过该类我们便可以添加自定义的错误数据,代码如下。  

package net.kaikeba.www.componet;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
import java.util.Map;
//向容器中添加自定义的储物属性处理工具
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options);
        //添加自定义的错误数据
        errorAttributes.put("company", "www.kaikeba.net");
        //获取 MyExceptionHandler 传入 request 域中的错误数据
        Map ext = (Map) webRequest.getAttribute("ext", 0);
        errorAttributes.put("ext", ext);
        return errorAttributes;
    }
}

2)在templates/error目录下,创建动态错误页面5xx.html,代码如下。  

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>自定义 error.html</title>
</head>
<body>
<p>status:<span th:text="${status}"></span></p>
<p>error:<span th:text="${error}"></span></p>
<p>timestamp:<span th:text="${timestamp}"></span></p>
<p>message:<span th:text="${message}"></span></p>
<p>path:<span th:text="${path}"></span></p>
<!--取出定制的错误信息-->
<h3>以下为定制错误数据:</h3>
<p>company:<span th:text="${company}"></span></p>
<p>code:<span th:text="${ext.code}"></span></p>
<p>path:<span th:text="${ext.message}"></span></p>
</body>
</html>

3)启动SpringBoot,访问“http://localhost:8080/testException?user=user”,

注意:为了避免拦截器干扰,建议先将拦截器屏蔽掉。  

以上就是开课吧广场小编为大家整理发布的“SpringBoot全局异常处理”一文,更多Java教程相关内容尽在开课吧广场Java教程频道!

SpringBoot全局异常处理

免责声明:本站所提供的内容均来源于网友提供或网络搜集,由本站编辑整理,仅供个人研究、交流学习使用。如涉及版权问题,请联系本站管理员予以更改或删除。
有用
分享
全部评论快来秀出你的观点
登录 后可发表观点…
发表
暂无评论,快来抢沙发!
高并发编程训练营