情景复现
- 当用Feign调用另外一个服务的
GET
方法,入参POJO对象有数据类型为LocalDateTime的属性时;
1 | java复制代码 // 服务调用方入参 OrderReq 类中有一个属性为 LocalDateTime |
url 经过解码之后,会莫名其妙的转成默认的ISO-8601
的日期格式即中间多了个T
/find-all?startTime=2020-05-23T23:23:23
这是我的全局配置
1 | java复制代码 @Bean |
当时尝试了很多办法,被调用方还是接不到数据类型为LocalDateTime的属性。
解决办法
经过和同事的讨论以及同事 debugger feign 对GET
方法的实现。解决方案如下:
- 方法一:把 GET 方法变成 POST ,这是最简单的。(手动狗头)
- 方法二:加上 @org.springframework.format.annotation.DateTimeFormat 注解
1 | java复制代码// 方法一:把 GET 方法变成 POST ,这是最简单的。(手动狗头) |
解析
知识点:spring 框架提供的org.springframework.format.annotation.DateTimeFormat
和 jackson 提供的com.fasterxml.jackson.annotation.JsonFormat
。
feign 对 GET 方法的处理
feign.Feign
中的静态内部类Builder
中的 queryMapEncoder 属性。FieldQueryMapEncoder
实现了QueryMapEncoder
接口并实现了Map<String, Object> encode(Object object)
方法。这个方法的作用是把GET
方法的入参变成Map<String, Object>
格式。这个方法仅在BuildTemplateByResolvingArgs#toQueryMap
方法中被引用。
1 | java复制代码private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder(); |
重点是BuildTemplateByResolvingArgs#addQueryMapQueryParameters
的这个方法。从这个方法中可以看到Map<String, Object>
被遍历解析并判断数据类型currValue instanceof Iterable<?>
是不是可迭代的。最终所有的参数都是通过currValue.toString()
方法被解析的。这也就是为什么LocalDateTime
数据类型的属性被解析成url
字符串中间带了一个T
。所以最终的解决办法也就是加上注解@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
。
整个的调用流程是:其实都是在
create
方法中完成的。
- BuildTemplateByResolvingArgs#create(Object[] argv)
- BuildTemplateByResolvingArgs#toQueryMap(Object value)
- BuildTemplateByResolvingArgs#addQueryMapQueryParameters(Map<String, Object> queryMap, RequestTemplate mutable)
1 | java复制代码@SuppressWarnings("unchecked") |
POST 方法
用jackson
序列化,post请求包括都是经过序列化器序列化。我的项目用了全局序列化器,也可以自定义序列化器。
@ResponseBody 响应
用jackson
序列化,post请求包括都是经过序列化器序列化。我的项目用了全局序列化器,也可以自定义序列化器。
本文转载自: 掘金