springcloud feign服务之间调用,date类型转换错误的问题

  • Post category:http

下面是详细讲解“Spring Cloud Feign服务之间调用Date类型转换错误的问题”的完整攻略:

问题描述

在使用Spring Cloud Feign进行服务之间的调用时,如果传递了Date类型参数,容易出现类型转换错误的问题。具体表现为:

java.lang.IllegalArgumentException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date': no matching editors or conversion strategy found

这是由于在进行参数传递的过程中,Feign不知道如何把Date类型的参数进行序列化和反序列化。

解决方案

解决这个问题需要进行如下几步操作:

  1. 添加Date类型参数的序列化和反序列化支持;

  2. 在Feign客户端和服务端之间添加Date类型参数的转换器。

下面分别进行详细讲解。

添加Date类型参数的序列化和反序列化支持

在Feign中,默认支持的参数类型只有String、byte[]以及一些基本类型。如果希望支持其他类型,需要添加相应的转换器。

针对Date类型的参数,可以使用Jackson序列化和反序列化库进行支持。需要添加以下两个依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>

其中,spring-cloud-starter-openfeign是Feign的依赖库,jackson-datatype-jsr310是Jackson库中对于Java 8日期和时间API的支持。

接着,在启动类上添加注解@EnableFeignClients,使得Feign能够自动扫描所有的接口,并生成相应的代理对象。

@EnableFeignClients
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

在配置文件中添加以下配置:

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai

这些配置是为了使得序列化和反序列化使用的日期格式和时区与当前应用相同。

最后,定义一个公共的抽象类,用于在所有的Feign客户端中统一定义将Date转换为String的规则。

public abstract class DateConverter {

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * 将Date类型转换成String类型
     * @param value Date类型的值
     * @return 转换后的String类型值
     */
    public static String convert(Date value) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(value.toInstant(), ZoneId.systemDefault());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
        return localDateTime.format(formatter);
    }

}

在Feign客户端和服务端之间添加Date类型参数的转换器。

在Feign客户端和服务端之间,如果希望支持Date类型的参数转换,还需要添加一个转换器。这个转换器用于将Date类型的参数转换成String类型,以便在Feign客户端和服务端之间进行传递。

以下是Feign客户端和服务端中分别添加转换器的示例:

Feign客户端添加转换器

public interface UserApi {

    @RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
    User getUser(@PathVariable(value = "id") Long id, @RequestParam(value = "startTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date startTime);

    class UserApiClientFallback implements UserApi {

        @Override
        public User getUser(Long id, Date startTime) {
            return null;
        }

    }

    class UserApiFeignConfiguration {

        @Bean
        public Encoder feignEncoder() {
            return new Encoder.Default() {
                @Override
                public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
                    if (bodyType instanceof Class && Date.class.isAssignableFrom((Class<?>) bodyType)) {
                        Date date = (Date) object;
                        String encoded = DateConverter.convert(date);
                        template.body(encoded, Charset.defaultCharset());
                        return;
                    }
                    super.encode(object, bodyType, template);
                }
            };
        }

    }

}

以上代码中,UserApi是一个Feign客户端接口,其中的getUser方法中包含一个Date类型的参数。在UserApiClientFallback中,实现了UserApi接口中的所有方法,并提供了一个默认的空实现。

UserApiFeignConfiguration中,为Feign添加了一个转换器,用于将Date类型的参数转换成String类型。

服务端添加转换器

@RestController
@RequestMapping("users")
public class UserController {

    @GetMapping("/{id}")
    public User getUser(@PathVariable("id") Long id, @RequestParam("startTime") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") Date startTime) {
        User user = userService.getUser(id);
        user.setStartTime(startTime);
        return user;
    }

    @Configuration
    public static class MvcConfigurer implements WebMvcConfigurer {

        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new DateConverter());
        }

    }

    static class DateConverter implements Converter<String, Date> {

        private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

        /**
         * 将String类型转换成Date类型
         * @param source String类型的值
         * @return 转换后的Date类型值
         */
        @Override
        public Date convert(String source) {
            LocalDateTime localDateTime = LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DATE_FORMAT));
            return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        }

    }

}

以上代码中,UserController是一个标准的Spring MVC控制器,在其中定义了一个返回User对象的接口getUser,同时包含一个Date类型的参数。在这个接口中,添加了注解@DateTimeFormat,用于指定这个参数的日期格式。

MvcConfigurer中,添加了一个转换器,用于将String类型的参数转换成Date类型。

经过以上操作,Feign客户端和服务端就可以进行Date类型的参数转换了。

结语

以上就是“Spring Cloud Feign服务之间调用Date类型转换错误的问题”的完整攻略,包含了添加Date类型参数的序列化和反序列化支持,以及在Feign客户端和服务端之间添加Date类型参数的转换器等内容。如果您在使用Spring Cloud Feign进行服务之间的调用中,遇到了类似的问题,可以参考这个攻略进行解决。