【快學springboot】5.全局異常捕獲,異常流處理業務邏輯

前言

上一篇文章說到,參數校驗,每每須要和全局的異常攔截器來配套使用,使得返回的數據結構永遠是保持一致的。參數異常springboot默認的返回結構:前端

{
 "timestamp": "2019-04-25T13:09:02.196+0000",
 "status": 400,
 "error": "Bad Request",
 "errors": [
 {
 "codes": [
 "Pattern.param.birthday",
 "Pattern.birthday",
 "Pattern.java.lang.String",
 "Pattern"
 ],
 "arguments": [
 {
 "codes": [
 "param.birthday",
 "birthday"
 ],
 "arguments": null,
 "defaultMessage": "birthday",
 "code": "birthday"
 },
 [],
 {
 "defaultMessage": "\d{4}-\d{2}-\d{2}",
 "codes": [
 "\d{4}-\d{2}-\d{2}"
 ],
 "arguments": null
 }
 ],
 "defaultMessage": "須要匹配正則表達式"\d{4}-\d{2}-\d{2}"",
 "objectName": "param",
 "field": "birthday",
 "rejectedValue": "apple",
 "bindingFailure": false,
 "code": "Pattern"
 }
 ],
 "message": "Validation failed for object='param'. Error count: 1",
 "path": "/validate/notblank"
}
複製代碼

無論是正常的狀況,仍是異常的狀況,對於前端(或者app)來講,最好返回值的結構都是一致的,這樣才方便解釋。java

定義一個BaseResult類,定義返回值的數據結構

public class BaseResult {
 private int code;
 private String message;
 private Object data;
 // 省略getter setter方法,全參構造方法
}
複製代碼

無論什麼接口,都採用這樣的數據結構返回給前端。好比約定code爲0時是成功,其餘錯誤定義出具體的錯誤碼,message放錯誤信息,data對象放相應的數據。web

定義全局異常處理器GlobalExceptionHandlerAdvice

@RestControllerAdvice
public class GlobalExceptionHandlerAdvice {

}
複製代碼

使用RestControllerAdvice能夠標識一個類爲異常捕獲類。正則表達式

捕獲異常

經過參數異常的測試,能夠知道參數有異常時會拋出org.springframework.web.bind.MethodArgumentNotValidException。咱們如今手動捕獲 這個異常,而且返回一個BaseResult格式的響應。spring

@ExceptionHandler(MethodArgumentNotValidException.class)
public BaseResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
 BindingResult result = e.getBindingResult();
 FieldError fieldError = result.getFieldError();
 String defaultMessage = fieldError.getDefaultMessage();
 return new BaseResult(11000, defaultMessage, null);
}
複製代碼

使用ExceptionHandler能夠捕獲異常類型。這裏捕獲了參數錯誤會拋出的異常,而後返回了自定義的結果。這裏錯誤碼爲隨便填寫,真實開發,建議定義一個錯誤碼枚舉類。springboot

效果以下:bash

【快學springboot】5.全局異常捕獲,異常流處理業務邏輯

返回的結果就比較友好了,前端處理起來也方便。數據結構

異常流處理業務邏輯

使用異常來處理業務邏輯,會使代碼寫起來更加流暢。好比說,一個刪除用戶數據的方法,返回值爲void(無返回值),可是當傳入的用戶id不存在的時候,就應該返回一個用戶不存在的結果,這對於void返回值的方法來講,顯得無能爲力。可是,使用異常流來處理該業務邏輯,會變得很是簡單。咱們直接拋出一個自定義異常,而後在異常捕獲器上捕獲該異常,再把結果返回給前端便可。app

定義一個WebException

public class WebException extends RuntimeException {
 private int code;
 private String errorMsg;
 public WebException(int code, String errorMsg) {
 super(errorMsg);
 this.code = code;
 this.errorMsg = errorMsg;
 }
 @Override
 public synchronized Throwable fillInStackTrace() {
 return this;
 }
 // 省略getter setter方法
}
複製代碼

這裏定義了一個運行時異常,重寫了fillInStackTrace方法,重寫該方法是不保留異常信息棧。由於咱們使用該異常來處理業務邏輯,都是咱們手動拋出的,因此也不須要保存異常信息棧了,這會提高性能。ide

在異常捕獲器添加WebException異常捕獲

@ExceptionHandler(WebException.class)
public BaseResult handleWebException(WebException e) {
 return new BaseResult(e.getCode(), e.getErrorMsg(), null);
}
複製代碼

模擬一段業務邏輯,拋出WebException

在以前的UserController類,修改以前寫的deleteUser方法,以下:

@DeleteMapping(value = "/{userId}")
public Object deleteUser(@PathVariable(value = "userId") Integer userId) {
 if (userId == 0) {
 throw new WebException(-1, "用戶不存在");
 }
 return new BaseResult(1, "成功", null);
}

複製代碼

這裏定義一個delete請求的接口,接收一個userId參數,若是userId等於0,則返回該用戶不存在。測試結果以下:

當userId爲0時,提示用戶不存在

【快學springboot】5.全局異常捕獲,異常流處理業務邏輯

當userId爲1時,提示成功.

【快學springboot】5.全局異常捕獲,異常流處理業務邏輯

總結

這裏實現了全局異常捕獲,而且介紹了異常流處理業務邏輯。這裏只是一個小demo,還有不少待改進的地方。好比說,我沒有定義一個錯誤碼枚舉類。在定義了錯誤碼枚舉類的前提下,修改構造BaseResult的模式,能夠採用靜態工廠模式來構造等。這裏就不展開討論了。

相關文章
相關標籤/搜索