@Valid —— Bean Validation定義 |
@Validated —— Spring Validation定義 |
|
分組 |
無分組功能 |
提供分組功能,可在入參驗證時,根據不同的分組採用不同的驗證機制。 |
巢狀驗證 |
用在方法入參上無法單獨提供巢狀驗證功能。 能夠用在成員屬性上,提示驗證框架進行巢狀驗證。 能配合巢狀驗證註解@Valid進行巢狀驗證。 |
用在方法入參上無法單獨提供巢狀驗證功能。 不能用在成員屬性上,也無法提供框架進行巢狀驗證。 能配合巢狀驗證註解@Valid進行巢狀驗證。 |
可註解位置 |
可以用在方法、建構函式、方法引數和成員屬性上(兩者是否能用於成員屬性上直接影響能否提供巢狀驗證的功能) |
可以用在型別、方法和方法引數上。但是不能用在成員屬性上 |
巢狀驗證使用@Valid,分組校驗時使用@Validated,在controller上對單個引數校驗時使用@Validated。
一、物件引數校驗
用法:哪用哪新增@Valid/@Validated
場景:POST方法,使用@RequestBody接收引數時使用
1.1 普通校驗——使用@Valid
一般場景校驗引數,使用valid註解就行,步驟如下:
1、新增校驗註解:給類中引數新增校驗註解,常用註解如下
//JSR 提供的校驗註解 @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(regex=,flag=) 被註釋的元素必須符合指定的正規表示式 //Hibernate Validator 提供的校驗註解(相當於擴充套件) @NotBlank(message =) 驗證字串非 null,且長度必須大於 0 @Email 被註釋的元素必須是電子郵箱地址 @Length(min=,max=) 被註釋的字串的大小必須在指定的範圍內 @NotEmpty 被註釋的字串的必須非空 @Range(min=,max=,message=) 被註釋的元素必須在合適的範圍內
@NotNull 、@NotEmpty、 @NotBlank 3個註解的區別
- @NotNull 適用於任何物件,不能為null (一般用這個,如Integer)
- @NotBlank 適用於String,不為null,並且字串trim()以後length要大於0(不為“”) (String型別的用這個)
- @NotEmpty 適用於String、Collection、Map或者陣列,不能為Null,且長度或元素個數必須大於0(可以為“”)
@Pattern:註解適用於String,對於其他型別會報錯:No validator could be found for constraint 'javax.validation.constraints.Pattern' validating type 'java.lang.Integer
2、新增@Valid註解:在需要校驗的物件前新增@Valid註解即可
- 1. 校驗對靜態變數不生效
- 2. 對於校驗不透過的處理
- 在使用 @Valid 註解的引數後可以緊跟著一個 BindingResult 型別的引數,用於獲取校驗結果(將校驗結果封裝在BingdingResult物件中,不會丟擲異常);
- 校驗不透過會丟擲異常,然後全域性異常處理(推薦)
3、處理異常:全域性捕獲異常,統一處理
@ControllerAdvice public class BaseExceptionHandler { @ResponseBody @ExceptionHandler(MethodArgumentNotValidException.class) public HttpResponse handle(MethodArgumentNotValidException e) { FieldError fieldError = e.getBindingResult().getFieldError(); return HttpResponse.builder().code(500).msg(fieldError.getDefaultMessage()).build(); } } //這裡的MethodArgumentNotValidException是在校驗時丟擲的,實際情上因為校驗失敗還會丟擲其它異常,不過一般都是由於開發過程中導致的問題,與使用者的輸入無關,所以可以統一響應"系統異常",無需單獨處理。
@ExceptionHandler(BindingException.class) //實體物件前不加@RequestBody註解,單個物件內屬性校驗未透過丟擲的異常型別 //spring-context包裡面的異常
@ExceptionHandler(ValidationException.class) //實體物件前不加@RequestBody註解,校驗方法引數或方法返回值時,未校驗透過時丟擲的異常 //Validation-api包裡面的異常
@ExceptionHandler(MethodArgumentNotValidException.class) //實體物件前加@RequestBody註解,丟擲的異常為該類異常 //spring-context包裡面的異常
1.2 分組校驗——@Validated
1、設定分組介面
package com.datamanager.vo.request; import javax.validation.groups.Default; public class ValidationGroups { public interface Create extends Default { } public interface Update extends Default { } } //分組介面類只是普通的介面類並沒有多大意義,只是用來標識這個屬性哪種情況下被驗證
不會自動驗證預設分組:使用分組功能後,對於不指定分組的屬性,屬於預設分組,但是不會自動驗證預設分組。
解決方法:1、所有需要驗證的屬性都必須新增指定分組 2、如上所示,分組介面繼承Default介面
2、新增校驗註解:給類中引數新增校驗註解
package com.datamanager.vo.request; import lombok.Data; import org.hibernate.validator.constraints.Range; import javax.validation.constraints.*; @Data public class DatasetRequest { //update分組 @NotNull(message = "id不能為空", groups = {ValidationGroups.Update.class}) private Integer id; //create分組 @NotBlank(message = "name不能為空", groups = {ValidationGroups.Create.class}) @Size(max = 32, message = "name超出最大長度", groups = {ValidationGroups.Create.class}) @Pattern(regexp = "^[A-Za-z0-9_-]+$", message = "name由中文、英文、下劃線和-組成", groups = {ValidationGroups.Create.class}) private String name; //預設分組 @NotBlank(message = "cnName不能為空") @Size(max = 20, message = "cnName超出最大長度") @Pattern(regexp = "^[\\u4e00-\\u9fa50-9]+$", message = "cn_name由中文和數字組成") private String cnName; }
3、使用Validated註解(在需要校驗的物件前新增@Validated註解,並指定分組)
@PutMapping("/update") public ResponseResult update(@Validated(ValidationGroups.Update.class) @RequestBody DatasetRequest request) { if (!authorityService.isAllowWrite(request.getId(), loginUser)) { return ResponseResult.build(ResponseCodeEnum.NO_AUTHORIZATION); } return datasetService.updateDataset(request); }
二、單個引數校驗
用法:類上新增@Validated,然後在需要的地方新增對應校驗註解
場景:當GET方法,使用@RequestParam接受引數時,針對單個引數分別校驗
1、controller類上新增註解@Validated
2、@RequestParam的引數前新增對應校驗註解
三、Service中對引數校驗
service類上新增註解@Validated
需要校驗的引數前加@Valid
參考資料
https://segmentfault.com/a/1190000038401180 (詳細)
https://juejin.cn/post/6844904118536912904 (簡潔 + 使用範圍)
@Validated分組校驗
使用@Validated分組遇到的坑