Spring 應用 可以 採用 多種 方式 來 消費 REST API, 包括 以下 三種 方式:
RestTemplate: Spring 核心 框架 提供 的 簡單、 同步 REST 客戶 端。
Traverson: Spring HATEOAS 提供 的 支持 超 鏈接、 同步的 REST 客戶 端, 其 靈感 來源於 同名 的 JavaScript 庫。
WebClient: Spring 5 所 引入 的反應式、 異步 REST 客戶 端。
RestTemplate的使用:
要 使用 RestTemplate, 你 可以 在 需要 的 地方 創建 一個 實例:
RestTemplate rest = new RestTemplate();
也可以 將其 聲明 爲 一個 bean 並 注入 到 需要 的 地方:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
package tacos.web.api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import tacos.Ingredient;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
/*
*消費REST服務的API
*/
@RestController
@RequestMapping(path = "/rest",produces = "application/json")
@CrossOrigin(origins = "*")
@Slf4j
public class RestTemplateController {
private RestTemplate rest=new RestTemplate();
//以下是RestTemplate的get的三種調用方法:
//1.接收一個String類型的URL並使用可變列表來指定 URL 變量。
@GetMapping("/{id}")
public Ingredient getIngredientById(@PathVariable String id){
return rest.getForObject("http://localhost:8080/ingredient/{id}",Ingredient.class,id);
}
//2. 使用 Map 來 指定 URL 變量:
@GetMapping("/map/{id}")
public Ingredient getIngredientById2(@PathVariable String id) {
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("id", id);
return rest.getForObject("http://localhost:8080/ingredient/{id}", Ingredient.class, urlVariables);
}
// 3.使用 URL 參數
@GetMapping("/uri/{id}")
public Ingredient getIngredientById3(@PathVariable String id) {
Map<String, String> urlVariables = new HashMap<>();
urlVariables.put("id", id);
URI url= UriComponentsBuilder.fromHttpUrl("http://localhost:8080/ingredient/{id}")
.build(urlVariables);
return rest.getForObject(url,Ingredient.class);
}
//通過getForEntity()方法得到ResponseEntity對象
@GetMapping("/entity/{id}")
public Ingredient getIngredientById4(@PathVariable String id) {
ResponseEntity<Ingredient> responseEntity = rest.getForEntity("http://localhost:8080/ingredient/entity/{id}", Ingredient.class, id);
log.info("Fetched time:" + responseEntity.getHeaders().getDate());
return responseEntity.getBody();
}
// 提示: getForEntity() 有 與 getForObject() 方法 相同 參數 的 重載 形式,
// 所以 我們 既可以 以 可變 列表 參數 的 形式 提供 URL 變量,
// 也可以 以 URI 對象 的 形式 調用 getForEntity()。
@PutMapping("/update")
public void updateIngredient(@RequestBody Ingredient ingredient){
rest.put("http://localhost:8080/ingredient",ingredient,ingredient.getId());
}
@DeleteMapping("/delete/{id}")
public void deleteIngredient(@PathVariable String id){
rest.delete("http://localhost:8080/ingredient/{id}",id);
}
//POST請求之後得到 新 創建 的 Ingredient 資源,
@PostMapping
public Ingredient createIngredient(@RequestBody Ingredient ingredient){
return rest.postForObject("http://localhost:8080/ingredient",ingredient,Ingredient.class);
}
//POST請求之後得到 新創建 資源 的 地址,
@PostMapping("/create")
public URI createIngredient2(@RequestBody Ingredient ingredient){
return rest.postForLocation("http://localhost:8080/ingredient",ingredient);
}
//POST請求之後同時得到,資源地址和響應本身
@PostMapping("createall")
public Ingredient createIngredient3(@RequestBody Ingredient ingredient){
ResponseEntity<Ingredient> responseEntity=rest.postForEntity("http://localhost:8080/ingredient",ingredient,Ingredient.class);
log.info("New resource created at "+responseEntity.getHeaders().getLocation());;
return responseEntity.getBody();
}
}
使用Traverson來消費帶有超鏈接的REST API資源
要 使用 Traverson, 首先 我們 要用 API 的 基礎 URI 來 實例 化 一個 Traverson 對象:
Traverson traverson=new Traverson(URI.create("http://localhost:8080/api"),MediaTypes.HAL_JSON);
例子:
ParameterizedTypeReference< Resources< Taco>> tacoType =
new ParameterizedTypeReference< Resources< Taco>>() {}; Resources< Taco> tacoRes = traverson .follow(" tacos") .follow(" recents") .toObject( tacoType); Collection< Taco> tacos = tacoRes. getContent();
當你 既要 導航 API 又要 更新 或 刪除 資源 時, 你需要組合 使用 RestTemplate 和 Traverson。 Traverson 仍然 可以 導航 至 創建 新 資源 的 鏈接。 然後, 可以 將 這個 鏈接 傳遞 給 RestTemplate 來 執行 POST、 PUT、 DELETE 或 任何 其他 需要 的 HTTP 請求。
private Ingredient addIngredient( Ingredient ingredient) {
String ingredientsUrl = traverson .follow(" ingredients") .asLink() .getHref();
return rest. postForObject( ingredientsUrl, ingredient, Ingredient. class);
}