REST(四)使用RestTemplate
REST(四)使用RestTemplate
在當今微服務中,會將一個大系統拆分為多個微服務系統。按微服務應用的建議,每個微服務系統都會暴露Rest風格的URI請求給別的微服務系統所呼叫。為了方便完成系統之間的相互呼叫,spring還給予了模板類RestTemplate,通過它可以很方便地對Rest請求進行系統之間的呼叫,完成系統之間的資料整合。
使用RestTemplate請求後端
RestTemplate的底層是通過類HttpURLConnection
實現的。
使用RestTemplate請求後端存在多種方法,這裡只講幾種常用的。
控制器
/**
* @Description:RestTemplate
* @Author: lay
* @Date: Created in 1:02 2018/11/18
* @Modified By:IntelliJ IDEA
*/
@RestController
public class RestTemplateController {
private RestTemplate restTemplate=new RestTemplate();
//具體方法如下.....
}
HTTP GET請求
//使用REST Template進行HTTP get請求
@GetMapping("/user/byId")
public UserVo getUser(){
Long id=1L;
//消費服務,第一個引數為url,第二個引數是返回型別,第三個是uri路徑引數
UserVo userVo=restTemplate.getForObject("http://localhost:8080/user/{id}",UserVo.class,id);
System.out.println(userVo.getUserName());
return userVo;
}
這裡的getForObject
方法是需要關注的核心方法
第一個引數URI標明請求伺服器什麼資源,而{id}
則代表引數。
第二個引數宣告為UserVo.class
,表示請求將返回UserVo
類的結果,但是實際上伺服器只會返回JSON型別的資料給我們,只是RestTemplate內部會將其轉換為Java物件。
第二個引數後面則是URI中對應的引數,只是這裡只有一個引數,所以就只有一個id。實際上它是一個可變長的引數,如果URI有多個引數,只需要按照順序寫就可以了。
但是如果請求引數很多,顯然可讀性就不是那麼好了,spring已經考慮了這個問題。下面對於使用者進行查詢,這裡設計使用者名稱稱(userName) ,備註(note),開始行數(start)和限制記錄數(limit)4個引數,實現程式碼如下。
//Rest Template使用多引數的HTTP get請求
@GetMapping("/users/select")
@ResponseBody
public List<UserVo> findUsers() {
//使用map封裝多個引數,提高可讀性
Map<String,Object> params=new HashMap<>();
params.put("userName","user");
params.put("note","note");
params.put("start",2);
params.put("limit",8);
//Map中的key和URI中的引數一一對應
String url="http://localhost:8080/users/{userName}/{note}/{start}/{limit}";
//請求後端
ResponseEntity<List> responseEntity = restTemplate.getForEntity(url, List.class, params);
List<UserVo> userVos=responseEntity.getBody();
return userVos;
}
這裡返回值是個List物件。
HTTP POST請求
新增使用者場景,因為新增使用者時欄位比較多,所以往往採用爨地請求體(Body)的方式。
//通過POST 請求傳遞JSON 請求體(BODY)
@GetMapping("/user/insert")
public User insertUser(){
UserVo userVo=new UserVo();
userVo.setUserName("蠟筆小新");
userVo.setSexCode(1);
userVo.setNote("喜歡吃冰淇淋");
String url="http://localhost:8080/user";
//請求頭
HttpHeaders headers=new HttpHeaders();
//設定請求內容為JSON型別
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//建立請求實體物件
HttpEntity<UserVo> request=new HttpEntity<>(userVo,headers);
User user = restTemplate.postForObject("http://localhost:8080/user", request, User.class);
//User user=restTemplate.postForObject(url,userVo,User.class);
System.out.println(user.getId());
return user;
}
HTTP DELETE請求
//restTemplate 執行DELETE請求
@GetMapping("/user/delete")
public void deleteUser(){
Long id=1L;
restTemplate.delete("http://localhost:8080/user{id}",id);
}
獲取響應頭和狀態碼
上面只是討論了成功獲取資源的情況,有時候請求並不能夠成功的獲取資源。例如,給出一個使用者的id,但是這個使用者在資料庫中並不存在,又如插入資料庫時發生了異常,這時報錯的資訊就可以存放在響應頭中,並且伺服器也會返回錯誤的狀態碼。在這樣的長興下獲取響應頭和HTTP狀態碼就可以辨別請求是否成功,如果是發生了錯誤,它還可以給出資訊反饋錯誤原因。
這裡假設一種情況,在插入使用者後需要它將響應頭和響應碼返回給客戶端,這時可以通過伺服器的響應頭或者響應碼判斷請求是否成功。如下程式碼
//獲取伺服器響應頭屬性和HTTP狀態碼
@GetMapping("/user/userEntity")
public Map<String,Object> insertUserEntity(){
UserVo userVo=new UserVo();
userVo.setUserName("蠟筆小新");
userVo.setSexCode(1);
userVo.setNote("喜歡吃冰淇淋");
String url="http://localhost:8080/user";
//請求頭
HttpHeaders headers=new HttpHeaders();
//設定請求內容為JSON型別
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
//建立請求實體物件
HttpEntity<UserVo> request=new HttpEntity<>(userVo,headers);
ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://localhost:8080/user2/entity", request, User.class);
//獲取響應體
User user=responseEntity.getBody();
HttpHeaders respHeaders=responseEntity.getHeaders();
//獲取響應屬性
List<String> success=respHeaders.get("success");
//響應的HTTP狀態碼
int status=responseEntity.getStatusCodeValue();
System.out.println(user.getId());
Map<String,Object> resultMap=new HashMap<>();
resultMap.put("body",user);
resultMap.put("responseHeaders",respHeaders);
resultMap.put("success",success);
resultMap.put("status",status);
return resultMap;
}
這裡可以看到RestTemplate的postForEntity
方法,它將返回一個ResponseEntity
物件。這個物件包含了伺服器返回的響應體(Body)、狀態碼(status)和響應頭。在請求不到資源時,往往伺服器會通過這些內容給與客戶端提示。