当前位置: 首页 > 知识库问答 >
问题:

spring中基于组的POJO动态验证

习高格
2023-03-14

参考以下pojo:

public class User{

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

    //getters and setters

}

我的应用程序基本上是一个基于Spring启动的REST API,它公开了两个endpoint,一个用于创建用户,另一个用于检索用户。

“用户”属于某些类别,a组、b组等。我从帖子请求的标题中获得。

我需要在运行时验证用户数据,并且验证可能因用户组而异。

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

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

我需要能够配置html" target="_blank">spring,以便在创建pojo并根据其组触发相应的验证集后,以某种方式动态验证我的pojo。

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

我不想用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");
        }
    }
}


public interface Validator {
    void validate(Object o);
}


@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;
    }
}


应用程序。yml

not-null:
  validators:

    -
      group: group-a
      target: user.username

    -
      group: group-b
      target: user.phone

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

P、 S。

请随意编辑问题以使其更好。

我正在使用杰克逊序列化和反序列化JSON。

共有3个答案

拓拔飞飙
2023-03-14

我能够通过使用Jayway JsonPath解决我的问题。我的解决方案如下:

>

validators:
  regexValidators:
    -
      target: $.userProfile.lastName
      pattern: '[A-Za-z]{0,12}'
      group: group-b

  minMaxValidators:
    -
      target: $.userProfile.age
      min: 18
      max: 50
      group: group-b

使用标头中的组调用此包装中的验证方法,然后调用各个验证器的验证方法。为了实现这一点,我在包装器中编写了以下代码:

public void validate(String input, String group) {
    regexValidators.stream()
            .filter(validator -> group.equals(validator.getGroup()))
            .forEach(validator -> validator.validate(input));

    minMaxValidators.stream()
            .filter(validator -> group.equals(validator.getGroup()))
            .forEach(validator -> validator.validate(input));
}

以及我的验证器中的以下方法:

public void validate(String input) {
    String data = JsonPath.parse(input).read(target);
    if (data == null) {
        throw new ValidationException("Target:  " + target + "  is NULL");
    }
    Matcher matcher = rule.matcher(data);
    if (!matcher.matches()) {
        throw new ValidationException("Target:  " + target + "  does not match the pattern:  " + pattern);
    }
}

我已经创建了一个功能正常的项目来演示验证,它可以在这里找到。
我知道单独的答案可能不是很清楚,请按照上面提到的url获取完整的源代码。

冉高寒
2023-03-14

您可以使用验证组来控制对哪个字段进行验证的用户类型。例如:

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

@NotBlank(groups = {GroupA.class, GroupB.class})
private String username;

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

看见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;
        }
    }
}

这不使用应用程序。yaml,而是在注释中设置为每个组验证哪些字段的映射,类似的结果使用Spring的内置验证支持。

胡承载
2023-03-14

在我看来,解决问题的最简单方法不是使用Spring或POJO本身,而是使用设计模式。

您所描述的问题可以通过策略模式解决方案轻松解决。

您可以匹配请求中预期的标头使用的策略,该标头描述了用户的类型,然后在策略本身内执行上述验证。

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

这是维基书籍中的一个链接,详细解释了这种模式

策略模式

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

interface Strategy { 

    boolean validate(User user);
}

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

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();
    }
}

您可以向您的用户POJO添加一个策略属性,并在收到post请求时将策略的正确实现分配给该属性。

每次您需要验证该用户的数据时,您只需调用分配策略的验证方法。

如果每个用户都能适应多种策略,您可以添加一个列表

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

除了验证方法之外,您还可以添加处理数据的方法,具体到每个策略。

希望这有帮助。

 类似资料:
  • 我正在尝试使用<code>Hibernate Validator</code>验证请求对象。 作为一个简单的例子,假设我要验证的对象的类有一个<code>B bObj</code>字段,其中<code>B 因此,我实现了自己的自定义,它链接到自定义类。 DTO类 我的endpoint方法签名(其中调用验证器,并设置活动组): 我的验证器类 我想要实现的是基于活动组对同一字段应用不同的验证。活动组是

  • 问题内容: 我正在研究一种基于注释的方法,用于使用spring模块验证Spring bean 。在本教程中,以以下bean(省略了getter和setters)为例: 如果不遵守特定的验证规则,则会使用以下错误消息: 上面显示的类的示例包括: 消息键包含类名的事实带来了两个问题: 如果重命名该类,则还需要更改消息键 如果我有另一个类(例如Person),其类的电子邮件属性已与User.email进

  • 本文向大家介绍基于C#实现12306的动态验证码变成静态验证码的方法,包括了基于C#实现12306的动态验证码变成静态验证码的方法的使用技巧和注意事项,需要的朋友参考一下 本以为这次12306的动态验证码很厉害,什么刷票软件都不行了,看了以后发现并不是很复杂,估计不出两日刷票软件又会卷土重来,开来要一个验证码很难遏制这些刷票软了。 这次换的动态验证码采用的是GIF格式在客户端输出,至于要拿到这个g

  • 我必须创建一个需要与Neo4J数据库交互的Web服务,使用Spring框架和Spring-Data-Neo4J。这需要静态数据域模型,例如定义的标签、关系、属性。 问题是,我的数据是基于本体论(通过neosemantics插件),将来可以修改。如果应用程序能够自动采用它,那就太好了。这样,数据模型可以只通过编辑本体论来扩展,不需要额外的编程知识。 这是否意味着我必须动态地生成Spring数据类(基

  • 我有一个名为selectedItem的数组,它是从多选择下拉按钮填充的。如果所有选项都被选中,选择项目可能看起来像这样: 我需要添加id值,不管选择了多少,作为超文本传输协议GET请求中的参数。现在我的逻辑看起来像这样。 我的SearchItem界面如下所示: 现在,它创建了一个请求选项对象,其中的值是一个数组,但是我的超文本传输协议请求没有在网络选项卡中的查询字符串参数字段中显示这一点。看来ad

  • 问题内容: 我在寻找一种不涉及引入一个额外的“通用”字段的溶液等,等这将是该变种领域的占位符。 我有一个JSON规范,它描述了几个大型结构,这些结构主要包含简单的值,但偶尔也有一个结构本身的值,其动态类型取决于某个字段的值。 例如,这两个JSON文档都应解组到相同的Go结构: 和 JSON结构已设置,我无法更改。 Go结构必须如下所示: 问题是如何实际执行操作以及该类型应为哪种类型。 我首先使其成