1. 简介

在本篇教程中,我们将学习如何在 Spring REST 请求中接收并解析 DateLocalDateLocalDateTime 类型的参数,包括在请求级别和应用级别的处理方式。

2. 问题背景

考虑如下一个 Controller,它包含三个方法,分别接收 DateLocalDateLocalDateTime 类型的参数:

@RestController
public class DateTimeController {

    @PostMapping("/date")
    public void date(@RequestParam("date") Date date) {
        // ...
    }

    @PostMapping("/localdate")
    public void localDate(@RequestParam("localDate") LocalDate localDate) {
        // ...
    }

    @PostMapping("/localdatetime")
    public void dateTime(@RequestParam("localDateTime") LocalDateTime localDateTime) {
        // ...
    }
}

当你向这些接口发送符合 ISO 8601 格式的日期字符串时,会抛出异常。

比如,向 /date 接口发送 "2018-10-22",你会收到类似下面的错误:

Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate'; 
  nested exception is org.springframework.core.convert.ConversionFailedException.

❌ 这是因为 Spring 默认无法将字符串自动转换为任何日期或时间类型对象。

3. 在请求级别处理日期参数

一种解决方式是在参数上使用 @DateTimeFormat 注解,并指定格式:

@RestController
public class DateTimeController {

    @PostMapping("/date")
    public void date(@RequestParam("date") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date date) {
        // ...
    }

    @PostMapping("/local-date")
    public void localDate(@RequestParam("localDate") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate localDate) {
        // ...
    }

    @PostMapping("/local-date-time")
    public void dateTime(@RequestParam("localDateTime") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime localDateTime) {
        // ...
    }
}

✅ 这样,只要字符串是 ISO 8601 格式,Spring 就能正确地将其转换为对应的日期对象。

你也可以自定义格式,通过 pattern 属性指定:

@PostMapping("/date")
public void date(@RequestParam("date") 
  @DateTimeFormat(pattern = "dd.MM.yyyy") Date date) {
    // ...
}

⚠️ 注意:这种方式只对当前接口生效,适用于格式不统一的场景。

4. 全局配置日期格式

如果你希望整个应用都使用统一的日期格式,可以通过全局配置来实现。参考 Spring 官方文档,我们需要继承 WebMvcConfigurationSupport 并重写 mvcConversionService 方法:

@Configuration
public class DateTimeConfig extends WebMvcConfigurationSupport {

    @Bean
    @Override
    public FormattingConversionService mvcConversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false);

        DateTimeFormatterRegistrar dateTimeRegistrar = new DateTimeFormatterRegistrar();
        dateTimeRegistrar.setDateFormatter(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
        dateTimeRegistrar.setDateTimeFormatter(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));
        dateTimeRegistrar.registerFormatters(conversionService);

        DateFormatterRegistrar dateRegistrar = new DateFormatterRegistrar();
        dateRegistrar.setFormatter(new DateFormatter("dd.MM.yyyy"));
        dateRegistrar.registerFormatters(conversionService);

        return conversionService;
    }
}

✅ 步骤说明:

  • DefaultFormattingConversionService(false) 表示不使用 Spring 默认的格式化器。
  • 使用 DateTimeFormatterRegistrar 注册 LocalDateLocalDateTime 的格式。
  • 使用 DateFormatterRegistrar 处理 java.util.Date 类型。

⚠️ 注意:这种方式适用于格式统一的项目,避免在每个接口上重复配置。

5. 通过配置文件设置日期格式

Spring 还支持通过 application.properties 文件来设置全局日期格式:

spring.mvc.format.date=yyyy-MM-dd
spring.mvc.format.date-time=yyyy-MM-dd HH:mm:ss
spring.mvc.format.time=HH:mm:ss

✅ 你也可以使用 iso 关键字来启用 ISO 8601 格式:

spring.mvc.format.date-time=iso

等价于:

spring.mvc.format.date-time=yyyy-MM-dd HH:mm:ss

⚠️ 注意:这种方式简单直接,适合格式统一、配置简单的项目。

6. 总结

在这篇文章中,我们学习了在 Spring MVC 中处理日期参数的几种方式:

  • 使用 @DateTimeFormat 在接口级别指定格式
  • 通过配置类全局注册日期格式化器
  • 利用 application.properties 配置全局格式

每种方式都有其适用场景,合理选择能让你的代码更清晰、更易维护。

📄 所有示例代码均可在 GitHub 上找到。


原始标题:Working with Date Parameters in Spring