RestTemplate
是 Spring 提供的一個調用 Restful 服務的抽象層,它簡化的同 Restful 服務的通訊方式,隱藏了沒必要要的一些細節,讓咱們更加優雅地在應用中調用 Restful 服務 。可是在 Spring 5.0 之後RestTemplate
處於維護模式,再也不進行新特性的開發,僅僅進行一些平常維護。Spring 建議咱們使用同時支持同步、異步和 Stream 的另外一個 API —— WebClient 。可是在 Spring MVC 下目前咱們尚未更好的選擇。java
咱們在項目中常常要使用第三方的 Rest API 服務,好比短信、快遞查詢、天氣預報等等。這些第三方只要提供了 Rest Api ,你均可以使用 RestTemplate
來調用它們。程序員
只要你的項目使用了 Spring MVC 就已經集成了RestTemplate
。可是一般狀況下該類不會自動被注入 Spring IoC容器,由於不少 Rest API 都具備特殊性,爲了更加靈活的進行定製,其構建類 RestTemplateBuilder
被自動注入了 Spring IoC 容器。 咱們能夠這樣初始化它:web
package cn.felord.rest.webclient;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/** * @author felord.cn * @since 14:58 **/
@Component
public class SomeWeb {
private final RestTemplateBuilder restTemplateBuilder;
public SomeWeb(RestTemplateBuilder restTemplateBuilder) {
this.restTemplateBuilder = restTemplateBuilder;
}
public RestTemplate restTemplate() {
// 經過 builder 定製
return restTemplateBuilder.requestFactory(OkHttp3ClientHttpRequestFactory::new).
build();
}
}
複製代碼
最佳實踐:針對每個第三方服務儘可能定製對應的
RestTemplate
,儘可能不公用,除非這些第三方的流程徹底一致。spring
默認狀況下,RestTemplate
使用 java.net.HttpURLConnection
做爲實現,一但使用它時有異常響應狀態(好比 401),就會引起異常,所以咱們通常不使用它。咱們能夠切換到 Netty 、Apache HttpComponents、okHttp 默認實現的客戶端庫,參考 2 中的 requestFactory(ClientHttpRequestFactory factory)
接入方法,也能夠自行實現 ClientHttpRequestFactory
對接其它第三方庫進行接入。這裏我使用 okHttp 。你能夠定製這些第三方庫提供的特性豐富你的 RestTemplate
,好比設置請求超時。json
RestTemplate
支持全部 Restful 風格方法,你能夠根據須要進行選擇,這裏咱們只介紹一些經常使用的方法。全部方法都支持URI 模板和 URI 參數,支持下面這種寫法:api
# 相似 spring mvc 中的 @PathVariable
https://api.apiopen.top/{method}
複製代碼
Get 請求後將響應映射爲 ResponseEntity<T>
響應對象,一個響應體的包裝對象。咱們使用下列代碼來隨機請求 5 條漂亮小姐姐的照片,你能夠打印進行查看:bash
@Autowired
RestTemplate restTemplate;
void contextLoads() {
String url = "https://api.apiopen.top/getImages?page=0&count=5";
ResponseEntity<String> responseEntity = restTemplate
.getForEntity(url,String.class);
String body = responseEntity.getBody();
System.out.println("body = " + body);
}
複製代碼
上面的方法改成按順序的可變參數:mvc
String url = "https://api.apiopen.top/getImages?page={page}&count={count}";
ResponseEntity<String> responseEntity = restTemplate
.getForEntity(url,String.class,0,5);
String body = responseEntity.getBody();
System.out.println("body = " + body);
複製代碼
或者使用 Map<String,Object>
:app
String url = "https://api.apiopen.top/getImages?page={page}&count={count}";
HashMap<String, Object> uriParams = new HashMap<>();
uriParams.put("page", 0);
uriParams.put("count", 5);
ResponseEntity<String> responseEntity = restTemplate
.getForEntity(url, String.class, uriParams);
String body = responseEntity.getBody();
System.out.println("body = " + body);
複製代碼
post 請求 額外會傳入一個可能爲 null
的 VO 對象,或者 MultiValueMap
來攜帶請求體參數 ,它們最終會被封裝入異步
org.springframework.http.HttpEntity
對象,該對象可包含如下兩個部分:
MultiValueMap
org.springframework.http.HttpHeaders
String url = "https://api.apiopen.top/getImages?page={page}&count={count}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<UserVO> httpEntity = new HttpEntity<>(new UserVO("userName"), headers);
HashMap<String, Object> uriParams = new HashMap<>();
uriParams.put("page", 0);
uriParams.put("count", 5);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class, uriParams);
複製代碼
以上是一個調用 Post 請求並攜帶請求體和請求頭的示例。
咱們還能夠將響應直接映射到 POJO, 固然你須要對響應結果的結構很是瞭解,建議先映射到 String
查看一下結構。咱們給出一種示例,其餘示例參考 3.1 :
String url = "https://api.apiopen.top/getImages?page={page}&count={count}";
HashMap<String, Object> uriParams = new HashMap<>();
uriParams.put("page", 0);
uriParams.put("count", 5);
String forObject = restTemplate.getForObject(url, String.class, uriParams);
System.out.println("forObject = " + forObject);
複製代碼
該方法用於獲取全部的 URI 模板聲明資源的 Header
String url = "https://api.apiopen.top/getImages?page={page}&count={count}";
HashMap<String, Object> uriParams = new HashMap<>();
uriParams.put("page", 0);
uriParams.put("count", 5);
HttpHeaders httpHeaders = restTemplate.headForHeaders(url, uriParams);
System.out.println(httpHeaders);
複製代碼
結果爲:
[Access-Control-Allow-Headers:"Content-Type, x-requested-with, X-Custom-Header, Authorization", Access-Control-Allow-Methods:"POST, GET, OPTIONS, DELETE", Access-Control-Allow-Origin:"*", Access-Control-Max-Age:"3600", Cache-Control:"private", Content-Length:"608", Content-Type:"application/json;charset=UTF-8", Date:"Tue, 14 Apr 2020 15:25:19 GMT", Expires:"Thu, 01 Jan 1970 00:00:00 GMT"]
複製代碼
該 Post 操做不是返回完整的資源,而是返回新建立的資源 URI 。好比上傳文件返回資源的請求路徑。
對應 put 請求 和 delete 請求,參考前面的 api。
該方法獲取該 URI 容許的全部請求方法好比 GET、POST、PUT、DELETE 中的一個或者幾個。
該方法是通用的請求方式,支持 GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE,當上面的方式不能知足你可採用該方式定製,該方式提供了更加靈活的 API,好比你能夠定製 GET 方法的請求頭,放入 Jwt Token等操做,這是getForObject
沒法比擬的。
RestTemplate
是一個頗有用的請求協調器,屏蔽了調用服務的複雜度而又不失靈活。可是值得注意的是它正在退出歷史舞臺。再牛逼的程序員也有轉行的那一天不是嗎?
關注公衆號:Felordcn獲取更多資訊