RestTemplate 使用总结

版权声明:欢迎交流、沟通 QQ:983433479 微信:wj983433479 ;努力学习~赚钱养家不是梦。 https://blog.csdn.net/u012881904/article/details/81185231

一、 RestTemplate 简单介绍

estTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
ClientHttpRequestFactory接口主要提供了两种实现方式
一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接,RestTemplate默认是使用SimpleClientHttpRequestFactory,内部是调用jdk的HttpConnection,默认超时为-1;
一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。
RestTemplate配置 可能无法访问 百度一下,查看快照
RestTemplate 深度解析
RestTemplate 使用总结
RestTemplate的设置及使用

这里写图片描述
长连接以保证高性能,RestTemplate 本身也是一个 wrapper 其底层默认是 SimpleClientHttpRequestFactory ,如果要保证长连接, HttpComponentsClientHttpRequestFactory 是个更好的选择,它不仅可以控制能够建立的连接数还能细粒度的控制到某个 server 的连接数,非常方便。在默认情况下,RestTemplate 到某个 server 的最大连接数只有 2, 一般需要调的更高些,最好等于 server 的 CPU 个数,所以通常下建议使用连接池的方式处理RestTeamplate;

配置

1. 基于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>

2. 使用Httpclient连接池的方式(推荐)

<!--使用httpclient的实现,带连接池-->
<!--在httpclient4.3版本后才有-->
<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
    <property name="connectionManager">
        <bean class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
            <!--整个连接池的并发-->
            <property name="maxTotal" value="50"/>
            <!--每个主机的并发-->
            <property name="defaultMaxPerRoute" value="50"/>
        </bean>
    </property>
    <!--开启重试-->
    <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="Content-Type"/>
                <constructor-arg value="text/html;charset=UTF-8"/>
            </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="httpClient" factory-bean="httpClientBuilder" factory-method="build"/>

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <property name="messageConverters">
        <list value-type="org.springframework.http.converter.HttpMessageConverter">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <value>text/html;charset=UTF-8</value>
                </property>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <value>application/json;charset=UTF-8</value>
                </property>
            </bean>
            <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter"/>
        </list>
    </property>
    <property name="requestFactory">
        <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
            <constructor-arg ref="httpClient"/>
            <!--连接时间(毫秒)-->
            <property name="connectTimeout" value="20000"/>
            <!--读取时间(毫秒)-->
            <property name="readTimeout" value="20000"/>
        </bean>
    </property>
</bean>

3. 上面两个配置都是来自博客的分享,下面为项目中使用配置

<?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">
    <!--RestTemplate -->
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter"/>
                <bean
                        class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>application/json;charset=UTF-8</value>
                            <value>application/x-www-form-urlencoded;charset=UTF-8</value>
                            <value>text/json;charset=UTF-8</value>
                            <value>text/html;charset=UTF-8</value><!-- 避免IE出现下载JSON文件的情况 -->
                            <value>application/octet-stream</value>
                        </list>
                    </property>
                </bean>

                <bean
                        class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/plain;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
        <property name="interceptors">
            <list>
                <bean class="com.inteceptor.RestTemplateTraceInterceptor"></bean>
            </list>
        </property>
        <constructor-arg ref="clientHttpRequestFactory"/>
    </bean>


    <bean id="clientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
        <property name="httpClient" ref="httpClient"/>
        <!--连接超时时间,毫秒-->
        <property name="connectTimeout" value="2000"/>
        <!--读写超时时间,毫秒-->
        <property name="readTimeout" value="30000"/>
    </bean>

    <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
        <property name="connectionManager" ref="pollingConnectionManager"/>
        <!--开启重试-->
        <property name="retryHandler">
            <bean class="org.apache.http.impl.client.DefaultHttpRequestRetryHandler">
                <constructor-arg value="2"/>
                <constructor-arg value="true"/>
            </bean>
        </property>
    </bean>
    <bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build"/>

    <bean id="pollingConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
        <!--整个连接池的并发-->
        <property name="maxTotal" value="1000"/>
        <!--每个主机的并发-->
        <property name="defaultMaxPerRoute" value="1000"/>
    </bean>
</beans>

拦截器处理:调用链日志,添加权限Token等等

public class RestTemplateTraceInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {

        //调用服务接口

        TraceContext tc = TraceLocalUtil.getTraceContext();
        if(tc==null){
            TraceRecordGenerator.traceStart();
        }
        URI uri = httpRequest.getURI();
        HttpMethod httpMethod = httpRequest.getMethod();

