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。

RestTemplate是 spring 的一个 rest 客户端,在 spring-web 这个包下,spring boot的依赖如下:

<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客户端实现。现在来看下其它最常用的几种客户端的引入

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前先得做一些初始化处理,比如指定http客户端工厂类、设置超时时间、响应参数转换器等。以 HttpComponents 为例说明。

package com.cxqz.config;
import lombok.extern.slf4j.Slf4j;
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.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContextBuilder;
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 java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

/**
 * resttemplate 配置
 */
@Configuration
@Slf4j
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请求的全部信息。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值