什么是RestTemplate?

RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
ClientHttpRequestFactory接口主要提供了两种实现方式

一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。
一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。

使用RestTemplate

Xml配置的方式

请查看RestTemplate源码了解细节,知其然知其所以然!

RestTemplate默认是使用SimpleClientHttpRequestFactory,内部是调用jdk的HttpConnection,默认超时为-1

@Autowired
RestTemplate simpleRestTemplate

@Autowired
RestTemplate restTemplate

基于jdk的spring的RestTemplate

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"><!--方式一、使用jdk的实现--><bean id="ky.requestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory"><property name="readTimeout" value="10000"/><property name="connectTimeout" value="5000"/></bean><bean id="simpleRestTemplate" class="org.springframework.web.client.RestTemplate"><constructor-arg ref="ky.requestFactory"/><property name="messageConverters"><list><bean class="org.springframework.http.converter.FormHttpMessageConverter"/><bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/plain;charset=UTF-8</value></list></property></bean></list></property></bean></beans>

使用Httpclient连接池的方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"default-autowire="byName" default-lazy-init="true"><!--方式二、使用httpclient的实现,带连接池--><bean id="ky.pollingConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager"><!--整个连接池的并发--><property name="maxTotal" value="1000" /><!--每个主机的并发--><property name="defaultMaxPerRoute" value="1000" /></bean><bean id="ky.httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create"><property name="connectionManager" ref="ky.pollingConnectionManager" /><!--开启重试--><property name="retryHandler"><bean class="org.apache.http.impl.client.DefaultHttpRequestRetryHandler"><constructor-arg value="2"/><constructor-arg value="true"/></bean></property><property name="defaultHeaders"><list><bean class="org.apache.http.message.BasicHeader"><constructor-arg value="User-Agent"/><constructor-arg value="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"/></bean><bean class="org.apache.http.message.BasicHeader"><constructor-arg value="Accept-Encoding"/><constructor-arg value="gzip,deflate"/></bean><bean class="org.apache.http.message.BasicHeader"><constructor-arg value="Accept-Language"/><constructor-arg value="zh-CN"/></bean></list></property></bean><bean id="ky.httpClient" factory-bean="ky.httpClientBuilder" factory-method="build" /><bean id="ky.clientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"><constructor-arg ref="ky.httpClient"/><!--连接超时时间,毫秒--><property name="connectTimeout" value="5000"/><!--读写超时时间,毫秒--><property name="readTimeout" value="10000"/></bean><bean id="restTemplate" class="org.springframework.web.client.RestTemplate"><constructor-arg ref="ky.clientHttpRequestFactory"/><property name="errorHandler"><bean class="org.springframework.web.client.DefaultResponseErrorHandler"/></property><property name="messageConverters"><list><bean class="org.springframework.http.converter.FormHttpMessageConverter"/><bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/plain;charset=UTF-8</value></list></property></bean></list></property></bean></beans>

Bean初始化方式

线程安全的单例(懒汉模式)、静态工具类

