前言
以後的知識點呀、報錯修復啥的都改成實習筆記啦,除非我實習期結束啦。這幾天鑑權部分基本完成了,老闆讓我寫CRUD,秉承着代碼優雅的前提,我開始看參數校驗。
整齊但是不優雅的if-else
你在日常敲代碼中,有沒有遇到這種情況,前端傳到後端的參數多,且大多數都需要校驗,這樣子你是不是需要很多if來判斷他們是否是符合邏輯的。比如:
if(schoolInfo!=null&&schoolInfo.getId()!=null) {
return RestResult.failure();
}
以上舉個小例子,這樣子寫雖然看起來很整齊且易懂,但是參數一多,邏輯還沒開始,就一堆if語句在上面,有點不太優雅。
@Validated
其實springboot官方文檔裏有推薦使用這個東西來做參數校驗,用法也很簡單,有興趣的小夥伴可以去網上搜索下用法,這裏舉個例子
@Null
表示參數必須爲空,只需要在實體類的參數上標識即可,您還可以加上報錯信息,例如:
@Null(message = "Id存在非法值")
private String id;
標識後,在接收參數的controller上,使用@Validated註解,例如
public RestResult addSchool(@Validated SchoolInfo schoolInfo)
如此,如果id中有值,會報異常,異常錯誤信息是你在message中填寫的字。
不太好看的返回
如果您將錯誤信息直接返回的話,會是一大串字符串,這裏測試的時候忘記截圖了,小夥伴可以自己看看,爲了使返回好看一點,有請今天的第二個主角:
@ControllerAdvice 統一異常處理
首先,我們要知道,在不同情況下,@Validated 返回的異常是不同的,以下:
//處理Get請求中 使用@Valid 驗證路徑中請求實體校驗失敗後拋出的異常,詳情繼續往下看代碼
BindException e
//處理請求參數格式錯誤 @RequestParam上validate失敗後拋出的異常是
ConstraintViolationException e
//處理請求參數格式錯誤 @RequestBody上validate失敗後拋出的異常是MethodArgumentNotValidException異常。
MethodArgumentNotValidException e
當我們知道這些之後,就可以開始寫異常處理:
/**
* 統一異常處理
* jackson
* 時間:2020年04月10日16:03:05
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public RestResult handle(Throwable e, HttpServletRequest request) {
/**
* 參數校驗
*/
if(e instanceof BindException)
return this.BindExceptionHandler((BindException) e);
if(e instanceof ConstraintViolationException)
return this.ConstraintViolationExceptionHandler((ConstraintViolationException) e);
if(e instanceof MethodArgumentNotValidException)
return this.MethodArgumentNotValidExceptionHandler((MethodArgumentNotValidException) e);
}
//處理Get請求中 使用@Valid 驗證路徑中請求實體校驗失敗後拋出的異常,詳情繼續往下看代碼
public RestResult BindExceptionHandler(BindException e) {
log.error("參數異常");
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return RestResult.failure(message);
}
//處理請求參數格式錯誤 @RequestParam上validate失敗後拋出的異常是javax.validation.ConstraintViolationException
public RestResult ConstraintViolationExceptionHandler(ConstraintViolationException e) {
log.error("參數異常");
String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
return RestResult.failure(message);
}
//處理請求參數格式錯誤 @RequestBody上validate失敗後拋出的異常是MethodArgumentNotValidException異常。
public RestResult MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
log.error("參數異常");
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return RestResult.failure(message);
}
}
如果對統一異常管理不瞭解的小夥伴,建議去別人的博客觀摩觀摩,這裏controller一旦拋出異常,會被@RestControllerAdvice捕獲到,進入邏輯判斷,這裏比對了三個不同的異常,進行不同的處理。
爲了方便小夥伴,我貼下我的返回類
/**
* Description: 返回結果對象
* Author: jackson
* Date: 2020年04月10日10:16:46
**/
@Data
public class RestResult<T> implements Serializable {
private String msg;
private Integer code;
private T data;
Long count;//數據數量
List<T> datas;//返回數據
public RestResult(Integer code, String msg) {
super();
this.code = code;
this.msg = msg;
}
public RestResult(Integer code, String msg,T data) {
super();
this.code = code;
this.msg = msg;
this.data = data;
}
public RestResult(Integer code, String msg, List<T> datas, Long count) {
this.code = code;
this.msg = msg;
this.datas = datas;
this.count = count;
}
/* 無數據傳輸的 成功返回 */
public static <T> RestResult<T> success() {
return new RestResult<T>( ErrorCode.SUCCESS.getErrorCode(), ErrorCode.SUCCESS.getErrorMsg());
}
// public static <T> RestResult<T> success(String msg) {
// return new RestResult<T>(ErrorCode.SUCCESS.getErrorCode(), msg);
// }
public static <T> RestResult<T> success(ErrorCode errorCode) {
return new RestResult<T>( errorCode.getErrorCode(), errorCode.getErrorMsg());
}
/* 單個數據傳輸的 成功返回 */
public static <T> RestResult<T> success(T data) {
return new RestResult<T>( ErrorCode.SUCCESS.getErrorCode(), ErrorCode.SUCCESS.getErrorMsg(), data);
}
public static <T> RestResult<T> success(String msg, T data) {
return new RestResult<T>(ErrorCode.SUCCESS.getErrorCode(), msg, data);
}
public static <T> RestResult<T> success(ErrorCode errorCode, T data) {
return new RestResult<T>( errorCode.getErrorCode(), errorCode.getErrorMsg(), data);
}
/* 分頁數據傳輸的 成功返回 */
public static <T> RestResult<T> success(Long count, List<T> datas) {
return new RestResult<T>(ErrorCode.SUCCESS.getErrorCode(),ErrorCode.SUCCESS.getErrorMsg(),datas,count);
}
public static <T> RestResult<T> success(String msg, Long count, List<T> datas) {
return new RestResult<T>(ErrorCode.SUCCESS.getErrorCode(), msg, datas, count);
}
public static <T> RestResult<T> success(ErrorCode resultCode, Long count, List<T> datas) {
return new RestResult<T>( resultCode.getErrorCode(), resultCode.getErrorMsg(), datas ,count);
}
/* 無數據傳輸的 失敗返回 */
public static <T> RestResult<T> failure(String message) {
return new RestResult<T>( ErrorCode.FAILED.getErrorCode(), message);
}
public static <T> RestResult<T> failure() {
return new RestResult<T>( ErrorCode.FAILED.getErrorCode(), ErrorCode.FAILED.getErrorMsg());
}
public static <T> RestResult<T> failure(ErrorCode resultCode) {
return new RestResult<T>( resultCode.getErrorCode(), resultCode.getErrorMsg());
}
public static <T> RestResult<T> failure(CustomizeException c) {
return new RestResult<T>( c.getCode(),c.getMessage());
}
public static <T> RestResult<T> failure(Integer code, String msg) {
return new RestResult<T>( code, msg);
}
}
哎喲,還是覺得自己的異常捕獲類寫的不太好,不知道有沒有大佬指正下。
以上,希望能幫助到小夥伴。