运行案例:
@Getter @Setter @ToString public class Person { @CollectionRange(min = 5, max = 10) private List<Integer> numbers; } // 测试用例 public static void main(String[] args) { Person person = new Person(); person.setNumbers(Arrays.asList(1, 2, 3)); Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false) .buildValidatorFactory().getValidator(); Set<ConstraintViolation<Person>> result = validator.validate(person); // 输出错误消息 result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue()) .forEach(System.out::println); }
输出校验信息如下(校验成功):
numbers [自定义消息]你的集合的长度必须介于5和10之间(包含边界值): [1, 2, 3]
组合约束
这块比较简单,很多情况下一个字段是需要有多个约束(不为空且大于0)的。这个时候我们有两种做法:
- 就在该属性上标注多个注解即可(推荐)
- 自定义一个注解,把这些注解封装起来,形成一个新的约束注解(使用场景相对较少)
自定义message消息可使用的变量
我们知道约束的失败消息message里是可以使用{}占位符来动态取值的,默认情况下能够取到约束注解里的所有属性值,并且也只能取到那些属性的值。
but,有的时候为了友好展示,我们需要自定义message里可取的值怎么办呢?下面给个例子,让大家知道怎么自定义可使用占位符的参数(备注:需要基于自定义注解):
自定义一个性别约束注解:
@Documented @Retention(RUNTIME) @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) @Constraint(validatedBy = {GenderConstraintValidator.class}) public @interface Gender { // 三个必备的基本属性 String message() default "{com.fsx.my.gender.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; int gender() default 0; //0:男生 1:女生 }
配置的消息资源是:
com.fsx.my.gender.message=[自定义消息]此处只能允许性别为[{zhGenderValue}]的
很显然,此处我们需要读取zhGenderValue这个自定义的属性值,并且希望它是中文。所以看看下面我实现的这个校验器吧:
public class GenderConstraintValidator implements ConstraintValidator<Gender, Integer> { int genderValue; @Override public void initialize(Gender constraintAnnotation) { genderValue = constraintAnnotation.gender(); } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { //添加参数 校验失败的时候可用 HibernateConstraintValidatorContext hibernateContext = context.unwrap(HibernateConstraintValidatorContext.class); hibernateContext.addMessageParameter("zhGenderValue", genderValue == 0 ? "男" : "女"); // 友好展示 //hibernateContext.buildConstraintViolationWithTemplate("{zhGenderValue}").addConstraintViolation(); if (value == null) { return false; // null is not valid } return value == genderValue; } }
运行单测:
@Getter @Setter @ToString public class Person { @Gender(gender = 0) private Integer personGender; } public static void main(String[] args) { Person person = new Person(); person.setPersonGender(1); Validator validator = Validation.byProvider(HibernateValidator.class).configure().failFast(false) .buildValidatorFactory().getValidator(); Set<ConstraintViolation<Person>> result = validator.validate(person); // 输出错误消息 result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue()) .forEach(System.out::println); }
打印如下:
personGender [自定义消息]此处只能允许性别为[男]的: 1
完美(效果达到)
总结
如果说前面文章是用机,那这篇可以称作是玩机了。Bean Validation是java官方定义的bean验证标准,现在最新的版本为2.x,hibernate validator作为其标准实现,对其进行了扩展,增加了多种约束,如果仍然不能满足业务需求,我们还可以自定义约束。
数据校验Bean Validation这一大块的内容到此就告一段落了,希望讲解的所有内容能给你实际工作中带来帮助,祝好~