Spring应用消费REST服务

  在微服务领域,使用Spring应用对另外一个应用的API发起请求的场景并不罕见。

  Spring应用可以采用多张方式来消费REST API,包括以下几种方式

⒈RestTemplate

  Spring核心框架提供的简单、同步REST客户端。

  为了避免单调的样板代码,Spring提供了RestTemplate。RestTemplate提供了41个与REST资源交互的方法,下表中提供了常见的12方法。

方法 描述
delete(...) 在特定的URL上对资源执行HTTP DELETE操作
exchange(...)

在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,

这个对象是从响应体中映射得到的

execute(...) 在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象
getForEntity(...)

发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所

映射成的对象。

getForObject(...) 发送一个HTTP GET请求,返回的请求体将映射为一个对象
headForHeaders(...) 发送HTTP  HEAD请求,返回包含特定资源URL的HTTP头信息
optionsForAllow(...) 发送HTTP OPTIONS请求,返回特定URL的Allow头信息
patchForObject(...) 发送HTTP PATCH请求,返回一个从响应体映射得到的对象
postForEntity(...)

POST数据到一个URL,返回包含一个对象的ResponseEntity,这个

对象是从响应体中映射得到的

postForLocation(...) POST数据到一个URL,返回新创建资源的URL
postForObject(...) POST数据到一个URL,返回根据响应体匹配形成的对象
put(...) PUT资源到特定的URL

  除了TRACE以外,RestTemplate对每种标准的HTTP方法都提供了至少一个方法。除此之外,execute()和exchange()提供了较低层次的通用方法,以便于进行任意的HTTP操作。

 1 @RestController
 2 @Log
 3 public class UserController {
 4 
 5     private RestTemplate restTemplate = new RestTemplate();
 6 
 7     // ----------------- getForObject -----------------------
 8     public User getUserById(String userId){
 9         return restTemplate.getForObject("http://localhost:8080/user/{id}",User.class,userId);
10     }
11 
12     public User getUserById2(String userId){
13         Map<String,String> urlVariables = new HashMap<>();
14         urlVariables.put("id",userId);
15         return restTemplate.getForObject("http://localhost:8080/user/{id}",User.class,urlVariables);
16     }
17 
18     //构建Url参数的方式
19     public User getUserById3(String userId){
20         Map<String,String> urlVariables = new HashMap<>();
21         urlVariables.put("id",userId);
22         URI url = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/user/{id}").build(urlVariables);
23         return restTemplate.getForObject(url, User.class);
24     }
25 
26     // ----------------- getForEntity -----------------------
27     // getForEntity()的工作方式和getForObject()类似,但是它返回的不是实体对象,而是一个包裹实体对象的ResponseEntity对象
28     // 借助ResponseEntity对象能够访问很多响应细节,比如响应头信息等。
29     public User getUserById4(String userId){
30         ResponseEntity<User> responseEntity = restTemplate.getForEntity("http://localhost:8080/user/{id}",User.class, userId);
31         log.info("记录时间: " + responseEntity.getHeaders().getDate());
32         return responseEntity.getBody();
33     }
34 
35     // ----------------- PUT -----------------------
36     public void updateUser(User user){
37         restTemplate.put("http://localhost:8080/user/{id}",user,user.getId());
38     }
39 
40     // ----------------- DELETE -----------------------
41     public void delUser(User user){
42         restTemplate.delete("http://localhost:8080/user/{id}",user.getId());
43     }
44 
45     // ----------------- POST -----------------------
46     //  1.希望在POST请求后获得新添加的资源,使用postForObject()
47     public User createUser(User user){
48         return restTemplate.postForObject("http://localhost:8080/user",user,User.class);
49     }
50 
51     // 2.如果想要在创建资源后获得新资源的地址,使用postForLocation()
52     public URI createUser2(User user){
53         return restTemplate.postForLocation("http://localhost:8080/user",user);
54     }
55 
56     // 3.如果想要获取新添加的资源以及资源地址及更多信息,使用postForEntity()
57     public User createUser3(User user){
58         ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://localhost:8080/user",user,User.class);
59         log.info("资源创建时间: " + responseEntity.getHeaders().getLocation());
60         return responseEntity.getBody();
61     }
62 }

 

⒉Traverson

  Spring HATEOAS提供的支持超链接、同步的REST客户端,其灵感来源于同名的JavaScript库

  当所消费的API在响应中包含了超链接,那么RestTemplate就力所不及了,我们可以使用RestTemplate获取详细的资源数据,然后手动创建逻辑来处理里面所包含的内容和链接。但这个过程并不简单,与其使用RestTemplate来处理超媒体API不如选择一个专门关注该领域的工具,那就是Traverson。

  Traverson来源于Spring Data HATEOAS项目,是Spring应用中开箱即用的消费超媒体API的解决方案,这个基于Java的库灵感来源于同名的JavaScript库。

  Traverson的名字有点类似于“tracerse on”,这种叫法其实可以很好地描述它的用法。它将会以遍历API关系名的方式来消费API。

 1 @RestController
 2 @Log
 3 public class UserController {
 4 
 5     private RestTemplate restTemplate = new RestTemplate();
 6     //使用API的基础URI来实例化一个Traverson对象
 7     private Traverson traverson = new Traverson(URI.create("http://localhost:8080/api"), MediaTypes.HAL_JSON);
 8 
 9     //获取用户列表
10     public Collection<User> getUsers(){
11         ParameterizedTypeReference<CollectionModel<User>> userType = new ParameterizedTypeReference<CollectionModel<User>>() {};
12         //通过follow()方法,就可以导航至链接关系名为users的资源,然后通过toObject()来提取资源。
13         CollectionModel<User> userRes = traverson.follow("users").toObject(userType);
14         Collection<User> users = userRes.getContent();
15         return users;
16     }
17 
18     //获取最近创建的用户
19     public Collection<User> getNewUsers(){
20         ParameterizedTypeReference<CollectionModel<User>> userType = new ParameterizedTypeReference<CollectionModel<User>>() {};
21         //CollectionModel<User> userRes = traverson.follow("users").follow("recents").toObject(userType);   //可以简写
22         CollectionModel<User> userRes = traverson.follow("users","recents").toObject(userType);
23         Collection<User> users = userRes.getContent();
24         return users;
25     }
26 
27     //添加新用户
28     public User createUser(User user){
29         //通过asLink()方法得到链接本身,然后getHref()得到链接的URL
30         String createUserUrl = traverson.follow("users").asLink().getHref();
31         return restTemplate.postForObject(createUserUrl, user, User.class);
32     }
33 
34 }

  Traverson能够很容器地导航HATEOAS的API并消费其资源,但它并没有提供这些API写入或删除资源的方法。相反,RestTemplate能够写入和删除资源,但是在导航API方面支持得并不太好。

  当既要导航API有需要更新或删除资源时,就需要组合使用RestTemplate和Traverson。Traverson仍然可以导航至创建新资源的链接。然后,可以将这个链接传递给RestTemplate来执行PUST、PUT、DELETE或任何其他需要的HTTP请求。【参见上面代码中的`添加新用户`节点】

⒊WebClient

  Spring 5 所引入的反应式、异步REST客户端。【未完待续】

posted @ 2020-12-02 17:56  SpringCore  阅读(164)  评论(0编辑  收藏  举报