0

尝试使用 Spring Boot 时出现以下异常。它无法转换请求参数。我在这里想念什么?如何在 Spring Boot 中自定义请求数据类型转换器?

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]

我的 Controller 方法如下所示。

@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;
  }

}

应用程序属性

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>
4

2 回答 2

0

您可以通过创建实现JsonDeserializer的类然后将它们添加到 Jackson 的 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 是您的类,您使用正确的模式格式实现转换。

于 2018-02-23T16:41:14.610 回答
0

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

于 2018-02-23T17:07:57.723 回答