springboot實現(xiàn)全局異常捕獲的使用示例
導(dǎo)言:
為什么要做異常處理:
原因有三:
1、將系統(tǒng)產(chǎn)生的全部異常統(tǒng)一捕獲處理。
2、自定義異常需要由全局異常來捕獲。
3、JSR303規(guī)范的validator參數(shù)校驗器、參數(shù)校驗不通過、本身無法使用try…catch
其實對于前后端分離的項目做異常處理是很有必要的
在不出異常的情況下,后端將數(shù)據(jù)封裝成固定格式(也就是R類)返回給前端,方便前端去解析數(shù)據(jù)
例如如下R類:
@Data public class R<T> implements Serializable { private Integer code; //編碼:1成功,0和其它數(shù)字為失敗 private String msg; //錯誤信息 private T data; //數(shù)據(jù) private Map map = new HashMap(); //動態(tài)數(shù)據(jù) public static <T> R<T> success(T object) { R<T> r = new R<T>(); r.data = object; r.code = 1; return r; } public static <T> R<T> success(String msg,T object) { R<T> r = new R<T>(); r.data = object; r.code = 1; r.msg = msg; return r; } public static <T> R<T> error(String msg) { R r = new R(); r.msg = msg; r.code = 0; return r; } public static <T> R<T> success(String msg) { R r = new R(); r.msg = msg; r.code = 1; return r; } public R<T> add(String key, Object value) { this.map.put(key, value); return this; } }
正常不出異常的情況下根據(jù)controller層返回的數(shù)據(jù):
controller層
//正常情況 @GetMapping("/hhy/1") public R info(){ int i = 60/1; return R.success("成功",i); }
請求成功返回給前端數(shù)據(jù):
在出異常的情況下(模擬除0異常):
controller層:
//空指針異常 @GetMapping("/hhy/2") public R info2(){ int i = 60/0; return R.success("成功",i); }
出現(xiàn)異常前端拿不到數(shù)據(jù),并且后端報錯:
前端:
后端:
這樣雖然后端可以知道異常情況,但是前端就難受了,啥也不知道,就知道出錯了;
重點來了?。。。?!
這里就可以體現(xiàn)全局異常處理器的重要性了;讓前端的兄弟好受一點。
實現(xiàn)全局異常處理器捕獲異常
舉例:異常還是除0 異常:
java.lang.ArithmeticException: / by zero
這里的異常就是ArithmeticException
,異常信息為/ by zero
編寫全局異常捕獲類:GlobalExceptionHandler
/** * 全局異常捕獲 */ @Slf4j @ControllerAdvice(annotations = {RestController.class, Controller.class}) //只要類的注解上有這些注解。那么發(fā)生的異常都能被捕獲到 @ResponseBody public class GlobalExceptionHandler { /** * 處理除0異常捕獲 * @param exception * @return */ @ExceptionHandler(ArithmeticException.class)//ArithmeticException異常類型通過注解拿到 public R<String> exceptionHandler(ArithmeticException exception){ log.error(exception.getMessage());//在控制臺打印錯誤信息 return R.error(exception.getMessage()); } }
此時在controller層出現(xiàn)ArithmeticException(除0)異常時就會被全局異常處理器捕獲到:
后端::相比之前一大串報錯,是不是很清爽
前端:
在異常處理器里面已將錯誤信息封裝成返回類R返回給前端
相比之前返回給前端的一大串雜七雜八的,這個是不是超級清爽,并且可以根據(jù)code碼在前端將錯誤信息設(shè)置警告框
這樣前端的兄弟看到信息就知道,嗷嗷 后端出問題了 問題是除0異常,這樣就可以安心的去甩鍋給后端的哥們了;
實現(xiàn)原理:
想必注意到這個注解:
@ControllerAdvice(annotations = {RestController.class, Controller.class})
意思只要類的注解上有這些注解。那么發(fā)生的異常都能被捕獲到,例如例子中出現(xiàn)的異常的類的注解為:
異常捕獲類的@ResponseBody注解
當(dāng)我們在全局異常處理中使用@ResponseBody注解時,它可以將異常信息序列化為JSON或其他格式的字符串,并作為HTTP響應(yīng)的Body部分返回給客戶端。
這就是為什么前端的兄弟能看到如此清爽的返回數(shù)據(jù)格式:
不加@ResponseBody那就智能看到又臭又長的這個:
@ExceptionHandler(ArithmeticException.class)
具體攔截類上的@ExceptionHandler注解主要是指定去捕獲哪一種異常,這個很好理解
需要攔截捕獲哪一類異常就去指定具體的類異常,捕獲原理如上;
but··························
那么如果用戶在操作的時候,出現(xiàn)一些有違背業(yè)務(wù)邏輯的情況下,我們也視為操作異常,拋出自定義的異常,返回給前端,然后告訴用戶不能這么操作
自定義異常處理
1、首先要編寫異常自定義處理類:
CustomException
public class CustomException extends RuntimeException{ /** * 自定義業(yè)務(wù)異常類 * @param message */ public CustomException(String message){ super(message); log.info(message.toString()); } }
這里將業(yè)務(wù)層拋出的異常信息捕獲到,然后歸類為runtime運行時異常,
然后交給全局異常處理器去處理,給前端提供錯誤信息
2、在全局異常類里面去捕獲自定義異常CustomException
/** * 將業(yè)務(wù)層拋出的異常信息捕獲到,然后交給全局異常處理器去處理,給前端提供錯誤信息 * @param exception * @return */ @ExceptionHandler(CustomException.class)//RuntimeException異常類型通過注解拿到 public R<String> exceptionCategoryDelete(CustomException exception){ log.error(exception.getMessage());//在控制臺打印錯誤信息 return R.error(exception.getMessage()); }
原理上面已經(jīng)講過了,不在贅述
那我們來測試一下,在業(yè)務(wù)層拋出一個CustomException ,看能不能被全局異常類捕獲到:
后端:
前端:
這樣我們就可以愉快的解決異常問題了
這里稍稍解釋下@ControllerAdvice注解
@ControllerAdvice注解是基于Spring框架的AOP(面向切面編程)實現(xiàn)的。AOP是一種編程范式,它通過在應(yīng)用程序運行時,將橫跨多個組件的行為進行分離和管理。
在Spring框架中,通過AOP可以將一些通用的橫切關(guān)注點(比如異常處理、日志記錄等)從業(yè)務(wù)邏輯中剝離出來,并以聲明的方式進行集中管理。@ControllerAdvice注解就是利用了AOP的機制,在應(yīng)用程序的控制器層進行統(tǒng)一的全局異常處理和數(shù)據(jù)綁定。
底層實現(xiàn)上,@ControllerAdvice注解使用了Spring的核心功能之一:切面(Aspect)和增強(Advice)。通過定義一個帶有@ControllerAdvice注解的類,并在其中定義不同類型的增強(比如@ExceptionHandler注解用于異常處理),Spring會在運行時動態(tài)生成代理對象,將增強邏輯織入到目標控制器的方法調(diào)用中。
總結(jié)來說,@ControllerAdvice注解的底層實現(xiàn)基于Spring框架的AOP機制,通過切面和增強的方式,實現(xiàn)了全局異常處理和數(shù)據(jù)綁定的功能。
到此這篇關(guān)于springboot實現(xiàn)全局異常捕獲的使用示例的文章就介紹到這了,更多相關(guān)springboot 全局異常捕獲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何用Java?幾分鐘處理完?30?億個數(shù)據(jù)(項目難題)
現(xiàn)有一個 10G 文件的數(shù)據(jù),里面包含了 18-70 之間的整數(shù),分別表示 18-70 歲的人群數(shù)量統(tǒng)計,今天小編通過本文給大家講解如何用Java?幾分鐘處理完?30?億個數(shù)據(jù),這個問題一直以來是項目難題,今天通過本文給大家詳細介紹下,感興趣的朋友一起看看吧2022-07-07SpringBoot中引入MyBatisPlus的常規(guī)操作
這篇文章主要介紹了SpringBoot中引入MyBatisPlus的常規(guī)操作,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11Java 創(chuàng)建動態(tài)類和查看方法列表信息的實例
這篇文章主要介紹了 Java 創(chuàng)建動態(tài)類和查看方法列表信息的實例的相關(guān)資料,需要的朋友可以參考下2017-06-06Java并發(fā)源碼分析ConcurrentHashMap線程集合
這篇文章主要為大家介紹了Java并發(fā)源碼分析ConcurrentHashMap線程集合,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02