Spring Boot 2.0.1中WebTestClient绑定导致LocalDate格式不一致的解决方法
嘿,这个问题我之前踩过坑!咱们来捋清楚怎么回事,以及怎么解决:
首先明确问题:用WebTestClient.bindToServer()测试时,LocalDate能正常返回2018-04-13这种字符串格式,但直接用bindToController()绑定控制器测试时,返回的却是LocalDate的对象结构(比如包含year、month、dayOfMonth这些字段),完全不是预期的格式。
问题根源
这是因为bindToController()是直接调用控制器的方法,没有经过完整的Spring MVC消息转换流程——也就是说,我们配置的Jackson日期序列化规则没生效。而bindToServer()是模拟真实HTTP请求,走了完整的Spring MVC处理链路,自然会应用我们配置的序列化规则。
解决方案
这里给你两种可行的方案,按需选择:
方案一:手动给WebTestClient配置消息转换器
如果想保持bindToController()的轻量性,我们可以手动把应用里配置好的ObjectMapper注入到WebTestClient的消息转换器中,让它使用和业务代码一致的序列化规则。
首先,先确保你的项目里有Jackson的JavaTime模块配置(用来处理Java 8日期类型),比如:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); // 注册Java 8时间模块 JavaTimeModule timeModule = new JavaTimeModule(); // 给LocalDate指定序列化格式 timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE)); mapper.registerModule(timeModule); return mapper; } }
然后在测试类里,注入这个ObjectMapper,并配置WebTestClient的消息转换器:
@ExtendWith(SpringExtension.class) // 加载控制器和Jackson配置类 @ContextConfiguration(classes = {TodayController.class, JacksonConfig.class}) public class TodayControllerTest { @Autowired private TodayController todayController; @Autowired private ObjectMapper objectMapper; private WebTestClient webTestClient; @BeforeEach void setUp() { webTestClient = WebTestClient.bindToController(todayController) .configureClient() .messageConverters(converters -> { // 创建Jackson消息转换器并设置我们的ObjectMapper MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(); jacksonConverter.setObjectMapper(objectMapper); converters.add(jacksonConverter); }) .build(); } @Test void testFetchToday() { String expectedDate = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE); webTestClient.get().uri("/today") .exchange() .expectStatus().isOk() .expectBody() .jsonPath("$.today").isEqualTo(expectedDate); } }
方案二:用@SpringBootTest加载完整上下文
如果你的测试需要更贴近真实运行环境,直接用@SpringBootTest来启动完整的Spring上下文,这样WebTestClient会自动应用所有Spring Boot的自动配置(包括Jackson的日期格式配置),不用手动处理消息转换器。
示例代码:
@ExtendWith(SpringExtension.class) // 启动完整Spring Boot上下文,随机端口启动 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class TodayControllerTest { @Autowired private WebTestClient webTestClient; @Test void testFetchToday() { String expectedDate = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE); webTestClient.get().uri("/today") .exchange() .expectStatus().isOk() .expectBody() .jsonPath("$.today").isEqualTo(expectedDate); } }
补充说明
如果你习惯用配置文件来设置日期格式(比如application.properties):
spring.jackson.date-format=yyyy-MM-dd spring.jackson.serialization.write-dates-as-timestamps=false
这个配置在bindToController()模式下不会自动生效,因为这种模式不会加载Spring Boot的自动配置类,所以还是需要用方案一的方式手动注入ObjectMapper才行。
内容的提问来源于stack exchange,提问作者BewdyM8

