spring+httpclient完美集成,封装常用客户端工具类
1.导入依赖
<!-- spring版本号 -->
<spring.version>4.0.2.RELEASE</spring.version>
<!-- httpClient -->
<httpclient.version>4.5.2</httpclient.version>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 添加扫描javabean的注解包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- web-mvc依赖web,不用导包 -->
<!-- <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency> -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
<!-- 排除依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
<!-- 排除依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
<!-- 排除依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
<!-- 排除依赖 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- httpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
2.spring-httpclient.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 定义httpclient连接池 -->
<bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager" destroy-method="close">
<!-- 设置连接总数 -->
<property name="maxTotal" value="${http.pool.maxTotal}"></property>
<!-- 设置每个地址的并发数 -->
<property name="defaultMaxPerRoute" value="${http.pool.defaultMaxPerRoute}"></property>
</bean>
<!-- 定义 HttpClient工厂,这里使用HttpClientBuilder构建-->
<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
<property name="connectionManager" ref="httpClientConnectionManager"></property>
</bean>
<!-- 得到httpClient的实例 -->
<bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build"/>
<!-- 定期清理无效的连接 -->
<bean class="com.ssm.common.http.ClearConnectionsHandler" destroy-method="shutdown">
<constructor-arg index="0" ref="httpClientConnectionManager"/>
</bean>
<!-- 定义requestConfig的工厂 -->
<bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig.Builder">
<!-- 从连接池中获取到连接的最长时间 -->
<property name="connectionRequestTimeout" value="${http.request.connectionRequestTimeout}"/>
<!-- 创建连接的最长时间 -->
<property name="connectTimeout" value="${http.request.connectTimeout}"/>
<!-- 数据传输的最长时间 -->
<property name="socketTimeout" value="${http.request.socketTimeout}"/>
<!-- 提交请求前测试连接是否可用 -->
<property name="staleConnectionCheckEnabled" value="${http.request.staleConnectionCheckEnabled}"/>
</bean>
<!-- 得到requestConfig实例 -->
<bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />
</beans>
3.httpclient.properties
#从连接池中获取到连接的最长时间
http.request.connectionRequestTimeout=500
#设置链接超时
http.request.connectTimeout=5000
#数据传输的最长时间
http.request.socketTimeout=30000
#提交请求前测试连接是否可用
http.request.staleConnectionCheckEnabled=true
#设置连接总数
http.pool.maxTotal=200
#设置每个地址的并发数
http.pool.defaultMaxPerRoute=100
#设置定时清除无效链接时间
http.maxIdleTime=1
封装代码
1.HttpClient响应实体,还可以拓展响应体内容,主要就是这2个了
package com.ssm.common.http;
import java.io.Serializable;
/**
* HttpClient响应实体
* @autho 董杨炀
* @time 2017年5月8日 下午3:35:26
*/
public class HttpResult implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 状体码
*/
private Integer statusCode;
/**
* 响应内容
*/
private String content;
public HttpResult(){
}
public HttpResult(Integer statusCode, String content) {
this.statusCode = statusCode;
this.content = content;
}
/**
* 获取状体码
* @return 状体码
*/
public Integer getStatusCode() {
return statusCode;
}
/**
* 设置状体码
* @param statusCode 状体码
*/
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
/**
* 获取响应内容
* @return 响应内容
*/
public String getContent() {
return content;
}
/**
* 设置响应内容
* @param content 响应内容
*/
public void setContent(String content) {
this.content = content;
}
/**
* @autho 董杨炀
* @time 2017年5月8日 下午3:37:23
* @return
*/
@Override
public String toString() {
return "HttpResult [statusCode=" + statusCode + ", content=" + content + "]";
}
}
2.定义暴露出来的httpClient操作对象.此对象实现spring的BeanFactoryAware接口.
实现BeanFactoryAware接口,重写setBeanFactory方法可以拥有BeanFactory对象,也就是springIOC的核心容器工厂.通过该工厂可以获取IOC容器管理的所有bean
package com.ssm.common.http;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ssm.utils.StringUtils;
/**
* @autho 董杨炀
* @time 2017年5月8日 下午3:22:09
*/
@Component("httpClientOperate")
public class HttpClientOperate implements BeanFactoryAware{
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* 将required设置为false:
* 为了避免RequestConfig没被注进来的时候其他方法都不能用,报createbeanfailedexception
*
*/
@Autowired(required=false)
private RequestConfig requestConfig;
private CloseableHttpClient getHttpClient(){
return this.beanFactory.getBean(CloseableHttpClient.class);
}
/**
* 无参get请求
* @autho 董杨炀
* @time 2017年5月8日 下午3:30:08
* @param url
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public String doGet(String url) throws ClientProtocolException, IOException{
// 创建http GET请求
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(requestConfig);//设置请求参数
CloseableHttpResponse response = null;
try {
// 执行请求
response = this.getHttpClient().execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
return content;
}
} finally {
if (response != null) {
response.close();
}
//httpclient.close();
}
return null;
}
/**
* 有参get请求
* @param url
* @return
* @throws URISyntaxException
* @throws IOException
* @throws ClientProtocolException
*/
public String doGet(String url , Map<String, String> params) throws URISyntaxException, ClientProtocolException, IOException{
URIBuilder uriBuilder = new URIBuilder(url);
if(params != null){
for(String key : params.keySet()){
uriBuilder.setParameter(key, params.get(key));
}
}
return this.doGet(uriBuilder.build().toString());
}
/**
* 有参post请求
* @autho 董杨炀
* @time 2017年5月8日 下午3:32:48
* @param url
* @param params
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public HttpResult doPost(String url , Map<String, String> params) throws ClientProtocolException, IOException{
// 创建http POST请求
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
if(params != null){
// 设置2个post参数,一个是scope、一个是q
List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
for(String key : params.keySet()){
parameters.add(new BasicNameValuePair(key, params.get(key)));
}
// 构造一个form表单式的实体
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
// 将请求实体设置到httpPost对象中
httpPost.setEntity(formEntity);
}
CloseableHttpResponse response = null;
try {
// 执行请求
response = this.getHttpClient().execute(httpPost);
// 判断返回状态是否为200
/*if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}*/
return new HttpResult(response.getStatusLine().getStatusCode(),EntityUtils.toString(response.getEntity(), "UTF-8"));
} finally {
if (response != null) {
response.close();
}
//httpclient.close();
}
}
/**
* 有参post请求,json交互
* @autho 董杨炀
* @time 2017年5月8日 下午3:33:01
* @param url
* @param json
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public HttpResult doPostJson(String url , String json) throws ClientProtocolException, IOException{
// 创建http POST请求
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
if(StringUtils.isNotBlank(json)){
//标识出传递的参数是 application/json
StringEntity stringEntity = new StringEntity(json, ContentType.APPLICATION_JSON);
httpPost.setEntity(stringEntity);
}
CloseableHttpResponse response = null;
try {
// 执行请求
response = this.getHttpClient().execute(httpPost);
// 判断返回状态是否为200
/*if (response.getStatusLine().getStatusCode() == 200) {
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}*/
return new HttpResult(response.getStatusLine().getStatusCode(),EntityUtils.toString(response.getEntity(), "UTF-8"));
} finally {
if (response != null) {
response.close();
}
//httpclient.close();
}
}
/**
* 无参post请求
* @autho 董杨炀
* @time 2017年5月8日 下午3:33:27
* @param url
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public HttpResult doPost(String url) throws ClientProtocolException, IOException{
return this.doPost(url, null);
}
}
3.自定义类,利用线程定时扫描清理无效连接
package com.ssm.common.http;
import org.apache.http.conn.HttpClientConnectionManager;
/**
* 自定义定时清理无效链接(httpclient)
* @autho 董杨炀
* @time 2017年5月8日 下午3:16:59
*/
public class ClearConnectionsHandler extends Thread{
private final HttpClientConnectionManager connMgr;
private volatile boolean shutdown;
public ClearConnectionsHandler(HttpClientConnectionManager connMgr) {
this.connMgr = connMgr;
this.start();
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// 关闭失效的连接
connMgr.closeExpiredConnections();
}
}
} catch (InterruptedException ex) {
// 结束
}
}
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
客户端访问测试
1.直接启动ssm工程war测试,写一个bean实现InitializingBean接口,重写afterPropertiesSet()方法.
InitializingBean接口作用:在bean初始化完成之后自动执行afterPropertiesSet()方法
@Component:当IOC容器扫描到此注解标记的class就会装载该bean
package com.ssm.common.http;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
/**
* @autho 董杨炀
* @time 2017年5月8日 下午4:25:54
*/
@Component
public class MyHttpTest implements InitializingBean{
@Resource
private HttpClientOperate httpClientOperate;
/**
* @autho 董杨炀
* @time 2017年5月8日 下午4:26:20
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
//无参get请求
String result = httpClientOperate.doGet("http://www.baidu.com");
System.out.println(result);
//有参get请求
Map<String,String> map = new HashMap<>();
map.put("waybillNo", "12341223");
String result2 = httpClientOperate.doGet("http://www.baidu.com", map);
System.out.println(result2);
//post请求
HttpResult entity = httpClientOperate.doPost("http://10.230.21.133:8180/esb2/rs/ESB_FOSS2ESB_FOSS_THE_RECEIVING_VERIFY");
System.out.println(entity);
//有参post请求
HttpResult entity2 = httpClientOperate.doPost("http://10.230.21.133:8180/esb2/rs/ESB_FOSS2ESB_FOSS_THE_RECEIVING_VERIFY", map);
System.out.println(entity2);
//有参post请求rest服务 JSON
String json = "{\"waybillNo\":\"12341223\"}";
HttpResult entity3 = httpClientOperate.doPostJson("http://10.230.21.133:8180/esb2/rs/ESB_FOSS2ESB_FOSS_THE_RECEIVING_VERIFY",json);
System.out.println(entity3);
}
}
2.如果你没有去git检出改ssm项目.利用junit测试也可以.或者手动main启动spring容器加载配置来测试
package com.ssm.httptest;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ssm.common.http.HttpClientOperate;
import com.ssm.common.http.HttpResult;
/**
* 手动启动spring容器测试
* @autho 董杨炀
* @time 2017年5月8日 下午3:55:10
*/
public class HttpClientTest {
public static void main(String[] args) throws IOException, URISyntaxException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "spring-test.xml" });
HttpClientOperate httpClientOperate = (HttpClientOperate)context.getBean("httpClientOperate");
//无参get请求
String result = httpClientOperate.doGet("http://www.baidu.com");
System.out.println(result);
//有参get请求
Map<String,String> map = new HashMap<>();
map.put("waybillNo", "12341223");
String result2 = httpClientOperate.doGet("http://www.baidu.com", map);
System.out.println(result2);
//post请求
HttpResult entity = httpClientOperate.doPost("http://10.230.21.133:8180/esb2/rs/ESB_FOSS2ESB_FOSS_THE_RECEIVING_VERIFY");
System.out.println(entity);
//有参post请求
HttpResult entity2 = httpClientOperate.doPost("http://10.230.21.133:8180/esb2/rs/ESB_FOSS2ESB_FOSS_THE_RECEIVING_VERIFY", map);
System.out.println(entity2);
//有参post请求rest服务 JSON
String json = "{\"waybillNo\":\"12341223\"}";
HttpResult entity3 = httpClientOperate.doPostJson("http://10.230.21.133:8180/esb2/rs/ESB_FOSS2ESB_FOSS_THE_RECEIVING_VERIFY",json);
System.out.println(entity3);
}
}
spring-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 引入httpclient -->
<import resource="spring-httpclient.xml"/>
<!-- 配置注解扫描器 -->
<context:component-scan base-package="com.ssm.common.http"/>
<!-- 加载资源文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- 配置资源文件 -->
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
<value>classpath:httpclient.properties</value>
</list>
</property>
</bean>
<!-- 配置连接池,数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${driver}"></property>
<property name="jdbcUrl" value="${url}"></property>
<property name="user" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
</beans>
jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
username=root
password=root
#定义初始连接数
initialSize=10
#定义最大连接数
maxActive=20
#定义最大空闲
maxIdle=20
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000
测试结果如下图:完美