我正在创建一个注释来验证开始/结束日期,我想确保它们不重叠。
注解:
@Documented
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { NonOverlappingDatesValidator.class })
public @interface NonOverlappingDates {
String start();
String end();
String message() default "OVERLAPPING_OF_DATES";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
验证器:
public class NonOverlappingDatesValidator implements ConstraintValidator<NonOverlappingDates, Object> {
private String start;
private String end;
/**
* Initialize.
*/
@Override
public void initialize(NonOverlappingDates nonOverlappingDates) {
start = nonOverlappingDates.start();
end = nonOverlappingDates.end();
}
/**
* Checks if is valid.
*/
@Override
public boolean isValid(Object instanceToValidate, ConstraintValidatorContext constraintValidatorContext) {
Class<?> classToValidate = instanceToValidate.getClass();
LocalDateTime startDate;
LocalDateTime endDate;
try {
startDate = getLocalDateTimeFromFieldName(classToValidate, instanceToValidate, start);
endDate = getLocalDateTimeFromFieldName(classToValidate, instanceToValidate, end);
} catch (ReflectionException e) {
throw new RuntimeException(e);
}
return DateTimeUtils.isBefore(startDate, endDate);
}
private LocalDateTime getLocalDateTimeFromFieldName(Class<?> classToValidate, Object instanceToValidate, String fieldName) throws ReflectionException {
Method getter = ReflectionUtils.getPublicGetterOfFieldName(classToValidate, fieldName);
Object value = ReflectionUtils.invokeMethod(instanceToValidate, getter);
if (value instanceof LocalDateTime localDateTime) {
return localDateTime;
} else {
throw new RuntimeException(fieldName+" is not a LocalDateTime");
}
}
}
待验证的DTO:
@Data
@NonOverlappingDates(start = "startDate", end = "endDate")
public class IdentityCardDTO {
@JsonProperty
private Long id;
@JsonProperty
private String name;
@JsonProperty
private String surname;
@JsonProperty
@JsonSerialize(using = LocalDateSerializer.class)
@JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate dateOfBirth;
@JsonProperty
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime startDate;
@JsonProperty
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime endDate;
}
我想知道是否可以直接传递我想要验证的字段的值,而不是传递字段名称然后使用反射来检索值。
您可以通过抽象需要验证的数据来实现这种效果。您需要一个带有方法的接口来获取所需的数据。比方说:
不是一个很好的名字,但用于示例目的还可以。然后启用您的实际验证器来验证此接口的实例,而不是
Object
像现在这样。像这样你也可以简化很多:NonOverlappingDatesValidator
现在可以验证任何实现DatesData
.IdentityCardDTO
变成:这
NonOverlappingDates
也简化了,因为您不再需要start()
和end()
方法。