springboot實現(xiàn)全局異常處理的方法(住家飯系統(tǒng))
在實際項目開發(fā)中,定義全局異常處理至關重要通過全局異常處理器(使@ControllerAdvice
和@ExceptionHandler
注解),可以集中捕獲和處理各種異常,避免在每個控制器方法中重復編寫異常處理代碼。
住家飯系統(tǒng)將異常類型分為客戶端異常(ClientException),系統(tǒng)異常(ServiceException),遠程調用異常(RemoteException)。類結構圖如下:
我們需先定義一個抽象異常類 AbstractException ,該抽象類繼承自 RuntimeException 類,通過該類約束異常類行為。
/** * 抽象項目中的三類異常,客戶端異常、服務端異常和遠程服務調用異常 */ @Data public abstract class AbstractException extends RuntimeException{ public final String errorCode; public final String errorMsg; public AbstractException(String errorMsg, Throwable throwable, IErrorCode errorCode) { super(errorMsg, throwable); this.errorCode = errorCode.code(); this.errorMsg = Optional.ofNullable(StringUtils.hasLength(errorMsg) ? errorMsg : null).orElse(errorCode.msg()); } }
接著在分別定義客戶端異常、服務端異常和遠程調用異常類。
public class ClientException extends AbstractException{ public ClientException (IErrorCode errorCode) { super(null, null, errorCode); } public ClientException(IErrorCode errorCode, String errorMsg) { super(errorMsg, null, errorCode); } public ClientException(String message, Throwable throwable, IErrorCode errorCode) { super(message, throwable, errorCode); } @Override public String toString() { return "ClientException{" + "code='" + errorCode + "'," + "message='" + errorMsg + "'" + '}'; } }
public class ServiceException extends AbstractException{ public ServiceException(String message) { this(message, null, BaseErrorCode.SERVICE_ERROR); } public ServiceException(IErrorCode errorCode) { this(null, errorCode); } public ServiceException(String message, IErrorCode errorCode) { this(message, null, errorCode); } public ServiceException(String message, Throwable throwable, IErrorCode errorCode) { super(Optional.ofNullable(message).orElse(errorCode.msg()), throwable, errorCode); } @Override public String toString() { return "ServiceException{" + "code='" + errorCode + "'," + "message='" + errorMsg + "'" + '}'; } }
public class RemoteException extends AbstractException{ public RemoteException(String errorMsg, Throwable throwable, IErrorCode errorCode) { super(errorMsg, throwable, errorCode); } @Override public String toString() { return "RemoteException{" + "code='" + errorCode + "'," + "message='" + errorMsg + "'" + '}'; } }
這樣,我們就完成了對三大基本異常類的定義。接下來我們需要通過springboot提供的@ControllerAdvice
和@ExceptionHandler
注解來實現(xiàn)全局異常攔截并處理。我們需定義一個GlobalExceptionHandler類,在該類中分別對參數(shù)驗證異常、應用內拋出的異常和最頂級的Throwable異常進行處理。
Component("globalExceptionHandlerByAdmin") @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { /** * 攔截參數(shù)驗證異常 */ @SneakyThrows @ExceptionHandler(value = MethodArgumentNotValidException.class) public Result validExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException ex) { BindingResult bindingResult = ex.getBindingResult(); FieldError firstFieldError = CollectionUtil.getFirst(bindingResult.getFieldErrors()); String exceptionStr = Optional.ofNullable(firstFieldError) .map(FieldError::getDefaultMessage) .orElse(StrUtil.EMPTY); log.error("[{}] {} [ex] {}", request.getMethod(), getUrl(request), exceptionStr); return Results.failure(BaseErrorCode.CLIENT_ERROR.code(), exceptionStr); } /** * 攔截應用內拋出的異常 */ @ExceptionHandler(value = {AbstractException.class}) public Result abstractException(HttpServletRequest request, AbstractException ex) { if (ex.getCause() != null) { log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString(), ex.getCause()); return Results.failure(ex); } log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString()); return Results.failure(ex); } /** * 攔截未捕獲異常 */ @ExceptionHandler(value = Throwable.class) public Result defaultErrorHandler(HttpServletRequest request, Throwable throwable) { log.error("[{}] {} ", request.getMethod(), getUrl(request), throwable); if (Objects.equals(throwable.getClass().getSuperclass().getSimpleName(), AbstractException.class.getSimpleName())) { String errorCode = ReflectUtil.getFieldValue(throwable, "errorCode").toString(); String errorMessage = ReflectUtil.getFieldValue(throwable, "errorMessage").toString(); return Results.failure(errorCode, errorMessage); } return Results.failure(); } private String getUrl(HttpServletRequest request) { if (StringUtils.isEmpty(request.getQueryString())) { return request.getRequestURL().toString(); } return request.getRequestURL().toString() + "?" + request.getQueryString(); } }
今后,我們在項目里拋出的所有異常,都可以被 GlobalExceptionHandler 類捕獲并進行相應的處理。
public void register(UserRegisterReqDTO requestParam) { if(ObjectUtils.isEmpty(requestParam)) throw new ClientException(CLIENT_ERROR); if (hasUserName(requestParam.getUsername())) { throw new ServiceException(USER_NAME_EXIST); } try { int inserted = baseMapper.insert(BeanUtil.toBean(requestParam, UserDao.class)); if (inserted <= 0) { throw new ClientException(USER_SAVE_ERROR); } } catch (DuplicateKeyException ex) { throw new ServiceException(USER_EXIST); } }
到此這篇關于springboot實現(xiàn)全局異常處理的文章就介紹到這了,更多相關springboot全局異常處理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Springboot中@Async異步,實現(xiàn)異步結果合并統(tǒng)一返回方式
這篇文章主要介紹了Springboot中@Async異步,實現(xiàn)異步結果合并統(tǒng)一返回方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09Spring?boot集成easy?excel實現(xiàn)導入導出功能
這篇文章主要介紹了Spring?boot集成easy?excel實現(xiàn)導入導出操作,使用easyexcel,首先要引入easyexcel的maven依賴,具體的版本根據(jù)你的需求去設置,本文結合實例代碼講解的非常詳細,需要的朋友可以參考下2024-05-05