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

JavaHibernate验证器需要一个或另一个

闽高峯
2023-03-14

这是我之前问题的扩展。我实现了Dennis R的答案,并且正在使用hibernate-validator。有没有办法要求在json请求中指定一个或另一个字段,但不能同时指定两个?从我之前的帖子中,在Request类中,我希望用户传入id或代码,但不能同时传入。

我发现这个资源对我来说可能是正确的解决方案,但我不完全理解那里发生了什么,为什么它有效,坦率地说,它看起来太冗长了。这是唯一的方法吗?

共有3个答案

洪凯定
2023-03-14

您可以使用Group作为替代方案。例如,这是请求。java:

public class Request {

public interface IdOrCodeValidationGroup {}

    @NotNull
    @NotEmpty
    private String id;

    @Digits(integer=4, fraction=0)
    private double code;

    @NotNull
    @NotEmpty
    private String name;

    @AssertTrue(groups = IdOrCodeValidationGroup.class)
    private boolean idOrCodeFilled;

    public Request(String id, double code, String name) {
        this.id = id;
        this.code = code;
        this.name = name;
    }

    public boolean isIdOrCodeFilled() {
        if (id == null && code > 0) {
            idOrCodeFilled = true;
        } else if (id != null && code == 0) {
            idOrCodeFilled = true;
        } else idOrCodeFilled = false;
        return idOrCodeFilled;
    }
}

然后像这样使用验证器:

@Test
public void testValidation() {
    // Of course all of this valid. No group at all.
    final Request request = new Request("ID-001", 111, "Data 1");
    final Set<ConstraintViolation<Request>> fails = this.validator.validate(request);
    Assert.assertTrue(fails.isEmpty());
}

@Test
public void testValidationWithGroup() {
    // We use "IdOrCodeValidationGroup.class" group, thus this is invalid.
    Request request = new Request("ID-001", 111, "Data 1");
    Set<ConstraintViolation<Request>> fails = this.validator.validate(request, IdOrCodeValidationGroup.class);
    Assert.assertFalse(fails.isEmpty());

    // Lets make one of constraint true; In this case, we set code = 0.
    request = new Request("ID-002", 0, "Data 2");
    fails = this.validator.validate(request, IdOrCodeValidationGroup.class);
    // Passed!
    Assert.assertFalse(fails.isEmpty()); 
}

下面是功能完整的示例代码。(别忘了结帐“so-36365734”分行)。这是关于Bean验证组的官方文档。

HTH。

裴令秋
2023-03-14

天哪在我看来,这些链接的参考文献过于复杂。存在注释:

@org.hibernate.annotations.Check

我经常遇到同样的情况,我想执行这种类型的验证,我有一个或另一个字段,或者我有两个或两个都没有。。。

@Entity
@org.hibernate.annotations.Check(constraints = "(field1 IS NULL OR field2 IS NULL) AND (field1 IS NOT NULL OR field2 IS NOT NULL)")
public class MyEntity{
    String field1;
    Double field2;
}

这将在数据库中创建一个检查约束,该约束将强制执行该约束。它将验证从Hibernate和您的代码转移到数据库(这也将防止任何在您的hibernate配置之外访问您的数据库的应用程序破坏此约束)。

此注释的创建不会自动在您的数据库上执行约束的创建,但如果/当您创建约束时,它也会通知hibernate它。

在Postgres中,该约束类似于:ALTER TABLE my\u entity ADD constraint my\u entity\u check check((field1为NULL或field2为NULL)和(field1不为NULL或field2不为NULL));

Postgres检查约束

Oracle检查约束

如果您无法生成精确的SQL,请创建注释,然后允许hibernate针对空数据库自动生成数据库模式,它将向您显示正确的SQL。但是有了注释,hibernate也知道约束,因此如果您允许hibernate为任何自动化测试等生成模式,则可以自动生成...

燕永昌
2023-03-14

