SpringBoot如何優雅的校驗引數
前言
做web開發有一點很煩人就是要校驗引數,基本上每個介面都要對引數進行校驗,比如一些格式校驗 非空校驗都是必不可少的。如果引數比較少的話還是容易 處理的一但引數比較多了的話程式碼中就會出現大量的IF ELSE
就比如下面這樣:
這個例子只是校驗了一下空引數。如果需要驗證郵箱格式和手機號格式校驗的話程式碼會更多,所以介紹一下validator
通過註解的方式進行校驗引數。
什麼是Validator
Bean Validation是Java定義的一套基於註解的資料校驗規範,目前已經從JSR 303的1.0版本升級到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成於2017.08),已經經歷了三個版本 。在SpringBoot
starter-web
中,所以無需在新增其他依賴。
註解介紹
validator內建註解
註解 |
詳細資訊 |
---|---|
@Null |
被註釋的元素必須為 null |
@NotNull |
被註釋的元素必須不為 null |
@AssertTrue |
被註釋的元素必須為 true |
@AssertFalse |
被註釋的元素必須為 false |
@Min(value) |
被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@Max(value) |
被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@DecimalMin(value) |
被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@DecimalMax(value) |
被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@Size(max,min) |
被註釋的元素的大小必須在指定的範圍內 |
@Digits (integer,fraction) |
被註釋的元素必須是一個數字,其值必須在可接受的範圍內 |
@Past |
被註釋的元素必須是一個過去的日期 |
@Future |
被註釋的元素必須是一個將來的日期 |
@Pattern(value) |
被註釋的元素必須符合指定的正則表示式 |
Hibernate Validator 附加的 constraint
註解 |
詳細資訊 |
---|---|
@Email |
被註釋的元素必須是電子郵箱地址 |
@Length |
被註釋的字串的大小必須在指定的範圍內 |
@NotEmpty |
被註釋的字串的必須非空 |
@Range |
被註釋的元素必須在合適的範圍內 |
@NotBlank |
驗證字串非null,且長度必須大於0 |
注意:
- @NotNull 適用於任何型別被註解的元素必須不能與NULL
- @NotEmpty 適用於String Map或者陣列不能為Null且長度必須大於0
- @NotBlank 只能用於String上面 不能為null,呼叫trim()後,長度必須大於0
使用
使用起來也非常簡單,下面略過建立專案
GITHUB地址:
模擬使用者註冊封裝了一個UserDTO
當提交資料的時候如果使用以前的做法就是IF ELSE
判斷引數使用validator
則是需要增加註解即可。
例如非空校驗:
然後需要在controller
方法體新增@Validated
不加@Validated
校驗會不起作用
然後請求一下請求介面,把Email引數設定為空
引數:
{
"userName":"luomengsun","mobileNo":"11111111111","sex":1,"age":21,"email":""
}複製程式碼
返回結果:
後臺丟擲異常
這樣是能校驗成功,但是有個問題就是返回引數並不理想,前端也並不容易處理返回引數,所以我們新增一下全域性異常處理,然後新增一下全域性統一返回引數這樣比較規範。
新增全域性異常
建立一個GlobalExceptionHandler
類,在類上方新增@RestControllerAdvice
註解然後新增以下程式碼:
/**
* 方法引數校驗
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ReturnVO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage(),e);
return new ReturnVO().error(e.getBindingResult().getFieldError().getDefaultMessage());
}複製程式碼
此方法主要捕捉MethodArgumentNotValidException
異常然後對異常結果進行封裝,如果需要在自行新增其他異常處理。
新增完之後我們在看一下執行結果,呼叫介面返回:
{
"code": "9999","desc": "郵箱不能為空","data": null
}複製程式碼
OK 已經對異常進行處理。
校驗格式
如果想要校驗郵箱格式或者手機號的話也非常簡單。
校驗郵箱
/**
* 郵箱
*/
@NotBlank(message = "郵箱不能為空")
@NotNull(message = "郵箱不能為空")
@Email(message = "郵箱格式錯誤")
private String email;複製程式碼
使用正則校驗手機號
校驗手機號使用正則進行校驗,然後限制了一下位數
/**
* 手機號
*/
@NotNull(message = "手機號不能為空")
@NotBlank(message = "手機號不能為空")
@Pattern(regexp ="^[1][3,4,5,6,7,8,9][0-9]{9}$",message = "手機號格式有誤")
@Max(value = 11,message = "手機號只能為{max}位")
@Min(value = 11,message = "手機號只能為{min}位")
private String mobileNo;複製程式碼
檢視一下執行結果
傳入引數:
{
"userName":"luomengsun","mobileNo":"111111a","email":"1212121"
}複製程式碼
返回結果:
{
"code": "9999","desc": "郵箱格式錯誤","data": null
}複製程式碼
這裡不再驗證手機號的例子
自定義註解
上面的註解只有這麼多,如果有特殊校驗的引數我們可以使用Validator
自定義註解進行校驗
首先建立一個IdCard
註解類
@Documented
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
String message() default "身份證號碼不合法";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}複製程式碼
在UserDTO中新增@IdCard
註解即可驗證,在執行時觸發,本文不對自定義註解做過多的解釋,下篇文章介紹自定義註解
- message 提示資訊
- groups 分組
- payload 針對於Bean
然後新增IdCardValidator
主要進行驗證邏輯
上面呼叫了is18ByteIdCardComplex
方法,傳入引數就是手機號,驗證身份證規則自行百度:seenoevil:
然後使用
@NotNull(message = "身份證號不能為空")
@IdCard(message = "身份證不合法")
private String IdCardNumber;複製程式碼
分組
就比如上面我們定義的UserDTO中的引數如果要服用的話怎麼辦?
在重新定義一個類然後裡面的引數要重新新增註解?
Validator
提供了分組方法完美瞭解決DTO服用問題
現在我們註冊的介面修改一下規則,只有使用者名稱不能為空其他引數都不進行校驗
先建立分組的介面
public interface Create extends Default {
}複製程式碼
我們只需要在註解加入分組引數即可例如:
/**
* 使用者名稱
*/
@NotBlank(message = "使用者姓名不能為空",groups = Create.class)
@NotNull(message = "使用者姓名不能為空",groups = Create.class)
private String userName;
@NotBlank(message = "郵箱不能為空",groups = Update.class)
@NotNull(message = "郵箱不能為空",groups = Update.class)
@Email(message = "郵箱格式錯誤",groups = Update.class)
private String email;複製程式碼
然後在修改Controller在@Validated
中傳入Create.class
@PostMapping("/user")
public ReturnVO userRegistra(@RequestBody @Validated(Create.class) UserDTO userDTO){
ReturnVO returnVO = userService.userRegistra(userDTO);
return returnVO ;
}複製程式碼
然後呼叫傳入引數:
{
"userName":"",}複製程式碼
返回引數:
{
"code": "9999","desc": "使用者姓名不能為空","data": null
}複製程式碼
OK 現在只對Create的進行校驗,而Updata組的不校驗,如果需要複用DTO的話可以使用分組校驗
校驗單個引數
在開發的時候一定遇到過單個引數的情況,在引數前面加上註解即可
@PostMapping("/get")
public ReturnVO getUserInfo(@RequestParam("userId") @NotNull(message = "使用者ID不能為空") String userId){
return new ReturnVO().success();
}複製程式碼
然後在Controller類上面增加@Validated
註解,注意不是增加在引數前面。