

RestTemplate是由Spring框架提供的一個(gè)可用于應(yīng)用中調(diào)用rest服務(wù)的類(lèi)它簡(jiǎn)化了與http服務(wù)的通信方式,統(tǒng)一了RESTFul的標(biāo)準(zhǔn),封裝了http連接,我們只需要傳入url及其返回值類(lèi)型即可。相較于之前常用的HttpClient,RestTemplate是一種更為優(yōu)雅的調(diào)用RESTFul服務(wù)的方式。Spring應(yīng)用程序中訪問(wèn)第三方REST服務(wù)與使用Spring RestTemplate類(lèi)有關(guān)。RestTemplate類(lèi)的設(shè)計(jì)原則與許多其他Spring的模板類(lèi)(例如JdbcTemplate)相同,為執(zhí)行復(fù)雜任務(wù)提供了一種具有默認(rèn)行為的簡(jiǎn)化方法。RestTemplate默認(rèn)依賴(lài)JDK提供了http連接的能力(HttpURLConnection),如果有需要的話也可以通過(guò)setRequestFactory方法替換為例如Apache HttpCompoent、Netty或OKHttp等其他Http libaray。RestTemplate類(lèi)是為了調(diào)用REST服務(wù)而設(shè)計(jì)的,因此它的主要方法與REST的基礎(chǔ)緊密相連就不足為奇了,后者時(shí)HTTP協(xié)議的方法:HEAD、GET、POST、PUT、DELETE、OPTIONS例如,RestTemplate類(lèi)具有headForHeaders()、getForObject()、putForObject(),put()和delete()等方法。RestTemplate? 因?yàn)?code>RestTemplate是Spirng框架提供的所以只要是一個(gè)Springboot項(xiàng)目就不用考慮導(dǎo)包的問(wèn)題,這些都是提供好的。
? 但是Spring并沒(méi)有將其加入SpringBean容器中,需要我們手動(dòng)加入,因?yàn)槲覀兪紫葎?chuàng)建一個(gè)Springboot配置類(lèi),再在配置類(lèi)中將我們的RestTemlate注冊(cè)到Bean容器中
? 使用Springboot提供的RestTemplateBuilder構(gòu)造類(lèi)來(lái)構(gòu)造一個(gè)RestTemplate,可以自定義一些連接參數(shù),如:連接超時(shí)時(shí)間,讀取超時(shí)時(shí)間,還有認(rèn)證信息等

@Configuration
public class WebConfiguration {@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){return builder
//設(shè)置連接超時(shí)時(shí)間
.setConnectTimeout(Duration.ofSeconds(5000))
//設(shè)置讀取超時(shí)時(shí)間
.setReadTimeout(Duration.ofSeconds(5000))
//設(shè)置認(rèn)證信息
.basicAuthentication("username","password")
//設(shè)置根路徑
.rootUri("https://api.test.com/")
//構(gòu)建
.build();
}
}添加自定義的攔截器? 自定義攔截器示例
@Slf4j
public class CustomClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {//打印請(qǐng)求明細(xì)
logRequestDetails(request,body);
ClientHttpResponse response = execution.execute(request, body);
//打印響應(yīng)明細(xì)
logResponseDetails(response);
return response;
}
private void logRequestDetails(HttpRequest request, byte[] body){log.debug("Headers:{}",request.getHeaders());
log.debug("body:{}",new String(body, StandardCharsets.UTF_8));
log.debug("{}:{}",request.getMethod(),request.getMethodValue());
}
private void logResponseDetails(ClientHttpResponse response) throws IOException {log.debug("Status code : {}",response.getStatusCode());
log.debug("Status text : {}",response.getStatusText());
log.debug("Headers : {}",response.getHeaders());
log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(),StandardCharsets.UTF_8));
}
}? 使用RestTemplateBuilder構(gòu)造類(lèi),添加自定義攔截器,構(gòu)造帶有自定義攔截器的RestTemplate實(shí)例
@Configuration
public class WebConfiguration {@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){return builder
.additionalInterceptors(new CustomClientHttpRequestInterceptor())
//構(gòu)建
.build();
}
}? 測(cè)試請(qǐng)求確實(shí)經(jīng)過(guò)了攔截器,注冊(cè)成功(注意請(qǐng)求和響應(yīng)的流只會(huì)被讀取一次,這里我們讀取了response后返回的response就讀取不到剛剛讀過(guò)的內(nèi)容了)
?
? 使用RestTemplate構(gòu)造方法構(gòu)造一個(gè)RestTemlate,雖然不能像RestTemplate構(gòu)造類(lèi)那樣更詳細(xì)、更多樣的配置參數(shù),但是RestTemplate構(gòu)造方法在一般情況是夠用的。