基于jdk的spring的RestTemplate

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;import javax.annotation.PostConstruct;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;/*** @title:基于jdk的spring的RestTemplate* @author:liuxing* @date:2015-05-18 09:35*/
@Component
@Lazy(false)
public class SimpleRestClient {private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRestClient.class);private static RestTemplate restTemplate;static {SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();requestFactory.setReadTimeout(5000);requestFactory.setConnectTimeout(5000);// 添加转换器List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));messageConverters.add(new FormHttpMessageConverter());messageConverters.add(new MappingJackson2XmlHttpMessageConverter());messageConverters.add(new MappingJackson2HttpMessageConverter());restTemplate = new RestTemplate(messageConverters);restTemplate.setRequestFactory(requestFactory);restTemplate.setErrorHandler(new DefaultResponseErrorHandler());LOGGER.info("SimpleRestClient初始化完成");}private SimpleRestClient() {}@PostConstructpublic static RestTemplate getClient() {return restTemplate;}}

使用Httpclient连接池的方式

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;import org.apache.http.Header;
import org.apache.http.client.HttpClient;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;/*** 使用spring的restTemplate替代httpclient工具*/
public class RestClient {private static final Logger LOGGER = LoggerFactory.getLogger(RestClient.class);private static RestTemplate restTemplate;private final static Object syncLock = new Object();private static void initRestTemplate() {// 长连接保持30秒PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);// 总连接数pollingConnectionManager.setMaxTotal(1000);// 同路由的并发数pollingConnectionManager.setDefaultMaxPerRoute(1000);HttpClientBuilder httpClientBuilder = HttpClients.custom();httpClientBuilder.setConnectionManager(pollingConnectionManager);// 重试次数,默认是3次,没有开启httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));// 保持长连接配置,需要在头添加Keep-AlivehttpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());//        RequestConfig.Builder builder = RequestConfig.custom();
//        builder.setConnectionRequestTimeout(200);
//        builder.setConnectTimeout(5000);
//        builder.setSocketTimeout(5000);
//
//        RequestConfig requestConfig = builder.build();
//        httpClientBuilder.setDefaultRequestConfig(requestConfig);List<Header> headers = new ArrayList<>();headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));headers.add(new BasicHeader("Accept-Language", "zh-CN"));headers.add(new BasicHeader("Connection", "Keep-Alive"));httpClientBuilder.setDefaultHeaders(headers);HttpClient httpClient = httpClientBuilder.build();// httpClient连接配置,底层是配置RequestConfigHttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);// 连接超时clientHttpRequestFactory.setConnectTimeout(5000);// 数据读取超时时间,即SocketTimeoutclientHttpRequestFactory.setReadTimeout(5000);// 连接不够用的等待时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的clientHttpRequestFactory.setConnectionRequestTimeout(200);// 缓冲请求数据,默认值是true。通过POST或者PUT大量发送数据时,建议将此属性更改为false,以免耗尽内存。// clientHttpRequestFactory.setBufferRequestBody(false);// 添加内容转换器List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));messageConverters.add(new FormHttpMessageConverter());messageConverters.add(new MappingJackson2XmlHttpMessageConverter());messageConverters.add(new MappingJackson2HttpMessageConverter());restTemplate = new RestTemplate(messageConverters);restTemplate.setRequestFactory(clientHttpRequestFactory);restTemplate.setErrorHandler(new DefaultResponseErrorHandler());LOGGER.info("RestClient初始化完成");}private RestClient() {}public static RestTemplate getClient() {if(restTemplate == null){synchronized (syncLock) {if(restTemplate == null){initRestTemplate();}}}return restTemplate;}}

HttpClientUtils


import java.util.Map;import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;/**** 类功能说明:httpclient工具类,基于httpclient 4.x*/
public class HttpClientUtils {private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtils.class);/*** post请求* @param url* @param formParams* @return*/public static String doPost(String url, Map<String, String> formParams) {if (MapUtils.isEmpty(formParams)) {return doPost(url);}try {MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();formParams.keySet().stream().forEach(key -> requestEntity.add(key, MapUtils.getString(formParams, key, "")));return RestClient.getClient().postForObject(url, requestEntity, String.class);} catch (Exception e) {LOGGER.error("POST请求出错:{}", url, e);}return null;}/*** post请求* @param url* @return*/public static String doPost(String url) {try {return RestClient.getClient().postForObject(url, HttpEntity.EMPTY, String.class);} catch (Exception e) {LOGGER.error("POST请求出错:{}", url, e);}return null;}/*** get请求* @param url* @return*/public static String doGet(String url) {try {return RestClient.getClient().getForObject(url, String.class);} catch (Exception e) {LOGGER.error("GET请求出错:{}", url, e);}return null;}}

ErrorHolder
自定义的一个异常结果包装类

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;/*** @title:ErrorHolder* @author:liuxing* @date:2015-06-16 11:01*/
public class ErrorHolder {private HttpStatus statusCode;private String statusText;private String responseBody;private HttpHeaders responseHeaders;public ErrorHolder(HttpStatus statusCode, String statusText, String responseBody) {this.statusCode = statusCode;this.statusText = statusText;this.responseBody = responseBody;}public ErrorHolder(String statusText) {this.statusText = statusText;}public HttpStatus getStatusCode() {return statusCode;}public void setStatusCode(HttpStatus statusCode) {this.statusCode = statusCode;}public String getStatusText() {return statusText;}public void setStatusText(String statusText) {this.statusText = statusText;}public String getResponseBody() {return responseBody;}public void setResponseBody(String responseBody) {this.responseBody = responseBody;}public HttpHeaders getResponseHeaders() {return responseHeaders;}public void setResponseHeaders(HttpHeaders responseHeaders) {this.responseHeaders = responseHeaders;}public static ErrorHolder build(Exception exception) {if (exception instanceof HttpServerErrorException) {HttpServerErrorException e = (HttpServerErrorException) exception;return new ErrorHolder(e.getStatusCode(), e.getStatusText(), e.getResponseBodyAsString());}if (exception instanceof HttpClientErrorException) {HttpClientErrorException e = (HttpClientErrorException) exception;return new ErrorHolder(e.getStatusCode(), e.getStatusText(), e.getResponseBodyAsString());}return new ErrorHolder(exception.getMessage());}
}

使用样例
api里面可以做自动的参数匹配:
如:http://you domainn name/test?empNo={empNo},则下面方法的最后一个参数为数据匹配参数,会自动根据key进行查找,然后替换

API没有声明异常,注意进行异常处理

更多使用语法请查看API文档

ResponseEntity<List<KyArea>> result = RestClient.getClient().exchange(DIVIDE_PLATE_API, HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference<List<KyArea>>() {}, map("empNo", empNo));
List<KyArea> list = result.getBody();ResponseEntity<KyArea> result = RestClient.getClient().exchange(DIVIDE_PLATE_API, HttpMethod.GET, HttpEntity.EMPTY, KyArea.class, map("empNo", empNo));
KyArea kyArea = result.getBody();

更多

RestTemplate API说明和使用参考

http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/web/client/RestTemplate.html

http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/http/client/SimpleClientHttpRequestFactory.html

http://docs.spring.io/spring/docs/4.1.x/javadoc-api/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.html

HttpClient官方示例和参数配置说明

http://hc.apache.org/httpcomponents-client-4.4.x/examples.html

http://hc.apache.org/httpcomponents-client-4.4.x/tutorial/html/index.html

依赖
spring 3.x以上

<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.5.3</version>
</dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.9.13</version>
</dependency>

注意点

1.关于httpclient配置的defaultMaxPerRoute和maxTotal
defaultMaxPerRoute:最大路由并发数,以主机为单位
maxTotal:整个连接池的并发数

例如:
defaultMaxPerRoute为10,maxTotal为100
假设只会访问http://www.baidu.com和http://www.google.com
那么能同时并发到客源的只能是10,房源也是10,整个连接永远不会到100

2.部分方法注意查看源码,默认构造里面会新增常用的数据转换器,spring对jackson比较情有独钟,在解析xml和json时,优先使用jackson

/*** Create a new instance of the {@link RestTemplate} using default settings.* Default {@link HttpMessageConverter}s are initialized.*/
public RestTemplate() {this.messageConverters.add(new ByteArrayHttpMessageConverter());this.messageConverters.add(new StringHttpMessageConverter());this.messageConverters.add(new ResourceHttpMessageConverter());this.messageConverters.add(new SourceHttpMessageConverter<Source>());this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());if (romePresent) {this.messageConverters.add(new AtomFeedHttpMessageConverter());this.messageConverters.add(new RssChannelHttpMessageConverter());}if (jackson2XmlPresent) {messageConverters.add(new MappingJackson2XmlHttpMessageConverter());}else if (jaxb2Present) {this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());}if (jackson2Present) {this.messageConverters.add(new MappingJackson2HttpMessageConverter());}else if (gsonPresent) {this.messageConverters.add(new GsonHttpMessageConverter());}
}/*** Create a new instance of the {@link RestTemplate} based on the given {@link ClientHttpRequestFactory}.* @param requestFactory HTTP request factory to use* @see org.springframework.http.client.SimpleClientHttpRequestFactory* @see org.springframework.http.client.HttpComponentsClientHttpRequestFactory*/
public RestTemplate(ClientHttpRequestFactory requestFactory) {this();setRequestFactory(requestFactory);
}

