在開發中,我們經常會使用try/catch塊來捕獲異常進行處理,如果有些代碼中忘記捕獲異常或者不可見的一些異常出現,就會響應給前端一些不友好的提示,這時候我們可以使用全局異常處理。這樣就不用在代碼中寫那些煩人的try/catch塊了,代碼的可讀性也會提高。
SpringBoot提供的的注解@ControllerAdvice表示開啟全局異常捕獲,在自定義的異常方法上使用ExceptionHandler來進行統一處理。
下面一起看看如何優雅的處理全局異常!
一 定義響應狀態碼及信息的枚舉類
@Getter
public enum CodeEnum {
SUCCESS(0,"請求成功"),
ERROR(500,"未知異常"),
ERROR_EMPTY_RESULT(1001,"查詢結果為空"),
ERROR_INCOMPLETE_RESULT(1002,"請求參數不全");
private int code;
private String message;
CodeEnum(int code,String message){
this.code = code;
this.message = message;
}
}
二 定義響應數據的實體類
@Slf4j
@Data
public class R<T> implements Serializable {
private static final long serialVersionUID = 572235155491705152L;
/**
* 響應的狀態碼
*/
private int code;
/***
* 響應的信息
*/
private String message;
/**
* 響應數據
*/
private T data;
/**
* 放入響應碼並返回
* @param code
* @param msg
* @return
*/
public R fillCode(int code,String msg){
this.code = code;
this.message = msg;
return this;
}
/**
* 放入響應碼並返回
* @param codeEnum
* @return
*/
public R fillCode(CodeEnum codeEnum){
this.code = codeEnum.getCode();
this.message = codeEnum.getMessage();
return this;
}
/**
* 放入數據並響應成功狀態
* @param data
* @return
*/
public R fillData(T data){
this.code = CodeEnum.SUCCESS.getCode();
this.message = CodeEnum.SUCCESS.getMessage();
this.data = data;
return this;
}
}
三 自定義兩個異常
根據業務需求自定義異常,在本文中我定義了兩個異常,分別用作響應結果為空時處理和請求參數錯誤時處理。
@Data
public class EmptyResutlException extends RuntimeException {
private static final long serialVersionUID = -8839210969758687047L;
private int code;
private String message;
public EmptyResutlException(CodeEnum codeEnum){
this.code = codeEnum.getCode();
this.message = codeEnum.getMessage();
}
}
@Data
public class RequestParamException extends RuntimeException {
private static final long serialVersionUID = 4748844811214637041L;
private int code;
private String message;
public RequestParamException(CodeEnum codeEnum){
this.code = codeEnum.getCode();
this.message = codeEnum.getMessage();
}
}
四 定義全局異常處理類
由於這里我想要響應的結果為實體類對象,因此我直接用@RestControllerAdvice來代替了@ControllerAdvice,這兩個注解的差別跟@Controller和@RestController一樣,rest的響應體為json格式的數據。
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 查詢結果為空時處理
* @param e
* @return
*/
@ExceptionHandler(EmptyResutlException.class)
public R emptyResultExceptionHandler(EmptyResutlException e){
log.error("查詢結果為空:{}",e.getMessage());
R result = new R();
result.fillCode(e.getCode(),e.getMessage());
return result;
}
/**
* 請求參數錯誤時處理
* @param e
* @return
*/
@ExceptionHandler(RequestParamException.class)
public R requestParamExceptionHandler(RequestParamException e){
log.error("請求參數不合法:{}",e.getMessage());
R result = new R();
result.fillCode(e.getCode(),e.getMessage());
return result;
}
/**
* 處理其他異常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public R exceptionHandler(Exception e){
log.error("未知異常:{}",e.getMessage());
R result = new R();
result.fillCode(CodeEnum.ERROR);
return result;
}
}
五 自定義接口測試異常
@RestController
public class TestController {
@GetMapping("getString")
public R getString(String name){
if(StringUtils.isEmpty(name)){
throw new RequestParamException(1002,"請求參數name為空");
}else if ("Java旅途".equals(name)) {
// 這里沒有查詢操作,當請求參數是Java旅途的時候,模擬成查詢結果為空
throw new EmptyResutlException(1001,"查詢結果為空");
}
// 這里模擬一下除自定義異常外的其他兩種異常
int i = 0;
i = 5/i;
return new R().fillData(name);
}
}
在實際開發中可以自定義響應狀態碼的枚舉類和自定義異常以滿足需求。
本文示例代碼已上傳至github,點個star支持一下!
Spring Boot系列教程目錄
spring-boot-route(一)Controller接收參數的幾種方式
spring-boot-route(二)讀取配置文件的幾種方式
spring-boot-route(五)整合swagger生成接口文檔
spring-boot-route(六)整合JApiDocs生成接口文檔
spring-boot-route(七)整合jdbcTemplate操作數據庫
spring-boot-route(八)整合mybatis操作數據庫
spring-boot-route(九)整合JPA操作數據庫
spring-boot-route(十一)數據庫配置信息加密
spring-boot-route(十二)整合redis做為緩存
spring-boot-route(十三)整合RabbitMQ
spring-boot-route(十五)整合RocketMQ
spring-boot-route(十六)使用logback生產日志文件
spring-boot-route(十七)使用aop記錄操作日志
spring-boot-route(十八)spring-boot-adtuator監控應用
spring-boot-route(十九)spring-boot-admin監控服務
spring-boot-route(二十)Spring Task實現簡單定時任務
spring-boot-route(二十一)quartz實現動態定時任務
spring-boot-route(二十二)實現郵件發送功能
spring-boot-route(二十四)分布式session的一致性處理
spring-boot-route(二十五)兩行代碼實現國際化
spring-boot-route(二十六)整合webSocket
這個系列的文章都是工作中頻繁用到的知識,學完這個系列,應付日常開發綽綽有余。如果還想了解其他內容,掃面下方二維碼告訴我,我會進一步完善這個系列的文章!

