基于spring boot實現(xiàn)一個全局異常處理器
還記得前面我們的實現(xiàn)邏輯,在service
層如果有校驗失敗我們會拋出異常,而controller
中我們對其并沒有處理,實際上spring boot有自己全局的錯誤處理形式。我們可以基于spring boot提供的切面特性,來很輕松的實現(xiàn)全局異常的處理,現(xiàn)在我們約定,只要后臺邏輯處理失敗的情況,我們都將拋出異常,包括controller
中的處理邏輯。
實現(xiàn)全局異常處理器
現(xiàn)在我們就來編寫全局異常處理器。
package com.xiaojuan.boot.common.web.support; import ... import static com.xiaojuan.boot.common.enums.BusinessError.*; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { /** 維護一個錯誤碼與http狀態(tài)碼的映射 */ private Map<Integer, HttpStatus> httpStatusMap; @PostConstruct private void init() { httpStatusMap = new HashMap<>(); httpStatusMap.put(NO_LOGIN.getValue(), HttpStatus.UNAUTHORIZED); httpStatusMap.put(HAS_NO_ROLE.getValue(), HttpStatus.FORBIDDEN); } @ExceptionHandler(BusinessException.class) public ResponseEntity<Response<?>> handleException(BusinessException ex) { log.error(ex.getMessage(), ex); // 默認服務(wù)器端錯誤,返回500狀態(tài)碼 HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; if (!StringUtils.isEmpty(ex.getErrCode()) && httpStatusMap.containsKey(ex.getErrCode())) { status = httpStatusMap.get(ex.getErrCode()); } return ResponseEntity.status(status).body(Response.fail(ex.getMessage(), ex.getErrCode(), ex.getData())); } @ExceptionHandler(Exception.class) public ResponseEntity<Response<?>> handleException(Exception ex) { log.error(ex.getMessage(), ex); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Response.fail("小卷生鮮電商系統(tǒng)異常:" + ex.getMessage())); } }
代碼詳解
這里我們用了@RestControllerAdvice
注解對所有的@RestController
修飾的controller
都進行攔截,只要拋出了異常,就交給這個處理器來處理。
這里要說下響應(yīng)的http狀態(tài)碼,一般都返回200
,某些情況下我們將返回一個可以讓前端特別處理的狀態(tài)碼,比如用戶未登錄的請求被攔截了我們可以返回401
,用戶登錄了卻沒有權(quán)限的操作,我們返回403
,這樣前端對這塊直接從http狀態(tài)就能識別請求結(jié)果的狀態(tài)。而對于我們業(yè)務(wù)開發(fā)來說,關(guān)注的是業(yè)務(wù)處理的錯誤碼,在這里我們和請求http狀態(tài)碼之間做了一個映射轉(zhuǎn)換,維護在httpStatusMap
成員變量中。
接下來,我們寫了兩個異常處理方法,它們都必須用@ExceptionHandler
注解來指定我們要處理的異常的類型,這里我們只考慮兩種異常:我們自定義的業(yè)務(wù)異常BusinessException
和最大的Exception
。
對于BusinessException
,我們要考慮HttpStatus
的判斷邏輯,如果我們將某些業(yè)務(wù)錯誤碼和http狀態(tài)碼做了映射,那么對于這些業(yè)務(wù)錯誤碼我們就取映射到的http狀態(tài)碼來返回,否則我們返回服務(wù)器端錯誤的500
狀態(tài)碼。
注意處理方法最后的返回結(jié)果,我們使用的是ResponseEntity<Response<?>>
,spring web模塊提供的ResponseEntity
可以幫助我們按照指定的http狀態(tài)碼并解析指定格式的內(nèi)容體(Spring Boot默認配置json形式)進行前端響應(yīng)。而要響應(yīng)的對象就是我們之前定義的Response
,只不過我們將字段errCode
的類型從原來的String
改成了Integer
,因為業(yè)務(wù)錯誤碼我們就定義為數(shù)值型,同樣的還有BusinessException
類中的errCode
字段類型的調(diào)整。
除了BusinessException
,我們只處理最大的Exception
,http狀態(tài)碼固定為500
,錯誤消息也統(tǒng)一以固定的形式開頭。
錯誤碼枚舉類
將應(yīng)用中業(yè)務(wù)錯誤碼我們定義在一個枚舉中進行維護:
package com.xiaojuan.boot.common.enums; import ... @Getter @AllArgsConstructor public enum BusinessError { PARAM_INVALID("參數(shù)校驗失敗", 10001), RECORD_EXISTS("后臺記錄已存在", 10002), HAS_NO_ROLE("用戶未授權(quán),不能訪問", 403), NO_LOGIN("請先登錄再操作", 401); private final String label; private final Integer value; }
這里我們給出默認的說明,一般在拋出業(yè)務(wù)異常時我們可以指定更具體的錯誤,而不會使用這里默認的錯誤消息。
service層拋出異常調(diào)整
現(xiàn)在我們對service層拋出異常做下調(diào)整,一般我們只要傳入錯誤信息來構(gòu)造BusinessException
。有些時候我們還可以傳入錯誤碼來進一步區(qū)分這些錯誤。
實現(xiàn)自己的Assert工具
既然我們先前定義了自己的BusinessException
,并且在其中維護了業(yè)務(wù)錯誤碼errCode
,就沒必要用spring的Assert
工具了,因為它拋出來的是IllegalStateException
異常,最終被我們?nèi)之惓L幚砥饕宰畲蟮?code>Exception的處理邏輯進行包裝響應(yīng)結(jié)果,自然“參數(shù)校驗失敗”的錯誤碼類型就丟了,因此這里我們基于spring對Assert
的實現(xiàn),我們包裝為自己的Assert
:
package com.xiaojuan.boot.util; import ... public class Assert { public static void hasText(@Nullable String text, String message) { if (!StringUtils.hasText(text)) { throw new BusinessException(message, BusinessError.PARAM_INVALID.getValue()); } } }
controller層拋出異常
最后我們將原來預(yù)留todo
注釋的地方改為拋出異常的形式:
最后,我們再基于test.http
對拋出異常的測試場景進行測試,看是否達到預(yù)期的http狀態(tài)碼和json結(jié)構(gòu),這個大家自行測試。
到此這篇關(guān)于基于spring boot實現(xiàn)一個全局異常處理器的文章就介紹到這了,更多相關(guān)spring boot全局異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java批量插入數(shù)據(jù)的代碼實現(xiàn)
日常工作或者學(xué)習(xí)中,可能會遇到批量插入數(shù)據(jù)的需求,一般情況下數(shù)據(jù)量少的時候,我們會直接調(diào)用批量接口插入數(shù)據(jù)即可,當數(shù)據(jù)量特別大時,我們就會用到分批插入數(shù)據(jù),所以本文給大家介紹了Java批量插入數(shù)據(jù)的代碼實現(xiàn),需要的朋友可以參考下2024-01-01springmvc實現(xiàn)導(dǎo)出數(shù)據(jù)信息為excle表格示例代碼
本篇文章主要介紹了springmvc實現(xiàn)導(dǎo)出數(shù)據(jù)信息為excle表格,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧。2017-01-01基于Jenkins搭建.NET FrameWork持續(xù)集成環(huán)境
這篇文章主要介紹了基于Jenkins搭建.NET FrameWork持續(xù)集成環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08Java使用JXLS實現(xiàn)導(dǎo)出Excel
jxls作為一個開源工具,提供了一種高效且易于維護的方式來處理復(fù)雜的Excel導(dǎo)出需求,下面就跟隨小編一起來學(xué)習(xí)一下如何使用jxls實現(xiàn)導(dǎo)出Excel吧2025-01-01IDEA下Maven的pom文件導(dǎo)入依賴出現(xiàn)Auto build completed with errors的問題
這篇文章主要介紹了IDEA下Maven的pom文件導(dǎo)入依賴出現(xiàn)Auto build completed with errors,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06