ClientHttpRequestFactory的構(gòu)造方法可以指定自己實(shí)現(xiàn)的ClientHttpRequestFactory(客戶(hù)端http請(qǐng)求工廠)其他的與無(wú)參構(gòu)造相同。ClientHttpRequestFactoryList> 的構(gòu)造方法可以指定自己是實(shí)現(xiàn)的HttpMessageConverter(Http消息轉(zhuǎn)換器)傳入其他與無(wú)參構(gòu)造相同。@Configuration
public class WebConfiguration {@Bean
public RestTemplate restTemplate(){return new RestTemplate();
}
}? 兩者方法都可使用,前者提供了多樣的自定義參數(shù)的選擇,可以將RestTemplate配置的更為完善,后者則簡(jiǎn)化了配置雖然配置多樣性不如前者,但是日常使用調(diào)用些API還是足以使用
RestTemplate API使用? 在使用RestTemplate前先讓我們看看RestTemplate有哪些API


? 相信大家看到這么多方法,一定很頭大,但是我們仔細(xì)看上述的方法,我們可以提取出主要的幾種方法是(這里只討論Http請(qǐng)求的):
GETPOSTPUTDELETEHEADOPTIONSEXCHANGEEXECUTE? 這里我給大家安利一個(gè)一個(gè)網(wǎng)站,它提供免費(fèi)的RESTFul api的樣例測(cè)試。httpbin A simple HTTP Request & Response Service.
? 通過(guò)上圖我們可以發(fā)現(xiàn)RestTemlate發(fā)送GET請(qǐng)求的方法有兩種
publicT getForObject(...) publicResponseEntity getForEntity(...)
getForEntity()? 后綴帶有Entity的方法都代表返回一個(gè)ResponseEntity,ResponseEntity是Spring對(duì)HTTP請(qǐng)求響應(yīng)的封裝,包括了幾個(gè)重要的元素,如響應(yīng)碼,contentType、contentLength、響應(yīng)消息體等

