0

我们有一个用例,其中我们有一个结构相当糟糕的 bean,其中包含如下字段:

public class DataBean {
    private boolean flag1;
    private boolean flag2;

    private String phone1;
    private String address1;
    private String city1;
    private String state1;

    private String phone2;
    private String address2;
    private String city2;
    private String state2;
}

仅当标志 [1|2] 为真时,我们才需要验证电话/地址/城市/州 [1|2]。糟糕,糟糕的设计,理所当然。

我们当前的策略是在每个“真实”数据字段上使用@NotNull(或我们需要的任何验证),并使用组指示符,如下所示:

public class DataBean {
    private boolean flag1;
    private boolean flag2;

    @NotNull(groups = Info.First.class)
    private String phone1;
    @NotNull(groups = Info.First.class)
    private String address1;
    @NotNull(groups = Info.First.class)
    private String city1;
    @NotNull(groups = Info.First.class)
    private String state1;

    @NotNull(groups = Info.Second.class)
    private String phone2;
    @NotNull(groups = Info.Second.class)
    private String address2;
    @NotNull(groups = Info.Second.class)
    private String city2;
    @NotNull(groups = Info.Second.class)
    private String state2;
}

在我们验证此 bean 的业务逻辑中(其中包含将由“默认”验证组验证的各种其他字段),我们将违反“默认”组,然后检查 flag1 是否为真,如果因此,对 Info.First.class 运行验证,检查 flag2 是否为真,然后对 Info.Second.class 运行验证。

现在的问题......有没有办法从自定义类验证器中连接到这些组?我设想有一个类验证器,它采用 flag1/flag2 属性及其相应的自定义组,当调用 isValid 时,它会为这些组执行这些二级/三级调用。简单地说,目的是自定义类验证器将位于默认组中,因此验证此类的业务逻辑不会因为必须单独调用验证而将这种丑陋的遗留设计的细节泄漏到其中。

想法?谢谢!

4

2 回答 2

0

制作一个类级别的验证器并在其中初始化验证器。然后,您可以通过在每个字段上添加约束例外,按类级别约束的主要有效方法内的组来验证对象。见下文:

约束界面:

@Documented
@Constraint(validatedBy = {DataBeanValidator.class})
@Target({METHOD, FIELD, ANNOTATION_TYPE, TYPE})
@Retention(RUNTIME)
public @interface DataBeanConstraint {

    String message() default "validation.dataBean";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

验证器:

public class DataBeanValidator implements ConstraintValidator<DataBeanConstraint, DataBean> {

    private Validator validator;

    @Override
    public void initialize(DataBeanConstraint constraintAnnotation) {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Override
    public boolean isValid(BeanData beanData, ConstraintValidatorContext context) {
        if (beanData == null) {
            return true;
        }
        if (beanData.isFlag1) {
            Set<ConstraintViolation<DataBean>> constraintViolations = validator.validate(beanData, Info.First.class);
            if (constraintViolations != null) {
                for (ConstraintViolation<BeanData> constraintViolation : constraintViolations) {
                    context.disableDefaultConstraintViolation();
                    context.buildConstraintViolationWithTemplate("required field").
                            addNode(constraintViolation.getPropertyPath().toString())
                            .addConstraintViolation();
                }
            }
        }

    }
}

类级别验证器:

@DataBeanConstraint
public class DataBean {
    private boolean flag1;
    private boolean flag2;

    @NotNull(groups = Info.First.class)
    private String phone1;
    @NotNull(groups = Info.First.class)
    private String address1;
    @NotNull(groups = Info.First.class)
    private String city1;
    @NotNull(groups = Info.First.class)
    private String state1;

    @NotNull(groups = Info.Second.class)
    private String phone2;
    @NotNull(groups = Info.Second.class)
    private String address2;
    @NotNull(groups = Info.Second.class)
    private String city2;
    @NotNull(groups = Info.Second.class)
    private String state2;
}
于 2013-10-16T18:03:03.230 回答
0

我不完全确定我已经掌握了您要解决的问题。我的解释是试图避免显式地为每个验证组单独调用,而是根据标志调用两个非默认组?不能只定义一些组序列并使用这些而不是标志吗?组序列的使用方式与组相同。他们唯一的事情是,如果一个组失败,他们将停止验证组。

如果您需要验证始终根据标志验证所有组,您的自定义类验证器可以调用groups()传递给其初始化方法的约束注释。

于 2011-03-03T16:00:44.023 回答