Spring學習筆記之RestTemplate使用小結(jié)

前言

創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),鹽城企業(yè)網(wǎng)站建設(shè),鹽城品牌網(wǎng)站建設(shè),網(wǎng)站定制,鹽城網(wǎng)站建設(shè)報價,網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,鹽城網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網(wǎng)站。

作為一個Java后端,需要通過HTTP請求其他的網(wǎng)絡(luò)資源可以說是一個比較常見的case了;一般怎么做呢?

可能大部分的小伙伴直接撈起Apache的HttpClient開始做,或者用其他的一些知名的開源庫如OkHttp, 當然原生的HttpURLConnection也是沒問題的

本篇博文則主要關(guān)注點放在Sprig的生態(tài)下,利用RestTemplate來發(fā)起Http請求的使用姿勢

I. RestTempalate 基本使用

0. 目標

在介紹如何使用RestTemplate之前,我們先拋出一些小目標,至少需要知道通過RestTemplate可以做些什么,以及我們要用它來干些什么

簡單的給出了一下常見的問題如下

  • 普通的Get請求獲取返回數(shù)據(jù),怎么玩?
  • post提交表達的請求,如何處理
  • post請求中RequestBody的請求方式與普通的請求方式區(qū)別
  • https/http兩種訪問如何分別處理
  • 如何在請求中帶上指定的Header
  • 有跨域的問題么?如果有怎么解決
  • 有登錄驗證的請求,該怎么辦,怎樣攜帶身份信息
  • 上傳文件可以支持么
  • 對于需要代理才能訪問的http資源,加代理的姿勢是怎樣的

上面的問題比較多,目測不是一篇博文可以弄完的,因此對這個拆解一下,本篇主要關(guān)注在RestTemplate的簡單Get/Post請求的使用方式上

1. 基本接口

撈出源碼,看一下其給出的一些常用接口,基本上可以分為下面幾種

// get 請求
public <T> T getForObject();
public <T> ResponseEntity<T> getForEntity();

// head 請求
public HttpHeaders headForHeaders();

// post 請求
public URI postForLocation();
public <T> T postForObject();
public <T> ResponseEntity<T> postForEntity();

// put 請求
public void put();

// pathch 
public <T> T patchForObject

// delete
public void delete()

// options
public Set<HttpMethod> optionsForAllow

// exchange
public <T> ResponseEntity<T> exchange()

上面提供的幾個接口,基本上就是Http提供的幾種訪問方式的對應(yīng),其中exchange卻又不一樣,后面細說

2. Get請求

從上面的接口命名上,可以看出可以使用的有兩種方式 getForObject 和 getForEntity,那么這兩種有什么區(qū)別?

  • 從接口的簽名上,可以看出一個是直接返回預期的對象,一個則是將對象包裝到 ResponseEntity 封裝類中
  • 如果只關(guān)心返回結(jié)果,那么直接用 GetForObject 即可
  • 如果除了返回的實體內(nèi)容之外,還需要獲取返回的header等信息,則可以使用 getForEntit

a. 創(chuàng)建Get接口

為了驗證RestTemplate的使用姿勢,當然得先提供一個后端的REST服務(wù),這了直接用了我個人的一個古詩詞的后端接口,來作為簡單的Get測試使用

請求連接: https://story.hhui.top/detail?id=666106231640

返回結(jié)果:

{
 "status": {
 "code": 200,
 "msg": "SUCCESS"
 },
 "result": {
 "id": 666106231640,
 "title": "西塞山二首(今謂之道士磯,即興國軍大冶縣",
 "author": "王周",
 "content": "西塞名山立翠屏,濃嵐橫入半江青。\n千尋鐵鎖無由問,石壁空存道者形。\n匹婦頑然莫問因,匹夫何去望千春。\n翻思岵屺傳詩什,舉世曾無化石人。",
 "explain": "",
 "theme": "無",
 "dynasty": "唐詩"
 }
}

b. getForObject方式

首先看下完整的接口簽名

@Nullable
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ;

@Nullable
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException ;

@Nullable
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException;

有三個重載的方法,從接口上也比較容易看出如何使用,其中有點疑惑的則是第一鐘,參數(shù)應(yīng)該怎么傳了,下面給出上面幾種的使用姿勢

public class RestTestmplateTest {
 private RestTemplate restTemplate;

 @Before
 public void init() {
 restTemplate = new RestTemplate();
 }

 @lombok.Data
 static class InnerRes {
 private Status status;
 private Data result;
 }

 @lombok.Data
 static class Status {
 int code;
 String msg;
 }

 @lombok.Data
 static class Data {
 long id;
 String theme;
 String title;
 String dynasty;
 String explain;
 String content;
 String author;
 }

