1. 程式人生 > 其它 >Spring註解之引數校驗@Validated和@Valid

Spring註解之引數校驗@Validated和@Valid

詳解Spring 引數驗證@Validated和@Valid的區別

Spring Validation驗證框架對引數的驗證機制提供了@Validated(Spring's JSR-303 規範,是標準 JSR-303 的一個變種),javax提供了@Valid(標準JSR-303規範),配合 BindingResult 可以直接提供引數驗證結果。

在檢驗 Controller 的入參是否符合規範時,使用 @Validated 或者 @Valid 在基本驗證功能上沒有太多區別。
但是在分組、註解地方、巢狀驗證等功能上兩個有所不同:
1. 分組
@Validated:提供了一個分組功能,可以在入參驗證時,根據不同的分組採用不同的驗證機制,這個網上也有資料,不詳述。
@Valid:作為標準JSR-303規範,還沒有吸收分組的功能。

2. 註解地方
@Validated:可以用在型別、方法和方法引數上。但是不能用在成員屬性(欄位)上。
@Valid:可以用在建構函式、方法和方法引數和成員屬性(欄位)上。
兩者是否能用於成員屬性(欄位)上直接影響能否提供巢狀驗證的功能。

3. 巢狀驗證

在比較兩者巢狀驗證時,先說明下什麼叫做巢狀驗證。比如我們現在有個實體叫做Item:

public class Item {
 
  @NotNull(message = "id不能為空")
  @Min(value = 1, message = "id必須為正整數")
  private Long id;
 
  @Valid // 巢狀驗證必須用@Valid
  @NotNull(message = "props不能為空")
  @Size(min = 1, message = "至少要有一個屬性")
  private List<Prop> props;
}

Item的成員屬性props必須加上@Valid註解支援巢狀驗證功能。

Item帶有很多屬性,如下所示:

public class Prop {
 
  @NotNull(message = "pid不能為空")
  @Min(value = 1, message = "pid必須為正整數")
  private Long pid;
 
  @NotNull(message = "vid不能為空")
  @Min(value = 1, message = "vid必須為正整數")
  private Long vid;
 
  @NotBlank(message = "pidName不能為空")
  private String pidName;
 
  @NotBlank(message = "vidName不能為空")
  private String vidName;
}

屬性這個實體也有自己的驗證機制,比如屬性和屬性值id不能為空,屬性名和屬性值不能為空等。

現在我們有個 ItemController 接受一個Item的入參,想要對Item進行驗證,如下所示:

@RestController
public class ItemController {
 
  @RequestMapping("/item/add")
  public void addItem(@Validated Item item, BindingResult bindingResult) {
    doSomething();
  }
}

此時Item裡面的props如果含有Prop的相應欄位為空的情況,Spring Validation框架就會檢測出來,bindingResult就會記錄相應的錯誤。

@Validated分組校驗

定義實體類

@Data
public class User {

  @NotBlank(groups = {UpdateGroup.class}, message = "id不能為空")
  private String id;

  @NotBlank(groups = {SaveGroup.class, UpdateGroup.class}, message = "姓名不能為空")
  private String name;
    
  @NotNull(message = "性別不能為空")
  private String sex;
    
  @Max(value = 20 ,message = "最大長度為20")
  private String address;
    
  @Email(message = "不滿足郵箱格式")
  private String email;
    
  @AssertTrue(message = "欄位為true才能通過")
  private boolean isAuth;
    
  @NotBlank(message = "手機號不能為空")
  @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手機號格式有誤")
  private String mobile;
    
  @Future(message = "時間在當前時間之後才可以通過")
  private Date date;


  // 新增時校驗,繼承Default類表示會包含沒有分組的校驗
  public interface SaveGroup extends Default {
  }
  // 修改時校驗
  public interface UpdateGroup extends Default {
  }

}

controller 介面中使用 @Validated(groups) 設定了 groups 屬性。
只有配置 groups = User.SaveGroup.class 的效驗註解才會生效。
沒有設定 groups 屬性,則所有效驗註解都會生效。

@RestController(value = "/user")
public class UserController {
    @Autowired
    private UserService userService;

    /**
     * 新增使用者
     * @param user
     * @return
     */
    @RequestMapping("/insert")
    @ResponseBody
    public User insert(@RequestBody @Validated(User.SaveGroup.class) User user){
        return userService.insert(user);
    }

    /**
     * 修改使用者
     * @param user
     * @return
     */
    @RequestMapping("/update")
    @ResponseBody
    public boolean update(@RequestBody @Validated(User.UpdateGroup.class) User user){
        return userService.update(user);
    }

}

對Controller裡的方法的多個引數進行校驗

對Controller裡的方法的多個引數進行校驗(扁平化引數):在Controller類上加註解@Validated

@RestController
@RequestMapping
@Validated
public class HelloController {
    @PutMapping("/hello/id/{id}/status/{status}")
    public Object helloGet(@Max(5) @PathVariable Integer id, @Min(5) @PathVariable Integer status) {
        return "hello world";
    }
}

@NotEmpty、@NotNull、@NotBlank的區別

  • @NotNull :不能為null,但可以為empty,沒有Size的約束,帶註釋的元素不能為null。接受任何型別。一般用在Integer、Double等基本資料型別的非空校驗上,使用** @size、@Max、@Min **對欄位數值進行大小的控制。

  • @NotEmpty:不能為null,且Size>0,@NotEmpty註解的String、Collection、Map、陣列是不能為null或長度為0

  • @NotBlank:只用於String,不能為null且trim()之後size>0,純空格的String也是不符合規則的,此註解只能用於驗證String型別