        TraceRecordGenerator.clientSend("call->" + httpMethod.name() + ":" + uri.toString());
        HttpHeaders httpHeaders = httpRequest.getHeaders();
        tc = TraceLocalUtil.getTraceContext();
        if (tc != null) {
            httpHeaders.set("trace_id", tc.getTraceId());
            httpHeaders.set("rpc_id",tc.getSpanId());
        }
        if( CollectionUtils.isEmpty(httpHeaders.get("Token"))){
            httpHeaders.set("Token",SecurityTool.getIdentityToken(null));
        }

        //调用其他服务,需要将trace_id,rpc_id信息放在头部
        ClientHttpResponse resp = clientHttpRequestExecution.execute(httpRequest, bytes);
        int statusCode = resp.getStatusCode().value();
        if (statusCode >= 200 && statusCode < 400) {
            TraceRecordGenerator.clientReceiveSucceed();
        }
        return resp;
    }
}

三、 使用

一般情况下,调用Rest风格的接口都是有固定的格式的,比如

public class BaseResponse<T> {

    private String code;

    private String message;

    private String msg;

    private T data;
    }

上面的T中可能为分页的信息,也可能不是分页的信息,层层的包装,如下是分页在进行包装;

public class BaseDataModel<T> {

    private int total;

    private int pageSize;

    private int pageNo;

    private List<T> list;
    //总页数
    private int countTotal;

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getPageNo() {
        return pageNo;
    }

    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }

    public int getCountTotal() {
        if(total > 0 && pageSize > 0){
            countTotal = total / pageSize;
            if(total % pageSize != 0){
                countTotal++;
            }
        }
        return countTotal;
    }

    public void setCountTotal(int countTotal) {
        this.countTotal = countTotal;
    }
}

最后假如请求分页的数据可能是组织信息,那么包装后构造的数据形式形如这样的格式;
BaseResponse< BaseDataModel< OrganizationInfo > >
对于这种T参数结果不确定性的处理,通常都是通过泛型参数进行包装,目前Rest服务返回值都是Json字符串数据。fastJson泛型如何转换看这个例子中,很简单的处理泛型参数的问题,对于调用RestTempalte中的方法,如果面对这样的情况我们改如何处理?最好转换成一种通用的数据类信息

Result<User> obj = (Result<User>) JSON.parseObject(js, new TypeReference<Result<User>>(){});

下面两个为FastJson中泛型参数处理的函数

    /**
     * This method deserializes the specified Json into an object of the specified type. This method
     * is useful if the specified object is a generic type. For non-generic objects, use
     * {@link #parseObject(String, Class, Feature[])} instead. If you have the Json in a {@link InputStream} instead of
     * a String, use {@link #parseObject(InputStream, Type, Feature[])} instead.
     *
     * @param <T> the type of the desired object
     * @param json the string from which the object is to be deserialized
     * @param type The specific genericized type of src. You can obtain this type by using the
     * {@link com.alibaba.fastjson.TypeReference} class. For example, to get the type for
     * {@code Collection<Foo>}, you should use:
     * <pre>
     * Type type = new TypeReference&lt;Collection&lt;Foo&gt;&gt;(){}.getType();
     * </pre>
     * @return an object of type T from the string
     */
    @SuppressWarnings("unchecked")
    public static <T> T parseObject(String json, Type type, Feature... features) {
        return (T) parseObject(json, type, ParserConfig.global, DEFAULT_PARSER_FEATURE, features);
    }
