Spring boot GET преобразование типов данных не работает
Я получаю следующее исключение при попытке использовать загрузку Spring. Не удалось преобразовать параметр запроса. Что мне здесь не хватает? Как настроить конвертер типа данных запроса при загрузке Spring?
2018-02-23 17:05:11.868 WARN 13976 --- [nio-9988-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to bind request element: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.annotations.ApiParam @org.springframework.web.bind.annotation.RequestParam java.time.LocalDate] for value '2017-07-21'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2017-07-21]
2018-02-23 17:18:29.582 WARN 13976 --- [nio-9988-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to bind request element: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.OffsetDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@io.swagger.annotations.ApiParam @org.springframework.web.bind.annotation.RequestParam java.time.OffsetDateTime] for value '2017-07-21T17:32:28Z'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2017-07-21T17:32:28Z]
Мой метод контроллера выглядит следующим образом.
@RequestMapping(value = "/mypath/status",
produces = { "application/json" },
method = RequestMethod.GET)
default ResponseEntity<MyStatusResponse> _getMyStatusByQuery(@RequestHeader(value="myId", required=true) Integer myId,
@Valid @RequestParam(value = "param1", required = false) String param1,
@Valid @RequestParam(value = "param2", required = false) String param2,
@Valid @RequestParam(value = "dueDateStart", required = false) LocalDate dueDateStart,
@Valid @RequestParam(value = "dueDateEnd", required = false) LocalDate dueDateEnd,
@Valid @RequestParam(value = "sentOnEnd", required = false) OffsetDateTime sentOnEnd) {
return getMyStatusByQuery(myId, param1, param2, dueDateStart, dueDateEnd, sentOnStart, sentOnEnd);
}
Я также добавил конвертер для OffsetDateTime (в основном это генерируется swagger)
public class RFC3339DateFormat extends ISO8601DateFormat {
// Same as ISO8601DateFormat but serializing milliseconds.
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
String value = ISO8601Utils.format(date, true);
toAppendTo.append(value);
return toAppendTo;
}
}
application.properties
spring.jackson.date-format=my.test.RFC3339DateFormat
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
Ниже мой pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.jigarshah.api</groupId>
<artifactId>test-me</artifactId>
<packaging>jar</packaging>
<name>test-me</name>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<springfox-version>2.8.0</springfox-version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
</build>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!--SpringFox dependencies -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${springfox-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${springfox-version}</version>
</dependency>
<!-- XML processing: Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- Bean Validation API support -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
2 ответа
https://blog.codecentric.de/en/2017/08/parsing-of-localdate-query-parameters-in-spring-boot/
Это было правильное решение. Spring Boot 2 может иметь лучшее решение для этого.
https://github.com/spring-projects/spring-boot/commit/2fa0539e7f7bf93505f67303955cc7da6f9f5846
Вы можете достичь этого, создав классы, реализующие JsonDeserializer, а затем добавьте их в ObjectMapper Джексона.
Пример класса конфигурации для этого:
@Configuration
public class JacksonConfiguration {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(LocalDate.class, new JsonDateDeserializer());
simpleModule.addDeserializer(OffsetDateTime.class, new JsonDateTimeDeserializer());
objectMapper.registerModule(simpleModule);
return objectMapper;
}
}
Где JsonDateDeserializer и JsonDateTimeDeserializer - это ваши классы с вашей реализацией преобразования с правильными форматами шаблонов.