You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenAPI date格式校验:requestBody中date字段未按yyyy-mm-dd规则校验问题

根本原因

两类参数的解析链路不同导致校验表现不一致:

  • Query参数先做字符串格式校验再转换为LocalDate,格式不匹配直接触发400
  • RequestBody先由JSON序列化框架(通常是Jackson)完成字符串到LocalDate的反序列化,默认宽松配置下会自动截断ISO时间戳的时间部分解析为合法LocalDate,不会抛出异常,且@Pattern注解仅对字符串类型生效,对LocalDate类型无效

以下是3种符合不删除format: date配置要求的可落地方案:

方案1:配置Jackson严格反序列化规则(推荐,改动最小)

直接修改Jackson全局反序列化配置,禁止LocalDate宽松解析,只要输入格式不是严格的yyyy-MM-dd就抛出解析异常,自动触发400返回。
如果是SpringBoot项目,直接在配置文件添加如下配置:

spring:
  jackson:
    deserialization:
      lenient: false
    date-format: yyyy-MM-dd

如果需要更精细的控制,可以自定义LocalDate反序列化器:

public class StrictLocalDateDeserializer extends StdDeserializer<LocalDate> {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public StrictLocalDateDeserializer() {
        super(LocalDate.class);
    }

    @Override
    public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String value = p.getText().trim();
        if (value.contains("T")) { // 匹配带时间戳的ISO格式
            throw new JsonParseException(p, "Invalid date format, only yyyy-MM-dd is allowed");
        }
        return LocalDate.parse(value, FORMATTER);
    }
}

然后在OpenAPI的schema配置中给bodyDate字段添加扩展注解,指定使用该反序列化器:

bodyDate:
  type: string
  format: date
  x-field-extra-annotation: "@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = com.yourpackage.StrictLocalDateDeserializer.class)"

方案2:自定义校验注解实现格式校验

针对LocalDate类型无法使用@Pattern的问题,自定义校验注解完成格式校验:

  1. 定义校验注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = StrictDateValidator.class)
public @interface StrictDate {
    String message() default "Invalid date format, only yyyy-MM-dd is allowed";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  1. 实现校验器,从请求中拿到原始JSON值做格式校验
public class StrictDateValidator implements ConstraintValidator<StrictDate, LocalDate> {
    private static final Pattern DATE_PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$");

    @Override
    public boolean isValid(LocalDate value, ConstraintValidatorContext context) {
        if (value == null) return true; // 非空校验由其他注解负责
        // 从请求上下文获取原始请求body
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        // 解析JSON获取对应的bodyDate原始值
        try {
            JsonNode jsonNode = new ObjectMapper().readTree(body);
            String rawDate = jsonNode.get("bodyDate").asText();
            return DATE_PATTERN.matcher(rawDate).matches();
        } catch (Exception e) {
            return false;
        }
    }
}
  1. 在OpenAPI配置中给bodyDate添加该注解扩展即可

方案3:调整OpenAPI生成规则,字段用String类型接收

修改OpenAPI生成器配置,将format: date的请求体字段映射为String类型而非LocalDate,此时@Pattern注解即可正常生效,校验通过后再手动转换为LocalDate使用。
以openapi-generator-maven-plugin为例,添加如下配置:

<configuration>
  <typeMappings>
    <typeMapping>date=String</typeMapping>
  </typeMappings>
  <importMappings>
    <importMapping>java.time.LocalDate=</importMapping>
  </importMappings>
</configuration>

同时在schema中保留pattern配置:

bodyDate:
  type: string
  format: date
  pattern: ^\d{4}-\d{2}-\d{2}$

内容的提问来源于stack exchange,提问作者Valéry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 21:57:01