前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot2.3.12.RELEASE优雅的全局异常处理(模板一)

SpringBoot2.3.12.RELEASE优雅的全局异常处理(模板一)

作者头像
别先生
发布2021-07-01 10:15:59
7720
发布2021-07-01 10:15:59
举报
文章被收录于专栏:别先生

参考:https://www.cnblogs.com/xuwujing/p/10933082.html

1、首先,需要引入maven依赖包,如下所示:

代码语言:javascript
复制
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6     <parent>
 7         <groupId>org.springframework.boot</groupId>
 8         <artifactId>spring-boot-starter-parent</artifactId>
 9         <version>2.3.12.RELEASE</version>
10         <relativePath /> <!-- lookup parent from repository -->
11     </parent>
12     <groupId>com.bie</groupId>
13     <artifactId>SpringbootException</artifactId>
14     <version>0.0.1-SNAPSHOT</version>
15     <name>SpringbootException</name>
16     <description>Demo project for Spring Boot</description>
17 
18     <properties>
19         <java.version>1.8</java.version>
20     </properties>
21 
22     <dependencies>
23         <!-- 引入springboot web模块 -->
24         <dependency>
25             <groupId>org.springframework.boot</groupId>
26             <artifactId>spring-boot-starter-web</artifactId>
27         </dependency>
28         <!-- 引入fastjson的依赖 -->
29         <dependency>
30             <groupId>com.alibaba</groupId>
31             <artifactId>fastjson</artifactId>
32             <version>1.2.41</version>
33         </dependency>
34 
35         <dependency>
36             <groupId>org.springframework.boot</groupId>
37             <artifactId>spring-boot-starter-test</artifactId>
38             <scope>test</scope>
39             <exclusions>
40                 <exclusion>
41                     <groupId>org.junit.vintage</groupId>
42                     <artifactId>junit-vintage-engine</artifactId>
43                 </exclusion>
44             </exclusions>
45         </dependency>
46     </dependencies>
47 
48     <build>
49         <plugins>
50             <plugin>
51                 <groupId>org.springframework.boot</groupId>
52                 <artifactId>spring-boot-maven-plugin</artifactId>
53             </plugin>
54         </plugins>
55     </build>
56 
57 </project>

  SpringBoot中有一个ControllerAdvice的注解,使用该注解表示开启了全局异常的捕获,我们只需再自定义一个方法,然后使用ExceptionHandler注解,在该注解的value属性里面,定义捕获异常的类型,即可对这些捕获的异常进行统一的处理。

2、自定义基础接口类。

  首先定义一个基础的接口类,自定义的错误描述枚举类需实现该接口。

代码语言:javascript
复制
 1 package com.bie.enums;
 2 
 3 public interface BaseErrorInfoInterface {
 4 
 5     // 错误码
 6     public String getResultCode();
 7 
 8     // 错误描述
 9     public String getResultMsg();
10 
11 }

3、自定义枚举类。

  然后我们这里在自定义一个枚举类,并实现该接口。而使用枚举类的好处是处理异常的时候,可以通过枚举类直接获取到错误码、错误描述,方便调用。

代码语言:javascript
复制
 1 package com.bie.enums;
 2 
 3 public enum CommonEnum implements BaseErrorInfoInterface {
 4 
 5     // 数据操作错误定义
 6     SUCCESS("200", "接口调用成功!"),
 7 
 8     BODY_NOT_MATCH("400", "请求的数据格式不符!"),
 9 
10     SIGNATURE_NOT_MATCH("401", "请求的数字签名不匹配!"),
11 
12     NOT_FOUND("404", "未找到该资源!"),
13 
14     INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
15 
16     SERVER_BUSY("503", "服务器正忙,请稍后再试!");
17 
18     // 错误码
19     private String resultCode;
20 
21     // 错误描述
22     private String resultMsg;
23 
24     CommonEnum(String resultCode, String resultMsg) {
25         this.resultCode = resultCode;
26         this.resultMsg = resultMsg;
27     }
28 
29     @Override
30     public String getResultCode() {
31         return resultCode;
32     }
33 
34     @Override
35     public String getResultMsg() {
36         return resultMsg;
37     }
38 
39 }

4、自定义异常类。

  然后我们在来自定义一个异常类,用于处理我们发生的业务异常。