再看添加转换器的方法外部添加转换器时,this.messageConverters.clear();会先清除已有的,需要注意

/*** Create a new instance of the {@link RestTemplate} using the given list of* {@link HttpMessageConverter} to use* @param messageConverters the list of {@link HttpMessageConverter} to use* @since 3.2.7*/
public RestTemplate(List<HttpMessageConverter<?>> messageConverters) {Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");this.messageConverters.addAll(messageConverters);
}/*** Set the message body converters to use.* <p>These converters are used to convert from and to HTTP requests and responses.*/
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");// Take getMessageConverters() List as-is when passed in hereif (this.messageConverters != messageConverters) {this.messageConverters.clear();this.messageConverters.addAll(messageConverters);}
}

本文转自:http://liuxing.info/2015/05/21/RestTemplate%E5%AE%9E%E8%B7%B5/

Spring RestTemplate 实践相关推荐

  1. Spring RestTemplate中文乱码解决方案

    Spring RestTemplate中文乱码解决方案 参考文章: (1)Spring RestTemplate中文乱码解决方案 (2)https://www.cnblogs.com/accesski ...

  2. java 获取400的错误信息_获取400错误的请求Spring RestTemplate POST

    我想使用POST方法使用Spring Rest web服务.我无法在客户端(网站)访问POJO文件,因此必须在客户端使用JSON并在Web服务中使用POJO.下面是我的代码:获取400错误的请求Spr ...

  3. Spring RestTemplate中几种常见的请求方式GET请求 POST请求 PUT请求 DELETE请求

    Spring RestTemplate中几种常见的请求方式 原文地址: https://blog.csdn.net/u012702547/article/details/77917939 版权声明:本 ...

  4. spring aop实践_使用Spring AOP实现活动记录模式

    spring aop实践 在课堂设计过程中,我们应就每个班级的职责分配做出决定. 如果我们选择的不错,系统将更易于理解,维护和扩展. 我们几乎所有的项目都有一个持久层,即关系数据库,文档存储或仅XML ...

  5. 具有链接资源的Spring RestTemplate

    Spring Data REST是一个了不起的项目,它提供了一些机制来将基于Spring Data的存储库中的资源公开为REST资源. 使用链接资源公开服务 考虑两个简单的基于JPA的实体,课程和教师 ...

  6. 使用Spring RestTemplate和Super类型令牌消费Spring-hateoas Rest服务

    Spring-hateoas为应用程序创建遵循HATEOAS原理的基于REST的服务提供了一种极好的方法. 我的目的不是要展示如何创建服务本身,而是要展示如何将客户端写入服务. 我将要使用的示例服务是 ...

  7. spring RestTemplate用法详解

    spring RestTemplate用法详解 spring 3.2.3 框架参考有说明 21.9 Accessing RESTful services on the Client 转载于:https ...

  8. Spring MVC 实践 - Component

    Spring MVC 实践 标签 : Java与Web Converter Spring MVC的数据绑定并非没有任何限制, 有案例表明: Spring在如何正确绑定数据方面是杂乱无章的. 比如: S ...

  9. Spring MVC 实践 - Base

    Spring MVC 实践 标签 : Java与Web Spring Web MVC Spring-Web-MVC是一种基于请求驱动的轻量级Web-MVC设计模式框架, Spring MVC使用MVC ...

  10. Spring RestTemplate示例

    Spring RestTemplate示例 Spring RestTemplate提供了一种测试RESTful Web服务的便捷方式. 目录[ 隐藏 ] 1 Spring RestTemplate 1 ...

