摘要
- 客户端可以使用RestTemplate对REST API发出HTTP请求。
- Traverson使客户能够使用嵌入在响应中的超链接来导航API。
要使用RestTemplate,您需要在需要的时候创建一个实例
RestTemplate rest = new RestTemplate();
或者你可以将它声明为bean并将其注入你需要的地方:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
Get resources
@GetMapping("/my/{ingredientId}")
public Ingredient getMyIngredientById(@PathVariable String ingredientId){
return rest.getForObject("http://localhost:8080/ingredients/{id}",Ingredient.class,ingredientId);
}
@GetMapping("/my/{ingredientId}")
public ResponseEntity<Ingredient> getMyIngredientById(@PathVariable String ingredientId){
return rest.getForEntity("http://localhost:8080/ingredients/{id}",Ingredient.class,ingredientId);
}
使用Map来指定URL变量:
@GetMapping("/my/{ingredientId}")
public Ingredient getMyIngredientById(@PathVariable String ingredientId) {
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("id", ingredientId);
return rest.getForObject("http://localhost:8080/ingredients/{id}", Ingredient.class, urlVariables);
}
使用URI参数来指定URL变量:
@GetMapping("/my/{ingredientId}")
public Ingredient getMyIngredientById(@PathVariable String ingredientId) {
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("id", ingredientId);
URI url = UriComponentsBuilder.fromHttpUrl("http://localhost:8080/ingredients/{id}").build(urlVariables);
return rest.getForObject(url, Ingredient.class);
}
getForEntity()
检查响应中的Date标头
@GetMapping("/my/{ingredientId}")
public Ingredient getMyIngredientById(@PathVariable String ingredientId) {
ResponseEntity<Ingredient> responseEntity = rest.getForEntity("http://localhost:8080/ingredients/{id}", Ingredient.class, ingredientId);
log.info("Fetcded time: " + responseEntity.getHeaders().getDate());
return responseEntity.getBody();
}
Put resources
//客户端Put
@PutMapping(path = "/my",consumes = "application/json")
public void updateIngredient2(@RequestBody Ingredient ingredient){
rest.put("http://localhost:8080/ingredients/{id}",ingredient,ingredient.getId());
}
//服务端
@PutMapping("/{id}")
public void updateIngredient(@RequestBody Ingredient ingredient) {
ingredientRepo.save(ingredient);
}
@PatchMapping(path = "/{id}",consumes = "application/json")
public void patchIngredient(@PathVariable String id,@RequestBody Ingredient patch) {
Ingredient ingredient = ingredientRepo.findById(id).get();
if (patch.getType() != null) {
ingredient.setType(patch.getType());
}
if (patch.getName() != null) {
ingredient.setName(patch.getName());
}
ingredientRepo.save(ingredient);
}
public void deleteIngredient(Ingredient ingredient) {
rest.delete("http://localhost:8080/ingredients/{id}",
ingredient.getId());
}
Post resource data
在POST请求后收到新创建的资源,您可以这样使用postForObject():
public Ingredient createIngredient(Ingredient ingredient) {
return rest.postForObject("http://localhost:8080/ingredients",
ingredient,
Ingredient.class);
}
需要新创建的资源的位置,那么您可以调用postForLocation():
public URI createIngredient(Ingredient ingredient) {
return rest.postForLocation("http://localhost:8080/ingredients",
ingredient);
}
需要位置和响应实例,则可以调用postForEntity():
public Ingredient createIngredient(Ingredient ingredient) {
ResponseEntity<Ingredient> responseEntity =
rest.postForEntity("http://localhost:8080/ingredients",
ingredient,
Ingredient.class);
log.info("New resource created at " +
responseEntity.getHeaders().getLocation());
return responseEntity.getBody();
}
使用Traverson导航REST API
Traverson附带Spring Data HATEOAS作为在Spring应用程序中使用超媒体API的开箱即用解决方案。
Traverson的名称听起来像“遍历”,这是描述它如何使用的好方法。在本节中,您将通过遍历关系名称的API来使用API。
使用Traverson开始使用TraversonAPI的基URI 实例化对象:
Traverson traverson = new Traverson(
URI.create("http://localhost:8080/api"), MediaTypes.HAL_JSON);
我将Traverson指向了Taco Cloud的基本URL(在本地运行)。这是您需要向Traverson提供的唯一网址。
有了一个Traverson对象,您可以通过以下链接开始使用API。
ParameterizedTypeReference<Resources<Ingredient>> ingredientType =
new ParameterizedTypeReference<Resources<Ingredient>>() {};
Resources<Ingredient> ingredientRes =
traverson
.follow("ingredients")
.toObject(ingredientType);
Collection<Ingredient> ingredients = ingredientRes.getContent();
该toObject()方法要求您告诉它将数据读入哪种对象。考虑到您需要将其作为Resources<Ingredient>对象读取,这可能会有点棘手,而Java类型擦除使得难以为泛型类型提供类型信息。但是要创造一个ParameterizedTypeReference帮助。
现在让我们考虑一个稍微有趣的用例。假设你想要获取最近创建的玉米饼。从主资源开始,您可以导航到最近的tacos资源,如下所示:
ParameterizedTypeReference<Resources<Taco>> tacoType =
new ParameterizedTypeReference<Resources<Taco>>() {};
Resources<Taco> tacoRes =
traverson
.follow("tacos")
.follow("recents")
.toObject(tacoType);
Collection<Taco> tacos = tacoRes.getContent();
.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请求你所需要的。
例如,假设您要向IngredientTaco Cloud菜单添加新内容。以下addIngredient()方法组合Traverson并向API RestTemplate发布新内容Ingredient:
private Ingredient addIngredient(Ingredient ingredient) {
String ingredientsUrl = traverson
.follow("ingredients")
.asLink()
.getHref();
return rest.postForObject(ingredientsUrl,
ingredient,
Ingredient.class);
}
按照“成分”链接后,您可以通过致电询问链接本身asLink()。从该链接,您可以通过调用来请求链接的URL getHref()。随着在手的URL,你有你需要的一切调用postForObject()的RestTemplate实例,并保存新的成分。