7.2使用Traverson引导REST API
Traverson附带了Spring Data HATEOAS,作为在Spring应用程序中使用超媒体API的开箱即用解决方案。这个基于Java的库的灵感来自于同名的类似的JavaScript库(https://github.com/traverson)。
你可能已经注意到Traverson的名字听起来有点像 “traverse on”,这是描述它用法的好方式。在本节中,将通过遍历关系名称上的API来调用API。
要使用Traverson,首先需要实例化一个Traverson对象和一个API的基础URI:
Traverson traverson = new Traverson(
URI.create("http://localhost:8080/api"), MediaType.HAL_JSON);
这里将Traverson指向Taco Cloud的基本URL(在本地运行),这是需要给Traverson的唯一URL。从这里开始,将通过链接关系名称来引导API。还将指定API将生成带有HAL风格的超链接的JSON响应,以便Traverson知道如何解析传入的资源数据。与RestTemplate一样,可以选择在使用Traverson对象之前实例化它,或者将它声明为一个bean,以便在需要的地方注入它。
有了Traverson对象,可以通过以下链接开始使用API。例如,假设想检索所有Ingredient的列表。从第6.3.1节了解到,Ingredient链接有一个链接到配料资源的href属性,需要点击这个链接:
ParameterizedTypeReference<Resources<Ingredient>> ingredientType =
new ParameterizedTypeReference<Resources<Ingredient>>() {};
Resources<Ingredient> ingredientRes =
traverson.follow("ingredients").toObject(ingredientType);
Collection<Ingredient> ingredients = ingredientRes.getContent();
通过调用Traverson对象上的follow()方法,可以引导到链接关系名称为ingredients的资源。现在客户端已经引导到ingredients,需要通过调用toObject()来提取该资源的内容。
toObject()方法要求你告诉它要将数据读入哪种对象。考虑到需要将其作为Resources对象读入,而Java类型擦除机制使让其为泛型提供类型信息变得困难,因此这可能有点棘手。但是创建一个ParameterizedTypeReference有助于实现这一点。
打个比方,假设这不是一个REST API,而是一个网站的主页。设想这是在浏览器中查看的主页,而不是REST客户端代码。在页面上看到一个链接,上面写着Ingredient,然后点击这个链接。当到达下一页时,将读取该页,这类似于Traverson以Resources对象的形式提取内容。
现在让我们考虑一个更有趣的用例,假设想获取最近创建的tacos,从home资源开始,可以引导到最近的tacos资源,像这样:
ParameterizeTypeReference<Resources<Taco>> tacoType =
new ParameterizedTypeReference<Resources<Taco>>() {};
Resources<Taco> tacoRes =
traverson.follow("tacos").follow("recents").toObject(tacoType);
Collection<Taco> tacos = tacoRes.getContent();
在这里可以点击Tacos链接,然后点击Recents链接。这会将你带到你所感兴趣的资源,因此使用适当的ParameterizedTypeReference调用toObject()可以得到想要的结果。调用follow()方法可以通过列出跟随的关系名称来简化:
Resources<Taco> tacoRes =
traverson.follow("tacos", "recents").toObject(tacoType);
Traverson可以轻松地引导启用了HATEOAS的API并调用其资源。但有一件事它没有提供任何方法来编写或删除这些API。相比之下,RestTemplate可以编写和删除资源,但不便于引导API。
当需要同时引导API和更新或删除资源时,需要同时使用RestTemplate和Traverson。Traverson仍然可以用于引导到将创建新资源的链接。然后可以给RestTemplate一个链接来执行POST、PUT、DELETE或任何其他HTTP请求。
例如,假设想要向Taco Cloud菜单添加新的Ingredient。下面的addIngredient()方法将Traverson和RestTemplate组合起来,向API POST一个新Ingredient:
private Ingredient addIngredient(Ingredient ingredient) {
String ingredientsUrl = traverson.follow("ingredients")
.asLink().getHref();
return rest.postForObject(ingredientsUrl,
ingredient,
Ingredient.class);
}
在follow Ingredient链接之后,通过调用asLink()请求链接本身。在该链接中,通过调用getHref()请求链接的URL。有了URL,就有了在RestTemplate实例上调用postForObject()并保存新Ingredient所需的一切。