【问题标题】:Validating a subset of List items using Java Hibernate, aquiring the full property path使用 Java Hibernate 验证列表项的子集,获取完整的属性路径
【发布时间】:2018-05-07 12:25:22
【问题描述】:

我正在使用 javax 和 hibernate 创建我的第一个 Spring Boot Web 应用程序,以验证来自 JSP 表单的数据输入。我有一个包含旅程模型列表的 Booking 模型:

@ValidBooking(groups = {BookingI.class})
public class Booking {

  @Min(value = 1, groups = {BookingI.class, Default.class})
  private int totalJourneys;
  @Valid
  private List<Journey> journeys;
  // relevant getters and setters

我需要知道如何在提交表单时仅验证旅程项目的选择,现在复杂的地方在于旅程模型包含位置列表:

@ValidJourney
public class Journey {

  @Valid
  private List<Location> locations;
  private List<String> dates;
  private List<String> times;

  // relevant getters and setters

我可以使用 @Valid 注释成功验证所有预订旅程,但是在提交表单时,我只对某些旅程的成功感兴趣,因此想忽略某些旅程项目约束违规。

到目前为止,我的尝试是使用自定义类验证器来迭代并仅验证所需的旅程,然后使用 buildConstraint ViolationWithTemplate,如下所示:

public class ValidBookingValidator implements ConstraintValidator<ValidBooking, Booking> {

  @Override
  public boolean isValid(Booking booking, ConstraintValidatorContext constraintValidatorContext) {

    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();

    int totalJourneys = booking.getTotalJourneys();
    int validJourneys = 0;
    for (int journeyIdx = 0; journeyIdx < totalJourneys; journeyIdx++) {
        Set<ConstraintViolation<Journey>> journeyConstraintViolations = validator.validate(booking.getJourneys().get(journeyIdx));

        if (journeyConstraintViolations.isEmpty()) {
            validJourneys++;
        } else {
            for (ConstraintViolation<Journey> violation : journeyConstraintViolations) {
                constraintValidatorContext.buildConstraintViolationWithTemplate(violation.getMessage())
                .addPropertyNode(violation.getPropertyPath().toString())
                .addConstraintViolation();
            }
        }
    }
    return totalJourneys == validJourneys;
  }

}

上面的代码适用于我的测试,但是当使用 jsp 表单渲染时,spring 数据绑定失败,因为违规约束的属性路径返回为 'locations[0]' 而不是预期的 'booking.journeys[0] .locations[0]'。

是否有人对如何返回完整的属性路径有任何建议,或者对此提供更好的解决方案。

提前致谢。

Java 8, javax validation api 2.0.1, hibernate-validator 6.0.7

【问题讨论】:

    标签: java spring-boot hibernate-validator


    【解决方案1】:

    所以,先来几个 cmets:

    • 在验证器中构建ValidatorFactory 不是一个好主意。这是一个非常重的对象,每次验证它时都需要构建 Journey bean 的元数据,而且速度会很慢。
    • 要构建约束,您需要构建确切的路径,即使用inContainer()atIndex()...您不能简单地将toString() 传递给属性。

    当然你可以解决后者,但前者绝对是不行的。

    你可以试试:

    • 创建一个实现DefaultGroupSequenceProviderJourneyDefaultGroupSequenceProvider 并在它是您要验证的对象时返回有效组,当您不想验证旅程时返回一些未用于任何约束的随机组。 List&lt;Class&lt;?&gt;&gt; getValidationGroups(T object) 有一个你的对象的实例,所以你可以在这里做。
    • 声明它

      @GroupSequenceProvider(JourneyDefaultGroupSequenceProvider.class)
      public class Journey {
          // ...
      }
      
    • 删除您添加的所有怪癖并正常验证您的Booking bean。

    更新:我创建了https://hibernate.atlassian.net/browse/HV-1613,看看我们是否可以提供一种更自然的方式在 HV 中执行此操作。

    【讨论】:

    • 感谢@GuillaumeSmet 的回复和建议,我正在实施GroupSequenceProvider。我唯一的问题是我可以访问 Journey GroupSequenceProvider 中的父对象信息(在本例中为 Booking),以便我可以确定 Journey 对象的索引位置是否小于 Booking.totalJourneys 值?
    • 您只有拥有@GroupSequenceProvider 的实例。因此,不幸的是,您需要一个指向对象中父级的链接。仅供参考,我创建了hibernate.atlassian.net/browse/HV-1613 以考虑添加更明显的内容。将在其中添加有关索引的案例,但我不确定找到解决方案是否容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    相关资源
    最近更新 更多