? 通過(guò)它繼承父類(lèi)(HttpEntity)的getHeader()方法我們可以獲取contentType、contentLength、響應(yīng)消息體等。比如下面這個(gè)例子。
public void queryWeather() {ResponseEntity? 該例子中getForEntity()方法的第一個(gè)參數(shù)為我要調(diào)用服務(wù)的URL,第二個(gè)參數(shù)則為響應(yīng)內(nèi)容的類(lèi)的類(lèi)型(Java嘛 萬(wàn)物皆對(duì)象)還可以添加第三個(gè)參數(shù),第三個(gè)參數(shù)為一個(gè)可變參數(shù) 代表著調(diào)用服務(wù)時(shí)的傳參。
第三個(gè)參數(shù)可以使用key-value的map來(lái)傳入?yún)?shù)
? get請(qǐng)求也可通過(guò)向在url上添加查詢(xún)參數(shù)來(lái)發(fā)送帶有請(qǐng)求的參數(shù)
getForObject()? 相比于前者getForEntity()該方法則是,更偏向于直接獲取響應(yīng)內(nèi)容的,因?yàn)樗苯臃祷仨憫?yīng)實(shí)體的body(響應(yīng)內(nèi)容),。比如下面這個(gè)例子
public void queryWeather() {
Object body = restTemplate.getForObject("https://restapi.amap.com/v3/weather/weatherInfo?city=510100&key=e7a5fa943f706602033b6b329c49fbc6", Object.class);
System.out.println(body);
}方法參數(shù)簽名與`getForEntity()`基本一致。? 當(dāng)你只需要返回的響應(yīng)內(nèi)容時(shí),使用getForObject()是一個(gè)很好的選擇,但當(dāng)你需要獲得更詳細(xì)的響應(yīng)信息,如響應(yīng)頭中的信息,你就只能選擇getForEntity()了。
?POST請(qǐng)求有如下三種方法
public URI postForLocation(...)publicT postForObject(...) publicResponseEntity postForEntity(...)
? 后兩種用法與GET基本一致不做詳細(xì)介紹,這里著重介紹postForLocation()
postForEntity()? 該方法有三個(gè)參數(shù),第一個(gè)為調(diào)用服務(wù)的地址(URL)
? 第二個(gè)參數(shù)表示上傳的參數(shù)(json格式提交)
? 第三個(gè)表示返回響應(yīng)內(nèi)容的具體類(lèi)型
? 第四個(gè)參數(shù)也用于指定參數(shù)(在URL中添加)
@Override
public void queryWeather() {User user = new User();
user.setName("魯大師");
ResponseEntitypostForObject()? 使用方法與getForObject類(lèi)似只是多了一個(gè)傳入對(duì)象參數(shù)(傳入方式與postForEntity()相同)
public void queryWeather() {User user = new User();
user.setName("魯大師");
ResponseEntitypostForLocation()?postForLocation傳參用法與前兩者一致,只不過(guò)返回從實(shí)體變成了一個(gè)URL,因此它不需要指定返回響應(yīng)內(nèi)容的類(lèi)型。
public void queryWeather() {User user = new User();
user.setName("魯大師");
URI uri = restTemplate.postForLocation("https://httpbin.org/post", user);
System.out.println(uri);
}這個(gè)只需要服務(wù)提供者返回一個(gè) URI 即可,該URI返回值體現(xiàn)的是:用于提交完成數(shù)據(jù)之后的頁(yè)面跳轉(zhuǎn),或數(shù)據(jù)提交完成之后的下一步數(shù)據(jù)操作URI。
? 這里我們著重說(shuō)一下,如何自己封裝一個(gè)請(qǐng)求體。
? 我們需要用到如下幾個(gè)類(lèi)
HttpHeadersMultiValueMapHttpEntity
HttpHeaders? 故名思意,就是用來(lái)封裝Http請(qǐng)求的請(qǐng)求頭的,這里我們要設(shè)置他的ContentType為**MediaType.APPLICATION_FORM_URLENCODED**以使得我們提交的參數(shù)是以Form(表單)的形式提交。
//設(shè)置請(qǐng)求頭, x-www-form-urlencoded格式的數(shù)據(jù)
HttpHeaders httpHeaders = new HttpHeaders();
//這里指定參數(shù)以UTF-8編碼格式傳輸
MediaType mediaType = new MediaType(MediaType.APPLICATION_FORM_URLENCODED, UTF_8);
httpHeaders.setContentType(mediaType);
//提交參數(shù)設(shè)置
MultiValueMapmap = new LinkedMultiValueMap<>();
map.add("name","魯大師"); MultiValueMap? 該類(lèi)是用來(lái)封裝請(qǐng)求參數(shù)的,是以key-value的形式封裝但是以單個(gè)key對(duì)應(yīng)多個(gè)value的格式傳輸(也就是是以單個(gè)key:[value...]的格式傳輸?shù)?。
//提交參數(shù)設(shè)置
MultiValueMapmap = new LinkedMultiValueMap<>();
map.add("name","魯大師"); ? 如果像傳輸單個(gè)key對(duì)應(yīng)單個(gè)value使用普通的Map傳參即可
HttpEntity? 該類(lèi)是用來(lái)封裝請(qǐng)求的,主要作用就是將請(qǐng)求頭和請(qǐng)求體封裝在一起成為一個(gè)請(qǐng)求實(shí)體 T用來(lái)指定用來(lái)封裝參數(shù)的容器的類(lèi)型。
//組裝請(qǐng)求體
HttpEntity>request = new HttpEntity<>(map, httpHeaders); 通過(guò)上述介紹后,我們就可以自己封裝一個(gè)以form形式提交參數(shù)的POST請(qǐng)求了。
@Test
void contextLoads() {//請(qǐng)求地址
String url = "https://httpbin.org/post";
//設(shè)置請(qǐng)求頭, x-www-form-urlencoded格式的數(shù)據(jù)
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//提交參數(shù)設(shè)置
MultiValueMapmap = new LinkedMultiValueMap<>();
map.add("name","魯大師");
//組裝請(qǐng)求體
HttpEntity>request = new HttpEntity<>(map, httpHeaders);
//發(fā)送post請(qǐng)求并打印結(jié)果 以String類(lèi)型接收響應(yīng)結(jié)果JSON字符串
String s = restTemplate.postForObject(url, request, String.class);
System.out.println(s);
} 
? 通過(guò)攔截器攔截了請(qǐng)求并對(duì)請(qǐng)求頭進(jìn)行拆包,可以發(fā)現(xiàn)ContentType已經(jīng)被修改成了x-www-form-urlencoded格式了。
?PUT請(qǐng)求的方法只有一類(lèi)
void put()
PUT()? 使用方法與postForEntity()參數(shù)基本一致,只是put方法沒(méi)有返回值(也就不必去設(shè)置響應(yīng)內(nèi)容的類(lèi)型了)。
@Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/put";
User user = new User();
user.setName("魯大師");
restTemplate.put(url,user);
}
? 與PUT一樣,DELETE方法只有一類(lèi)
void delete()
delete()?delete()可以指定url中的中的參數(shù),但是RestTemplate的delete()方法是不支持上傳requestBody的。
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/delete";
restTemplate.delete(url);
}?HEADER也只有一類(lèi)方法
public HttpHeaders headForHeaders()
? 主要用來(lái)發(fā)送請(qǐng)求獲取響應(yīng)頭部信息,但是像DELETE、PUT這類(lèi)沒(méi)有響應(yīng)的方法,是不能使用該方法的(因?yàn)闆](méi)有響應(yīng)也就沒(méi)有響應(yīng)頭了)。
@Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/get";
HttpHeaders httpHeaders = restTemplate.headForHeaders(url);
System.out.println(httpHeaders);
}
public SetoptionsForAllow()
? 該方法的主要用來(lái)判斷該服務(wù)地址,能夠使用那種方法去執(zhí)行
@Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/get";
SethttpMethods = restTemplate.optionsForAllow(url);
System.out.println(httpMethods);
} 
ResponseEntity exchange()
? 該接口與其他接口不同
- 該方法允許用戶(hù)指定請(qǐng)求的方法(
get,post,put等)- 可以在請(qǐng)求中增加body以及頭信息,其內(nèi)容通過(guò)參數(shù)
HttpEntity>requestEntity描述exchange支持’含參數(shù)的類(lèi)型(即泛型)'作為返回類(lèi)型,該特性通過(guò)ParameterizedTypeReferenceresponseType描述
? 該方法支持五個(gè)參數(shù)
- 第一個(gè)是服務(wù)地址
- 第二個(gè)是請(qǐng)求方法
- 第三個(gè)是寫(xiě)入的請(qǐng)求實(shí)體
- 第四個(gè)是響應(yīng)內(nèi)容的類(lèi)型
- 第五個(gè)是擴(kuò)展模板的變量或包含
URI模板變量的映射
@Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/post";
User user = new User();
user.setName("彭于晏");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntityuserHttpEntity = new HttpEntity<>(user, httpHeaders);
ResponseEntity ? 上述代碼模擬了一個(gè)簡(jiǎn)單的POST請(qǐng)求 可以理解為可以動(dòng)態(tài)的指定請(qǐng)求方法和請(qǐng)求實(shí)體的一個(gè)方法。
響應(yīng)實(shí)體

