SpringBoot接口@RequestParam接收日期报String转Date失败问题
发起GET请求访问接口地址 http://www.localhost:8080/api/employee/search?startDate=2000-10-22&salary=10000 时,系统抛出类型转换异常,核心错误信息如下:
Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam java.util.Date] for value '2000-10-22'; nested exception is java.lang.IllegalArgumentException
本次请求传入参数:startDate = 2000-10-22,salary = 10000。
- GET请求的查询参数默认都是字符串类型,SpringMVC处理
@RequestParam标注的参数时,需要通过内置的类型转换器把字符串转为接口声明的目标参数类型,本次报错的核心是字符串转java.util.Date环节失败。 - 实体类
startDate字段上添加的@JsonFormat(pattern="yyyy-MM-dd")注解,仅对请求体/响应体的JSON序列化、反序列化流程生效,对@RequestParam接收的查询参数转换流程无效。 - SpringMVC默认没有内置匹配
yyyy-MM-dd格式的字符串转Date转换器,默认转换规则和传入的日期字符串格式不匹配,因此抛出转换失败异常。
以下三种方案任选其一即可:
方案1:单接口参数加格式注解(改动最小)
在Controller层接口的startDate参数上添加@DateTimeFormat注解,明确指定接收的日期格式:
@GetMapping(path="/search") public ResponseEntity<List<Employee>> searchEmployees( @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, @RequestParam("salary") Integer salary){ return ResponseEntity.ok(employeeService.searchEmployees(startDate,salary)); }
方案2:全局配置日期转换器(一劳永逸)
新增MVC配置类,注册全局字符串转Date的转换器,所有接口的@RequestParam、@PathVariable等非JSON传参的Date类型都会统一使用该转换规则,无需单独加注解:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new Converter<String, Date>() { @Override public Date convert(String source) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { return sdf.parse(source); } catch (ParseException e) { throw new IllegalArgumentException("日期格式非法,需符合yyyy-MM-dd规范"); } } }); } }
方案3:SpringBoot配置文件统一指定
如果是SpringBoot项目,直接在配置文件中添加全局日期格式配置即可,无需写代码:
- yaml格式配置(application.yml):
spring: mvc: format: date: yyyy-MM-dd
- properties格式配置(application.properties):
spring.mvc.format.date=yyyy-MM-dd
注意:
@JsonFormat和@DateTimeFormat作用场景完全不同,前者负责JSON序列化/反序列化,后者负责非JSON传参(查询参数、表单参数、路径参数)的类型转换,不要混淆使用。
内容的提问来源于stack exchange,提问作者RohanRider

