`

RestTemplate实践

阅读更多


什么是RestTemplate?

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

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

最新实例代码 更新于2015-07-30
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() {

    }

    @PostConstruct
    public static RestTemplate getClient() {
        return restTemplate;
    }

}

使用Httpclient连接池的方式


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.context.annotation.Lazy;
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.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;
import java.util.concurrent.TimeUnit;

/**
 * @title:使用spring的restTemplate替代httpclient工具
 * @author:liuxing
 * @date:2015-05-18 08:48
 */
public class RestClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRestClient.class);

    private static RestTemplate restTemplate;

    static {
        // 长连接保持30秒
        PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
        // 总连接数
        pollingConnectionManager.setMaxTotal(500);
        // 同路由的并发数
        pollingConnectionManager.setDefaultMaxPerRoute(500);

        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setConnectionManager(pollingConnectionManager);
        // 重试次数,默认是3次,没有开启
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, 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) 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,zh;q=0.8,en;q=0.6"));
        headers.add(new BasicHeader("Connection", "keep-alive"));

        httpClientBuilder.setDefaultHeaders(headers);

        HttpClient httpClient = httpClientBuilder.build();

        // httpClient连接配置,底层是配置RequestConfig
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        // 连接超时
        clientHttpRequestFactory.setConnectTimeout(5000);
        // 数据读取超时时间,即SocketTimeout
        clientHttpRequestFactory.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());
        messageConverters.add(new ByteArrayHttpMessageConverter());

        restTemplate = new RestTemplate(messageConverters);
        restTemplate.setRequestFactory(clientHttpRequestFactory);
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());

        LOGGER.info("RestClient初始化完成");
    }

    private RestClient() {

    }

    public static RestTemplate getClient() {
        return restTemplate;
    }

}

使用样例
注意点

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

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

更多使用语法请查看API文档
完整的实例代码

定义一个异常

import org.springframework.core.NestedRuntimeException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;

/**
 * 包装一个RestClient请求时抛出的异常
 *
 * @author :liuxing
 * @since :2015-07-15 21:33
 */
public class RestClientException extends NestedRuntimeException {

    /**
     * 状态码
     */
    private HttpStatus statusCode;
    /**
     * 状态码文本
     */
    private String statusText;
    /**
     * 异常时返回的内容
     */
    private String responseBody;
    /**
     * 返回的头
     */
    private HttpHeaders responseHeaders;

    public RestClientException(Exception exception) {
        super(exception.getMessage(), exception);

        if (exception instanceof HttpServerErrorException) {
            HttpServerErrorException e = (HttpServerErrorException) exception;

            this.statusCode = e.getStatusCode();
            this.statusText = e.getStatusText();
            this.responseBody = e.getResponseBodyAsString();
            this.responseHeaders = e.getResponseHeaders();
        } else if (exception instanceof HttpClientErrorException) {
            HttpClientErrorException e = (HttpClientErrorException) exception;

            this.statusCode = e.getStatusCode();
            this.statusText = e.getStatusText();
            this.responseBody = e.getResponseBodyAsString();
            this.responseHeaders = e.getResponseHeaders();
        } else {
            this.statusText = exception.getMessage();
        }
    }

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

工具集

import com.dooioo.se.commons.Lang;
import com.dooioo.se.utils.RestClientBuilder;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * httpclient工具类,基于httpclient 4.x
 * 不需要设置header的情况:
 * 1.普通的非校验型请求
 * 2.普通的表单请求
 * <p/>
 * 需要设置header的情况:
 * 1.头部带token校验的请求
 * 2.提交json数据的请求
 *
 * @author 刘兴
 * @version V1.0
 * @since 2014-3-7 下午7:48:58
 */
public class RestClient {

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param responseType 返回的数据类型
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, Class<T> responseType, Object... uriVariables) throws RestClientException {
        return exchange(url, method, null, null, responseType, uriVariables);
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param headers      设置的头信息
     * @param responseType 返回的数据类型
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, HttpHeaders headers, Class<T> responseType, Object... uriVariables) throws RestClientException {
        return exchange(url, method, headers, null, responseType, uriVariables);
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param body         要提交的数据
     * @param responseType 返回数据类型
     *                     返回bean时指定Class
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, Object body, Class<T> responseType, Object... uriVariables) throws RestClientException {
        return exchange(url, method, null, body, responseType, uriVariables);
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param httpHeaders  请求头
     * @param body         要提交的数据
     * @param responseType 返回数据类型
     *                     返回bean时指定Class
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, HttpHeaders httpHeaders, Object body, Class<T> responseType, Object... uriVariables) throws RestClientException {
        try {
            HttpEntity<?> requestEntity = new HttpEntity(body, httpHeaders);
            requestEntity = convert(requestEntity);

            if (uriVariables.length == 1 && uriVariables[0] instanceof Map) {
                Map<String, ?> _uriVariables = (Map<String, ?>) uriVariables[0];
                return getClient().exchange(url, method, requestEntity, responseType, _uriVariables).getBody();
            }

            return getClient().exchange(url, method, requestEntity, responseType, uriVariables).getBody();
        } catch (Exception e) {
            throw new RestClientException(e);
        }
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param responseType 返回的数据类型,例:new ParameterizedTypeReference<List<Bean>>(){}
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {
        return exchange(url, method, null, null, responseType, uriVariables);
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param headers      设置的头信息
     * @param responseType 返回的数据类型,例:new ParameterizedTypeReference<List<Bean>>(){}
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, HttpHeaders headers, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {
        return exchange(url, method, headers, null, responseType, uriVariables);
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param body         要提交的数据
     * @param responseType 返回数据类型,例:new ParameterizedTypeReference<List<Bean>>(){}
     *                     返回bean时指定Class
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, Object body, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {
        return exchange(url, method, null, body, responseType, uriVariables);
    }

    /**
     * 执行请求
     *
     * @param url          请求地址
     * @param method       请求方式
     * @param httpHeaders  请求头
     * @param body         要提交的数据
     * @param responseType 返回数据类型,例:new ParameterizedTypeReference<List<Bean>>(){}
     *                     返回bean时指定Class
     * @param uriVariables url自动匹配替换的参数,如url为api/{a}/{b},参数为["1","2"],则解析的url为api/1/2,使用Map参数时,遵循按key匹配
     * @return 结果对象
     * @throws RestClientException RestClient异常,包含状态码和非200的返回内容
     */
    public static <T> T exchange(String url, HttpMethod method, HttpHeaders httpHeaders, Object body, ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {
        try {
            HttpEntity<?> requestEntity = new HttpEntity(body, httpHeaders);
            requestEntity = convert(requestEntity);

            if (uriVariables.length == 1 && uriVariables[0] instanceof Map) {
                Map<String, ?> _uriVariables = (Map<String, ?>) uriVariables[0];
                return getClient().exchange(url, method, requestEntity, responseType, _uriVariables).getBody();
            }

            return getClient().exchange(url, method, requestEntity, responseType, uriVariables).getBody();
        } catch (Exception e) {
            throw new RestClientException(e);
        }
    }

    /**
     * 获得一个RestTemplate客户端
     *
     * @return
     */
    public static RestTemplate getClient() {
        return RestClientBuilder.build();
    }

    /**
     * 获取一个application/x-www-form-urlencoded头
     *
     * @return
     */
    public static HttpHeaders buildBasicFORMHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        return headers;
    }

    /**
     * 获取一个application/json头
     *
     * @return
     */
    public static HttpHeaders buildBasicJSONHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }

    /**
     * 获取一个text/html头
     *
     * @return
     */
    public static HttpHeaders buildBasicHTMLHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_HTML);
        return headers;
    }

    /**
     * 构建一个json头
     *
     * @param arrays
     * @return
     */
    public static HttpHeaders buildJSONHeaders(Object... arrays) {
        if (arrays.length % 2 != 0) {
            throw new RuntimeException("arrays 长度 必须为偶数");
        }

        HttpHeaders headers = buildBasicJSONHeaders();

        for (int i = 0; i < arrays.length; i++) {
            headers.add(Lang.defaultEmptyStr(arrays[i]), Lang.defaultEmptyStr(arrays[++i]));
        }

        return headers;
    }

    /**
     * 对bean对象转表单模型做处理
     *
     * @param requestEntity
     * @return
     */
    private static HttpEntity<?> convert(HttpEntity<?> requestEntity) {
        Object body = requestEntity.getBody();
        HttpHeaders headers = requestEntity.getHeaders();

        if (body == null) {
            return requestEntity;
        }

        if (body instanceof Map) {
            MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
            Map<String, ?> _body = (Map<String, ?>) body;
            for (String key : _body.keySet()) {
                multiValueMap.add(key, MapUtils.getString(_body, key));
            }

            requestEntity = new HttpEntity<>(multiValueMap, headers);
        }

        if (headers == null || !MediaType.APPLICATION_FORM_URLENCODED.equals(headers.getContentType())) {
            return requestEntity;
        }

        if (body instanceof String) {
            return requestEntity;
        }

        if (body instanceof Collection) {
            return requestEntity;
        }

        if (body instanceof Map) {
            return requestEntity;
        }

        MultiValueMap<String, Object> formEntity = new LinkedMultiValueMap<>();

        Field[] fields = body.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            String name = fields[i].getName();
            String value = null;

            try {
                value = BeanUtils.getProperty(body, name);
            } catch (Exception e) {
                e.printStackTrace();
            }

            formEntity.add(name, value);
        }

        return new HttpEntity<>(formEntity, headers);
    }

    public final static Object[] EMPTY_URI_VARIABLES = new Object[]{};

    public final static HttpHeaders EMPTY_HEADERS = new HttpHeaders();

    public final static Map<String, ?> EMPTY_BODY = new HashMap<>(1);

    public final static HttpEntity EMPTY_ENTITY = new HttpEntity(EMPTY_HEADERS);

}

更多

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 here
    if (this.messageConverters != messageConverters) {
            this.messageConverters.clear();
            this.messageConverters.addAll(messageConverters);
    }
}

分享到:
评论

相关推荐

    RestTemplate实现服务间调用demo案例

    本示例将详细解析如何利用RestTemplate进行服务间的调用,帮助开发者理解并实践相关知识。 首先,我们要知道什么是RestTemplate。RestTemplate是Spring提供的一个用于执行RESTful HTTP请求的模板类。它支持GET、...

    RestTemplate如何通过HTTP Basic Auth认证.docx

    RestTemplate 是 Spring 提供的一个用于发送 HTTP 请求的客户端工具,它可以方便地进行 GET、POST 等...在实际开发中,确保遵循安全最佳实践,不要明文传输敏感信息,如密码,而是应该使用安全的认证机制和传输层加密。

    RestTemplate例子

    这篇博客“RestTemplate例子”可能是介绍如何使用`RestTemplate`进行RESTful API调用的实践教程。下面将详细讨论`RestTemplate`的核心概念、用途、使用方法以及其在实际开发中的应用。 `RestTemplate`是Spring的一...

    springRestTemplate

    7. **最佳实践** - 使用 `ResponseEntity` 类来获取完整的 HTTP 响应,包括状态码、头部信息和响应体。 - 使用 MessageConverter 进行数据序列化和反序列化,Spring Boot 默认已经配置了一些常见的转换器,如 ...

    spring rest mvc使用RestTemplate调用

    在Spring MVC框架中,开发RESTful API已经成为标准实践。`RestTemplate`是Spring提供的一种简单易用的HTTP客户端工具,用于发起HTTP请求并与REST服务进行交互。本文将深入探讨`RestTemplate`的使用方法,以及如何在...

    从Eureka到Ribbon、RestTemplate、Hystrix、Feign、zuul一个小例子

    在Spring Cloud生态系统中,Eureka、Ribbon、RestTemplate、Hystrix、Feign和Zuul是构建微服务架构的关键组件。...通过学习和实践这个例子,开发者可以更好地理解和掌握Spring Cloud的核心组件及其相互协作的方式。

    SpringBoot-CallRestApi:使用resttemplate的SpringBoot-CallRestApi

    在Spring Boot应用中,`RestTemplate`是Spring提供的一个强大且灵活的工具,用于执行HTTP客户端请求,如GET、POST等。...如果你深入研究项目中的代码,将有助于你掌握`RestTemplate`的使用技巧和最佳实践。

    Spring Cloud微服务开发实践

    7、RestTemplate 用法详解 8、 服务请求负载均衡 9、声明式服务调用 Feign 10、Feign 中的继承、日志与数据压缩 11、Resilience4j 基本用法详解 12、Resilience4j 在微服务中的应用 13、Micrometer 实现微服务监控 ...

    [课堂课件讲解]Java微服务实践-Spring Boot Web篇(中).pptx

    在 REST 客户端实践中,我们可以使用 Web 浏览器、Apache HttpClient、Spring RestTemplate 等来实现对 RESTful 服务的访问。 Web 浏览器是最常用的 REST 客户端,它可以直接访问 RESTful 服务。Apache HttpClient ...

    http-demo.rar

    《深入理解SpringCloud RestTemplate工程实践》 在现代微服务架构中,通信是核心的一环。Spring Cloud RestTemplate作为Spring框架的一部分,为开发者提供了一种简单而强大的方式来与RESTful服务进行交互。本篇文章...

    using-either-resttemplate:的源代码

    7. **最佳实践** - 使用`RestTemplate`时,考虑使用`RestTemplateBuilder`来创建实例,以便更好地控制其行为。 - 针对特定的REST API,可以创建一个包装类,封装`RestTemplate`的方法,以提高代码可读性和可维护性...

    038-retrieve-file-spring-resttemplate

    六、最佳实践 - 使用Spring Boot时,考虑使用`WebClient`替代`RestTemplate`,因为它提供了更强大的功能和非阻塞I/O支持。 - 为避免内存溢出,大文件下载时可使用流式处理。 - 注意安全性,避免敏感信息泄露。 总结...

    看透Spring MVC源代码分析与实践

    不过,从标题和描述中可以提取出的知识点是关于“Spring MVC”的源代码分析与实践。 Spring MVC是Spring框架的一部分,专门用于构建Web应用程序的一个模型-视图-控制器(MVC)实现。它利用了Spring框架强大的依赖...

    restemplate封装

    在Spring Boot应用中,`RestTemplate` 是一个强大的工具,用于执行HTTP客户端操作,如GET、POST、PUT...在`springRestTemplate`项目中,我们可以看到这样的封装实践,使得与其他RESTful服务的交互变得更加便捷和可控。

    XX大学计算机网络实验报告.docx

    【XX大学计算机网络实验报告】 本实验报告主要围绕着计算机网络中的交换机基本配置展开,旨在让学生掌握桌面网络组建和华为Quidway S...通过这样的实践,学生不仅可以深化理论知识,还能提高动手能力和问题解决能力。

    eureka实践源码.zip

    服务消费者通常使用RestTemplate或者Feign等工具,根据从Eureka获取的服务信息,动态地发起HTTP请求,实现服务间的通信。 在实际操作中,这三个工程启动后,服务提供者会向eureka-demo注册,服务消费者则会从eureka...

    Java EE设计模式:Spring企业级开发最佳实践_JavaEE_企业应用开发_

    《Java EE设计模式:Spring企业级开发最佳实践》是一本深度探讨如何在企业级Java应用程序中有效运用设计模式的著作。这本书聚焦于Spring框架,它作为Java EE领域中最为广泛使用的开源框架之一,极大地简化了企业级...

    聊天室(自己实现HTTP长连接)

    综上所述,这个项目不仅涉及到HTTP协议的基础知识,还涵盖了实时通信的技术选型和实现策略,对于学习网络编程和提升Web应用性能具有很高的实践价值。通过阅读博主分享的源码和工具使用,我们可以深入理解HTTP长连接...

    spring-etcd:基于Spring RestTemplate的etcd v2客户端

    **正文** 在IT行业中,Spring框架是Java应用开发的核心组件,它简化了应用程序的构建和管理。而Etcd是一款分布式键值...通过深入学习和实践这个客户端,开发者可以更好地理解和运用分布式系统中的服务发现和配置管理。

    Rest服务学习

    这是一篇深入了解`RestTemplate`用法和最佳实践的重要资源。 总结,学习REST服务意味着理解REST原则并掌握如何在Spring框架中应用这些原则。`RestTemplate`作为Spring提供的实用工具,大大简化了与REST服务的交互。...

Global site tag (gtag.js) - Google Analytics