springboot實(shí)現(xiàn)全局異常處理的方法(住家飯系統(tǒng))
在實(shí)際項(xiàng)目開發(fā)中,定義全局異常處理至關(guān)重要通過(guò)全局異常處理器(使@ControllerAdvice和@ExceptionHandler注解),可以集中捕獲和處理各種異常,避免在每個(gè)控制器方法中重復(fù)編寫異常處理代碼。
住家飯系統(tǒng)將異常類型分為客戶端異常(ClientException),系統(tǒng)異常(ServiceException),遠(yuǎn)程調(diào)用異常(RemoteException)。類結(jié)構(gòu)圖如下:

我們需先定義一個(gè)抽象異常類 AbstractException ,該抽象類繼承自 RuntimeException 類,通過(guò)該類約束異常類行為。
/**
* 抽象項(xiàng)目中的三類異常,客戶端異常、服務(wù)端異常和遠(yuǎn)程服務(wù)調(diào)用異常
*/
@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());
}
}接著在分別定義客戶端異常、服務(wù)端異常和遠(yuǎn)程調(diào)用異常類。
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 + "'" +
'}';
}
}這樣,我們就完成了對(duì)三大基本異常類的定義。接下來(lái)我們需要通過(guò)springboot提供的@ControllerAdvice和@ExceptionHandler注解來(lái)實(shí)現(xiàn)全局異常攔截并處理。我們需定義一個(gè)GlobalExceptionHandler類,在該類中分別對(duì)參數(shù)驗(yàn)證異常、應(yīng)用內(nèi)拋出的異常和最頂級(jí)的Throwable異常進(jìn)行處理。
Component("globalExceptionHandlerByAdmin")
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 攔截參數(shù)驗(yàn)證異常
*/
@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);
}
/**
* 攔截應(yīng)用內(nèi)拋出的異常
*/
@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();
}
}今后,我們?cè)陧?xiàng)目里拋出的所有異常,都可以被 GlobalExceptionHandler 類捕獲并進(jìn)行相應(yīng)的處理。
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);
}
}到此這篇關(guān)于springboot實(shí)現(xiàn)全局異常處理的文章就介紹到這了,更多相關(guān)springboot全局異常處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot中@Async異步,實(shí)現(xiàn)異步結(jié)果合并統(tǒng)一返回方式
這篇文章主要介紹了Springboot中@Async異步,實(shí)現(xiàn)異步結(jié)果合并統(tǒng)一返回方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Java中如何編寫一個(gè)數(shù)的n次方(冪運(yùn)算)?
本文介紹了使用pow函數(shù)和自定義for循環(huán)計(jì)算冪的O(n)時(shí)間復(fù)雜度方法,然后重點(diǎn)講解了快速冪算法的分治思想,以及從二進(jìn)制角度的解釋,包括如何通過(guò)位運(yùn)算和循環(huán)迭代實(shí)現(xiàn)高效計(jì)算,給出了Java代碼實(shí)現(xiàn)2024-07-07
使用Java8實(shí)現(xiàn)觀察者模式的方法(上)
本文給大家介紹使用java8實(shí)現(xiàn)觀察者模式的方法,涉及到j(luò)ava8觀察者模式相關(guān)知識(shí),對(duì)此感興趣的朋友一起學(xué)習(xí)吧2016-02-02
Java學(xué)習(xí)教程之定時(shí)任務(wù)全家桶
這篇文章主要給大家介紹了關(guān)于Java學(xué)習(xí)教程之定時(shí)任務(wù)全家桶的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
SpringBoot項(xiàng)目@Async方法問題解決方案
這篇文章主要介紹了SpringBoot項(xiàng)目@Async方法問題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出功能
這篇文章主要介紹了Spring?boot集成easy?excel實(shí)現(xiàn)導(dǎo)入導(dǎo)出操作,使用easyexcel,首先要引入easyexcel的maven依賴,具體的版本根據(jù)你的需求去設(shè)置,本文結(jié)合實(shí)例代碼講解的非常詳細(xì),需要的朋友可以參考下2024-05-05
Java解析pdf格式發(fā)票的代碼實(shí)現(xiàn)
為了減少用戶工作量及誤操作的可能性,需要實(shí)現(xiàn)用戶上傳PDF格式的發(fā)票,系統(tǒng)通過(guò)解析PDF文件獲取發(fā)票內(nèi)容,并直接將其寫入表單,以下文章記錄了功能實(shí)現(xiàn)的代碼,需要的朋友可以參考下2024-08-08
Java如何比較兩個(gè)對(duì)象并獲取不相等的字段詳解
這篇文章主要給大家介紹了關(guān)于Java如何比較兩個(gè)對(duì)象并獲取不相等的字段以及JAVA判斷(獲取)兩個(gè)相同對(duì)象不同的數(shù)據(jù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-11-11

