成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

使用枚舉簡單封裝一個優(yōu)雅的 Spring Boot 全局異常處理!

開發(fā) 前端
通過這篇文章,可以搞懂如何在 Spring Boot 中進行異常處理。但是,光是會用了還不行,我們還要思考如何把異常處理這部分的代碼寫的稍微優(yōu)雅一點。下面我會以我在工作中學到的一點實際項目中異常處理的方式,來說說我覺得稍微優(yōu)雅點的異常處理解決方案。

[[318861]]

 這篇文章鴿了很久,我在這篇文章 《用好 Java 中的枚舉,真的沒有那么簡單!》 中就提到要分享。還是昨天一個讀者提醒我之后,我才發(fā)現(xiàn)自己沒有將這篇文章發(fā)到公眾號。說到這里,我發(fā)現(xiàn)自己一個很大的問題,就是有時候在文章里面說要更新什么,結(jié)果后面就忘記了,很多時候不是自己沒寫,就因為各種事情混雜導致忘記發(fā)了。以后要盡量改正這個問題!

在上一篇文章《SpringBoot 處理異常的幾種常見姿勢》中我介紹了:

  1. 使用 @ControllerAdvice 和 @ExceptionHandler 處理全局異常
  2. @ExceptionHandler 處理 Controller 級別的異常
  3. ResponseStatusException

通過這篇文章,可以搞懂如何在 Spring Boot 中進行異常處理。但是,光是會用了還不行,我們還要思考如何把異常處理這部分的代碼寫的稍微優(yōu)雅一點。下面我會以我在工作中學到的一點實際項目中異常處理的方式,來說說我覺得稍微優(yōu)雅點的異常處理解決方案。

下面僅僅是我作為一個我個人的角度來看的,如果各位讀者有更好的解決方案或者覺得本文提出的方案還有優(yōu)化的余地的話,歡迎在評論區(qū)評論。

最終效果展示

下面先來展示一下完成后的效果,當我們定義的異常被系統(tǒng)捕捉后返回給客戶端的信息是這樣的:

 

 

 

 

效果展示

返回的信息包含了異常下面 5 部分內(nèi)容:

  1. 唯一標示異常的 code
  2. HTTP 狀態(tài)碼
  3. 錯誤路徑
  4. 發(fā)生錯誤的時間戳
  5. 錯誤的具體信息

這樣返回異常信息,更利于我們前端根據(jù)異常信息做出相應的表現(xiàn)。

異常處理核心代碼

ErrorCode.java (此枚舉類中包含了異常的唯一標識、HTTP 狀態(tài)碼以及錯誤信息)

