現在REST服務已經很普及了,在我們的程序中,經常會需要調用REST API,這時候會有很多選擇,原始一點的JDK自帶的,再進一步點使用HttpClient,或者說如果我們使用Jersey這種框架的話,也會自帶rest client。但是我們項目使用的SpringMVC,所以直接使用RestTemplate。使用RestTemplate比直接使用Httpclient簡單很多,同時也可以借助httpclient來實現RestTemplate。
通過使用RestTemplate僅僅只需要寫幾行代碼,就可以完成直接使用httpclient很多行代碼的事情,具體見:https://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
RestTemplate有三個構造函數:
這裡主要討論的是通過第二個構造方法來使用HttpClient4 來進行網絡傳輸。下面我們來看下HttpComponentsClientHttpRequestFactory這個類。先看看他的構造方法
/**
* Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
* with a default {@link HttpClient}.
*/
public HttpComponentsClientHttpRequestFactory() {
this(HttpClients.createSystem());
}
/**
* Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
* with the given {@link HttpClient} instance.
* <p>As of Spring Framework 4.0, the given client is expected to be of type
* {@link CloseableHttpClient} (requiring HttpClient 4.3+).
* @param httpClient the HttpClient instance to use for this request factory
*/
public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) {
Assert.notNull(httpClient, "'httpClient' must not be null");
Assert.isInstanceOf(CloseableHttpClient.class, httpClient, "'httpClient' is not of type CloseableHttpClient");
this.httpClient = (CloseableHttpClient) httpClient;
}
如果我們不指定一個HttpClient的話,會默認幫我們創建一個,如果我們程序調用比較頻繁的話,為了提高性能,會考慮使用PoolingHttpClientConnectionManager來構建HttpClient,這時候就會使用到第二個。如何使用PoolingHttpClientConnectionManager來創建HttpClient呢?可以參考幾個文章:http://www.linuxidc.com/Linux/2015-06/119099.htm 以及我前面的一篇:http://www.linuxidc.com/Linux/2015-06/119098p2.htm ,這裡就不具體講了,可以網上搜索相關資料。
下面寫寫代碼來描述下怎麼通過HttpComponentsClientHttpRequestFactory來創建RestTemplate,為了方便創建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;
/**
* Created by Administrator on 2015/6/8.
*/
public class HttpClientUtils {
public static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
HttpClientBuilder b = 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();
b.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);
b.setConnectionManager( connMgr);
// finally, build the HttpClient;
// -- done!
CloseableHttpClient client = b.build();
return client;
}
}
CloseableHttpClient httpClient = HttpClientUtils.acceptsUntrustedCertsHttpClient();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
String result = restTemplate.getForObject("http://www.baidu.com",String.class);
System.out.println(result);
那麼問題來了,我們既然是使用Spring,那肯定希望把他RestTemplate配置成Spring bean來使用,HttpClient是線程安全的,他可以在程序中共享,創建一個成Spring bean剛好。下面是xml配置。
<bean id="httpClient" class="com.hupengcool.util.HttpClientUtils" factory-method="acceptsUntrustedCertsHttpClient"/>
<bean id="clientHttpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
</bean>
<bean id="restTemplate" class=" org.springframework.web.client.RestTemplate">
<constructor-arg ref="clientHttpRequestFactory" />
</bean>
開始使用Spring RestTemplate吧。。。。。
PS:項目中除了Spring相關jar包外。需要添加HttpClient4.5,jackson 2.x的jar包。
使用HttpClient實現文件的上傳下載 http://www.linuxidc.com/Linux/2014-07/104303.htm
Android 實現 HttpClient 請求Https http://www.linuxidc.com/Linux/2014-05/102306.htm
Android使用HttpClient下載圖片 http://www.linuxidc.com/Linux/2014-05/101855.htm
HttpClient使用詳解 http://www.linuxidc.com/Linux/2014-08/104945.htm