代码语言:javascript
复制
 1 package com.bie.exception;
 2 
 3 import com.bie.enums.BaseErrorInfoInterface;
 4 
 5 public class BizException extends RuntimeException {
 6 
 7     /**
 8      * 
 9      */
10     private static final long serialVersionUID = -6329783845738305585L;
11 
12     // 错误码
13     protected String errorCode;
14     // 错误信息
15     protected String errorMsg;
16 
17     public BizException() {
18         super();
19     }
20 
21     public BizException(BaseErrorInfoInterface errorInfoInterface) {
22         super(errorInfoInterface.getResultCode());
23         this.errorCode = errorInfoInterface.getResultCode();
24         this.errorMsg = errorInfoInterface.getResultMsg();
25     }
26 
27     public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
28         super(errorInfoInterface.getResultCode(), cause);
29         this.errorCode = errorInfoInterface.getResultCode();
30         this.errorMsg = errorInfoInterface.getResultMsg();
31     }
32 
33     public BizException(String errorMsg) {
34         super(errorMsg);
35         this.errorMsg = errorMsg;
36     }
37 
38     public BizException(String errorCode, String errorMsg) {
39         super(errorCode);
40         this.errorCode = errorCode;
41         this.errorMsg = errorMsg;
42     }
43 
44     public BizException(String errorCode, String errorMsg, Throwable cause) {
45         super(errorCode, cause);
46         this.errorCode = errorCode;
47         this.errorMsg = errorMsg;
48     }
49 
50     public String getErrorCode() {
51         return errorCode;
52     }
53 
54     public void setErrorCode(String errorCode) {
55         this.errorCode = errorCode;
56     }
57 
58     public String getErrorMsg() {
59         return errorMsg;
60     }
61 
62     public void setErrorMsg(String errorMsg) {
63         this.errorMsg = errorMsg;
64     }
65 
66     public String getMessage() {
67         return errorMsg;
68     }
69 
70     @Override
71     public Throwable fillInStackTrace() {
72         return this;
73     }
74 
75 }

5、自定义数据格式。

  顺便这里我们定义一下数据的传输格式,作用主要用于返回给前端的数据格式。

代码语言:javascript
复制
  1 package com.bie.utils;
  2 
  3 import com.alibaba.fastjson.JSONObject;
  4 import com.bie.enums.BaseErrorInfoInterface;
  5 import com.bie.enums.CommonEnum;
  6 
  7 public class ResultBody {
  8 
  9     // 响应代码
 10     private String code;
 11 
 12     // 响应消息
 13     private String message;
 14 
 15     // 响应结果
 16     private Object result;
 17 
 18     public ResultBody() {
 19     }
 20 
 21     public ResultBody(BaseErrorInfoInterface errorInfo) {
 22         this.code = errorInfo.getResultCode();
 23         this.message = errorInfo.getResultMsg();
 24     }
 25 
 26     public String getCode() {
 27         return code;
 28     }
 29 
 30     public void setCode(String code) {
 31         this.code = code;
 32     }
 33 
 34     public String getMessage() {
 35         return message;
 36     }
 37 
 38     public void setMessage(String message) {
 39         this.message = message;
 40     }
 41 
 42     public Object getResult() {
 43         return result;
 44     }
 45 
 46     public void setResult(Object result) {
 47         this.result = result;
 48     }
 49 
 50     /**
 51      * 成功
 52      * 
 53      * @return
 54      */
 55     public static ResultBody success() {
 56         return success(null);
 57     }
 58 
 59     /**
 60      * 成功
 61      * 
 62      * @param data
 63      * @return
 64      */
 65     public static ResultBody success(Object data) {
 66         ResultBody rb = new ResultBody();
 67         rb.setCode(CommonEnum.SUCCESS.getResultCode());
 68         rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
 69         rb.setResult(data);
 70         return rb;
 71     }
 72 
 73     /**
 74      * 失败
 75      */
 76     public static ResultBody error(BaseErrorInfoInterface errorInfo) {
 77         ResultBody rb = new ResultBody();
 78         rb.setCode(errorInfo.getResultCode());
 79         rb.setMessage(errorInfo.getResultMsg());
 80         rb.setResult(null);
 81         return rb;
 82     }
 83 
 84     /**
 85      * 失败
 86      */
 87     public static ResultBody error(String code, String message) {
 88         ResultBody rb = new ResultBody();
 89         rb.setCode(code);
 90         rb.setMessage(message);
 91         rb.setResult(null);
 92         return rb;
 93     }
 94 
 95     /**
 96      * 失败
 97      */
 98     public static ResultBody error(String message) {
 99         ResultBody rb = new ResultBody();
100         rb.setCode("-1");
101         rb.setMessage(message);
102         rb.setResult(null);
103         return rb;
104     }
105 
106     @Override
107     public String toString() {
108         return JSONObject.toJSONString(this);
109     }
110 
111 }

6、自定义全局异常处理类。

  最后我们再来编写一个自定义全局异常处理的类,可以用于处理各类异常。

代码语言:javascript
复制
 1 package com.bie.exception;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 
 5 import org.slf4j.Logger;
 6 import org.slf4j.LoggerFactory;
 7 import org.springframework.web.bind.annotation.ControllerAdvice;
 8 import org.springframework.web.bind.annotation.ExceptionHandler;
 9 import org.springframework.web.bind.annotation.ResponseBody;