 @Test
 public void testGet() {
 // 使用方法一,不帶參數(shù)
 String url = "https://story.hhui.top/detail?id=666106231640";
 InnerRes res = restTemplate.getForObject(url, InnerRes.class);
 System.out.println(res);


 // 使用方法一,傳參替換
 url = "https://story.hhui.top/detail?id={?}";
 res = restTemplate.getForObject(url, InnerRes.class, "666106231640");
 System.out.println(res);

 // 使用方法二,map傳參
 url = "https://story.hhui.top/detail?id={id}";
 Map<String, Object> params = new HashMap<>();
 params.put("id", 666106231640L);
 res = restTemplate.getForObject(url, InnerRes.class, params);
 System.out.println(res);

 // 使用方法三,URI訪問
 URI uri = URI.create("https://story.hhui.top/detail?id=666106231640");
 res = restTemplate.getForObject(uri, InnerRes.class);
 System.out.println(res);
 }
}

看上面的testcase,后面兩個方法的使用沒什么好說的,主要看一下org.springframework.web.client.RestTemplate#getForObject(java.lang.String, java.lang.Class<T>, java.lang.Object...) 的使用姿勢

  • 根據(jù)實際傳參替換url模板中的內(nèi)容
  • 使用方法一時,模板中使用 {?} 來代表坑位,根據(jù)實際的傳參順序來填充
  • 使用方法二時,模板中使用 {xx}, 而這個xx,對應(yīng)的就是map中的key

上面執(zhí)行后的截圖如下

Spring學習筆記之RestTemplate使用小結(jié)

c. getForEntity方式

既然getForObject有三種使用方法,那么getForEntity理論上也應(yīng)該有對應(yīng)的三種方式

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ;
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;

因為使用姿勢和上面一致,因此只拿一個進行測試

@Test
public void testGetForEntity() {
 String url = "https://story.hhui.top/detail?id=666106231640";
 ResponseEntity<InnerRes> res = restTemplate.getForEntity(url, InnerRes.class);
 System.out.println(res);
}

對這個,我們主要關(guān)注的就是ResponseEntity封裝中,多了哪些東西,截圖如下

從上面可以看出,多了兩個東西

  • 一個返回的http狀態(tài)碼,如200表示請求成功,500服務(wù)器錯誤,404not found等
  • 一個 ResponseHeader

3. Post請求

從上面的接口說明上看,post請求除了有forObject 和 forEntity之外,還多了個forLocation;其次post與get一個明顯的區(qū)別就是傳參的姿勢問題,get的參數(shù)一般會待在url上;post的則更常見的是通過表單的方式提交

因此接下來關(guān)注的重點在于forLocation是什么,以及如何傳參

a. post接口mock

首先創(chuàng)建一個簡單的提供POST請求的REST服務(wù),基于Spring-boot簡單搭建一個,如下

@ResponseBody
@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST})
public String post(HttpServletRequest request,
 @RequestParam(value = "email", required = false) String email,
 @RequestParam(value = "nick", required = false) String nick) {
 Map<String, Object> map = new HashMap<>();
 map.put("code", "200");
 map.put("result", "add " + email + " # " + nick + " success!");
 return JSON.toJSONString(map);
}

b. postForObject方法

首先看一下接口簽名

public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException ;

public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType) throws RestClientException ;

上面的三個方法,看起來和前面并沒有太大的區(qū)別,只是多了一個request參數(shù),那么具體的使用如何呢?

下面分別給出使用用例

@Test
public void testPost() {
 String url = "http://localhost:8080/post";
 String email = "test@hhui.top";
 String nick = "一灰灰Blog";

 MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
 request.add("email", email);
 request.add("nick", nick);

 // 使用方法三
 URI uri = URI.create(url);
 String ans = restTemplate.postForObject(uri, request, String.class);
 System.out.println(ans);

 // 使用方法一
 ans = restTemplate.postForObject(url, request, String.class);
 System.out.println(ans);

 // 使用方法一,但是結(jié)合表單參數(shù)和uri參數(shù)的方式,其中uri參數(shù)的填充和get請求一致
 request.clear();
 request.add("email", email);
 ans = restTemplate.postForObject(url + "?nick={?}", request, String.class, nick);
 System.out.println(ans);


 // 使用方法二
 Map<String, String> params = new HashMap<>();
 params.put("nick", nick);
 ans = restTemplate.postForObject(url + "?nick={nick}", request, String.class, params);
 System.out.println(ans);
}

復制代碼上面分別給出了三種方法的調(diào)用方式,其中post傳參區(qū)分為兩種,一個是uri參數(shù)即拼接在url中的,還有一個就是表單參數(shù)

  • uri參數(shù),使用姿勢和get請求中一樣,填充uri中模板坑位
  • 表單參數(shù),由MultiValueMap封裝,同樣是kv結(jié)構(gòu)

c. postForEntity

和前面的使用姿勢一樣,無非是多了一層包裝而已,略過不講

d. postForLocation

這個與前面有點區(qū)別,從接口定義上來說,主要是

POST 數(shù)據(jù)到一個URL,返回新創(chuàng)建資源的URL

同樣提供了三個接口,分別如下,需要注意的是返回結(jié)果,為URI對象,即網(wǎng)絡(luò)資源

