SpringBoot項目實現(xiàn)統(tǒng)一異常處理的最佳方案

前言
近日心血來潮想做一個開源項目,目標是做一款可以適配多端、功能完備的模板工程,包含后臺管理系統(tǒng)和前臺系統(tǒng),開發(fā)者基于此項目進行裁剪和擴展來完成自己的功能開發(fā)。本項目為前后端分離開發(fā),后端基于Java21和SpringBoot3開發(fā),后端使用Spring Security、JWT、Spring Data JPA等技術(shù)棧,前端提供了vue、angular、react、uniapp、微信小程序等多種腳手架工程。
項目地址:https://gitee.com/breezefaith/fast-alden
在前后端分離的項目開發(fā)過程中,我們通常會對數(shù)據(jù)返回格式進行統(tǒng)一的處理,這樣可以方便前端人員取數(shù)據(jù),后端發(fā)生異常時同樣會使用此格式將異常信息返回給前端。本文將介紹在SpringBoot項目中如何實現(xiàn)統(tǒng)一異常處理。
實現(xiàn)步驟
定義統(tǒng)一響應對象類
/**
* 響應結(jié)果類
*
* @param <T> 任意類型
*/
@Data
public class ResponseResult<T> {
/**
* 響應狀態(tài)碼,200是正常,非200表示異常
*/
private int status;
/**
* 異常編號
*/
private String errorCode;
/**
* 異常信息
*/
private String message;
/**
* 響應數(shù)據(jù)
*/
private T data;
public static <T> ResponseResult<T> success() {
return success(HttpServletResponse.SC_OK, null, null);
}
public static <T> ResponseResult<T> success(T data) {
return success(HttpServletResponse.SC_OK, null, data);
}
public static <T> ResponseResult<T> fail(String message) {
return fail(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, message, null);
}
public static <T> ResponseResult<T> fail(String errorCode, String message) {
return fail(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorCode, message, null);
}
public static <T> ResponseResult<T> success(int status, String message, T data) {
ResponseResult<T> r = new ResponseResult<>();
r.setStatus(status);
r.setMessage(message);
r.setData(data);
return r;
}
public static <T> ResponseResult<T> fail(int status, String errorCode, String message) {
return fail(status, errorCode, message, null);
}
public static <T> ResponseResult<T> fail(int status, String errorCode, String message, T data) {
ResponseResult<T> r = new ResponseResult<>();
r.setStatus(status);
r.setErrorCode(errorCode);
r.setMessage(message);
r.setData(data);
return r;
}
}定義業(yè)務異常枚舉接口和實現(xiàn)
通常一個系統(tǒng)中的自定義業(yè)務異常是可窮舉的,可以考慮通過定義枚舉的方式來列舉所有的業(yè)務異常。
首先我們來定義一個異常信息枚舉的基類接口。
public interface IBizExceptionEnum {
String getCode();
String getMessage();
}再給出一個常用的異常信息的枚舉類,如果有其他業(yè)務模塊的異常信息,同樣可以通過實現(xiàn)IBizExceptionEnum接口來進行定義。
@Getter
public enum BizExceptionEnum implements IBizExceptionEnum {
ENTITY_IS_NULL("Base_Entity_Exception_0001", "實體為空"),
ENTITY_ID_IS_NULL("Base_Entity_Exception_0002", "實體id字段為空"),
ENTITY_ID_IS_DUPLCATED("Base_Entity_Exception_0003", "實體id字段%s重復");
private final String code;
private final String message;
BizExceptionEnum(String code, String message) {
this.code = code;
this.message = message;
}
}定義業(yè)務異常基類
業(yè)務異?;?code>BizException繼承自RuntimeException,代碼中主動拋出的異常建議都包裝為該類的實例。
/**
* 業(yè)務異?;?,支持參數(shù)化的異常信息
*/
@Getter
@Setter
public class BizException extends RuntimeException {
private String code;
private Object[] args;
public BizException() {
super();
}
public BizException(String message) {
super(message);
}
public BizException(Throwable cause) {
super(cause);
}
public BizException(String message, Throwable cause) {
super(message, cause);
}
public BizException(Throwable cause, String code, String message, Object... args) {
super(message, cause);
this.code = code;
this.args = args;
}
public BizException(String code, String message, Object... args) {
super(message);
this.code = code;
this.args = args;
}
public BizException(IBizExceptionEnum exceptionEnum, Object... args) {
this(exceptionEnum.getCode(), exceptionEnum.getMessage(), args);
}
public BizException(Throwable cause, IBizExceptionEnum exceptionEnum, Object... args) {
this(cause, exceptionEnum.getCode(), exceptionEnum.getMessage(), args);
}
@Override
public String getMessage() {
if (code != null) {
if (args != null && args.length > 0) {
return String.format(super.getMessage(), args);
}
}
return super.getMessage();
}
}定義全局異常處理切面
本步驟需要使用@RestControllerAdvice注解,它是一個組合注解,由@ControllerAdvice、@ResponseBody組成,而@ControllerAdvice繼承了@Component,因此@RestControllerAdvice本質(zhì)上是個Component,用于定義@ExceptionHandler,@InitBinder和@ModelAttribute方法,適用于所有使用@RequestMapping方法。
還要用到@ExceptionHandler注解,可以認為它是一個異常攔截器,它采用“就近原則”,存在多個滿足條件的異常處理器時會選擇最接近的一個來使用。它本質(zhì)上就是使用Spring AOP定義的一個切面,在系統(tǒng)拋出異常后執(zhí)行。
具體實現(xiàn)代碼如下:
/**
* 全局異常處理切面
*/
@RestControllerAdvice
public class GlobalExceptionHandlerAdvice {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAdvice.class);
@ExceptionHandler({BizException.class})
public ResponseResult<Object> handleBizException(BizException e, HttpServletRequest request, HttpServletResponse response) {
log.error(e.getCode() + ": " + e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return ResponseResult.fail(e.getCode(), e.getMessage());
}
@ExceptionHandler({RuntimeException.class, Exception.class})
public ResponseResult<Object> handleRuntimeException(Exception e, HttpServletRequest request, HttpServletResponse response) {
log.error(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return ResponseResult.fail(e.getMessage());
}
}上述代碼會對系統(tǒng)中拋出的BizException、RuntimeException和Exception對象進行處理,把異常包裝為ResponseResult對象后將異常編號和異常信息返回給前端。
測試和驗證
下面我們就可以定義一個Controller類來進行簡單的測試。
@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/method1")
public ResponseResult<Integer> method1() {
throw new BizException(BizExceptionEnum.ENTITY_IS_NULL);
}
@GetMapping("/method2")
public void method2() {
throw new BizException(BizExceptionEnum.ENTITY_ID_IS_NULL);
}
@GetMapping(value = "/method3")
public String method3() {
throw new BizException(BizExceptionEnum.ENTITY_ID_IS_DUPLCATED, "1");
}
@GetMapping(value = "/method4")
public String method4() {
// 拋出ArithmeticException異常
return String.valueOf(1 / 0);
}
}總結(jié)
本文介紹了如何在SpringBoot項目中實現(xiàn)統(tǒng)一異常處理,如有錯誤,還望批評指正。
在后續(xù)實踐中我也是及時更新自己的學習心得和經(jīng)驗總結(jié),希望與諸位看官一起進步。
到此這篇關(guān)于SpringBoot項目實現(xiàn)統(tǒng)一異常處理的最佳方案的文章就介紹到這了,更多相關(guān)SpringBoot統(tǒng)一異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot 用監(jiān)聽器統(tǒng)計在線人數(shù)案例分析
這篇文章主要介紹了springboot 用監(jiān)聽器統(tǒng)計在線人數(shù)案例分析,質(zhì)是統(tǒng)計session 的數(shù)量,思路很簡單,具體實例代碼大家參考下本文2018-02-02
詳解SpringBoot中的統(tǒng)一結(jié)果返回與統(tǒng)一異常處理
這篇文章主要將通過詳細的討論和實例演示來幫助你更好地理解和應用Spring Boot中的統(tǒng)一結(jié)果返回和統(tǒng)一異常處理,感興趣的小伙伴可以了解下2024-03-03
Java哈希表HashTable(又稱散列表)的實現(xiàn)及練習題
哈希表又稱為散列表,是一種通過哈希函數(shù)將數(shù)據(jù)映射到特定位置的數(shù)據(jù)結(jié)構(gòu),這篇文章主要介紹了Java哈希表HashTable(又稱散列表)的實現(xiàn)及練習題的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2025-12-12
SpringBoot項目多模塊項目中父類與子類pom.xml的關(guān)聯(lián)問題小結(jié)
這篇文章主要介紹了SpringBoot項目多模塊項目中父類與子類pom.xml的關(guān)聯(lián)問題,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2025-04-04

