使用 Spring 配置 RestTemplate 结合 HttpClient 访问 Rest 接口
RestTemplate
是 Spring 提供的用于访问 Rest 服务的客户端,RestTemplate
提供了多种便捷访问远程 Http 服务的方法,能够大大提高客户端的编写效率。
调用 RestTemplate 的默认构造函数,RestTemplate
对象在底层通过使用 java.net
包下的实现创建 HTTP 请求,可以通过使用 ClientHttpRequestFactory
指定不同的 HTTP 请求方式。
ClientHttpRequestFactory
接口主要提供了两种实现方式:
- 一种是
SimpleClientHttpRequestFactory
,使用 J2SE 提供的方式(即java.net
包提供的方式)创建底层的 Http 请求连接。 - 一种方式是使用
HttpComponentsClientHttpRequestFactory
方式,底层使用HttpClient
访问远程的 Http 服务,使用HttpClient
可以配置连接池和证书等信息。
本文主要介绍的是使用 ClientHttpRequestFactory
接口的 HttpClient
实现方式来实现对 REST 接口的访问。
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" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:task="http://www.springframework.org/schema/task" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- http连接池 -->
<!-- <bean id="pollingConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager"> -->
<!-- 最大连接数 -->
<!-- <property name="maxTotal" value="10" /> -->
<!-- 同一个主机(IP)的最大并发连接数 -->
<!-- <property name="defaultMaxPerRoute" value="5" />
</bean> -->
<!-- <bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
<property name="connectionManager" ref="pollingConnectionManager" />
</bean> -->
<!-- <bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build" /> -->
<bean id="httpClient" class="com.liuqianfei.utils.HttpClientUtils" factory-method="acceptsUntrustedCertsHttpClient"/>
<!-- -->
<bean id="clientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="httpClient" />
<property name="connectTimeout" value="30000" />
<property name="readTimeout" value="30000" />
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="clientHttpRequestFactory" />
<!--
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter" />
</list>
</property>
-->
</bean>
</beans>
实现 HttpClientUtils
org.springframework.http.client.HttpComponentsClientHttpRequestFactory
对象的构造方法需要接受一个实现访问规则的 HttpClient
实例。
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* HttpClient工具,对https访问信任,不需要证书;<br>
* 设置http连接池的最大连接数,和同一个主机(IP)的最大并发连接数。
* @author liuqianfei
*
*/
public class HttpClientUtils
{
public static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException
{
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
// setup a Trust Strategy that allows all certificates.
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy()
{
public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
{
return true;
}
}).build();
httpClientBuilder.setSslcontext(sslContext);
// don't check Hostnames, either.
// -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if
// you don't want to weaken
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
// here's the special part:
// -- need to create an SSL Socket Factory, to use our weakened "trust
// strategy";
// -- and create a Registry, to register it.
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory).build();
// now, we create connection-manager using our Registry.
// -- allows multi-threaded use
PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connMgr.setMaxTotal(200);
connMgr.setDefaultMaxPerRoute(100);
httpClientBuilder.setConnectionManager(connMgr);
// finally, build the HttpClient;
// -- done!
CloseableHttpClient client = httpClientBuilder.build();
return client;
}
}
在控制器中使用并访问 REST 接口
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.support.WebApplicationContextUtils;
RestTemplate restTemplate = (RestTemplate) WebApplicationContextUtils.getWebApplicationContext(getRequest().getServletContext()).getBean("restTemplate");
String result = restTemplate.getForObject("https://192.168.1.10/lqf/business/getAllPolice", String.class);
RestTemplate
的 getForObject
完成 get 请求、postForObject
完成 post 请求、put
对应的完成 put 请求、delete
完成 delete 请求;还有 execute
可以执行任何请求的方法,需要你设置 RequestMethod
来指定当前请求类型。
RestTemplate.getForObject(String url, Class responseType, String... urlVariables);
参数 url 是 http 请求的地址,参数 Class 是请求响应返回后的数据的类型,最后一个参数是请求中需要设置的参数。
template.getForObject(url + "get/{id}.do", String.class, id);
如上面的参数是 {id}
,返回的是一个 String 类型,设置的参数是 id。最后执行该方法会返回一个 String 类型的结果。