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 。