RestTemplate 是 Spring 提供的用於訪問Rest服務的客戶端,RestTemplate 提供了多種便捷訪問遠程Http服務的方法,它簡化了與 http 服務的通訊方式,統一了 RESTful 的標準,封裝了 http 連接, 咱們只須要傳入 url 及返回值類型便可。相較於以前經常使用的 HttpClient,RestTemplate 是一種更優雅的調用 RESTful 服務的方式。默認狀況下,RestTemplate 默認依賴 jdk 的HTTP鏈接工具(HttpURLConnection),若是有須要的話也能夠經過setRequestFactory方法替換爲例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。java
該模板類的主要切入點爲如下幾個方法(其根據HTTP的六個方法制定六個主要方法)web
HTTPMethod | RestTemplate Method | 說明 |
---|---|---|
Post | postForLocation | POST 數據到一個URL,返回新建立資源的URL |
postForEntity | POST 數據到一個URL,返回包含一個對象的ResponseEntity | |
postForObject | POST 數據到一個URL,返回根據響應體匹配造成的對象 | |
Get | getForObject | 發送一個HTTP GET請求,返回的請求體將映射爲一個對象 |
getForEntity | 發送一個HTTP GET請求,返回的ResponseEntity包含了響應體所映射成的對象 | |
Delete | delete | |
head | headForHeaders | |
put | put | |
any | exchange | |
execute | 全部的get、post、delete、put、options、head、exchange方法最終調用的都是excute方法 |
RestTemplate是 spring 的一個 rest 客戶端,在 spring-web 這個包下,spring boot的依賴以下:spring
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
RestTemplate只是對其它Rest客戶端的一個封裝,自己並無本身的實現。在沒有第三方依賴的狀況下其默認實現是HttpURLConnection(集成了URLConnection),這是JDK自帶的REST客戶端實現。如今來看下其它最經常使用的幾種客戶端的引入apache
SimpleClientHttpRequestFactory(封裝URLConnection) HttpComponentsClientHttpRequestFactory(封裝HttpClient) OkHttp3ClientHttpRequestFactory(封裝OKHttp)
其切換與使用也很簡單,在pom中引入相應依賴併發
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> </dependency>
在Config中的配置:app
package org.dllwh.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); return restTemplate; } @Bean("urlConnection") public RestTemplate urlConnectionRestTemplate() { RestTemplate restTemplate = new RestTemplate(new SimpleClientHttpRequestFactory()); return restTemplate; } @Bean("httpClient") public RestTemplate httpClientRestTemplate() { RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory()); return restTemplate; } @Bean("OKHttp3") public RestTemplate OKHttp3RestTemplate() { RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory()); return restTemplate; } }
使用的時候通常都會只選擇其中的一種,因此上面的幾種配置任選其一。這裏僅僅只是演示說明socket
RestTemplate前先得作一些初始化處理,好比指定http客戶端工廠類、設置超時時間、響應參數轉換器等。以 HttpComponents 爲例說明。函數
package org.dllwh.config; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import org.apache.http.Header; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.TrustStrategy; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate; import lombok.extern.slf4j.Slf4j; @Slf4j @Configuration public class RestTemplateConfig { /** 創建鏈接的超時時間 */ private static int connectTimeout = 20000; /** 鏈接不夠用的等待時間 */ private static int requestTimeout = 20000; /** 每次請求等待返回的超時時間 */ private static int socketTimeout = 30000; /** 每一個主機最大鏈接數 */ private static int defaultMaxPerRoute = 100; /** 最大鏈接數 */ private static int maxTotalConnections = 300; @Bean public RestTemplate buildRestTemplate(ClientHttpRequestFactory factory) { RestTemplate restTemplate = new RestTemplate(factory); restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); return restTemplate; } /** * @方法描述:建立HTTP客戶端工廠 * @return */ @Bean public HttpComponentsClientHttpRequestFactory createFactory() { // httpClient鏈接配置 SSLContextBuilder builder = new SSLContextBuilder(); try { TrustStrategy acceptingTrustStrategy = new TrustStrategy() { public boolean isTrusted(X509Certificate[] chain, String authType) { return true; } }; builder.loadTrustMaterial(null, acceptingTrustStrategy); } catch (Exception e) { log.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); } SSLConnectionSocketFactory socketFactory = null; try { socketFactory = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE); } catch (KeyManagementException | NoSuchAlgorithmException e) { log.error("Pooling Connection Manager Initialisation failure because of " + e.getMessage(), e); } // 註冊http和https請求 Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", socketFactory).build(); // 開始設置鏈接池 PoolingHttpClientConnectionManager phccm = new PoolingHttpClientConnectionManager(registry); // 最大鏈接數 phccm.setMaxTotal(maxTotalConnections); // 同路由併發數 phccm.setDefaultMaxPerRoute(defaultMaxPerRoute); HttpClientBuilder httpClientBuilder = HttpClients.custom(); httpClientBuilder.setSSLSocketFactory(socketFactory); httpClientBuilder.setConnectionManager(phccm); httpClientBuilder.setConnectionManagerShared(true); // 重試次數,默認是3次,沒有開啓 httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 保持長鏈接配置,須要在頭添加Keep-Alive httpClientBuilder.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE); List<Header> headers = new ArrayList<>(); headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36")); headers.add(new BasicHeader("Connection", "keep-alive")); httpClientBuilder.setDefaultHeaders(headers); CloseableHttpClient httpClient = httpClientBuilder.build(); // httpClient鏈接配置,底層是配置RequestConfig HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setHttpClient(httpClient); // 鏈接超時 factory.setConnectTimeout(connectTimeout); // 數據讀取超時時間,即SocketTimeout factory.setReadTimeout(socketTimeout); // 鏈接不夠用的等待時間,不宜過長,必須設置,好比鏈接不夠用時,時間過長將是災難性的 factory.setConnectionRequestTimeout(requestTimeout); // 緩衝請求數據,默認值是true。經過POST或者PUT大量發送數據時,建議將此屬性更改成false,以避免耗盡內存。 factory.setBufferRequestBody(false); return factory; } }
getForEntity() 的返回值類型 ResponseEntity,經過源碼能夠看到它繼承了 HttpEntity ,封裝了返回的響應信息,包括 響應狀態、響應頭、響應體等,獲取Http請求的所有信息。spring-boot
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException; <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;
ResponseEntity response = restTemplate.getForEntity("http://localhost:8081/server",String.class); response.getHeaders(); //響應頭 response.getStatusCode(); //響應碼 response.getBody(); //響應體,即前面的result
Map map = new HashMap(); map.put("1", "hello"); map.put("2", "world"); String result = restTemplate.getForObject("http://localhost:8081/server?param1={1}¶m2={2}", String.class, map);
String result = restTemplate.getForObject("http://localhost:8081/server?param1={1}¶m2={2}", String.class, "hello", "world");
getForObject 和 getForEntity 用法幾乎相同,其實是對getForEntity函數的進一步封裝,返回值返回的是 響應體,省去了咱們 再去 getBody()。工具
postForObject指post請求,並返回一個Object對象
String response = restTemplate.postForObject("http://localhost:8081/server?param1={1}¶m2={2}", null, String.class, "hello", "world");
postForObject除了第2個參數爲null,其它地方用法和getForObject是如出一轍的。可是post請求傳參一般不是寫在url上實現的,而是放在請求體中。此時,就須要使用第2個參數來傳參,同時可省略第4個參數的url傳參
Map map = new HashMap(); map.put("param1", "hello"); map.put("param2", "world"); String response = restTemplate.postForObject("http://localhost:8081/server", map, String.class);
public String server(@RequestBody Map map,String param1,String param2)
<T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables) throws RestClientException; <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException; <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;
在RestTemplate中,PUT請求能夠經過put方法調用,put方法的參數和前面介紹的postForEntity方法的參數基本一致,只是put方法沒有返回值而已
@RequestMapping("put") public void put() { restTemplate.put("http://http://localhost:8081/server/put/?userName={1}", '獨淚了無痕'); }
delete請求咱們能夠經過delete方法調用來實現
@RequestMapping("delete") public void delete() { restTemplate.delete("http://localhost:8081/server/delete/{1}", 100); }
exchange()方法跟上面的getForObject()、getForEntity()、postForObject()、postForEntity()等方法不一樣之處在於它能夠指定請求的HTTP類型。
須要注意的一點是對於返回結果爲204 no content,這種沒有返回值的請求,RestTemplate會拋錯,有須要的話可使用httpClient的fluent
excute() 的用法與 exchange() 大同小異了,它一樣能夠指定不一樣的 HttpMethod,不一樣的是它返回的對象是響應體所映射成的對象 ,而不是 ResponseEntity 。