Feign 日期格式转换错误的问题

  • Post category:http

Feign是一种轻量级的声明式HTTP客户端,可以用于方便的进行RESTful API调用。但是在使用过程中,可能会遇到日期格式转换错误的问题,本文将详细讲解如何解决这个问题。

问题描述

在使用Feign调用API过程中,当传递的参数或返回的结果中包含日期类型时,Feign默认会使用ISO8601格式进行转换。但是,在不同的服务中,日期的格式可能会不一致,例如有些服务采用的是”yyyy-MM-dd”格式,而有些服务采用的是”yyyy/MM/dd”格式,这就会导致Feign无法正确转换日期格式而报错。

解决方法

方法一:使用自定义日期格式转换器

Feign提供了自定义日期格式转换器的功能,可以通过该功能来指定日期的格式,从而解决日期转换错误的问题。下面是一个示例:

首先定义一个自定义日期格式转换器:

public class DateFormatter implements Encoder, Decoder {

    private final DateTimeFormatter dateFormatter;

    public DateFormatter(String dateFormatPattern) {
        this.dateFormatter = DateTimeFormatter.ofPattern(dateFormatPattern);
    }

    @Override
    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
        if (object instanceof LocalDate) {
            LocalDate date = (LocalDate) object;
            String formattedDate = dateFormatter.format(date);
            template.body(formattedDate, StandardCharsets.UTF_8);
        }
    }

    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        if (type instanceof Class && ((Class<?>) type).isAssignableFrom(LocalDate.class)) {
            String dateString = Util.toString(response.body().asReader(StandardCharsets.UTF_8));
            return LocalDate.parse(dateString, dateFormatter);
        }
        return null;
    }

    @Override
    public Object decode(Response response, Type type, ExceptionMapper exceptionMapper) throws IOException, DecodeException, FeignException {
        return decode(response, type);
    }
}

然后在Feign客户端上面配置该自定义日期格式转换器:

@FeignClient(name = "example", configuration = ExampleClientConfig.class)
public interface ExampleClient {
    @GetMapping("/api/example")
    ExampleResponse getExampleData(@RequestParam("date") LocalDate date);
}

@Configuration
public class ExampleClientConfig {
    @Bean
    public Encoder feignEncoder() {
        return new DateFormatter("yyyy-MM-dd");
    }

    @Bean
    public Decoder feignDecoder() {
        return new DateFormatter("yyyy-MM-dd");
    }
}

上述代码中,我们定义了一个自定义Feign日期格式转换器DateFormatter,并在Feign客户端上面使用@FeignClient注解指定了ExampleClientConfig配置类,该配置类中配置了使用DateFormatter实例做为编码器和解码器,将”yyyy-MM-dd”格式的日期转换为LocalDate类型。

方法二:使用JsonFormat注解

如果在服务端返回JSON数据时,可以使用JsonFormat注解来将日期格式转换成指定的格式。例如:

@Data
public class ExampleResponse {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
    private String name;
    private int age;
}

上述代码中,我们在ExampleResponse类上使用了@JsonFormat注解来指定date字段的日期格式为”yyyy-MM-dd”。

示例说明

下面是一个使用Feign调用”yyyy-MM-dd”格式日期的API:

@FeignClient(name = "example", configuration = ExampleClientConfig.class)
public interface ExampleClient {
    @GetMapping("/api/example")
    ExampleResponse getExampleData(@RequestParam("date") LocalDate date);
}

@Data
public class ExampleResponse {
    private LocalDate date;
    private String name;
    private int age;
}

@RequestMapping("/api/example")
@RestController
public class ExampleController {
    @GetMapping
    public ExampleResponse getExampleData(@RequestParam("date") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) {
        ExampleResponse response = new ExampleResponse();
        response.setDate(date);
        response.setName("John Doe");
        response.setAge(18);
        return response;
    }
}

上述代码中,我们在ExampleController类上使用了@DateTimeFormat注解来指定date字段的日期格式为”yyyy-MM-dd”。在ExampleClient客户端接口中也使用了LocalDate类型的参数来调用”/api/example“接口,使用该方式,可以避免Feign的日期转换错误问题。

下面是一个使用JsonFormat注解进行日期格式转换的示例:

@Data
public class ExampleResponse {
    @JsonFormat(pattern = "yyyy-MM-dd")
    private LocalDate date;
    private String name;
    private int age;
}

@RequestMapping("/api/example")
@RestController
public class ExampleController {
    @GetMapping
    public ExampleResponse getExampleData() {
        ExampleResponse response = new ExampleResponse();
        response.setDate(LocalDate.of(2022, 6, 30));
        response.setName("John Doe");
        response.setAge(18);
        return response;
    }
}

上述代码中,我们在ExampleResponse类上使用了@JsonFormat注解来指定date字段的日期格式为”yyyy-MM-dd”。在ExampleController类中,我们返回一个ExampleResponse对象,其date字段使用了LocalDate.of(2022, 6, 30)方法指定日期值,在返回对象时,date会被转换成”yyyy-MM-dd”格式的字符串。