Spring Boot微服务中TestRestTemplate测试参数'+'及日期接口问题
Hey there, let's break down and solve these two closely related issues for your Spring Boot 2.0.1 service:
The root problem here is that URL encoding rules treat the '+' character as a space. When you pass a parameter like an ISO 8601 datetime (e.g., 2024-05-20T14:30:00+08:00) directly via TestRestTemplate's standard methods, the framework automatically encodes the '+' as a space. This leads your backend to receive a malformed datetime string that fails parsing.
Here are two reliable fixes:
Option 1: Use UriComponentsBuilder (Recommended)
This class handles URL encoding correctly, ensuring special characters like '+' are converted to their proper URL-safe representation (%2B) which the backend will automatically decode back to '+'.
// Sample test code ZonedDateTime testFromDate = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); ZonedDateTime testToDate = testFromDate.plusDays(2); // Build the encoded URI UriComponents uri = UriComponentsBuilder.fromPath("/range") .queryParam("fromDate", testFromDate.format(DateTimeFormatter.ISO_DATE_TIME)) .queryParam("toDate", testToDate.format(DateTimeFormatter.ISO_DATE_TIME)) .build(true); // `true` enables proper encoding of all special characters // Execute the request ResponseEntity<MyDTO> response = testRestTemplate.getForEntity(uri.toUri(), MyDTO.class);
Option 2: Manually encode parameters with URLEncoder
If you prefer using TestRestTemplate's parameterized URL syntax, explicitly encode your datetime strings first:
ZonedDateTime testFromDate = ZonedDateTime.now(ZoneId.of("UTC")); ZonedDateTime testToDate = testFromDate.plusHours(4); // Encode the datetime strings to preserve '+' String encodedFromDate = URLEncoder.encode( testFromDate.format(DateTimeFormatter.ISO_DATE_TIME), StandardCharsets.UTF_8 ); String encodedToDate = URLEncoder.encode( testToDate.format(DateTimeFormatter.ISO_DATE_TIME), StandardCharsets.UTF_8 ); // Pass encoded parameters as placeholders ResponseEntity<MyDTO> response = testRestTemplate.getForEntity( "/range?fromDate={fromDate}&toDate={toDate}", MyDTO.class, encodedFromDate, encodedToDate );
Your existing controller code is actually correct—@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) is designed to parse ZonedDateTime strings with timezone offsets (including those with '+'). The parsing failures you're seeing are almost certainly a side effect of the TestRestTemplate encoding issue above.
That said, here are a couple of small tweaks to make your setup more robust:
Explicitly define the datetime pattern (optional but clear)
If you want to remove any ambiguity about the expected format, you can replace the ISO annotation with an explicit pattern that matches the timezone offset format:@GetMapping("/range") public ResponseEntity<MyDTO> getDateRange( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX") ZonedDateTime fromDate, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX") ZonedDateTime toDate ) { // Your existing logic here }The
XXXpattern correctly handles timezone offsets like+08:00.Verify default decoding behavior
Spring Boot 2.0.1 automatically decodes request parameters by default, so as long as the incoming request sends%2Binstead of a raw '+', the controller will receive the correct literal '+'. Avoid overriding this default behavior in any customWebMvcConfigurerbeans unless you know exactly what you're doing.
内容的提问来源于stack exchange,提问作者dajoni