public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
 throws RestClientException ;

public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
 throws RestClientException ;

public URI postForLocation(URI url, @Nullable Object request) throws RestClientException ;

那么什么樣的接口適合用這種訪問姿勢呢?

想一下我們一般登錄or注冊都是post請求,而這些操作完成之后呢?大部分都是跳轉(zhuǎn)到別的頁面去了,這種場景下,就可以使用 postForLocation 了,提交數(shù)據(jù),并獲取返回的URI,一個測試如下

首先mock一個后端接口

@ResponseBody
@RequestMapping(path = "success")
public String loginSuccess(String email, String nick) {
 return "welcome " + nick;
}

@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST})
public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email,
  @RequestParam(value = "nick", required = false) String nick) {
 return "redirect:/success?email=" + email + "&nick=" + nick + "&status=success";
}

訪問的測試用例,基本上和前面的一樣,沒有什么特別值得一說的

@Test
public void testPostLocation() {
 String url = "http://localhost:8080/post";
 String email = "test@hhui.top";
 String nick = "一灰灰Blog";

 MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
 request.add("email", email);
 request.add("nick", nick);

 // 使用方法三
 URI uri = restTemplate.postForLocation(url, request);
 System.out.println(uri);
}

執(zhí)行結(jié)果如下

Spring學習筆記之RestTemplate使用小結(jié)

獲取到的就是302跳轉(zhuǎn)后端url,細心的朋友可能看到上面中文亂碼的問題,如何解決呢?

一個簡單的解決方案就是url編碼一下

@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST},
   produces = "charset/utf8")
public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email,
  @RequestParam(value = "nick", required = false) String nick) throws UnsupportedEncodingException {
 return "redirect:/success?email=" + email + "&nick=" + URLEncoder.encode(nick, "UTF-8") + "&status=success";
}

II. 小結(jié)

上面目前只給出了Get/Post兩種請求方式的基本使用方式,并沒有涉及到更高級的如添加請求頭,添加證書,設(shè)置代理等,高級的使用篇等待下一篇出爐,下面小結(jié)一下上面的使用姿勢

1. Get請求

get請求中,參數(shù)一般都是帶在url上,對于參數(shù)的填充,有兩種方式,思路一致都是根據(jù)實際的參數(shù)來填充url中的占位符的內(nèi)容;根據(jù)返回結(jié)果,也有兩種方式,一個是只關(guān)心返回對象,另一個則包含了返回headers信心
參數(shù)填充

1、形如  http://story.hhui.top?id={0} 的 url

  • 調(diào)用 getForObject(String url, Class<T> responseType, Object... uriVariables)
  • 模板中的0,表示 uriVariables 數(shù)組中的第0個, i,則表示第i個
  • 如果沒有url參數(shù),也推薦用這個方法,不傳uriVariables即可

2、形如  http://story.hhui.top?id={id} 的 url

  • 調(diào)用 getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
  • map參數(shù)中的key,就是url參數(shù)中 {} 中的內(nèi)容

其實還有一種傳參方式,就是path參數(shù),填充方式和上面一樣,并沒有什么特殊的玩法,上面沒有特別列出

返回結(jié)果

  • 直接獲取返回的數(shù)據(jù)  getForObject
  • 獲取待responseHeader的數(shù)據(jù) getForEntity

2. Post請求

  • post請求的返回也有兩種,和上面一樣
  • post請求,參數(shù)可以區(qū)分為表單提交和url參數(shù),其中url參數(shù)和前面的邏輯一致
  • post表單參數(shù),請包裝在 MultiValueMap 中,作為第二個參數(shù) Request 來提交
  • post的方法,還有一個 postForLocation,返回的是一個URI對象,即適用于返回網(wǎng)絡(luò)資源的請求方式

3. 其他

最前面提了多點關(guān)于網(wǎng)絡(luò)請求的常見case,但是上面的介紹,明顯只處于基礎(chǔ)篇,我們還需要關(guān)注的有

  • 如何設(shè)置請求頭?
  • 有身份驗證的請求,如何攜帶身份信息?
  • 代理的設(shè)置
  • 文件上傳可以怎么做?
  • post提交json串(即RequestBody) 又可以怎么處理

上面可能還停留在應(yīng)用篇,對于源碼和實現(xiàn)有興趣的話,問題也就來了

  • RestTemplaet的實現(xiàn)原理是怎樣的
  • 前面url參數(shù)的填充邏輯實現(xiàn)是否優(yōu)雅
  • 返回的對象如何解析
  • ....

小小的一個工具類,其實東西還挺多的,接下來的小目標,就是針對上面提出的點,逐一進行研究

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。

本文題目:Spring學習筆記之RestTemplate使用小結(jié)
當前鏈接:http://muchs.cn/article14/ishdge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站排名網(wǎng)站維護、網(wǎng)站制作、標簽優(yōu)化、全網(wǎng)營銷推廣用戶體驗

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)