1. 程式人生 > 其它 >SpringBoot2.3.12.RELEASE優雅的全域性異常處理(模板一)

SpringBoot2.3.12.RELEASE優雅的全域性異常處理(模板一)

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

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

 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、自定義基礎介面類。

  首先定義一個基礎的介面類,自定義的錯誤描述列舉類需實現該介面。

 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、自定義列舉類。

  然後我們這裡在自定義一個列舉類,並實現該介面。而使用列舉類的好處是處理異常的時候,可以通過列舉類直接獲取到錯誤碼、錯誤描述,方便呼叫。

 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、自定義異常類。

  然後我們在來自定義一個異常類,用於處理我們發生的業務異常。

 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、自定義資料格式。

  順便這裡我們定義一下資料的傳輸格式,作用主要用於返回給前端的資料格式。

  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、自定義全域性異常處理類。

  最後我們再來編寫一個自定義全域性異常處理的類,可以用於處理各類異常。

 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、建立一個使用者的實體類,如下所示:

 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,而請求路徑是一個,主要根據請求方式來做區分操作。

 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%完美,但是設計的已經很優秀了,基本可以滿足日常需求,贊一個。