SpringBoot 学习之RestTemplate

前言

概述

  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方法

对外开放的接口

对外开放的接口

  • [x] 在内部,RestTemplate默认使用HttpMessageConverter实例将HTTP消息转换成POJO或者从POJO转换成HTTP消息

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>

初始化RestTemplate

 在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;
	}
}

GET请求

getForEntity

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
  • [ ] 第1个参数:要调用的服务的地址
  • [ ] 第2个参数:表示但愿返回的body类型
  • [ ] 第3个以及之后参数:表示请求参数
  • 可使用map来封装请求参数,并做为getForObject的第三个参数,同时修改url以下,map中的"1"会替换url中的{1},"2"会替换url中的{2}
Map map = new HashMap();
map.put("1", "hello");
map.put("2", "world");
String result = restTemplate.getForObject("http://localhost:8081/server?param1={1}&param2={2}",
		String.class, map);
  • 也能够直接将要传递的值放到getForObject方法的参数结尾,数量不限,它会按顺序替换{1}和{2}
String result = restTemplate.getForObject("http://localhost:8081/server?param1={1}&param2={2}",
		String.class, "hello", "world");

getForObject

 getForObject 和 getForEntity 用法几乎相同,其实是对getForEntity函数的进一步封装,返回值返回的是 响应体,省去了咱们 再去 getBody()。工具

POST请求

postForObject

postForObject指post请求,并返回一个Object对象

String response = restTemplate.postForObject("http://localhost:8081/server?param1={1}&param2={2}",
		null, String.class, "hello", "world");
  • [ ] 第1个参数就是getForObject第1个参数。
  • [ ] 第2个参数为null,其实是HttpEntity
  • [ ] 第3个参数就是getForObject第2个参数
  • [ ] 第4个及之后的参数就是getForObject第3个及之后的参数

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);
  • [x] 注意,服务端端接收不一样参数时,语法也有所不一样
public String server(@RequestBody Map map,String param1,String param2)

postForEntity

<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;

postForLocation

PUT请求

 在RestTemplate中,PUT请求能够经过put方法调用,put方法的参数和前面介绍的postForEntity方法的参数基本一致,只是put方法没有返回值而已

@RequestMapping("put")
public void put() {
    restTemplate.put("http://http://localhost:8081/server/put/?userName={1}", '独泪了无痕');
}

DELETE请求

 delete请求咱们能够经过delete方法调用来实现

@RequestMapping("delete")
public void delete() {
    restTemplate.delete("http://localhost:8081/server/delete/{1}", 100);
}

Exchange请求

 exchange()方法跟上面的getForObject()、getForEntity()、postForObject()、postForEntity()等方法不一样之处在于它能够指定请求的HTTP类型。

须要注意的一点是对于返回结果为204 no content,这种没有返回值的请求,RestTemplate会抛错,有须要的话可使用httpClient的fluent

Excute请求

excute() 的用法与 exchange() 大同小异了,它一样能够指定不一样的 HttpMethod,不一样的是它返回的对象是响应体所映射成的对象 ,而不是 ResponseEntity 。

Excute方法的调用过程

相关文章
相关标签/搜索