/**
     * <pre>
     * String jsonStr = "[{\"id\":1001,\"name\":\"Jobs\"}]";
     * List&lt;Model&gt; models = JSON.parseObject(jsonStr, new TypeReference&lt;List&lt;Model&gt;&gt;() {});
     * </pre>
     * @param text json string
     * @param type type refernce
     * @param features
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T parseObject(String text, TypeReference<T> type, Feature... features) {
        return (T) parseObject(text, type.type, ParserConfig.global, DEFAULT_PARSER_FEATURE, features);
    }

避免直接将数据转换为JSon处理,类似这样的处理方式,对于后续的维护者不太清楚整体的调用的数据结构;

JSONArray jsonArray = JSON.parseObject((String) data).getJSONArray("data")

1. 使用FastJson进行数据转换带统一结构的泛型参数的返回值

    @Override
    public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
            HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {

        RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
        return execute(url, method, requestCallback, responseExtractor, uriVariables);
    }

例如:

ResponseEntity<String> responseEntity = restTemplate.exchange(url, httpMethod, httpEntity
, String.class, args);

使用FastJSon转换泛型参数

/**
     * 这里使用自己通过 FastJson进行数据信息的转换
     *
     * @see ParameterizedTypeReference#getType()
     * @see com.alibaba.fastjson.TypeReference#getType()
     */
    @SuppressWarnings("unchecked")
    public static <T> ResponseEntity<T> exchange(String url, HttpMethod httpMethod
    , HttpHeaders headers, Object body, Type type, Object... args) {
        headers = resolveHttpHeaders(headers);
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(body, headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange(url
        , httpMethod, httpEntity, String.class, args);
        if (responseEntity != null && StringUtils.isNotEmpty(responseEntity.getBody()) && type != null) {
JSON.parseObject(responseEntity.getBody(), type), responseEntity.getHeaders()
            , responseEntity.getStatusCode());
        }
        return new ResponseEntity<T>(HttpStatus.BAD_REQUEST);
    }

重点是构造Type信息字段构造:你真的了解Java泛型参数?spring ResolvableType更好的处理泛型

ParameterizedTypeReference#getType() spring提供的处理泛型参数Type信息

 ParameterizedTypeReference<BaseResponse<BaseDataModel<OrganizationInfo>>> typeRef
  = new ParameterizedTypeReference<BaseResponse<BaseDataModel<OrganizationInfo>>>() {
        };

TypeReference#getType() FastJson提供的处理泛型参数Type信息

TypeReference<BaseResponse<BaseDataModel<String>>> typeReference 
= new TypeReference<BaseResponse<BaseDataModel<String>>>() {
        };

通过FastJSon转换泛型参数就这样啦!在实际的使用场景中这样的例子也是比较多的!

2. RestTemplate 自带泛型参数处理

@Override
    public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
            ParameterizedTypeReference<T> responseType, Object... uriVariables) throws RestClientException {

        Type type = responseType.getType();
        RequestCallback requestCallback = httpEntityCallback(requestEntity, type);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(type);
        return execute(url, method, requestCallback, responseExtractor, uriVariables);
    }

一般使用调用方式如下所示:

 @SuppressWarnings("unchecked")
    private static <T> ResponseEntity<T> exchange(String url, HttpMethod httpMethod, HttpHeaders headers, Object body, ParameterizedTypeReference typeReference, Object... args) {
        headers = resolveHttpHeaders(headers);
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(body, headers);
        ResponseEntity<T> responseEntity = 
        (ResponseEntity<T>) restTemplate.exchange(url, httpMethod, httpEntity, typeReference, args);
        return responseEntity;
    }

创建一个带泛型的类型变量,然后调用自己的get post方法就ok啦,当然spring提供的不一定需要传递这么多的参数哦

 ParameterizedTypeReference<BaseResponse<BaseDataModel<OrganizationInfo>>> typeRef
  = new ParameterizedTypeReference<BaseResponse<BaseDataModel<OrganizationInfo>>>() {
        };

3. 对于一般的基本类似的处理(不包含泛型参数)

直接调使用 responseType就ok啦!和处理String.class类似,有些喜欢使用JsonObject.class,不太推荐,使用Java语言方便看清楚具体的处理逻辑 结构。