T execute()
? 該方法就是執(zhí)行請(qǐng)求的方法,我們可以發(fā)現(xiàn)上述的所有方法的最后執(zhí)行都是調(diào)用的該方法執(zhí)行,所以他在RestTemplate中十分重要
? 該方法有五個(gè)參數(shù)
- 服務(wù)地址
- 請(qǐng)求的方法
- 準(zhǔn)備請(qǐng)求的對(duì)象(
requestCallback)- 從響應(yīng)中提取返回值的對(duì)象
- 擴(kuò)展模板的變量或包含
URI模板變量的映射
execute()
@Override
@Nullable
publicT execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractorresponseExtractor, Object... uriVariables) throws RestClientException {URI expanded = getUriTemplateHandler().expand(url, uriVariables);
return doExecute(expanded, method, requestCallback, responseExtractor);
}
? 通過(guò)上述源碼我們可以發(fā)現(xiàn)execute()方法只是將我們傳入的String類(lèi)型的URL轉(zhuǎn)換為了URL類(lèi)型,最后執(zhí)行請(qǐng)求是由doExecute()方法
doExecute()? 這里需要了解兩個(gè)類(lèi):RequestCallback和ResPonseExtractor
?RequestCallback: 用于操作請(qǐng)求頭和body,在請(qǐng)求發(fā)出前執(zhí)行。不需要關(guān)心關(guān)閉請(qǐng)求或處理錯(cuò)誤:這都將由RestTemplate處理。
? 該接口有兩個(gè)實(shí)現(xiàn)類(lèi):
?
?ResPonseExtractor: 解析HTTP響應(yīng)的數(shù)據(jù),而且不需要擔(dān)心異常和資源的關(guān)閉。
? 該接口在RestTemplate中同樣有兩個(gè)實(shí)現(xiàn)類(lèi):
HeadersExtractor | 提取響應(yīng)HttpHeaders的響應(yīng)提取器。直接提取響應(yīng)體中的響應(yīng)頭 | |
|---|---|---|
ResponseEntityResponseExtractor | HttpEntity的響應(yīng)提取器。可以獲取響應(yīng)實(shí)體里面包括響應(yīng)頭,響應(yīng)體等。具體請(qǐng)查看HttpEntity |
@Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/post";
User user = new User();
user.setName("彭于晏");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntityuserHttpEntity = new HttpEntity<>(user, httpHeaders);
ResponseEntity 
URI模板變量的映射我們來(lái)簡(jiǎn)單看一下這個(gè)參數(shù),我們知道請(qǐng)求傳參可以通過(guò)url拼接參數(shù)的方式傳參,拼接參數(shù)也分為兩種:
- 路徑中嵌入占位的格式(
http://httpbin.org/{1}/post)也叫模板映射- 末尾添加
Key-value格式(http://httpbin.org/post?name="彭于晏")即擴(kuò)展模板的變量
key-value的格式拼接在URL后(通俗的說(shuō)就是這樣設(shè)置的變量會(huì)跟著URL路徑后面)?http://httpbin.org/post?name="彭于晏"
@Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/get";
HashMapmap = new HashMap<>();
map.put("name","彭于晏");
Object forObject = restTemplate.getForObject(url, Object.class, map);
System.out.println(forObject);
} @Test
void contextLoads() {//請(qǐng)求地址
String url = "http://httpbin.org/{2}/get";
HashMapmap = new HashMap<>();
Object forObject = restTemplate.getForObject(url, Object.class, 99);
System.out.println(forObject);
} 
spring cloud 做微服務(wù)時(shí)關(guān)于RestTemplate中的各種請(qǐng)求方法的使用總結(jié)_DWT_CCFK的博客-博客
RestTemplate 詳解 - 知乎 (zhihu.com)
RestTemplate使用教程 - 簡(jiǎn)書(shū) (jianshu.com)
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)頁(yè)名稱(chēng):RestTemplate-創(chuàng)新互聯(lián)
轉(zhuǎn)載來(lái)源:http://chinadenli.net/article22/gegcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、自適應(yīng)網(wǎng)站、定制開(kāi)發(fā)、網(wǎng)站策劃、建站公司、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容