Spring Boot中在DTO层验证请求参数的ISO-8601格式日期
如何在DTO层验证Date字段为ISO-8601格式
当然可以在DTO层对endDate字段做ISO-8601格式的验证!下面分享两种实用的实现方式,你可以根据自己的场景选择:
方法1:自定义验证注解(推荐)
这种方式最灵活,能直接对Date类型字段做格式校验,而且和现有的@NotNull注解完美配合,步骤很清晰:
1.1 先定义自定义验证注解
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Documented @Constraint(validatedBy = Iso8601DateValidator.class) @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface Iso8601Date { String message() default "日期格式必须为ISO-8601标准格式(例如:2007-04-05T14:30Z)"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
1.2 实现注解对应的验证逻辑
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Iso8601DateValidator implements ConstraintValidator<Iso8601Date, Date> { // 严格匹配ISO-8601的指定格式 private static final String ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm'Z'"; @Override public boolean isValid(Date date, ConstraintValidatorContext context) { // null的情况交给@NotNull处理,这里只验证非null的日期格式 if (date == null) { return true; } try { SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_PATTERN); sdf.setLenient(false); // 关闭宽松解析,确保格式完全匹配 // 把Date转成字符串再转回来,对比是否一致 String formattedDate = sdf.format(date); Date parsedDate = sdf.parse(formattedDate); return date.equals(parsedDate); } catch (ParseException e) { return false; } } }
1.3 在DTO字段上加上这个注解
import com.fasterxml.jackson.annotation.JsonProperty; import javax.validation.constraints.NotNull; public class ReceivedDTO { @JsonProperty("end_date") @NotNull(message = "end_date不能为空") @Iso8601Date // 加上自定义格式验证注解 private Date endDate; // getter、setter省略 }
方法2:转成String字段用@Pattern验证
如果你能接受调整DTO的字段类型,把Date改成String,可以直接用JSR-380自带的@Pattern注解做正则校验,之后再在服务层转成Date类型:
import com.fasterxml.jackson.annotation.JsonProperty; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class ReceivedDTO { @JsonProperty("end_date") @NotNull(message = "end_date不能为空") // 正则匹配ISO-8601的指定格式 @Pattern(regexp = "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}Z$", message = "日期格式必须为ISO-8601标准格式(例如:2007-04-05T14:30Z)") private String endDate; // 可以加个方法把字符串转成Date,方便后续使用 public Date getEndDateAsDate() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); sdf.setLenient(false); return sdf.parse(endDate); } // getter、setter省略 }
额外小建议
如果你用的是Java 8及以上,真心推荐用OffsetDateTime(或者LocalDateTime)替代Date,这些新的日期API天生支持ISO-8601格式,配合Jackson的@JsonFormat注解,既能自动解析/序列化,又能间接实现格式校验:
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import javax.validation.constraints.NotNull; import java.time.OffsetDateTime; public class ReceivedDTO { @JsonProperty("end_date") @NotNull(message = "end_date不能为空") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm'Z'") private OffsetDateTime endDate; // getter、setter省略 }
这种情况下,如果前端传的格式不对,Spring的消息转换器会直接抛出HttpMessageNotReadableException,你可以通过全局异常处理器捕获这个异常,返回友好的错误提示给前端。
内容的提问来源于stack exchange,提问作者htshame
相关产品推荐
相关产品推荐