10 
11 import com.bie.enums.CommonEnum;
12 import com.bie.utils.ResultBody;
13 
14 @ControllerAdvice
15 public class GlobalExceptionHandler {
16 
17     private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
18 
19     /**
20      * 处理自定义的业务异常
21      * 
22      * @param req
23      * @param e
24      * @return
25      */
26     @ExceptionHandler(value = BizException.class)
27     @ResponseBody
28     public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e) {
29         logger.error("发生业务异常!原因是:{}", e.getErrorMsg());
30         return ResultBody.error(e.getErrorCode(), e.getErrorMsg());
31     }
32 
33     /**
34      * 处理空指针的异常
35      * 
36      * @param req
37      * @param e
38      * @return
39      */
40     @ExceptionHandler(value = NullPointerException.class)
41     @ResponseBody
42     public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
43         logger.error("发生空指针异常!原因是:", e);
44         return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
45     }
46 
47     /**
48      * 处理其他异常
49      * 
50      * @param req
51      * @param e
52      * @return
53      */
54     @ExceptionHandler(value = Exception.class)
55     @ResponseBody
56     public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
57         logger.error("未知异常!原因是:", e);
58         return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
59     }
60 
61 }

7、创建一个用户的实体类,如下所示:

代码语言:javascript
复制
 1 package com.bie.po;
 2 
 3 import java.io.Serializable;
 4 
 5 import com.alibaba.fastjson.JSONObject;
 6 
 7 public class User implements Serializable {
 8 
 9     /**
10      * 
11      */
12     private static final long serialVersionUID = 1360679426784375558L;
13     
14     // 编号
15     private int id;
16     // 姓名 
17     private String name;
18     // 年龄
19     private int age;
20 
21     public User() {
22     }
23 
24     public int getId() {
25         return id;
26     }
27 
28     public void setId(int id) {
29         this.id = id;
30     }
31 
32     public String getName() {
33         return name;
34     }
35 
36     public void setName(String name) {
37         this.name = name;
38     }
39 
40     public int getAge() {
41         return age;
42     }
43 
44     public void setAge(int age) {
45         this.age = age;
46     }
47 
48     public String toString() {
49         return JSONObject.toJSONString(this);
50     }
51 
52 }

8、Controller 控制层。

  控制层这边也比较简单,使用Restful风格实现的CRUD功能,主要是Restful风格的,根据请求方式get、post、put、delete,而请求路径是一个,主要根据请求方式来做区分操作。

代码语言:javascript
复制
 1 package com.bie.controller;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 import org.springframework.web.bind.annotation.DeleteMapping;
 7 import org.springframework.web.bind.annotation.GetMapping;
 8 import org.springframework.web.bind.annotation.PostMapping;
 9 import org.springframework.web.bind.annotation.PutMapping;
10 import org.springframework.web.bind.annotation.RequestBody;
11 import org.springframework.web.bind.annotation.RequestMapping;
12 import org.springframework.web.bind.annotation.RestController;
13 
14 import com.bie.exception.BizException;
15 import com.bie.po.User;
16 
17 @RestController
18 @RequestMapping(value = "/api")
19 public class UserRestController {
20 
21     @PostMapping("/user")
22     public boolean insert(@RequestBody User user) {
23         System.out.println("开始新增...");
24         // 如果姓名为空就手动抛出一个自定义的异常!
25         if (user.getName() == null) {
26             throw new BizException("-1", "用户姓名不能为空!");
27         }
28         return true;
29     }
30 
31     @PutMapping("/user")
32     public boolean update(@RequestBody User user) {
33         System.out.println("开始更新...");
34         // 这里故意造成一个空指针的异常,并且不进行处理
35         String str = null;
36         str.equals("111");
37         return true;
38     }
39 
40     @DeleteMapping("/user")
41     public boolean delete(@RequestBody User user) {
42         System.out.println("开始删除...");
43         // 这里故意造成一个异常,并且不进行处理
44         Integer.parseInt("abc123");
45         return true;
46     }
47 
48     @GetMapping("/user")
49     public List<User> findByUser(User user) {
50         System.out.println("开始查询...");
51         List<User> userList = new ArrayList<>();
52         User user2 = new User();
53         user2.setId(1);
54         user2.setName("xuwujing");
55         user2.setAge(18);
56         userList.add(user2);
57         return userList;
58     }
59 
60 }

9、接口功能测试,使用postman进行测试,如下所示:

9.1、首先进行查询,查看程序是否正常运行,使用GET 方式进行请求,如下所示:

9.2、进行插入操作,使用POST方式进行请求,如下所示:

9.3、进行修改操作,使用PUT方式进行请求,如下所示:

9.4、进行删除操作,使用DELETE方式进行请求,如下所示:

10、整体思路解析,按照步骤操作,按道理来说,这个思路是很优秀的,那么下面来分析一下这个设计思路。

10.1、在自己的方法中抛出自定义异常,而抛出的自定义异常是被全局异常类进行捕获处理的。

  对抛出的自定义异常,在全局异常处理类中进行处理,然后返回的信息,是封装到自定义数据格式类中的,这样返回给前端的数据格式,就可以根据自己的需求进行设计。

10.2、而对于全局异常类中,可以定义捕获其他类型的异常。而在捕获其他异常之后,返回的数据封装到自定义数据格式里面,而对于其他异常而已直接使用定义的枚举类中来选择异常内容。

虽然,这种设计不能说100%完美,但是设计的已经很优秀了,基本可以满足日常需求,赞一个。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-06-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档