restTemplate配置及使用
1 場景
java開發(fā)中,使用http連接,訪問第三方網(wǎng)絡(luò)接口
,通常使用的連接工具為HttpClient
和OKHttp
。
這兩種連接工具,使用起來比較復(fù)雜
,新手容易出問題。如果使用spring框架,可以使用restTemplate
來進(jìn)行http連接請求。
restTemplate默認(rèn)的連接方式是java中的HttpConnection
,可以使用ClientHttpRequestFactory
指定不同的HTTP連接方式。
2 依賴
maven依賴如下:
作者:水煮魚又失敗了
一、什么是RestTemplate
??????? RestTemplate 是從 Spring3.0 開始支持的一個 HTTP 請求工具,它提供了常見的REST請求方案的模版,例如 GET 請求、POST 請求、PUT 請求、DELETE 請求以及一些通用的請求執(zhí)行方法 exchange 以及 execute。RestTemplate 繼承自 InterceptingHttpAccessor 并且實現(xiàn)了 RestOperations 接口,其中 RestOperations 接口定義了基本的 RESTful 操作,這些操作在 RestTemplate 中都得到了實現(xiàn)。
??????? 傳統(tǒng)情況下在java代碼里訪問Restful服務(wù),一般使用Apache的HttpClient。不過此種方法使用起來太繁瑣。Spring提供了一種簡單便捷的模板類RestTemplate來進(jìn)行操作:
定義一個簡單的例子:
??? @RestController
??? public class TestController
??? {
??????? @RequestMapping(value = "testPost", method = RequestMethod.POST)
??????? public ResponseBean testPost(@RequestBody RequestBean requestBean)
??????? {
??????????? ResponseBean responseBean = new ResponseBean();
??????????? responseBean.setRetCode("0000");
??????????? responseBean.setRetMsg("succ");
??? ?
??????????? return responseBean;
??????? }
??? }
使用RestTemplate訪問該服務(wù):
??????????? //請求地址
??????????? String url = "http://localhost:8080/testPost";
??????????? //入?yún)?br/>??????????? RequestBean requestBean = new RequestBean();
??????????? requestBean.setTest1("1");
??????????? requestBean.setTest2("2");
??????????? requestBean.setTest3("3");
??? ?
??????????? RestTemplate restTemplate = new RestTemplate();
??????????? ResponseBean responseBean = restTemplate.postForObject(url, requestBean, ResponseBean.class);
使用restTemplate訪問restful接口非常的簡單粗暴無腦。(url, requestBean, ResponseBean.class)這三個參數(shù)分別代表 請求地址、請求參數(shù)、HTTP響應(yīng)轉(zhuǎn)換被轉(zhuǎn)換成的對象類型。
二、RestTemplate 添加請求頭headers和請求體body
??? //headers & cookie
??? HttpHeaders headers = new HttpHeaders();
??? headers.setContentType(MediaType.APPLICATION_JSON);
??? ?
??? headers.add("basecret", config.getBasecret());
??? headers.add("baid", config.getBaid());
??? ?
??? List<String> cookies = new ArrayList<>();
??? cookies.add("COOKIE_USER" + Strings.nullToEmpty(config.getCookie()));
??? headers.put(HttpHeaders.COOKIE, cookies);
(1)POST請求
1、 調(diào)用postForObject方法?? 2、使用postForEntity方法? 3、調(diào)用exchange方法
??? postForObject和postForEntity方法的區(qū)別主要在于可以在postForEntity方法中設(shè)置header的屬性,當(dāng)需要指定header的屬性值的時候,使用postForEntity方法。exchange方法和postForEntity類似,但是更靈活,exchange還可以調(diào)用get請求。使用這三種方法傳遞參數(shù),Map不能定義為以下兩種類型
Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> paramMap = new LinkedHashMap<String, Object>();
把Map類型換成LinkedMultiValueMap后,參數(shù)成功傳遞到后臺
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
??? MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
??? paramMap.add("dt", "20190225");
??? ?
??? // 1、使用postForObject請求接口
??? String result = template.postForObject(url, paramMap, String.class);
??? ?
??? // 2、使用postForEntity請求接口
??? HttpHeaders headers = new HttpHeaders();
??? HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(paramMap,headers);
??? ResponseEntity<String> response2 = template.postForEntity(url, httpEntity, String.class);
??? ?
??? // 3、使用exchange請求接口
??? ResponseEntity<String> response3 = template.exchange(url, HttpMethod.POST, httpEntity, String.class);
如果post請求體是個Json的表單
??????????? //JSONObject userInfo = new JSONObject();
??????????? Map<String, Object> userInfo = Maps.newHashMap();
??????????? userInfo.put("phone", accountForm.getPhone());
??????????? userInfo.put("job", accountForm.getJob());
??????????? userInfo.put("email", accountForm.getEmail());
??? ?
??????????? Map<String, Object> postBody = Maps.newHashMap();
??????????? postBody.put("userInfo", userInfo);
??? ?
??????????? HttpEntity<Map> requestEntity = new HttpEntity<>(postBody, headers);
??? ?
???????????? try {
???????????????? ResponseEntity<String> result = restTemplate.postForEntity(config.getCreateWithAuthUrl(), requestEntity, String.class);
???????????????? JsonNode jsonNode = JsonUtils.toJsonNode(result.getBody());
???????????????? if (jsonNode.get("errno").asInt() == 200 || jsonNode.get("errno").asInt() == 505) {
???????????????????? return true;
???????????????? }
??? ?
??????????? } catch (Exception e) {
??????????????? logger.error(e.getMessage(), e);
??????????? }
(2)GET請求
如果是get請求,又想要把參數(shù)封裝到map里面進(jìn)行傳遞的話,Map需要使用HashMap,且url需要使用占位符,如下
??? RestTemplate restTemplate2 = new RestTemplate();
??? String url = "http://127.0.0.1:8081/interact/getData?dt={dt}&ht={ht}";
????????? ?
??? // 封裝參數(shù),這里是HashMap
??? Map<String, Object> paramMap = new HashMap<String, Object>();
??? paramMap.put("dt", "20190225");
??? paramMap.put("ht", "10");
??? ?
??? //1、使用getForObject請求接口
??? String result1 = template.getForObject(url, String.class, paramMap);
??? System.out.println("result1====================" + result1);
??? ?
??? //2、使用exchange請求接口
??? HttpHeaders headers = new HttpHeaders();
??? headers.set("id", "lidy");
??? HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(null,headers);
??? ResponseEntity<String> response2 = template.exchange(url, HttpMethod.GET, httpEntity, String.class,paramMap);
三、請求示例:
1、GET
??? private static void getEmployees(){
??????? final String uri = "http://localhost:8080/springrestexample/employees";
??????? ?
??????? RestTemplate restTemplate = new RestTemplate();
??????? String result = restTemplate.getForObject(uri, String.class);
??????? ?
??????? System.out.println(result);
??? }
2、使用RestTemplate定制HTTP頭文件
??? private static void getEmployees(){
??????? final String uri = "http://localhost:8080/springrestexample/employees";
??????? ?
??????? RestTemplate restTemplate = new RestTemplate();
??????? ?
??????? HttpHeaders headers = new HttpHeaders();
??????? headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
??????? HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
??????? ?
??????? ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
??????? ?
??????? System.out.println(result);
??? }
3、Get請求獲取響應(yīng)為一個對象
?
4、URL 參數(shù)
?
5、POST
???
6、Submit Form Data
?
?
7、PUT
?
??????? EmployeeVO updatedEmployee = new EmployeeVO(2, "New Name", "Gilly", "test@email.com");
??????? ?
??????? RestTemplate restTemplate = new RestTemplate();
??????? restTemplate.put ( uri, updatedEmployee, params);
??? }
8、Simple PUT
9、DELETE
??? private static void deleteEmployee(){
??????? final String uri = "http://localhost:8080/springrestexample/employees/{id}";
????????
10、發(fā)送帶header的Post請求
??? // header填充
? ew JSONObject();
??? json.put("oldMobile", mobile);
??? json.put("newMobile", form.getNewMobile());
??? HttpEntity<String> request = new HttpEntity<String>(json.toString(), headers);
??? // 一個單例的restTemplate
??? RestTemplate restTemplate = HttpInvoker.getRestTemplate();
??? // 發(fā)送請求
??? ResponseEntity<String> response = restTemplate.postForEntity(whiteListURL, request, String.class);
??????????? String url = prometheusServer + api;
??????????? MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
??????????? // 查詢參數(shù)
???????
11、發(fā)送帶header的Get請求
???????? /**
???????? * 帶header的GET請求
???????? */
??????
??????????????????? new HttpEntity<String>(headers),
??????????????????? UserBean.class,
??????????????????? userId);
??????????? logger.info("response={}", JSON.toJSONString(response.getBody()));
??????? }
??? private static void getEmployees(){
??????? final String uri = "http://localhost:8080/springrestexample/employees";
??????? RestTemplate restTemplate = new RestTemplate();
??????? HttpHeaders headers = new HttpHeaders();
??????? headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
??????? HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
??????? ResponseEntity<String> result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
??????? System.out.println(result);
??? }
?
————————————————
溫娉哲」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
背景
這段時間自己做的項目中需要調(diào)用服務(wù)提供者的服務(wù)(接口),具體就是:我這邊需要將頁面所輸入的
Groovy 腳本代碼傳給別人提供的服務(wù)接口,然后那邊返回腳本編譯的結(jié)果給我,我需要將編譯結(jié)果展示在頁面,用的就是 RestTemplate
了,那 RestTemplate 是什么呢?簡單說就是:簡化了發(fā)起 HTTP 請求以及處理響應(yīng)的過程,并且支持 REST 。下文就稍微總結(jié)下。
如何使用
先講講如何使用吧,我項目是 SpringBoot 項目,可以在啟動類中加入:
@Beanpublic RestTemplate restTemplate() {
?return new RestTemplate();}
然后在 Controller 層中引入:
@Autowiredprivate RestTemplate restTemplate;
接下來就可以在 Controller 中各個方法中使用 restTemplate 了,但是 restTemplate 里面有什么方法呢?
RestTemplate 內(nèi)部方法
從圖中 RestTemplate 可以看到有很多方法,我們可以提取出主要的幾種方法是:
GET
POST
PUT
DELETE
HEAD
OPTIONS
EXCHANGE
EXECUTE
圖片中依然可以知道 RestTemplate 類中的方法主要是來自接口 RestOperations,下面我們具體看看這些方法里面的具體實現(xiàn)與該如何使用。
Get 方法
在 RestTemplate 中,發(fā)送一個 GET 請求,我們可以通過如下兩種方式:
getForEntity
getForEntity 方法的返回值是一個ResponseEntity<T>
,ResponseEntity<T>
是 Spring 對 HTTP 請求響應(yīng)的封裝,包括了幾個重要的元素,如響應(yīng)碼、contentType、contentLength、響應(yīng)消息體等。比如下面一個例子:
@RequestMapping("/gethello")public String getHello() {
? ?ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class);
? ?String body = responseEntity.getBody();
? ?HttpStatus statusCode = responseEntity.getStatusCode();
? ?int statusCodeValue = responseEntity.getStatusCodeValue();
? ?HttpHeaders headers = responseEntity.getHeaders();
? ?StringBuffer result = new StringBuffer();
? ?result.append("responseEntity.getBody():").append(body).append("<hr>")
? ? ? ? ? ?.append("responseEntity.getStatusCode():").append(statusCode).append("<hr>")
? ? ? ? ? ?.append("responseEntity.getStatusCodeValue():").append(statusCodeValue).append("<hr>")
? ? ? ? ? ?.append("responseEntity.getHeaders():").append(headers).append("<hr>");
? ?return result.toString();}
關(guān)于這段代碼,說如下幾點:
getForEntity 的第一個參數(shù)為我要調(diào)用的服務(wù)的地址,這里我調(diào)用了服務(wù)提供者提供的 /hello 接口,注意這里是通過服務(wù)名調(diào)用而不是服務(wù)地址,如果寫成服務(wù)地址就沒法實現(xiàn)客戶端負(fù)載均衡了。(備注:我項目中需要通過 ConsulClient 去獲取服務(wù)名,然后在去獲取服務(wù)的 IP 和 Port,并把它拼接起來組合成我的服務(wù)地址,所以就沒法實現(xiàn)客戶端的負(fù)載均衡了,如果要是實現(xiàn)負(fù)載均衡,可以在 SpringBoot 啟動類的中加入注解
@LoadBalanced
, 如下:
@Bean@LoadBalancedpublic RestTemplate restTemplate() {
?return new RestTemplate();}
getForEntity 第二個參數(shù) String.class 表示我希望返回的 body 類型是 String
拿到返回結(jié)果之后,將返回結(jié)果遍歷打印出來
有時候我在調(diào)用服務(wù)提供者提供的接口時,可能需要傳遞參數(shù),有兩種不同的方式:
@RequestMapping("/sayhello")public String sayHello() {
? ?ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={1}", String.class, "張三");
? ?return responseEntity.getBody();}@RequestMapping("/sayhello2")public String sayHello2() {
? ?Map<String, String> map = new HashMap<>();
? ?map.put("name", "李四");
? ?ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={name}", String.class, map);
? ?return responseEntity.getBody();}
可以用一個數(shù)字做占位符,最后是一個可變長度的參數(shù),來一 一替換前面的占位符
也可以前面使用 name={name} 這種形式,最后一個參數(shù)是一個 map,map 的 key 即為前邊占位符的名字,map的 value 為參數(shù)值
第一個調(diào)用地址也可以是一個URI而不是字符串,這個時候我們構(gòu)建一個URI即可,參數(shù)神馬的都包含在URI中了,如下:
@RequestMapping("/sayhello3")public String sayHello3() {
? ?UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://HELLO-SERVICE/sayhello?name={name}").build().expand("王五").encode();
? ?URI uri = uriComponents.toUri();
? ?ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
? ?return responseEntity.getBody();}
通過Spring中提供的UriComponents來構(gòu)建Uri即可。
當(dāng)然,服務(wù)提供者不僅可以返回String,也可以返回一個自定義類型的對象,比如我的服務(wù)提供者中有如下方法:
@RequestMapping(value = "/getbook1", method = RequestMethod.GET)public Book book1() {
? ?return new Book("三國演義", 90, "羅貫中", "花城出版社");}
對于該方法我可以在服務(wù)消費者中通過如下方式來調(diào)用:
@RequestMapping("/book1")public Book book1() {
? ?ResponseEntity<Book> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/getbook1", Book.class);
? ?return responseEntity.getBody();}
運行結(jié)果如下:

getForObject
getForObject 函數(shù)實際上是對 getForEntity 函數(shù)的進(jìn)一步封裝,如果你只關(guān)注返回的消息體的內(nèi)容,對其他信息都不關(guān)注,此時可以使用 getForObject,舉一個簡單的例子,如下:
@RequestMapping("/book2")public Book book2() {
? ?Book book = restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
? ?return book;}
POST 方法
在 RestTemplate 中,POST 請求可以通過如下三個方法來發(fā)起:
postForEntity
該方法和get請求中的getForEntity方法類似,如下例子:
@RequestMapping("/book3")public Book book3() {
? ?Book book = new Book();
? ?book.setName("紅樓夢");
? ?ResponseEntity<Book> responseEntity = restTemplate.postForEntity("http://HELLO-SERVICE/getbook2", book, Book.class);
? ?return responseEntity.getBody();}
方法的第一參數(shù)表示要調(diào)用的服務(wù)的地址
方法的第二個參數(shù)表示上傳的參數(shù)
方法的第三個參數(shù)表示返回的消息體的數(shù)據(jù)類型
我這里創(chuàng)建了一個Book對象,這個Book對象只有name屬性有值,將之傳遞到服務(wù)提供者那里去,服務(wù)提供者代碼如下:
@RequestMapping(value = "/getbook2", method = RequestMethod.POST)public Book book2(@RequestBody Book book) {
? ?System.out.println(book.getName());
? ?book.setPrice(33);
? ?book.setAuthor("曹雪芹");
? ?book.setPublisher("人民文學(xué)出版社");
? ?return book;}
服務(wù)提供者接收到服務(wù)消費者傳來的參數(shù)book,給其他屬性設(shè)置上值再返回,調(diào)用結(jié)果如下:

postForObject
如果你只關(guān)注,返回的消息體,可以直接使用postForObject。用法和getForObject一致。
postForLocation
postForLocation 也是提交新資源,提交成功之后,返回新資源的 URI,postForLocation 的參數(shù)和前面兩種的參數(shù)基本一致,只不過該方法的返回值為 URI ,這個只需要服務(wù)提供者返回一個 URI 即可,該 URI 表示新資源的位置。
PUT 方法
在 RestTemplate 中,PUT 請求可以通過 put 方法調(diào)用,put 方法的參數(shù)和前面介紹的 postForEntity 方法的參數(shù)基本一致,只是 put 方法沒有返回值而已。舉一個簡單的例子,如下:
@RequestMapping("/put")public void put() {
? ?Book book = new Book();
? ?book.setName("紅樓夢");
? ?restTemplate.put("http://HELLO-SERVICE/getbook3/{1}", book, 99);}
book對象是我要提交的參數(shù),最后的99用來替換前面的占位符{1}
DELETE 方法

delete 請求我們可以通過 delete 方法調(diào)用來實現(xiàn),如下例子:
@RequestMapping("/delete")public void delete() {
? ?restTemplate.delete("http://HELLO-SERVICE/getbook4/{1}", 100);}
HEADER 方法
返回資源的所有 HTTP headers。
OPTIONS
問可以執(zhí)行哪些方法。
EXCHANGE
與其它接口的不同:
允許調(diào)用者指定HTTP請求的方法(GET,POST,PUT等)
可以在請求中增加body以及頭信息,其內(nèi)容通過參數(shù) HttpEntity<?>requestEntity 描述
exchange支持‘含參數(shù)的類型’(即泛型類)作為返回類型,該特性通過 ParameterizedTypeReferenceresponseType 描述
EXECUTE
細(xì)心的你,不知道有沒有發(fā)現(xiàn)上面所有的方法內(nèi)部返回值都調(diào)用了同一個方法 —— execute 方法。
下面我們來看看:
可以看到,Excute方法只是將 String 格式的 URI 轉(zhuǎn)成了 java.net.URI,之后調(diào)用了doExecute方法。整個調(diào)用過程關(guān)鍵起作用的是 doExecute 方法
doExecute 方法
這里需要了解兩個類: RequestCallback 和 ResponseExtractor

RestTemplate 類中可以看到他們兩的實現(xiàn)類。
RequestCallback :用于操作請求頭和body,在請求發(fā)出前執(zhí)行。
該接口有兩個實現(xiàn)類:

ResponseExtractor:解析HTTP響應(yīng)的數(shù)據(jù),而且不需要擔(dān)心異常和資源的關(guān)閉
上面圖紙這個實現(xiàn)類 ResponseEntityResponseExtractor 的作用是:使用 HttpMessageConverterExtractor 提取 body(委托模式),然后將 body 和響應(yīng)頭、狀態(tài)封裝成 ResponseEntity 對象。
本文作者:Zhisheng Tian
本文來源:RestTemplate 詳解
版權(quán)說明:本文由極樂科技簽約作者原創(chuàng),版權(quán)歸作者所有,轉(zhuǎn)載請注明作者及出處,謝謝!