情景复现
- 当用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请求包括都是经过序列化器序列化。我的项目用了全局序列化器,也可以自定义序列化器。
本文转载自: 掘金