具有多个字段的 Spring 自定义注释验证 [英] Spring Custom Annotation Validation with multiple field

查看:32
本文介绍了具有多个字段的 Spring 自定义注释验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里有点贪心的问题,希望这个问题也能帮助其他想了解更多注解验证的人

A little greedy question here, hope this one could also help others who want to know more about annotation validation

我目前正在学习 Spring,目前,我打算尝试自定义注释验证.

I am currently studying Spring, and for now, I am planning to try out the customize annotated validation.

我查了很多,现在知道验证主要有两种,一种用于控制器,另一种是使用@Valid的注解方法

I have searched a lot and now I know there are mainly two kinds of validations, one is used for the controller, and the other is the annotation method using @Valid

所以这是我的场景:假设我有两个或多个字段,当它们全部为 NULL 时可以为 null.但只有当这些字段之一包含除空字符串之外的任何值时,这些字段才需要有输入.我有两个想法,但不知道如何正确实施.

So here's my scenario: Suppose I have two or more fields which can be null when they are ALL NULL. But only when one of those fields contains any value except an empty string, those fields are required to have input. And I had two ideas but didn't know how to implement them correctly.

这是类示例:

public class Subscriber {
    private String name;
    private String email;
    private Integer age;
    private String phone;
    private Gender gender;
    private Date birthday;
    private Date confirmBirthday;
    private String birthdayMessage;
    private Boolean receiveNewsletter;

    //Getter and Setter
}

假设我希望birthday 和confirmBirthday 字段都需要为null 或相反,我可能想为它们中的每一个使用一个注释来注释它们,如下所示:

Suppose I want that the birthday and confirmBirthday field need to be both null or the oppose, I may want to annotate them using one annotation for each of them and looks like this:

public class Subscriber {
    private String name;
    private String email;
    private Integer age;
    private String phone;
    private Gender gender;

    @NotNullIf(fieldName="confirmBirthday")
    private Date birthday;

    @NotNullIf(fieldName="birthday")
    private Date confirmBirthday;

    private String birthdayMessage;
    private Boolean receiveNewsletter;

    //Getter and Setter
}

所以我确实需要像这样创建验证注释:

So i do need to create the validation Annotation like this:

@Documented
@Constraint(validatedBy = NotNullIfConstraintValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD })
public @interface NotNullIf {

    String fieldName();

    String message() default "{NotNullIf.message}";
    Class<?>[] group() default {};
    Class<? extends Payload>[] payload() default {};
}

然后我需要自己创建验证器:

And After that i will need to create the Validator itself:

public class NotNullIfConstraintValidator implements ConstraintValidator<NotNullIf, String>{

    private String fieldName;

    public void initialize(NotNullIf constraintAnnotation) {
        fieldName = constraintAnnotation.fieldName();
    }

    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(value == null) {
            return true;
        };
        //TODO Validation
        return false;
    }

}

那么如何才能实现呢?

对于使用相同类作为示例的另一个想法,它说我想要生日,confirmBirthday 和birthdayMessdage 只能同时为null 或反对.这次我可能需要使用类注释验证来进行跨字段验证.

So how can it be achievable?

For another idea using the same Class as an example which said that i want birthday, confirmBirthday and birthdayMessdage can only be null or the oppose at the same time. I may require to use the class annotated validation this time for cross-field validation.

这是我想对类进行注释的方式:

Here's how i suppose to annotate the class:

@NotNullIf(fieldName={"birthday", "confirmBirthday", "birthdayMessage"})
public class Subscriber {
    //Those field same as the above one
}

因此,当该字段之一不为空时,其余的也需要在客户端大小上输入.有可能吗?

So when one of that field is not null, the rest of them also needs to be entered on the client size. Is it Possible?

我已阅读这篇文章:如何访问注释属性中描述的字段

但是我仍然对上面列出的那些元素的注释验证是如何工作的感到困惑.也许我需要对该代码进行一些详细的解释,或者更糟的是,我可能需要一些基本的概念检查.

But I still confusing on how the annotation validation works from those elements I listed above. Maybe I need some detail explanation on that code or even worse I may need some basic concept inspection.

请帮忙!

推荐答案

为此,您可以使用 类型级注解只是因为一个字段级注解无法访问其他字段!

For this you can use a type level annotation only because a field level annotation has no access to other fields!

我做了类似的事情来允许选择验证(许多属性中的一个必须不为空).在您的情况下,@AllOrNone 注释(或您喜欢的任何名称)需要一个字段名称数组,您将获得带注释类型的整个对象给验证器:

I did something similar to allow a choice validation (exactly one of a number of properties has to be not null). In your case the @AllOrNone annotation (or whatever name you prefer) would need an array of field names and you will get the whole object of the annotated type to the validator:

@Target(ElementType.TYPE)
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = AllOrNoneValidator.class)
public @interface AllOrNone {
    String[] value();

    String message() default "{AllOrNone.message}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class AllOrNoneValidator implements ConstraintValidator<AllOrNone, Object> {
    private static final SpelExpressionParser PARSER = new SpelExpressionParser();
    private String[] fields;

    @Override
    public void initialize(AllOrNone constraintAnnotation) {
        fields = constraintAnnotation.value();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        long notNull = Stream.of(fields)
                .map(field -> PARSER.parseExpression(field).getValue(value))
                .filter(Objects::nonNull)
                .count();
        return notNull == 0 || notNull == fields.length;
    }
}

(如您所说,您使用 Spring 我使用 SpEL 甚至允许嵌套字段访问)

(As you said you use Spring I used SpEL to allow even nested fields access)

现在您可以注释您的 Subscriber 类型:

Now you can annotate your Subscriber type:

@AllOrNone({"birthday", "confirmBirthday"})
public class Subscriber {
    private String name;
    private String email;
    private Integer age;
    private String phone;
    private Gender gender;
    private Date birthday;
    private Date confirmBirthday;
    private String birthdayMessage;
    private Boolean receiveNewsletter;
}

这篇关于具有多个字段的 Spring 自定义注释验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