驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
利用RestTemplate.exchange()请求复杂对象
/    

利用RestTemplate.exchange()请求复杂对象

开篇

Spring有一个包org.springframework.web.client.RestTemplate,它可以协助开发者更加方便简单的发起HTTP请求并将结果转化为指定的类型。

Spring体系中存在不少 XXXTemplate,基本都是简化对XXX的操作。内部实现基本也都是模板方法,帮你分装和实现一部分通用代码,这不是本文重点,后续探讨。

RestTemplate提供了几类核心方法:

  • 对GET/POST/DELETE/UPDATE都可以作用的通用方法:exchange()
  • 对GET/POST/DELETE/UPDATE都可以作用的单独方法:xxxForEntityxxxForObject,其中xxx表示GET等方法中的一种,比如getForEntitypostForEntity

本文的重点是讲解的是一种: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处理复杂对象,你可以参考的我的另外一篇文章!

通过exchange() 处理复杂泛型对象

将复杂的泛型嵌套利用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);
骐骥一跃,不能十步。驽马十驾,功在不舍。