一、相关规范
- JSR 303 - Bean Validation 1.0
- 2009年发布
- 属于JavaEE6的一部分
- JSR 349 - Bean Validation 1.1
- 2013年发布
- 属于JavaEE7的一部分
- 添加方法级验证、错误消息、支持EL表达式等新特性
- JSR 380 - Bean Validation 2.0
二、Validation 比较
1、Bean Validation 与Hiberanate Validator
Bean Validation
仅仅是对验证框架定义了规范Hiberanate Validator
是对规范的具体实现
Bean Validation 1.0参考实现:Hibernate Validator 4.3.1 Final
Bean Validation 1.1参考实现:Hibernate Validator 5.1.1 Final
Bean Validation 2.0参考实现:Hibernate Validator 6.0.1 Final
2、Hiberanate Validator 与 Spring Validation
Spring Validation
在 Hiberanate Validator
的基础上,对其进行了二次封装,以满足在Spring环境上更简单、高效的对数据进行验证
三、常用约束注解
:::warning
⚠️ 注意@NotEmpty
用在集合类上面@NotBlank
用在String上面@NotNull
用在基本类型上("Accepts any type"可以接受任何类型对象)
:::
四、框架引入
1、依赖
<!-- Validation 相关依赖 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.16.Final</version>
</dependency>
<!-- Spring Web 自带,可不引入 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
2、使用
2.1、Field校验
/**
* 待验证对象实体类
* 用户信息类
*/
public class UserInfo {
// 登录场景
public interface LoginGroup {}
// 注册场景
public interface RegisterGroup {}
// 组排序场景
@GroupSequence({
LoginGroup.class,
RegisterGroup.class,
Default.class
})
public interface Group {}
/**
* 用户ID
*/
@NotNull(message = "用户ID不能为空",
groups = LoginGroup.class)
private String userId;
/**
* 用户名
* NotEmpty 不会自动去掉前后空格
*/
@NotEmpty(message = "用户名称不能为空")
private String userName;
/**
* 用户密码
* NotBlank 自动去掉字符串前后空格后验证是否为空
*/
@NotBlank(message = "用户密码不能为空")
@Length(min = 6, max = 20,
message = "密码长度不能少于6位,多于20位")
private String passWord;
/**
* 邮箱
*/
@NotNull(message = "邮箱不能为空",
groups = RegisterGroup.class)
@Email(message = "邮箱必须为有效邮箱")
private String email;
/**
* 手机号
*/
@Phone(message = "手机号不是158后头随便")
private String phone;
/**
* 年龄
*/
@Min(value = 18, message = "年龄不能小于18岁")
@Max(value = 60, message = "年龄不能大于60岁")
private Integer age;
/**
* 生日
*/
@Past(message = "生日不能为未来或当前时间点")
private Date birthday;
/**
* 好友列表
*/
@Size(min = 1, message = "不能少于1个好友")
private List<@Valid UserInfo> friends;
}
2.2、接口校验
/**
* 用户信息服务类
*/
public class UserInfoService {
/**
* UserInfo 作为输入参数
* @param userInfo
*/
public void setUserInfo(@Valid UserInfo userInfo) {}
/**
* UserInfo 作为输出参数
* @return
*/
public @Valid UserInfo getUserInfo() {
return new UserInfo();
}
/**
* 默认构造函数
*/
public UserInfoService() {}
/**
* 接收UserInfo作为参数的构造函数
* @param userInfo
*/
public UserInfoService(@Valid UserInfo userInfo) {}
}
2.3、自定义验证
/**
* 自定义手机号约束注解
*/
@Documented
// 注解的作用目标
@Target({ElementType.FIELD})
// 注解的保留策略
@Retention(RetentionPolicy.RUNTIME)
// 不同之处:于约束注解关联的验证器
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
// 约束注解验证时的输出信息
String message() default "手机号校验错误";
// 约束注解在验证时所属的组别
Class<?>[] groups() default {};
// 约束注解的有效负载
Class<? extends Payload>[] payload() default {};
}
/**
* 自定义手机号约束注解关联验证器
*/
public class PhoneValidator
implements ConstraintValidator<Phone, String> {
/**
* 自定义校验逻辑方法
* @param value
* @param context
* @return
*/
@Override
public boolean isValid(String value,
ConstraintValidatorContext context) {
// 手机号验证规则:158后头随便
String check = "158\\d{8}";
Pattern regex = Pattern.compile(check);
// 空值处理
String phone = Optional.ofNullable(value).orElse("");
Matcher matcher = regex.matcher(phone);
return matcher.matches();
}
}