iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Springcloud feign传日期类型参数报错怎么办
  • 285
分享到

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

2023-06-29 12:06:24 285人浏览 安东尼
摘要

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

这篇文章给大家分享的是有关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。

        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传日期类型参数报错怎么办”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

--结束END--

本文标题: Springcloud feign传日期类型参数报错怎么办

本文链接: https://www.lsjlt.com/news/324748.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MySQL怎么更新字段长度
    要更新MySQL表中的字段长度,可以使用ALTER TABLE语句。以下是更新字段长度的示例: ALTER TABLE table_...
    99+
    2024-05-14
    mysql
  • sql如何修改表字段长度
    要修改表字段的长度,可以使用ALTER TABLE语句,然后使用MODIFY COLUMN来修改字段的长度。以下是一个示例: ALT...
    99+
    2024-05-14
    sql
  • mysql数据量太大如何解决
    有几种方法可以解决MySQL数据量过大的问题: 数据库分区:将数据库表按照某种规则进行分区,分成多个小表,可以提高查询速度和管理...
    99+
    2024-05-14
    mysql
  • MySQL单表数据量过大如何解决
    在MySQL中,当单表的数据量过大时,可以采取以下几种方法来解决问题: 使用索引:在表的字段上创建适当的索引,可以提高查询效率,...
    99+
    2024-05-14
    mysql
  • mysql导出数据量过大如何解决
    当导出的数据量过大时,可以尝试以下方法来解决问题: 使用数据库工具:使用数据库管理工具如Navicat或MySQL Workbe...
    99+
    2024-05-14
    mysql
  • mysql中log_bin的作用是什么
    在MySQL中,log_bin是二进制日志文件的名称,用于记录所有对数据库进行更改的操作,如插入、更新、删除等。这些二进制日志文件可...
    99+
    2024-05-14
    mysql
  • mysql中log_bin的特点有哪些
    log_bin是MySQL的二进制日志文件,用于记录所有对数据库的修改操作,包括插入、更新、删除等。 log_bin文件是M...
    99+
    2024-05-14
    mysql
  • mysql rpm包安装的方法是什么
    要在Linux系统上安装MySQL RPM包,可以按照以下步骤操作: 下载MySQL的RPM包:你可以从MySQL官方网站下载适...
    99+
    2024-05-14
    mysql
  • mysql rpm包安装后怎么使用
    安装MySQL RPM包后,您可以通过以下步骤来使用MySQL: 启动MySQL服务:使用以下命令来启动MySQL服务: sud...
    99+
    2024-05-14
    mysql
  • lxml中怎么处理XML命名空间默认值
    在lxml中处理XML命名空间的默认值可以通过使用xpath()方法和register_namespace()方法来实现。...
    99+
    2024-05-14
    lxml
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作