我在要验证的Spring MVC请求中有一个输入DTO,特别是ZonedDateTime字段最多应该包含毫秒级的3位数,即它不能是完整的纳秒级精度。除此之外,输入请求应遵循ISO日期时间格式。我可以使字段成为一个字符串,然后用正则表达式限制它,但我更喜欢将它保留为ZonedDateTime,所以我不需要再次解析它。
该对象如下所示:
@Data
public class MeasurementDTO {
private ZonedDateTime date;
@Digits(integer = 20, fraction = 8) private BigDecimal value;
}
这是一个嵌套的DTO,其中父对象作为带有@RequestBody
注释的@Valid
进入。
我试过@JsonFormat,但我似乎无法限制毫秒级。有没有办法做到这一点,或者我应该自己解析它作为一个字符串然后处理它?或者甚至只是将它留在ZonedDateTime,然后检查纳秒组件,看看它是否在自定义验证器中?
感谢蒂姆的回答,我记得Java Date
s没有比millis更精确,所以我更新了问题,使用ZonedDateTime
s,它具有高达纳秒的精度。我确实希望能够在用户尝试传递更多精度时向用户发出警告,如果使用日期,则此信息将被吞下。
您可能不认为这是一个完整的答案,但java.util.Date
只存储精度高达毫秒,而不是超过这个。请参阅Jon Skeet的answer here,或阅读source code for CalendarDate,它显示它没有超过毫秒的存储空间。
因此,使用Hibernate验证将Date
限制为毫秒级精度是没有意义的,因为类型本身已经具有此限制。
我用自定义验证器这么做了。我仍然欢迎以更简洁的方式做到这一点的答案。
这是我的解决方案:
我添加了一个注释@ValidMeasurementInput
@Documented
@Constraint(validatedBy = MeasurementValidator.class)
@Target({TYPE, FIELD, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface ValidMeasurementInput {
String message() default "Invalid measurement input";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
并实现了自定义验证器
public class MeasurementValidator implements ConstraintValidator<ValidMeasurementInput, MetricsDTO> {
@Override
public boolean isValid(MetricsDTO metricsDTO, ConstraintValidatorContext context) {
...
}
}
在这个类中的某些其他验证中的代码是这个代码:
int nano = measurementDTO.getDate().getNano();
int remainderAfterMillis = nano % 1000000;
if (remainderAfterMillis != 0)
valid = false;
当然,我将@ValidMeasurementInput
添加到了我的DTO。