温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Springcloud feign传日期类型参数报错怎么办

发布时间:2022-03-15 09:13:28 来源:亿速云 阅读:648 作者:小新 栏目:开发技术

这篇文章给大家分享的是有关Springcloud feign传日期类型参数报错怎么办的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

feign传日期类型参数报错

Date类型参数报错

在Spring cloud feign接口中传递Date类型参数时报错,报错信息。

场景:

客户端传递一个new Date()的参数,服务端接受的参数和客户端有时间差。

客户端打印格式化的new Date():

2018-05-11 10:23:36

而服务端接收到的参数是:

2018-05-12 00:23:36

我们从Feign启动的源码可以看出,Feign在encode和decode时会用SpringEncoder类来实现:

    @Bean     @ConditionalOnMissingBean     public Decoder feignDecoder() {         return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));     }       @Bean     @ConditionalOnMissingBean     public Encoder feignEncoder() {         return new SpringEncoder(this.messageConverters);     }

而SpringEncoder的HttpMessageConverters使用的是Jackson默认模板,该模板来自基类WebMvcConfigurationSupport.java:

Springcloud feign传日期类型参数报错怎么办

    protected final List<HttpMessageConverter<?>> getMessageConverters() {         if (this.messageConverters == null) {             this.messageConverters = new ArrayList<HttpMessageConverter<?>>();             configureMessageConverters(this.messageConverters);             if (this.messageConverters.isEmpty()) {                 addDefaultHttpMessageConverters(this.messageConverters);             }             extendMessageConverters(this.messageConverters);         }         return this.messageConverters;     }

而WebMvcConfigurationSupport.java最终使用的是默认的ObjectMapper生成的MappingJackson2HttpMessageConverter。

至此可以看出该问题的产生并不是Feign的问题,而是Feign实现中使用的Spring MVC中的Jackson转换参数问题,默认的TimeZone并不是东八区,而是UTC。

    /**      * Override the default {@link TimeZone} to use for formatting.      * Default value used is UTC (NOT local timezone).      * @since 4.1.5      */     public Jackson2ObjectMapperBuilder timeZone(TimeZone timeZone) {         this.timeZone = timeZone;         return this;     }

这个问题,在Spring MVC中可以在接口或者字段上添加注解来解决,但在Feign中使用GET请求的接口添加注解是不行的。debug发现,Spring MVC在处理Date的时候,调用了sun.reflect.ConstructorAccessor#newInstance(Object[] var1),时间会加14个小时。具体实现没看到源码,后续再研究。需要说明的是,加JsonFormat注解对于Feign接口没生效,但Spring MVC是可以的。

OK,回到正题。要解决这个问题,最好的办法是自定义ObjectMapper。即使是加了注解可以解决问题,也依然推荐使用自定义ObjectMapper,因为大量的接口每个都添加注解太繁琐了。

    @Bean     @Primary     public ObjectMapper objectMapper() {         return Jackson2ObjectMapperBuilder.json()                 .serializationInclusion(JsonInclude.Include.NON_NULL)                 .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)                 .timeZone(TimeZone.getTimeZone("Asia/Shanghai"))                 .build();     }

这样注解进去的ObjectMapper就带了时区。

LocalDate类型报错

报错详情:

Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of java.time.LocalDate: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDate: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: java.io.PushbackInputStream@3ce2b1e2; line: 1, column: 44] (through reference chain: com.chunrun.user.param.UserParams["localDate"])

这是因为LocalDate没有提供默认的构造器,而Jackson还不支持Java8的特征。这时候只需要加上依赖,ObjectMapper加一行代码即可:

    <dependency>       <groupId>com.fasterxml.jackson.datatype</groupId>       <artifactId>jackson-datatype-jsr310</artifactId>       <version>2.4.0</version>     </dependency>
    @Bean     @Primary     public ObjectMapper objectMapper() {         return Jackson2ObjectMapperBuilder.json()                 .serializationInclusion(JsonInclude.Include.NON_NULL)                 .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)                 .timeZone(TimeZone.getTimeZone("Asia/Shanghai"))                 .modules(new JSR310Module())                 .build();     }

以上配置调用方也需要。

feign传参问题及传输Date类型参数时差的坑

feign的调用如下:

List<LeftSeatCountOfDaysResp> getLeftSeatCountOfDays(             @RequestParam("configType") Integer configType,             @RequestParam("courseId") Long courseId,             @RequestParam("startDateFrom") Date startDateFrom,             @RequestParam("startDateTo") Date startDateTo,             @RequestParam("level") Integer level);

我们采用了两个date类型的参数传参,结果:

我们传入的时间为:

Springcloud feign传日期类型参数报错怎么办

但服务端接受到的时间为:

Springcloud feign传日期类型参数报错怎么办

天啊撸,竟然出现了我们并不熟悉的14h时差,并不是我们熟悉的8个小时。feign真是天坑啊。这是SpringCloud Feign传Date类型参数的时差导致的。

备注:使用date类型传参,如果是body里面用对象传,是不会出现时差问题的。

下面说说两种解决方案

  • 当发送时间类型时,直接用String发送(推荐)

  • Feign客户端实现FeignFormatterRegistrar接口自定义DateFormatRegister

@Component     public class DateFormatRegister implements FeignFormatterRegistrar{         public DateFormatRegister(){         }         @Override         public void registerFormatters(FormatterRegistry registry) {         registry.addConverter(Date.class, String.class, new Date2StringConverter());          }         private class Date2StringConverter implements Converter<Date,String>{             @Override             public String convert(Date source) {             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");             return sdf.format(source);             }         }     }

服务端实现:

@Configuration     public class WebConfigBeans {         @Autowired         private RequestMappingHandlerAdapter handlerAdapter;         /**         * 增加字符串转日期的功能         */         @PostConstruct         public void initEditableValidation() {             ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) handlerAdapter                         .getWebBindingInitializer();             if (initializer.getConversionService() != null) {                 GenericConversionService genericConversionService = (GenericConversionService) initializer                             .getConversionService();                 genericConversionService.addConverter(String.class, Date.class, new String2DateConverter());             }         }     }

第二种比较麻烦,但是一劳永逸,代码的优雅性比第一种好。但个人而言,还是推荐使用第一种。

feign传参时候使用@DateTimeFormat注解的坑

@NotNull     @MyFuture     @DateTimeFormat(pattern = "yyyy-MM-dd")     private Date appointDate; //预定的预成班日期

比如这个字段,服务端上面用了@DateTimeFormat注解,这样的话,springMVC手机支持直接传字符串2018-03-03自动转换的。但是,但是,如果你是用client调用,那就不报错啦,报错啦。所以使用的时候,一定要注意啊,一定要注意啊。

感谢各位的阅读!关于“Springcloud feign传日期类型参数报错怎么办”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI