Hibernate Validator简单使用
介绍
JSR-303 是JAVA EE6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现,提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。
简单校验
添加maven依赖
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
hibernate-validator还依赖以下两个
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.0</version>
</dependency>
实体类
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
private String mobile;
@NotBlank(message = "性别不能为空")
private String gender;
@NotNull(message = "年龄不能为空")
@Range(min = 5, max = 90, message = "年龄必须在5-90之间")
private Integer age;
private List<Address> addressList;
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
static class Address {
private String province;
private String city;
private String region;
}
}
public class Client {
public static void main(String[] args) {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
User user = new User();
Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
System.out.println(constraintViolation.getMessage());
}
}
}
Validation会通过SPI的方式找到所有ValidationProvider接口的实现,自然就找到hibernate-validator的实现HibernateValidator了。
当然我们也可以自己指定实现,自定义配置
public class Client {
public static void main(String[] args) {
Validator validator = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true) //有一个失败就停止检查
.buildValidatorFactory()
.getValidator();
User user = new User();
Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
System.out.println(constraintViolation.getMessage());
}
}
}
级联校验
实体类
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
private String mobile;
@NotBlank(message = "性别不能为空")
private String gender;
@NotNull(message = "年龄不能为空")
@Range(min = 5, max = 90, message = "年龄必须在5-90之间")
private Integer age;
@Valid
@NotEmpty(message = "地址不能为空")
private List<Address> addressList;
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
static class Address {
@NotBlank(message = "省不能为空")
private String province;
@NotBlank(message = "市不能为空")
private String city;
@NotBlank(message = "区不能为空")
private String region;
}
}
使用Valid注解实现级联校验
public class Client {
public static void main(String[] args) {
Validator validator = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(false) //有一个失败就停止检查
.buildValidatorFactory()
.getValidator();
User user = new User();
user.setAddressList(Collections.singletonList(new Address()));
Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
System.out.println(constraintViolation.getMessage());
}
}
}
分组校验
实体类
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
private String mobile;
@NotBlank(message = "性别不能为空")
private String gender;
@NotNull(message = "年龄不能为空")
@Range(min = 18, max = 90, message = "年龄必须在18-90之间", groups = Adult.class)
@Range(min = 5, max = 17, message = "年龄必须在5-17之间", groups = Minor.class)
private Integer age;
private List<Address> addressList;
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
static class Address {
private String province;
private String city;
private String region;
}
/**
* 成年人
*/
interface Adult {
}
/**
* 未成年人
*/
interface Minor {
}
}
不设置分组,默认为Default分组
public class Client {
public static void main(String[] args) {
Validator validator = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(false) //有一个失败就停止检查
.buildValidatorFactory()
.getValidator();
User user = new User();
user.setAge(7);
Set<ConstraintViolation<User>> constraintViolationSet = validator
.validate(user, Default.class, Adult.class); // 设置要校验的分组
for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
System.out.println(constraintViolation.getMessage());
}
}
}
不设置也会添加一个默认分组Default
自定义校验器
校验注解
/**
* 当前值必须在给定的列表中
*/
@Target({FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ListRangeValidatorForString.class})
public @interface ListRange {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String[] value() default {};
}
校验器
public class ListRangeValidatorForString implements ConstraintValidator<ListRange, String> {
private String[] range;
@Override
public void initialize(ListRange listRange) {
this.range = listRange.value();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (Objects.isNull(value)) {
return true;
}
return Arrays.asList(range).contains(value);
}
}
实体类
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^1([34578])\\d{9}$", message = "手机号格式错误")
private String mobile;
@NotBlank(message = "性别不能为空")
@ListRange(value = {"male", "female"}, message = "性别必须在[male,female]之间")
private String gender;
@NotNull(message = "年龄不能为空")
@Range(min = 5, max = 90, message = "年龄必须在5-90之间")
private Integer age;
private List<Address> addressList;
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
static class Address {
private String province;
private String city;
private String region;
}
}
性别必须在male和female之间
public class Client {
public static void main(String[] args) {
Validator validator = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(false) //有一个失败就停止检查
.buildValidatorFactory()
.getValidator();
User user = new User();
user.setAge(7);
user.setGender("ss");
Set<ConstraintViolation<User>> constraintViolationSet = validator.validate(user);
for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
System.out.println(constraintViolation.getMessage());
}
}
}
hibernate-validator会先找内置的注解校验器,找不到就找自定义的校验器。
对国际化的支持
实体类
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class User {
@NotBlank(message = "{username.errormsg}")
private String username;
}
配置文件
文件内容为
username.errormsg=用户名称不能为空
校验
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import org.hibernate.validator.HibernateValidator;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
public class Client {
public static void main(String[] args) {
//创建ResourceBundle定位器,从哪里读取配置文件
ResourceBundleLocator resourceBundleLocator = new ResourceBundleLocator() {
@Override
public ResourceBundle getResourceBundle(Locale locale) {
return ResourceBundle.getBundle("i18n/messages", locale);
}
};
//定义消息interpolator,从ResourceBundle中读取
ResourceBundleMessageInterpolator interpolator = new ResourceBundleMessageInterpolator(
resourceBundleLocator);
Validator validator = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(false) //有一个失败就停止检查
.messageInterpolator(interpolator)
.buildValidatorFactory()
.getValidator();
User user = new User();
Set<ConstraintViolation<User>> constraintViolationSet = validator
.validate(user, Default.class);
for (ConstraintViolation<User> constraintViolation : constraintViolationSet) {
System.out.println(constraintViolation.getMessage());//用户名称不能为空
}
}
}
我们可以设置校验器的MessageInterpolator,可以看做消息处理器,这里我们从ResourceBundle中读取错误信息。