簡介
在Spring Boot
專案中實現統一的異常處理是一種常見的做法,這有助於保持程式碼的整潔並提供一致的錯誤響應格式。Spring Boot
中的統一異常處理是一種機制,用於集中管理和格式化應用程式中丟擲的所有異常。這種機制可以提高程式的健壯性和使用者體驗,同時簡化開發過程。
統一異常處理的一些主要作用:
- 一致性:
保證了在不同地方發生的異常都能以相同的方式被處理和響應。
使用者或客戶端接收到的錯誤資訊和格式保持一致,有助於問題定位。 - 錯誤資訊定製:
可以根據需要定製錯誤資訊,包括HTTP狀態碼、錯誤程式碼和描述等。
這樣可以更好地向使用者解釋發生了什麼問題,並提供可能的解決方法。 - 日誌記錄:
在捕獲異常後,可以根據異常型別和級別記錄到日誌檔案中,便於後續分析和除錯。
日誌記錄可以幫助追蹤問題發生的時間點、環境和上下文。 - 資源釋放:
在某些情況下,可以在異常處理過程中釋放資源或者進行清理工作,確保系統穩定執行。 - API 文件化:
對於對外提供的 API,可以透過異常處理來定義預期的錯誤情況,這有助於生成清晰的 API 文件。 - 安全性:
可以避免敏感資訊洩露給客戶端,例如資料庫查詢語句、內部類名等。
可以返回更泛化的錯誤資訊,而不是具體的異常堆疊跟蹤。 - 效能最佳化:
透過合理設計異常處理邏輯,可以減少不必要的資源消耗和呼叫鏈路,從而提升整體效能。
實現
1.建立自定義異常類
根據專案場景建立一些自定義異常類 extends
RuntimeException
WarnException
警告類異常
@Data
public class WarnException extends RuntimeException{
public WarnException(String msg){
super(msg);
}
}
返回告警資訊,
日誌記錄WARN
級別日誌,且不列印堆疊
異常概要資訊不會落庫
UserException
使用者業務類異常
@Data
public class UserException extends RuntimeException {
public UserException(String msg) {
super(msg);
}
@Override
public String toString() {
return getClass().getName() + StringConstant.COLON +this.getMessage();
}
}
返回告警資訊,
日誌記錄ERROR
級別日誌,且列印堆疊
異常概要資訊落庫
StringConstant.COLON = ":"
PlatformException
系統內部異常
@Data
public class PlatformException extends RuntimeException {
public PlatformException(String msg) {
super(msg);
}
@Override
public String toString() {
return getClass().getName() + StringConstant.COLON +this.getMessage();
}
}
返回告警資訊,
日誌記錄ERROR
級別日誌,且列印堆疊
異常概要資訊落庫
StringConstant.COLON = ":"
2.建立全域性異常處理器
定義一個帶有 @ControllerAdvice
註解的類,並在其中宣告一個或多個帶有 @ExceptionHandler
註解的方法來處理特定型別的異常
ZKExceptionHandler
統一異常處理類
@ControllerAdvice
@Slf4j
public class ZKExceptionHandler {
@Autowired
private AlarmMsgService alarmMsgService;
@ExceptionHandler(value = Exception.class)
@ResponseBody
public <T> MsgData<T> handleException(Exception e) {
//預期內告警類異常不計入資料庫;日誌不記錄堆疊
if (e instanceof WarnException) {
WarnException warnException = (WarnException) e;
log.warn(warnException.getMessage());
return MsgData.fill(warnException.getMessage());
}
String msg = e.getMessage();
String exceptionName = e.getClass().getName();
String stackTrace = ExceptionUtils.getStackTrace(e);
//使用者異常
if (e instanceof UserException) {
alarmMsgService.saveUserAlarmMsg(msg, AlarmLevelEnum.ALARM, exceptionName, stackTrace);
log.error("UserException", e);
return MsgData.fill(msg);
}
//平臺類異常
if (e instanceof PlatformException) {
alarmMsgService.savePlatformAlarmMsg(msg, AlarmLevelEnum.ALARM, exceptionName, stackTrace);
log.error("PlatformException", e);
return MsgData.fill(msg);
}
//其他異常
alarmMsgService.saveOtherAlarmMsg("系統異常", AlarmLevelEnum.ALARM, exceptionName, stackTrace);
log.error("OtherException", e);
return MsgData.fill(msg);
}
}
alarmMsgService
為異常概要資訊入庫操作,可自定義替換為自己的資料庫操作
這裡會對三種自定義異常分別進行處理,用於達到資訊返回及記錄預期
對於其他異常也會進行兜底記錄及處理
MsgData
返回實體類
@Data
public class MsgData<T> {
private int status;
private String errorCode;
private String msg;
private T data;
public static <T> MsgData<T> success() {
return success(null);
}
public static <T> MsgData<T> success(T data) {
return success(null, data);
}
public static <T> MsgData<T> success(String msg) {
return success(msg, null);
}
public static <T> MsgData<T> success(String msg, T data) {
return success(HttpCodeConstant.SUCCESS, msg, data);
}
public static <T> MsgData<T> success(int status, String msg, T data) {
MsgData<T> msgData = new MsgData<>();
msgData.setStatus(status);
msgData.setMsg(msg);
msgData.setData(data);
return msgData;
}
public static <T> MsgData<T> fill(String msg) {
return fill(null, msg);
}
public static <T> MsgData<T> fill(String errorCode, String msg) {
return fill(HttpCodeConstant.ERROR, errorCode, msg, null);
}
public static <T> MsgData<T> fill(int status, String errorCode, String msg, T data) {
MsgData<T> msgData = new MsgData<>();
msgData.setStatus(status);
msgData.setErrorCode(errorCode);
msgData.setMsg(msg);
msgData.setData(data);
return msgData;
}
}
HttpCodeConstant.SUCCESS = 200
HttpCodeConstant.ERROR = 500
使用
透過throw
不同的Exception
進行區分不同的異常
// 警告類異常
throw new WarnException("測試WARN告警");
// 使用者業務類異常
throw new UserException("測試使用者告警");
// 平臺系統類異常
throw new PlatformException("測試平臺告警");
// 其他異常
throw new RuntimeException("測試系統告警");
結束