SpringBoot中@RestControllerAdvice注解實現(xiàn)全局異常處理類
需求
springboot中使用@RestControllerAdvice注解,完成優(yōu)雅的全局異常處理類,可以針對所有異常類型先進行通用處理后再對特定異常類型進行不同的處理操作。
注解講解
@RestControllerAdvice注解
@RestControllerAdvice是一個用于定義全局異常處理器的注解。當應(yīng)用程序內(nèi)發(fā)生未捕獲的異常時,全局異常處理器將捕獲該異常并返回對應(yīng)的響應(yīng),以避免應(yīng)用程序崩潰。它可以處理所有控制器中拋出的異常,包括請求處理方法中的異常、控制器構(gòu)造函數(shù)中的異常等。
@RestControllerAdvice注解是@ControllerAdvice和@ResponseBody注解的組合,它的作用是將所有的異常處理結(jié)果都以JSON格式返回給客戶端。
具體來說,當控制器中發(fā)生異常時,SpringBoot會在全局異常處理器中查找與異常匹配的處理方法,并執(zhí)行該方法來處理異常。
處理方法可以返回任何類型的值,如果返回對象是DataVO類型,則會將其轉(zhuǎn)換為JSON格式并返回給客戶端。
如果返回值是String類型,則會將其解釋為視圖名稱,并使用視圖解析器來解析視圖并生成HTML響應(yīng)。
因此,使用@RestControllerAdvice注解可以方便地定義全局異常處理器,并將所有異常處理結(jié)果以JSON格式返回給客戶端。
@ExceptionHandler注解
@ExceptionHandler是一個注解,用于定義異常處理方法。
當控制器中發(fā)生異常時,Spring Boot會在@ControllerAdvice或@RestControllerAdvice注解的類中查找與異常匹配的@ExceptionHandler注解標記的方法,并執(zhí)行該方法來處理異常。
@ExceptionHandler注解可以定義一個或多個異常類型,并將它們映射到對應(yīng)的異常處理方法。當控制器中發(fā)生指定類型的異常時,SpringBoot會自動調(diào)用對應(yīng)的異常處理方法,并將異常對象傳遞給該方法作為參數(shù)。
一般的全局異常處理類
@Slf4j @RestControllerAdvice public class GlobalExceptionHandler { private static final String DEFAULT_ERROR_MESSAGE = "系統(tǒng)繁忙,請稍后再試"; @ExceptionHandler(value = {SQLIntegrityConstraintViolationException.class}) public DataVO handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) { log.error(e.getMessage(), e); return new DataVO(SysConstant.CODE_ERROR, "當前主鍵存在于其他表的外鍵約束,請先處理父表中的該外鍵"); } @ExceptionHandler(value = {FileNotFoundException.class}) public DataVO handleFileNotFoundException(FileNotFoundException e) { log.error(e.getMessage(), e); return new DataVO(SysConstant.CODE_ERROR, "路徑不存在"); } @ExceptionHandler(value = {Exception.class}) public DataVO handleException(Exception e) { log.error(e.getMessage(), e); return new DataVO(SysConstant.CODE_ERROR, DEFAULT_ERROR_MESSAGE); } }
如例所示,使用@RestControllerAdvice注解聲明了GlobalExceptionHandler作為全局異常處理類,在這個類中的方法使用@ExceptionHandler注解指定某個方法處理對應(yīng)的錯誤類型。
在這個一般的全局處理類中,@ExceptionHandler注解會根據(jù)異常類型選擇最精確的處理方法進行處理,如果沒有找到對應(yīng)的處理方法,則會選擇更加通用的處理方法。這樣的處理方式會導(dǎo)致代碼重復(fù),每個處理方法都需要寫一遍通用的操作,例如日志記錄。
改進全局異常處理類
為了解決這個問題,我們可以將通用的異常處理邏輯抽象到一個方法中,并在處理方法中調(diào)用該方法
@Slf4j @RestControllerAdvice public class GlobalExceptionHandler { private static final String DEFAULT_ERROR_MESSAGE = "系統(tǒng)繁忙,請稍后再試"; @ExceptionHandler(value = {SQLIntegrityConstraintViolationException.class}) public DataVO handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) { log.error(e.getMessage(), e); return handleException(DEFAULT_ERROR_MESSAGE, e); } @ExceptionHandler(value = {FileNotFoundException.class}) public DataVO handleFileNotFoundException(FileNotFoundException e) { log.error(e.getMessage(), e); return handleException(DEFAULT_ERROR_MESSAGE, e); } @ExceptionHandler(value = {Exception.class}) public DataVO handleException(Exception e) { log.error(e.getMessage(), e); return handleException(DEFAULT_ERROR_MESSAGE, e); } private DataVO handleException(String defaultMessage, Throwable e) { if (e instanceof BusinessException) { return new DataVO(SysConstant.CODE_ERROR, e.getMessage()); } else if (e instanceof MethodArgumentNotValidException) { return new DataVO(SysConstant.CODE_ERROR, ((MethodArgumentNotValidException) e).getBindingResult().getFieldError().getDefaultMessage()); } else { return new DataVO(SysConstant.CODE_ERROR, defaultMessage); } } }
在這個示例中,定義了一個私有方法handleException,該方法接受一個默認錯誤消息和一個Throwable對象作為參數(shù),并返回一個DataVO對象。
在處理方法中,調(diào)用handleException方法來處理異常,并將默認錯誤消息作為參數(shù)傳遞給handleException方法。
這樣,我們就可以將通用的異常處理邏輯抽象到一個方法中,避免了重復(fù)代碼。同時,我們也可以在handleException方法中添加自己的邏輯,例如記錄日志等。
優(yōu)雅的全局異常處理類
handleException方法中的if-else語句太過臃腫,可以使用Map來優(yōu)化這個方法
@Slf4j @RestControllerAdvice public class GlobalExceptionHandler { private static final String errorMsg = SysConstant.DEFAULT_ERROR; private static final Map<Class<? extends Throwable>, Function<Throwable, DataVO<Null>>> EXCEPTION_HANDLER_MAP = new HashMap<>(); static { EXCEPTION_HANDLER_MAP.put(RuntimeException.class, e -> new DataVO<>(SysConstant.CODE_ERROR, e.getMessage())); EXCEPTION_HANDLER_MAP.put(DataIntegrityViolationException.class, e -> new DataVO<>(SysConstant.CODE_ERROR, "當前主鍵存在于其他表的外鍵約束,請先處理父表中的該外鍵")); EXCEPTION_HANDLER_MAP.put(FileNotFoundException.class, e -> new DataVO<>(SysConstant.CODE_ERROR, "路徑不存在")); } @ExceptionHandler(Exception.class) public DataVO<Null> handleException(Exception e) { log.error(e.toString()); return EXCEPTION_HANDLER_MAP.getOrDefault(e.getClass(), t -> new DataVO<>(SysConstant.CODE_ERROR, errorMsg)).apply(e); } }
在這個示例中,使用Map來存儲異常處理函數(shù),每個函數(shù)都接受一個Throwable對象作為參數(shù),并返回一個DataVO對象。
在處理方法中,根據(jù)異常類型從Map中獲取對應(yīng)的處理函數(shù),如果沒有找到對應(yīng)的處理函數(shù),則使用默認的處理函數(shù)。
然后,調(diào)用獲取到的處理函數(shù)來處理異常。這樣,就可以將異常處理函數(shù)集中在一個Map中,避免了if-else語句的臃腫。同時,也可以在異常處理函數(shù)handleException中添加自己的邏輯,例如記錄日志等。
我的通用值對象類DataVO(Data Value Object)
@Data //@JsonPropertyOrder({"code","msg","count","data"})//指定返回給前端的字段順序 public class DataVO<T> { private Integer code = 0; private String msg = ""; private Long count; private List<T> data; public DataVO() { } public DataVO(Integer code, String msg) { this.code = code; this.msg = msg; } public DataVO(Integer code, String msg, Long count, List<T> data) { this.code = code; this.msg = msg; this.count = count; this.data = data; } }
遇到問題
在測試的時候要處理外鍵約束報錯問題,控制臺發(fā)現(xiàn)報錯原因是SQLIntegrityConstraintViolationException,于是我在靜態(tài)異常Map中加入了SQLIntegrityConstraintViolationException處理,但是發(fā)現(xiàn)并沒有正常處理,還是返回的默認異常信息。
于是在控制臺輸出了一下那個錯誤的類,e.getClass()發(fā)現(xiàn)實際上是DataIntegrityViolationException,SQLIntegrityConstraintViolationException只是cause,改完之后測試成功處理異常并返回特定異常信息給前端。
到此這篇關(guān)于SpringBoot中@RestControllerAdvice注解全局異常處理類的文章就介紹到這了,更多相關(guān)@RestControllerAdvice注解全局異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot使用@RestController處理GET和POST請求的代碼詳解
- SpringBoot中@RestControllerAdvice @ExceptionHandler異常統(tǒng)一處理類失效原因分析
- SpringBoot中@RestControllerAdvice注解的使用
- SpringBoot的@RestControllerAdvice作用詳解
- SpringBoot常用注解@RestControllerAdvice詳解
- SpringBoot中的@RestControllerAdvice注解詳解
- SpringBoot?@RestControllerAdvice注解對返回值統(tǒng)一封裝的處理方法
- springboot @Controller和@RestController的區(qū)別及應(yīng)用詳解
- SpringBoot http請求注解@RestController原理解析
- springboot中@RestController注解實現(xiàn)
相關(guān)文章
Java中ArrayList與LinkedList的使用及區(qū)別詳解
這篇文章主要給大家介紹了關(guān)于Java中ArrayList與LinkedList的使用及區(qū)別的相關(guān)資料,ArrayList和LinkedList都是實現(xiàn)了List接口的容器類,用于存儲一系列的對象引用,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-11-11Spring Boot 非web應(yīng)用程序的實現(xiàn)
SpringBoot框架中,要創(chuàng)建一個非Web應(yīng)用程序(純 Java 程序),有兩種方式,下面就來介紹一下,感興趣的可以來了解一下2025-03-03Java字符編碼原理(動力節(jié)點Java學(xué)院整理)
Java開發(fā)中,常常會遇到亂碼的問題,一旦遇到這種問題,常常比較煩惱,大家都不想承認是自己的代碼問題,其實搞明白編碼的本質(zhì)過程就簡單多了,接下來小編給大家?guī)韏ava字符編碼原理,要求看看吧2017-04-04在SpringBoot 中從application.yml中獲取自定義常量方式
這篇文章主要介紹了在SpringBoot 中從application.yml中獲取自定義常量方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04