最新文章

  1. 钻进眼球的致盲寄生虫威胁近亿人,却只是生存竞争的失败者
  2. JS基础 -- 枚举对象中的属性
  3. boost::type_erasure::incrementable相关的测试程序
  4. 反思PHP多个字符串函数
  5. Java 文件的拷贝
  6. java gc full gc_Java中full gc什么意思?
  7. 报告一下近期读书情况
  8. 智能贴图样机素材在手,海报逼格马上就有!
  9. 手机里tencent文件夹能删吗_手机内存卡里的tencent这个文件夹可以删吗?
  10. Sublime Text 2 快捷键用法大全(转)
  11. 《数学模型(第五版)》简记
  12. Linux PCI驱动编写
  13. 今天我又发现一个宝藏应用:时光序-个人日程管理应用,记录生活的方方面面!
  14. 什么是工作流?(转贴)
  15. 对数组名取地址 a[ ],a
  16. android auto只能用谷歌地图吗,谷歌独立车载系统 新版Android Auto无需汽车兼容
  17. 审计溯源 | IP-guard终端操作审计,助力高效防控泄密风险
  18. 【翻译1】Multivariate Time Series Forecasting with LSTMs in Keras——PM2.5
  19. EndNote的下载、安装与配置!(绝对保姆级教程)!
  20. Rufus 制作U盘启动盘

热门文章

  1. 爱德泰科普 | 了解单模光纤跳线和多模光纤跳线,看着一篇就够了
  2. 菠萝罐头的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  3. 第九章 贝叶斯信念网络分类
  4. SVN update拒绝访问,clean up失败
  5. logisim数据选择器_【Logisim实验】构建立即数-随机存储器-寄存器的传送
  6. android文件地址,Android文件夹在哪
  7. java栅栏_Java多线程 5.栅栏
  8. “新元宇宙”奇科幻小说原创作品《地球人奇游天球记》第四回飞离地球
  9. 探究网络信息安全问题及防范措施
  10. bzoj3162 独钓寒江雪