Springcloud feign传日期类型参数报错的解决方案

  • Post category:http

这里给出详细讲解“Springcloud feign传日期类型参数报错的解决方案”的完整攻略。

问题描述

在使用SpringCloud Feign进行服务调用时,当接口中含有日期类型参数时,调用服务时会报错,如下:

 Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.time.LocalDate: parameterless constructor not available.
 at [Source: (PushbackInputStream); line: 1, column: 380] (through reference chain: com.xxx.XXXVO["date"])

原因分析

出现这个问题的原因是因为Feign默认使用的是Spring MVC的HttpMessageConverters进行数据转换,Spring MVC的默认数据转换器无法对日期类型参数进行正确的反序列化。

解决方案

第一种解决方案

在Feign的配置文件中配置使用Jackson序列化和反序列化器,如下:

feign:
  client:
    config:
      default:
        encoder: feign.jackson.JacksonEncoder
        decoder: feign.jackson.JacksonDecoder

将Feign默认的httpMessageConverters替换成Jackson序列化和反序列化器,这样就能够对日期类型的参数进行正确的序列化和反序列化了。通过此方式解决后接口调用的参数可以使用LocalDateTime、LocalDate或者ZonedDateTime。

第二种解决方案

在DTO类上使用@JsonFormat注解指定日期格式,如下:

public class XXXDTO {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
    // ...
}

在我们定义接口DTO的日期类型参数时,使用@JsonFormat注解来指定日期格式,这样就可以完成对日期类型的参数的序列化和反序列化了。通过此方式解决后接口调用的参数只能使用字符串类型。

示例说明

接下来通过两个示例来展示如何使用上述方法解决问题:

第一个示例:

我们定义一个接口,其中包含一个日期类型的参数,如下:

public interface XxxxService {

    @GetMapping("/test")
    public String test(@RequestParam LocalDate date);

}

使用Feign进行服务调用,测试接口是否可用:

@RestController
public class TestController {

    @Autowired
    private XxxxService xxxxService;

    @GetMapping("/test")
    public String test() {
        String res = xxxxService.test(LocalDate.now());
        return "res: " + res;
    }

}

此时调用接口会抛出异常:com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.time.LocalDate

采用第一种解决方案,增加配置文件:

feign:
  client:
    config:
      default:
        encoder: feign.jackson.JacksonEncoder
        decoder: feign.jackson.JacksonDecoder

重新启动服务,再次调用接口,可以正常返回。

第二个示例:

我们定义一个DTO,其中包含一个日期类型的参数,如下:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxxxDTO {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
}

我们使用DTO来作为接口的参数,如下:

public interface XxxxService {

    @PostMapping("/test")
    public String test(@RequestBody XxxxDTO dto);

}

使用Feign进行服务调用,测试接口是否可用:

@RestController
public class TestController {

    @Autowired
    private XxxxService xxxxService;

    @GetMapping("/test")
    public String test() {
        XxxxDTO dto = new XxxxDTO(LocalDate.now());
        String res = xxxxService.test(dto);
        return "res: " + res;
    }

}

此时调用接口仍然会抛出异常:com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.time.LocalDate

采用第二种解决方案,为DTO类中的date属性添加@JsonFormat注解:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class XxxxDTO {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
}

重新启动服务,再次调用接口,可以正常返回。

以上就是Springcloud feign传日期类型参数报错的解决方案的完整攻略,包含了两个示例说明。