validation-api中@GroupSequence的使用

考虑一种场景:一个bean有1个属性(假如说是attrA),这个属性上添加了3个约束(假如说是@NotNull、@NotEmpty、@NotBlank)。默认情况下,validation-api对这3个约束的校验顺序是随机的。也就是说,可能先校验@NotNull,再校验@NotEmpty,最后校验@NotBlank,也有可能先校验@NotBlank,再校验@NotEmpty,最后校验@NotNull。

那么,如果我们的需求是先校验@NotNull,再校验@NotBlank,最后校验@NotEmpty。validation-api能否做到这一点呢?答案是:能。这就要用到validation-api提供的 @GroupSequence 注解了。

  • 要被校验的bean
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class GroupSequenceDemoForm {

    @NotBlank(message = "至少包含一个非空字符", groups = {First.class})
    @Size(min = 11, max = 11, message = "长度必须是11", groups = {Second.class})
    private String demoAttr;

    public interface First {

    }

    public interface Second {

    }

    @GroupSequence(value = {First.class, Second.class})
    public interface GroupOrderedOne {
        // 先计算属于 First 组的约束,再计算属于 Second 组的约束
    }


    @GroupSequence(value = {Second.class, First.class})
    public interface GroupOrderedTwo {
        // 先计算属于 Second 组的约束,再计算属于 First 组的约束
    }

}
  • 单元测试
public class UnitFiveTest {

    private static Validator validator;

    @BeforeClass
    public static void setUpValidator() {
        // 通过工厂获取到一个Validator的实例
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.getValidator();
    }

    @Test
    public void groupValidateThirdTestVerTwo() {
        GroupSequenceDemoForm form = new GroupSequenceDemoForm(" ");

        // 校验属于 First 和 Second 的约束
        // 默认情况下,不论约束是 First 组还是 Second 组,校验顺序是不确定的
        System.out.println("\n" + validator.validate(form, GroupSequenceDemoForm.First.class,
                GroupSequenceDemoForm.Second.class) + "\n");

        // 校验属于 First 和 Second 的约束
        // 默认情况下,不论约束是 First 组还是 Second 组,校验顺序是不确定的
        System.out.println("\n" + validator.validate(form, GroupSequenceDemoForm.Second.class,
                GroupSequenceDemoForm.First.class) + "\n");

        // 校验属于 First 和 Second 的约束
        // 明确指定先计算属于 First 组的约束,再计算属于 Second 组的约束
        System.out.println("\n"
                + validator.validate(form, GroupSequenceDemoForm.GroupOrderedOne.class) + "\n");

        // 校验属于 First 和 Second 的约束
        // 明确指定先计算属于 Second 组的约束,再计算属于 First 组的约束
        System.out.println("\n"
                + validator.validate(form, GroupSequenceDemoForm.GroupOrderedTwo.class) + "\n");
    }
  • 输出结果
[ConstraintViolationImpl{interpolatedMessage='长度必须是11', propertyPath=demoAttr, rootBeanClass=class com.qs.mmeng.hibernate.validator.group.three.ver2.GroupSequenceDemoForm, messageTemplate='长度必须是11'}, ConstraintViolationImpl{interpolatedMessage='至少包含一个非空字符', propertyPath=demoAttr, rootBeanClass=class com.qs.mmeng.hibernate.validator.group.three.ver2.GroupSequenceDemoForm, messageTemplate='至少包含一个非空字符'}]


[ConstraintViolationImpl{interpolatedMessage='长度必须是11', propertyPath=demoAttr, rootBeanClass=class com.qs.mmeng.hibernate.validator.group.three.ver2.GroupSequenceDemoForm, messageTemplate='长度必须是11'}, ConstraintViolationImpl{interpolatedMessage='至少包含一个非空字符', propertyPath=demoAttr, rootBeanClass=class com.qs.mmeng.hibernate.validator.group.three.ver2.GroupSequenceDemoForm, messageTemplate='至少包含一个非空字符'}]


[ConstraintViolationImpl{interpolatedMessage='至少包含一个非空字符', propertyPath=demoAttr, rootBeanClass=class com.qs.mmeng.hibernate.validator.group.three.ver2.GroupSequenceDemoForm, messageTemplate='至少包含一个非空字符'}]


[ConstraintViolationImpl{interpolatedMessage='长度必须是11', propertyPath=demoAttr, rootBeanClass=class com.qs.mmeng.hibernate.validator.group.three.ver2.GroupSequenceDemoForm, messageTemplate='长度必须是11'}]

从上面的输出结果可以看出,如果明确指定校验顺序,当前面的约束校验失败的话,后面的约束就不会继续校验了。这种特性其实刚好符合下面这种需求:每次调用接口,只返回一个校验错误,前一个校验错误纠正过后,后一个校验错误才返回。比如说:产品要求你写的接口要满足姓名不能为空校验通后,再校验年龄是否满十八岁,年龄满十八岁之后,再校验身份证号是否为空,身份证不为空之后,再校验身份证号码格式是否正确。

看完这个例子,有的小伙伴可能要问了:你这里用的是单元测试,那要是放到spring项目中怎么搞?其实也很简单。只需要把 @Valided 的 value 属性设置为上面代码中的 GroupOrderedOne.class 或者 GroupOrderedTwo.class 就可以了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值