beanvalidation是一種規范,hibernate-validator是它的最佳實現。
常用注解
beanvalidation
所有注解在 javax.validation.constraints
包下:
hibernate-validator
所有注解在 org.hibernate.validator.constraints
包下:
常用注解解釋
約束注解 | 詳細信息 |
---|---|
@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) |
被注釋的元素必須符合指定的正則表達式 |
@Email |
被注釋的元素必須是電子郵箱地址 |
@Length |
被注釋的字符串的大小必須在指定的范圍內 |
@NotEmpty |
被注釋的字符串的必須非空 |
@Range |
被注釋的元素必須在合適的范圍內 |
約束與校驗器類的綁定原理
在 org.hibernate.validator.internal.metadata.core.ConstraintHelper
類下:
- 從上述兩幅圖中可以看出,NotEmpty注解可以校驗字符串,集合,Map,數組類型的屬性,而為了滿足一個注解可以校驗多種類型的數據,所有需要為這個注解適配多個對應的校驗器。
- 注解名稱是xxx,那么校驗器的名稱就是xxxValidator。
自定義消息模板
消息模板中可以使用 el 表達式。
public class User {
@NotNull(groups = {Update.class})
private Integer id;
@NotBlank(message = "名字不能為空")
private String name;
@Min(value = 18, message = "年齡小於{value},不得進入")
private int age;
}
分組校驗
注解上不區分組的話,會使用默認的組:javax.validation.groups.Default
public class User {
@NotNull(groups = {Update.class})
private Integer id;
@NotBlank(message = "名字不能為空")
private String name;
@Min(value = 18, message = "年齡小於{value},不得進入")
private int age;
public interface Insert {
}
public interface Update {
}
}
特別注意的地方:如果使用了某個組進行校驗的話,那么默認的組就不會進行校驗****。就比如校驗 Update 組,那么就算 name 名字為空也不會再校驗。如果想在對某個組進行校驗,默認的組同時被校驗的話,可以讓 分組接口繼承 Default 接口即可****。
public class User {
@NotNull(groups = {Update.class})
private Integer id;
@NotBlank(message = "名字不能為空")
private String name;
@Min(value = 18, message = "年齡小於{value},不得進入")
private int age;
public interface Insert {
}
public interface Update extends Default {
}
}
級聯校驗
public class Grade {
@NotBlank
private String no;
}
public class User {
@NotNull(groups = {Update.class})
private Integer id;
@NotBlank(message = "名字不能為空")
private String name;
@Min(value = 18, message = "年齡小於{value},不得進入")
private int age;
@NotNull(message = "年級不能為空")
@Valid
private Grade grade;
public interface Insert {
}
public interface Update extends Default {
}
}
被引用對象加上 @valid 注解才能完成級聯校驗。也就是說在校驗 User 對象里的屬性的時候,能一起校驗 Grade 對象。
自定義校驗規則
public class User {
@NotNull(groups = {Update.class})
private Integer id;
@NotBlank(message = "名字不能為空")
private String name;
@Min(value = 18, message = "年齡小於{value},不得進入")
private int age;
@NotNull(message = "年級不能為空")
@Valid
private Grade grade;
@UserStatus
private Integer userStatus;
public interface Insert {
}
public interface Update extends Default {
}
}
@Constraint(validatedBy = {UserStatusValidator.class})
@Target({FIELD})
@Retention(RUNTIME)
public @interface UserStatus {
String message() default "用戶狀態不正確,值必須在1001或者1002或者1003中";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class UserStatusValidator implements ConstraintValidator<UserStatus, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return Arrays.asList(1001, 1002, 1003).contains(value);
}
}
當現有的約束注解不滿足實際項目需要時,可以仿照現有的 NotEmpty
注解和 NotEmptyValidatorForArray
校驗器進行改造以下,就可以實現自己的校驗規則。
@Validated自動校驗
在 springboot 中可以使用在控制器中給每個需要進行校驗的方法的參數前加上 @Validated
注解,在參數校驗不通過的時候會自動拋出 BindException
異常。
@PutMapping
public String update(@Validated({User.Update.class}) User user) {
return "更新成功!";
}
統一異常處理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = BindException.class)
public RespBean entityException(BindException e) {
String msg = e.getBindingResult().getFieldError().getDefaultMessage();
return RespBean.error(HttpStatus.BAD_REQUEST.value(), msg);
}
}