使用javax验证,如何比较一个属性与另一个属性的大小?

13
关于 javax.validation 的问题:
  @NotNull(message = "From can't be null")
  @Min(value = 1, message = "From must be greater than zero")
  private Long from;
  @NotNull(message = "To can't be null")
  @Min(value = 1, message = "To must be greater than zero")
  private Long to;

我希望您能验证FROM应该小于TO,并且TO应该大于FROM。我们如何使用javax validation的注释来实现这一点?

2个回答

5
你需要一个定制的“跨域字段验证”注释。
一种方法是使用“@YourCustomAnnotation”对你的自定义类进行注释。
在“YourCustomAnnotationValidator”中,你可以访问你的值,因此可以在那里实现你的逻辑:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Constraint(validatedBy = DateValidator.class)
public @interface RangeCheck {

    String message();

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

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

public class RangeCheckValidtor implements ConstraintValidator<RangeCheck, YourDto> {

    @Override
    public void initialize(RangeCheck date) {
        // Nothing here
    }

    @Override
    public boolean isValid(YourDto dto, ConstraintValidatorContext constraintValidatorContext) {
        if (dto.getFrom() == null || dto.getTo() == null) {
            return true;
        }
        return from < to;
    }
}

然后在你的YourDto类上标记@RangeCheck

@RangeCheck(message = "your messgae")
public class YourDto {
   // from
   // to
}

或者手动验证两个字段的关系。

0
对于任何需要更通用解决方案的人来说,可以实现验证器来比较两个给定属性。以下是我想到的方法:
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { CompareFieldsValidator.class })
public @interface CompareFields {

    String message() default "{CompareFields.message}";

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

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

    String left();

    String right();
    
    int[] vals() default {0};

    @Target({ TYPE, ANNOTATION_TYPE })
    @Retention(RUNTIME)
    public @interface List {
        CompareFields[] value();
    }
}


public class CompareFieldsValidator implements ConstraintValidator<CompareFields, Object> {

    private static final Logger log = LoggerFactory.getLogger(FieldsEqualityValidator.class);

    private String left;
    private String right;
    private Set<Integer> vals;

    @Override
    public void initialize(CompareFields constraintAnnotation) {
        left = constraintAnnotation.left();
        right = constraintAnnotation.right();
        vals = Arrays.stream(constraintAnnotation.vals()).boxed().collect(Collectors.toSet());
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (value == null)
            return true;

        try {
            Class<?> clazz = value.getClass();
            //get left operand as comparable
            Field leftField = ReflectionUtils.findField(clazz, left);
            leftField.setAccessible(true);
            Object leftObj = leftField.get(value);
            Comparable<Object> leftComparable = (Comparable<Object>)leftObj;
            //get right operand
            Field rightField = ReflectionUtils.findField(clazz, right);
            rightField.setAccessible(true);
            Object rightObj = rightField.get(value);
            
            //null check : return true if both null
            if(leftComparable == null) {
                if(rightObj == null) {
                    return true;
                } else {
                    context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                        .addPropertyNode(left).addPropertyNode(right);
                    return false;
                }
            }
            
            //return true if compareTo result in vals array
            if(vals.contains(leftComparable.compareTo(rightObj))) {
                return true;
            }else {
                context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                .addPropertyNode(left).addConstraintViolation();
                return false;
            }
        } catch (Exception e) {
            log.error("Cannot validate one of two field in '" + value + "'!", e);
            return false;
        }
    }
}


//Usage: selling price must be smallar than or equal to list price
@CompareFields(left = "sellingPrice", right = "listPrice", vals = {-1,0})
public class InventoryDto{
...
}
//Usage: start time must be before finish time
@CompareFields(left = "startTime", right = "finishTime", vals = {-1})
public class GateLogDto{
...
}

1
根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接