@Override
    public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
            HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {

        RequestCallback requestCallback = httpEntityCallback(requestEntity, responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
        return execute(url, method, requestCallback, responseExtractor, uriVariables);
    }

4. 一般的基本操作

很多的getForEntity postForEntity getForObject 这些不需要传递全部的参数,可以根据自己的需要进行处理哦,具体详细看博客,相对于Exchange来说参数相对比较的简单,Exchange的参数调用能够满足大多数复杂的需求;
详解 RestTemplate 操作

5. 对于RestTemplate 对于URL参数处理

假设传递的URL需要传递 phone and msg信息,放置在URL中你需要构造有两种形式,但是传递URL的形式都是一样的
,必须按照这个标准才能解析
http://localhost:8888/context/sendMsg?msg={msg}&phone={phone}
你可以根据变量的顺序传递变量或者构造一个Map按照key的值传递信息
这里写图片描述

四、 这样就完啦?

1. 异常逻辑处理

restTemplate老是喜欢抛异常?为啥因为有个异常处理逻辑!是谁?就是他DefaultResponseErrorHandler!你可以自定义异常处理体系,根据自己的需要来进行逻辑处理,默认情况下抛的异常就是下图所示

/**
     * This default implementation throws a {@link HttpClientErrorException} if the response status code
     * is {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR}, a {@link HttpServerErrorException}
     * if it is {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR},
     * and a {@link RestClientException} in other cases.
     */
    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        HttpStatus statusCode = getHttpStatusCode(response);
        switch (statusCode.series()) {
            case CLIENT_ERROR:
                throw new HttpClientErrorException(statusCode, response.getStatusText(),
                        response.getHeaders(), getResponseBody(response), getCharset(response));
            case SERVER_ERROR:
                throw new HttpServerErrorException(statusCode, response.getStatusText(),
                        response.getHeaders(), getResponseBody(response), getCharset(response));
            default:
                throw new RestClientException("Unknown status code [" + statusCode + "]");
        }
    }

2. RestTemplate同时支持Https and Http 绕过证书验证

由于HttpClinet天然的对于证书支持,所以restTemplate使用httpclient作为底层请求Http包必然是可以支持的;
HttpClient中post请求http、https示例
httpclient4.5 https请求忽略身份验证
使用HttpClient4来构建Spring RestTemplate

