Spring有一个包org.springframework.web.client.RestTemplate
,它可以协助开发者更加方便简单的发起HTTP
请求并将结果转化为指定的类型。
Spring体系中存在不少
XXXTemplate,
基本都是简化对XXX
的操作。内部实现基本也都是模板方法,帮你分装和实现一部分通用代码,这不是本文重点,后续探讨。
RestTemplate
提供了几类核心方法:
通用
方法:exchange()
单独
方法:xxxForEntity
和xxxForObject
,其中xxx表示GET等方法中的一种,比如getForEntity
、postForEntity
本文的重点是讲解的是一种:exchange()
,其他东西暂不讨论。
项目服务端返回的是一个 Result<T>
对象,其中T可能是简单类型:Boolean,也可能是一个泛型嵌套的负载对象例如:Rest<Map<String,Set<Person>>>
。
最开始图省事,使用的是postForEntity
,打算如下写代码:
ResponseEntity<Result<Map<String,Set<Person>>> result = template.postForEntity("url", null, Result<Map<String,Set<Person>>>.class);
但是很遗憾,IDE提示不支持内部的泛型,只能写成如下形式:
ResponseEntity<Result> result = template.postForEntity("url", null, Result.class);
对于该请求返回值只能精确到 Result
,无法更加精确的匹配到Result
的泛型T: Map<String,Set<Person>>
代码本身是没有办法精确解析的,只能按照既定的规范解析,比如Set它自身默认会给你解析为
Collection
或者List
很遗憾这样解决不了我的问题。
结合自身经验再查阅资料和研读API发现一个很有特点的方法:
<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables)
throws RestClientException;
其特点在于有一个形参的类型是:ParameterizedTypeReference<T>
如果你对Jackson有过了解,你可能会猜出这个类正是处理复杂对象的关键点。
关于Jackson处理复杂对象,你可以参考的我的另外一篇文章!
将复杂的泛型嵌套利用ParameterizedTypeReference
来进行描述,然后调用上述的API即可。
在该类的API说明上给出了基本的使用描述:
ParameterizedTypeReference<List<String>> typeRef = new ParameterizedTypeReference<List<String>>() {};
所以你可以依样画瓢来构造一个你所需Result<Map<String, Set<ServiceItem>>>
类型的ParameterizedTypeReference
,代码如下所示:
ParameterizedTypeReference<Result<Map<String, Set<ServiceItem>>>> typeRef =
new ParameterizedTypeReference<Result<Map<String, Set<ServiceItem>>>>() {};
接下来就简单了:
ResponseEntity<Result<Map<String, Set<ServiceItem>>>> entity =
restTemplate.exchange(desUri, HttpMethod.GET, null, typeRef);