基于spring的组动态POJO验证

Adi*_*lai 12 java validation spring jackson spring-boot

考虑以下pojo以供参考:

public class User{

    private  String username;
    private String firstName;
    private String middleName;
    private String lastName;
    private String phone;

    //getters and setters

}
Run Code Online (Sandbox Code Playgroud)

我的应用程序基本上是基于spring-boot的REST API,它公开了两个端点,一个用于创建用户,另一个用于检索用户.

"用户"属于某些类别,group-a,group-b等,我从post请求的标题中获取.

我需要在运行时验证用户数据,验证可能会因用户组而有所不同.

例如,属于组-a的用户可能将电话号码作为可选字段,而对于某些其他组,它可能是必填字段.

正则表达式也可能因其组而异.

我需要能够配置spring,以某种方式动态验证我的pojo一旦创建它们各自的验证集就会根据它们的组触发.

也许我可以创建一个yml/xml配置,允许我启用它?

我宁愿不标注我private String phone@NotNull@Pattern.

我的配置如下:

public class NotNullValidator implements Validator {
    private String group;
    private Object target;

    public String getGroup() {
        return group;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public void validate(Object o) {
        if (Objects.nonNull(o)) {
            throw new RuntimeException("Target is null");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


public interface Validator {
    void validate(Object o);
}
Run Code Online (Sandbox Code Playgroud)


@ConfigurationProperties(prefix = "not-null")
@Component
public class NotNullValidators {
    List<NotNullValidator> validators;

    public List<NotNullValidator> getValidators() {
        return validators;
    }

    public void setValidators(List<NotNullValidator> validators) {
        this.validators = validators;
    }
}
Run Code Online (Sandbox Code Playgroud)


application.yml

not-null:
  validators:

    -
      group: group-a
      target: user.username

    -
      group: group-b
      target: user.phone
Run Code Online (Sandbox Code Playgroud)

我想配置我的应用程序以某种方式允许验证器选择他们的目标(实际的对象,而不是 yml中提到的字符串),并public void validate(Object o)在他们的目标上调用他们各自的.

PS

请随时编辑问题以使其更好.

我正在使用jackson序列化和反序列化JSON.

ric*_*070 16

正如我所看到的,对您的问题最简单的解决方案不是Spring或POJO本身,而是设计模式.

您描述的问题很容易通过策略模式解决方案解决.

您将策略与您在请求中期望的标头匹配,描述用户的类型,然后在策略本身内执行所述验证.

这将允许您对整个方法使用相同的POJO,并根据每种类型的用户策略处理处理/解析和验证数据的细节.

这是来自维基书籍的链接,以及对模式的详细解释

战略模式

假设您有一个基本的策略界面:

interface Strategy { 

    boolean validate(User user);
}
Run Code Online (Sandbox Code Playgroud)

对于2种不同类型的用户,您有2种不同的实现:

public class StrategyA implements Strategy {

    public boolean validate(User user){

         return user.getUsername().isEmpty();
    }
}

public class StrategyB implements Strategy {

    public boolean validate(User user){

         return user.getPhone().isEmpty();
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以向UserPOJO 添加策略属性,并Strategy在收到发布请求时为该属性分配正确的实现.

每当您需要验证该用户的数据时,您只需调用validate指定策略的方法即可.

如果每个User策略都适合多种策略,则可以添加List<Strategy>属性而不是单个属性.

如果您不想更改POJO,则每次收到邮件请求时都必须检查哪个是正确的策略.

除了该validate方法,您还可以添加处理数据的方法,特定于每个策略.

希望这可以帮助.


Ser*_*eyB 5

您可以使用验证组来控制哪个类型的用户被验证哪个字段.例如:

@NotBlank(groups = {GroupB.class})
private String phone;

@NotBlank(groups = {GroupA.class, GroupB.class})
private String username;
Run Code Online (Sandbox Code Playgroud)

然后,您使用您提到的请求中的标头来决定要对哪个组进行验证.

有关完整示例,请参阅http://blog.codeleak.pl/2014/08/validation-groups-in-spring-mvc.html?m=1.


更新以包含更全面的示例:

public class Val {
    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    public boolean isValid(User user, String userType) {
        usergroups userGroup = usergroups.valueOf(userType);
        Set<ConstraintViolation<User>> constraintViolations = validator.validate(user, userGroup.getValidationClass());
        return constraintViolations.isEmpty();
    }

    public interface GroupA {}
    public interface GroupB {}

    public enum usergroups {
        a(GroupA.class),
        b(GroupB.class);

        private final Class clazz;

        usergroups(Class clazz) {
            this.clazz = clazz;
        }

        public Class getValidationClass() {
            return clazz;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这不使用application.yaml,而是使用Spring内置的验证支持在注释中设置为每个组验证哪些字段的映射.