/**
     * 忽略Http证书验证方式
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");

        // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);
        return sc;
    }

  private static void init() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        //region HttpClient构造
        //region 连接池httpClientConnectionManager
        //采用绕过验证的方式处理https请求
        SSLContext sslcontext = createIgnoreVerifySSL();
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier()))
                .build();
        PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        httpClientConnectionManager.setMaxTotal(2);
        httpClientConnectionManager.setDefaultMaxPerRoute(20);

        //endregion

        //region 重试机制 retryHandler
        DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(2, true);
        //endregion

        HttpClient httpClient = HttpClientBuilder.create()
                .setRetryHandler(retryHandler)
                .setConnectionManager(httpClientConnectionManager)
                //默认客户端连接重用策略
                .setConnectionReuseStrategy(new DefaultClientConnectionReuseStrategy())
                //保持长连接配置,需要在头添加Keep-Alive
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                .setConnectionManagerShared(true)
                .build();
        //endregion
        //region http连接工厂
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setHttpClient(httpClient);
        //连接超时
        httpRequestFactory.setConnectTimeout(2000);
        // 读写超时
        httpRequestFactory.setReadTimeout(30000);
        //endregion
        restTemplate = new RestTemplate(httpRequestFactory);
        restTemplate.getInterceptors().add(new RestTemplateTraceInterceptor());
        //异常处理逻辑,根据自己的需要可以自定义异常处理
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());

    }

测试

  RestTemplateFactory.init();
  String url = "https://www.baidu.com/;
  String resp = restTemplate.getForObject(url, String.class);
  System.out.println(resp);

响应数据

<!DOCTYPE html>
<!--STATUS OK-->----

总结完整包装,还有些不足

restTemplate访问https
HttpClient容易忽视的细节——连接关闭
httpclient4.5 https请求 忽略身份验证
HttpClient中post请求http、https示例

public class RestTemplateFactory {


    private static RestTemplate restTemplate;

    /**
     * 忽略Http证书验证方式
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    public static SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
        SSLContext sc = SSLContext.getInstance("SSLv3");

        // 实现一个X509TrustManager接口,用于绕过验证,不用修改里面的方法
        X509TrustManager trustManager = new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                    String paramString) throws CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sc.init(null, new TrustManager[]{trustManager}, null);
        return sc;
    }


    private static void init() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        //region HttpClient构造
        //region 连接池httpClientConnectionManager
        //采用绕过验证的方式处理https请求
        SSLContext sslcontext = createIgnoreVerifySSL();
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier()))
                .build();
        PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        httpClientConnectionManager.setMaxTotal(2);
        httpClientConnectionManager.setDefaultMaxPerRoute(20);

        //endregion

        //region 重试机制 retryHandler
        DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(2, true);
        //endregion

        HttpClient httpClient = HttpClientBuilder.create()
                .setRetryHandler(retryHandler)
                .setConnectionManager(httpClientConnectionManager)
                //默认客户端连接重用策略
                .setConnectionReuseStrategy(new DefaultClientConnectionReuseStrategy())
                //保持长连接配置,需要在头添加Keep-Alive
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy())
                .setConnectionManagerShared(true)
                .build();
        //endregion
        //region http连接工厂
        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setHttpClient(httpClient);
        //连接超时
        httpRequestFactory.setConnectTimeout(2000);
        // 读写超时
        httpRequestFactory.setReadTimeout(30000);
        //endregion
        restTemplate = new RestTemplate(httpRequestFactory);
        restTemplate.getInterceptors().add(new RestTemplateTraceInterceptor());
        //异常处理逻辑,根据自己的需要可以自定义异常处理
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());

    }


    /**
     * 根据返回的Class进行请求
     *
     * @param url
     * @param headers
     * @param responseType
     * @param body
     * @param args
     * @return org.springframework.http.ResponseEntity<T>
     */
    public static <T> ResponseEntity<T> postForEntity(String url, HttpHeaders headers, Object body, Class<T> responseType, Object... args) {
        return exchange(url, HttpMethod.POST, headers, body, responseType, args);
    }

    /**
     * 根据包装的类型进行请求
     *
     * @param url
     * @param httpHeaders
     * @param body
     * @param typeReference
     * @param args
     * @return org.springframework.http.ResponseEntity<T>
     * @see ParameterizedTypeReference
     */
    public static <T> ResponseEntity<T> postForObject(String url, HttpHeaders httpHeaders, Object body, ParameterizedTypeReference<T> typeReference, Object... args) {
        return exchange(url, HttpMethod.POST, httpHeaders, body, typeReference, args);
    }

    /**
     * 根据 TypeReference类型 使用FastJson进行转换获取返回Class的类型
     *
     * @param url
     * @param headers
     * @param body
     * @param typeReference
     * @param args
     * @return org.springframework.http.ResponseEntity<T>
     */
    public static <T> ResponseEntity<T> postForEntity(String url, HttpHeaders headers, Object body, TypeReference typeReference, Object... args) {
        ResponseEntity<T> responseEntity = new ResponseEntity<T>(HttpStatus.BAD_REQUEST);
        if (typeReference != null) {
            responseEntity = exchange(url, HttpMethod.GET, headers, body, typeReference.getType(), args);
        }
        return responseEntity;
    }

    /**
     * 根据 Type类型 使用FastJson进行转换获取返回Class的类型
     *
     * @param url
     * @param headers
     * @param body
     * @param type
     * @param args
     * @return org.springframework.http.ResponseEntity<T>
     * @see ParameterizedTypeReference#getType()
     * @see TypeReference#getType()
     */
    public static <T> ResponseEntity<T> postForEntity(String url, HttpHeaders headers, Object body, Type type, Object... args) {
        return exchange(url, HttpMethod.POST, headers, body, type, args);
    }


    /**
     * 根据 ParameterizedTypeReference 类型获取信息
     *
     * @param url
     * @param httpHeaders
     * @param typeReference
     * @param args
     * @return <T> ResponseEntity<T>
     */
    public static <T> ResponseEntity<T> getForEntity(String url, HttpHeaders httpHeaders, ParameterizedTypeReference<T> typeReference, Object... args) {
        return exchange(url, HttpMethod.GET, httpHeaders, null, typeReference, args);
    }


    /**
     * 根据 Type类型 使用FastJson进行转换获取返回Class的类型
     *
     * @param url
     * @param headers
     * @param type
     * @param args
     * @return <T> ResponseEntity<T>
     * @see ParameterizedTypeReference#getType()
     * @see TypeReference#getType()
     */
    public static <T> ResponseEntity<T> getForEntity(String url, HttpHeaders headers, Type type, Object... args) {
        return exchange(url, HttpMethod.GET, headers, null, type, args);
    }


    /**
     * 根据 TypeReference类型 使用FastJson进行转换获取返回Class的类型
     *
     * @param url
     * @param headers
     * @param typeReference
     * @param args
     * @return org.springframework.http.ResponseEntity<T>
     */
    public static <T> ResponseEntity<T> getForEntity(String url, HttpHeaders headers, TypeReference typeReference, Object... args) {
        ResponseEntity<T> responseEntity = new ResponseEntity<T>(HttpStatus.BAD_REQUEST);
        if (typeReference != null) {
            responseEntity = exchange(url, HttpMethod.GET, headers, null, typeReference.getType(), args);
        }
        return responseEntity;
    }


    /**
     * 根据Class类型获取返回的信息
     *
     * @param url
     * @param headers
     * @param responseType
     * @param args
     * @return org.springframework.http.ResponseEntity<T>
     */
    public static <T> ResponseEntity<T> getForEntity(String url, HttpHeaders headers, Class<T> responseType, Object... args) {
        return exchange(url, HttpMethod.GET, headers, null, responseType, args);
    }


    private static <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpHeaders headers, Object body, Class<T> responseType, Object... args) {
        headers = resolveHttpHeaders(headers);
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(body, headers);
        ResponseEntity<T> responseEntity = restTemplate.exchange(url, method, httpEntity, responseType, args);
        return responseEntity;
    }

    @SuppressWarnings("unchecked")
    private static <T> ResponseEntity<T> exchange(String url, HttpMethod httpMethod, HttpHeaders headers, Object body, ParameterizedTypeReference typeReference, Object... args) {
        headers = resolveHttpHeaders(headers);
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(body, headers);
        ResponseEntity<T> responseEntity = (ResponseEntity<T>) restTemplate.exchange(url, httpMethod, httpEntity, typeReference, args);
        return responseEntity;
    }

    /**
     * 这里使用自己通过 FastJson进行数据信息的转换
     *
     * @see ParameterizedTypeReference#getType()
     * @see com.alibaba.fastjson.TypeReference#getType()
     */
    @SuppressWarnings("unchecked")
    public static <T> ResponseEntity<T> exchange(String url, HttpMethod httpMethod, HttpHeaders headers, Object body, Type type, Object... args) {
        headers = resolveHttpHeaders(headers);
        HttpEntity<Object> httpEntity = new HttpEntity<Object>(body, headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, httpMethod, httpEntity, String.class, args);
        if (responseEntity != null && StringUtils.isNotEmpty(responseEntity.getBody()) && type != null) {
            return new ResponseEntity<T>(JSON.parseObject(responseEntity.getBody(), type), responseEntity.getHeaders(), responseEntity.getStatusCode());
        }
        return new ResponseEntity<T>(HttpStatus.BAD_REQUEST);
    }

    /**
     * 没有就设置默认的 HttpHeaders
     *
     * @see HttpHeaders#setContentType(MediaType)
     * @see MediaType#APPLICATION_JSON
     * @see MediaType#APPLICATION_JSON_UTF8 (部分版本不支持)
     */
    private static HttpHeaders resolveHttpHeaders(HttpHeaders headers) {
        if (headers == null) {
            headers = new HttpHeaders();
            headers.set("Content-Type", "application/json;charset=UTF-8");
            headers.set("Accept", MediaType.APPLICATION_JSON_UTF8_VALUE);
        }
        return headers;
    }

    public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        testHttps();
    }

    public static void testHttps() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        RestTemplateFactory.init();
        String url = "https://www.baidu.com";
        String resp = restTemplate.getForObject(url, String.class);
        System.out.println(resp);
    }

    //上传文件
    private static void test3() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        RestTemplateFactory.init();
        String API = "http://localhost:8888/spms/web/safeOperationHandle/upload";
        String FilePath = "F://RestTemplateFactory.java";
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.parseMediaType("multipart/form-data"));
        FileSystemResource resource = new FileSystemResource(new File(FilePath));
        MultiValueMap<String, Object> form = new LinkedMultiValueMap<String, Object>();
        form.add("file", resource);
        ResponseEntity<String> responseEntity = RestTemplateFactory.postForEntity(API, httpHeaders, form, String.class);
        System.out.println(responseEntity.getBody().toString());

    }

    private static void test1() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        RestTemplateFactory.init();
        String API = "http://apis.baidu.com/apix/apix_station_data/apix_telecom?sid={sid}&nid={0}&cellid={cellid}&ishex={ishex}";
        List<Object> array = Lists.newArrayList(13824, 0, 291, 0);
        HttpHeaders httpHeaders = resolveHttpHeaders(null);
        httpHeaders.add("apikey", "04fcf47d812436965e1e1d05fe06fb4a");
        httpHeaders.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8");
        httpHeaders.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON_UTF8));
        ResponseEntity<Test> responseEntity = RestTemplateFactory.getForEntity(API, httpHeaders, Test.class, array.toArray());
        System.out.println(responseEntity.getBody().toString());
    }
}

就这样子啦~~~

猜你喜欢

转载自blog.csdn.net/u012881904/article/details/81185231