Validation
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);
}
}