正如我之前评论的那样,在这里遵循Nicko的回答,您可以使用以下代码实现您想要的:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
public @interface FieldMatch {

    String message() default "something is wrong!";

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

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

    /**
     * @return The first field
     */
    String first();

    /**
     * @return The second field
     */
    String second();

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        FieldMatch[] value();
    }

    public static class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {

        private String firstFieldName;
        private String secondFieldName;

        @Override
        public void initialize(FieldMatch fieldMatch) {
            firstFieldName = fieldMatch.first();
            secondFieldName = fieldMatch.second();
        }

        public boolean isValid(Object object, ConstraintValidatorContext constraintContext) {
            try {
                final Object firstObj = getProperty(object, firstFieldName);
                final Object secondObj = getProperty(object, secondFieldName);

                if(firstObj == null && secondObj == null || firstObj != null && secondObj != null) {
                    return false;
                }
            } catch (final Exception ignore) {
                // ignore
            }
            return true;
        }

        private Object getProperty(Object value, String fieldName) {
            Field[] fields = value.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (field.getName().equals(fieldName)) {
                    field.setAccessible(true);
                    try {
                        return field.get(value);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;
        }
    }

}

用法:

@FieldMatch.List({
        @FieldMatch(first = "name", second = "people"),
        @FieldMatch(first = "age", second = "abc")
})
public class Foo {

    private String name;
    private List<String> people;
    private int age;
    private Boolean abc; 
}

唯一的区别是,您不想检查内容是否相等,只要一个字段为空,另一个字段不为空。

编辑:

要按照注释的要求在ExceptionHandler上获取对象,只需将异常包装在自定义异常周围,并在抛出时传递对象,即:

public class CustomException extends Exception {

    private String message;
    private Object model;

    public CustomException(String message, Object model) {
        super(message);
        this.model = model;
    }

    public Object getModel() {
        return model;
    }
}

有了这个,你可以简单地得到如下结果:

@ExceptionHandler(CustomException.class)
public ModelAndView handleCustomException(CustomException ex) {
    Object obj = ex.getModel();
    //do whatever you have to
}
 类似资料:
  • 问题内容: 我有两个字段,仅当两个字段都不存在时才是可选的: 现在,需要大于。如何包含此过滤器? 问题答案: 有 没有内置的验证 ,它可以让你比较字段值一样,在 Laravel ,所以你需要实现一个 自定义的验证 ,这将让你重新使用验证需要的地方。幸运的是,Laravel使编写自定义验证器 变得非常容易 。 首先在您的 AppServiceProvider中 定义新的验证器: 现在,您可以在 $

  • 我使用Symfony 5.3。我有一个表单,有3个字段没有映射到任何实体: "原因"-文本, use_predefined复选框 "predefined_reason"-下拉列表。 我构建的表单如下(一个片段): “原因”字段应根据需要显示在UI中,但其他两个字段不应显示。但是,在验证过程中,如果选中了复选框“预定义的原因”,则第一个字段不应为必填字段,而“预定义的原因”应为必填字段。

  • 我有一个Spring Boot rest服务,它将调用另一个web服务(用.NET编写),但它需要安装web服务的服务器的公共证书。

  • 晚上好,我正在尝试在下面的场景中使用Hibernate验证器:

  • 我想验证字段,如果存在,将失败,如果另一个字段不存在如何做到这一点?我已经创建了自定义验证,以获得基于存储ID的记录 我有字段和,并且字段根据在最大值和最小值之间进行验证,如果我显示=且未填写字段,则验证字段将通过,并显示错误,因为我未填写我希望在执行自定义验证之前检查是否为空。。 我已经阅读了laravel文档上的所有验证方法,但仍然没有找到解决方案。怎么做?

  • 我的mac电脑中没有internet连接。我需要使用docker pull。我的想法是,我将使用docker拉入我的一台连接互联网的mac电脑,然后将其复制到没有互联网连接的mac电脑上。如何复制?