這個類的主要作用就是統(tǒng)一管理系統(tǒng)中可能出現(xiàn)的異常,比較清晰明了。但是,可能出現(xiàn)的問題是當系統(tǒng)過于復雜,出現(xiàn)的異常過多之后,這個類會比較龐大。有一種解決辦法:將多種相似的異常統(tǒng)一為一個,比如將用戶找不到異常和訂單信息未找到的異常都統(tǒng)一為“未找到該資源”這一種異常,然后前端再對相應的情況做詳細處理(我個人的一種處理方法,不敢保證是比較好的一種做法)。

 

  1. import org.springframework.http.HttpStatus; 
  2.  
  3.  
  4. public enum ErrorCode { 
  5.  
  6.     RESOURCE_NOT_FOUND(1001, HttpStatus.NOT_FOUND, "未找到該資源"), 
  7.     REQUEST_VALIDATION_FAILED(1002, HttpStatus.BAD_REQUEST, "請求數(shù)據(jù)格式驗證失敗"); 
  8.     private final int code; 
  9.  
  10.     private final HttpStatus status; 
  11.  
  12.     private final String message; 
  13.  
  14.     ErrorCode(int code, HttpStatus status, String message) { 
  15.         this.code = code; 
  16.         this.status = status; 
  17.         this.message = message; 
  18.     } 
  19.  
  20.     public int getCode() { 
  21.         return code; 
  22.     } 
  23.  
  24.     public HttpStatus getStatus() { 
  25.         return status; 
  26.     } 
  27.  
  28.     public String getMessage() { 
  29.         return message; 
  30.     } 
  31.  
  32.     @Override 
  33.     public String toString() { 
  34.         return "ErrorCode{" + 
  35.                 "code=" + code + 
  36.                 ", status=" + status + 
  37.                 ", message='" + message + '\'' + 
  38.                 '}'
  39.     } 

ErrorReponse.java(返回給客戶端具體的異常對象)

這個類作為異常信息返回給客戶端,里面包括了當出現(xiàn)異常時我們想要返回給客戶端的所有信息。

 

  1. import org.springframework.util.ObjectUtils; 
  2.  
  3. import java.time.Instant; 
  4. import java.util.HashMap; 
  5. import java.util.Map; 
  6.  
  7. public class ErrorReponse { 
  8.     private int code; 
  9.     private int status; 
  10.     private String message; 
  11.     private String path; 
  12.     private Instant timestamp
  13.     private HashMap<String, Object> data = new HashMap<String, Object>(); 
  14.  
  15.     public ErrorReponse() { 
  16.     } 
  17.  
  18.     public ErrorReponse(BaseException ex, String path) { 
  19.         this(ex.getError().getCode(), ex.getError().getStatus().value(), ex.getError().getMessage(), path, ex.getData()); 
  20.     } 
  21.  
  22.     public ErrorReponse(int code, int status, String message, String path, Map<String, Object> data) { 
  23.         this.code = code; 
  24.         this.status = status; 
  25.         this.message = message; 
  26.         this.path = path; 
  27.         this.timestamp = Instant.now(); 
  28.         if (!ObjectUtils.isEmpty(data)) { 
  29.             this.data.putAll(data); 
  30.         } 
  31.     } 
  32.  
  33. // 省略 getter/setter 方法 
  34.  
  35.     @Override 
  36.     public String toString() { 
  37.         return "ErrorReponse{" + 
  38.                 "code=" + code + 
  39.                 ", status=" + status + 
  40.                 ", message='" + message + '\'' + 
  41.                 ", path='" + path + '\'' + 
  42.                 ", timestamp=" + timestamp + 
  43.                 ", data=" + data + 
  44.                 '}'
  45.     } 

BaseException.java(繼承自 RuntimeException 的抽象類,可以看做系統(tǒng)中其他異常類的父類)

系統(tǒng)中的異常類都要繼承自這個類。

 

  1. public abstract class BaseException extends RuntimeException { 
  2.     private final ErrorCode error; 
  3.     private final HashMap<String, Object> data = new HashMap<>(); 
  4.  
  5.     public BaseException(ErrorCode error, Map<String, Object> data) { 
  6.         super(error.getMessage()); 
  7.         this.error = error; 
  8.         if (!ObjectUtils.isEmpty(data)) { 
  9.             this.data.putAll(data); 
  10.         } 
  11.     } 
  12.  
  13.     protected BaseException(ErrorCode error, Map<String, Object> data, Throwable cause) { 
  14.         super(error.getMessage(), cause); 
  15.         this.error = error; 
  16.         if (!ObjectUtils.isEmpty(data)) { 
  17.             this.data.putAll(data); 
  18.         } 
  19.     } 
  20.  
  21.     public ErrorCode getError() { 
  22.         return error; 
  23.     } 
  24.  
  25.     public Map<String, Object> getData() { 
  26.         return data; 
  27.     } 
  28.  

ResourceNotFoundException.java (自定義異常)

可以看出通過繼承 BaseException 類我們自定義異常會變的非常簡單!

 

  1. import java.util.Map; 
  2.  
  3. public class ResourceNotFoundException extends BaseException { 
  4.  
  5.     public ResourceNotFoundException(Map<String, Object> data) { 
  6.         super(ErrorCode.RESOURCE_NOT_FOUND, data); 
  7.     } 

GlobalExceptionHandler.java(全局異常捕獲)

我們定義了兩個異常捕獲方法。

這里再說明一下,實際上這個類只需要 handleAppException() 這一個方法就夠了,因為它是本系統(tǒng)所有異常的父類。只要是拋出了繼承 BaseException 類的異常后都會在這里被處理。

 

  1. import com.twuc.webApp.web.ExceptionController; 
  2. import org.springframework.http.HttpHeaders; 
  3. import org.springframework.http.HttpStatus; 
  4. import org.springframework.http.ResponseEntity; 
  5. import org.springframework.web.bind.annotation.ControllerAdvice; 
  6. import org.springframework.web.bind.annotation.ExceptionHandler; 
  7. import org.springframework.web.bind.annotation.ResponseBody; 
  8. import javax.servlet.http.HttpServletRequest; 
  9.  
  10. @ControllerAdvice(assignableTypes = {ExceptionController.class}) 
  11. @ResponseBody 
  12. public class GlobalExceptionHandler { 
  13.  
  14.     // 也可以將 BaseException 換為 RuntimeException 
  15.     // 因為 RuntimeException 是 BaseException 的父類 
  16.     @ExceptionHandler(BaseException.class) 
  17.     public ResponseEntity<?> handleAppException(BaseException ex, HttpServletRequest request) { 
  18.         ErrorReponse representation = new ErrorReponse(ex, request.getRequestURI()); 
  19.         return new ResponseEntity<>(representation, new HttpHeaders(), ex.getError().getStatus()); 
  20.     } 
  21.  
  22.     @ExceptionHandler(value = ResourceNotFoundException.class) 
  23.     public ResponseEntity<ErrorReponse> handleResourceNotFoundException(ResourceNotFoundException ex, HttpServletRequest request) { 
  24.         ErrorReponse errorReponse = new ErrorReponse(ex, request.getRequestURI()); 
  25.         return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorReponse); 
  26.     } 

(重要)一點擴展:

哈哈!實際上我多加了一個算是多余的異常捕獲方法handleResourceNotFoundException() 主要是為了考考大家當我們拋出了 ResourceNotFoundException異常會被下面哪一個方法捕獲呢?

答案:

會被handleResourceNotFoundException()方法捕獲。因為 @ExceptionHandler 捕獲異常的過程中,會優(yōu)先找到最匹配的。

下面通過源碼簡單分析一下:

ExceptionHandlerMethodResolver.java中g(shù)etMappedMethod決定了具體被哪個方法處理。

 

  1. @Nullable 
  2.     private Method getMappedMethod(Class<? extends Throwable> exceptionType) { 
  3.         List<Class<? extends Throwable>> matches = new ArrayList<>(); 
  4.     //找到可以處理的所有異常信息。mappedMethods 中存放了異常和處理異常的方法的對應關(guān)系 
  5.         for (Class<? extends Throwable> mappedException : this.mappedMethods.keySet()) { 
  6.             if (mappedException.isAssignableFrom(exceptionType)) { 
  7.                 matches.add(mappedException); 
  8.             } 
  9.         } 
  10.     // 不為空說明有方法處理異常 
  11.         if (!matches.isEmpty()) { 
  12.       // 按照匹配程度從小到大排序 
  13.             matches.sort(new ExceptionDepthComparator(exceptionType)); 
  14.       // 返回處理異常的方法 
  15.             return this.mappedMethods.get(matches.get(0)); 
  16.         } 
  17.         else { 
  18.             return null
  19.         } 
  20.     } 

從源代碼看出:getMappedMethod()會首先找到可以匹配處理異常的所有方法信息,然后對其進行從小到大的排序,最后取最小的那一個匹配的方法(即匹配度最高的那個)。

寫一個拋出異常的類測試

Person.java

 

  1. public class Person { 
  2.     private Long id; 
  3.     private String name
  4.  
  5.     // 省略 getter/setter 方法 

ExceptionController.java(拋出一場的類)

 

  1. @RestController 
  2. @RequestMapping("/api"
  3. public class ExceptionController { 
  4.  
  5.     @GetMapping("/resourceNotFound"
  6.     public void throwException() { 
  7.         Person p=new Person(1L,"SnailClimb"); 
  8.         throw new ResourceNotFoundException(ImmutableMap.of("person id:", p.getId())); 
  9.     } 
  10.  

源碼地址:https://github.com/Snailclimb/springboot-guide/tree/master/source-code/basis/springboot-handle-exception-improved

 

責任編輯:武曉燕 來源: JavaGuide
相關(guān)推薦

2021-04-20 10:50:38

Spring Boot代碼Java

2022-10-26 07:14:25

Spring 6Spring業(yè)務

2024-10-24 08:21:33

2019-01-24 16:11:19

前端全局異常數(shù)據(jù)校驗

2024-08-02 09:15:22

Spring捕捉格式

2023-09-24 13:55:42

Spring應用程序

2025-02-07 09:11:04

JSON對象策略

2024-10-28 08:32:22

統(tǒng)一接口響應SpringBoot響應框架

2011-03-24 09:34:41

SPRING

2022-04-08 16:27:48

SpringBoot異常處理

2013-03-18 10:31:22

JS異常

2022-08-03 07:07:10

Spring數(shù)據(jù)封裝框架

2023-10-10 13:23:18

空指針異常Java

2024-09-27 12:27:31

2025-02-13 00:34:22

Spring對象系統(tǒng)

2024-11-11 11:30:34

2021-04-30 07:34:01

Spring BootController項目

2024-12-18 16:19:51

2025-05-23 10:20:00

2025-04-22 08:20:51

點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产色在线 | 国产女人第一次做爰毛片 | 日韩色视频| 国产精品久久久久久久久久久久久 | 免费黄网站在线观看 | 狠狠草视频 | 国产精品久久久久久吹潮 | 91精品国产乱码麻豆白嫩 | 亚洲一区视频在线播放 | 欧美激情在线精品一区二区三区 | 国产亚洲一区二区三区在线 | 国产精品国产精品国产专区不卡 | 天天草视频 | 91视频88av| 亚洲播放一区 | 青青艹在线视频 | 麻豆一区二区三区精品视频 | 成人一区二区三区在线观看 | 国产午夜精品久久久久免费视高清 | 91精品国产乱码久久久久久久久 | 91精品在线观看入口 | 国产www. | 精品1区 | 久久高清免费视频 | 美女久久 | 91精品国产综合久久久久久漫画 | 久久毛片| 精精国产xxxx视频在线播放7 | 久久网站免费视频 | 黄色免费网 | 成人欧美一区二区三区在线播放 | 蜜桃在线视频 | 56pao在线 | 久久久一二三 | 精品久久久久久久久久久院品网 | 9999久久 | 天天操夜夜操 | xxx.在线观看 | 一级网站 | 97av| 亚洲精品自在在线观看 |