import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource(value="classpath:/properties/httpClient.properties")
public class HttpClientConfig {
@Value("${http.maxTotal}")
private Integer maxTotal; //最大连接数
@Value("${http.defaultMaxPerRoute}")
private Integer defaultMaxPerRoute; //最大并发链接数
@Value("${http.connectTimeout}")
private Integer connectTimeout; //创建链接的最大时间
@Value("${http.connectionRequestTimeout}")
private Integer connectionRequestTimeout; //链接获取超时时间
@Value("${http.socketTimeout}")
private Integer socketTimeout; //数据传输最长时间
@Value("${http.staleConnectionCheckEnabled}")
private boolean staleConnectionCheckEnabled; //提交时检查链接是否可用
//定义httpClient链接池
@Bean(name="httpClientConnectionManager")
public PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
manager.setMaxTotal(maxTotal); //设定最大链接数
manager.setDefaultMaxPerRoute(defaultMaxPerRoute); //设定并发链接数
return manager;
}
//定义HttpClient
/**
* 实例化连接池,设置连接池管理器。
* 这里需要以参数形式注入上面实例化的连接池管理器
@Qualifier 指定bean标签进行注入
*/
@Bean(name = "httpClientBuilder")
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){
//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
return httpClientBuilder;
}
/**
* 注入连接池,用于获取httpClient
* @param httpClientBuilder
* @return
*/
@Bean
public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){
return httpClientBuilder.build();
}
/**
* Builder是RequestConfig的一个内部类
* 通过RequestConfig的custom方法来获取到一个Builder对象
* 设置builder的连接信息
* @return
*/
@Bean(name = "builder")
public RequestConfig.Builder getBuilder(){
RequestConfig.Builder builder = RequestConfig.custom();
return builder.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout)
.setSocketTimeout(socketTimeout)
.setStaleConnectionCheckEnabled(staleConnectionCheckEnabled);
}
/**
* 使用builder构建一个RequestConfig对象
* @param builder
* @return
*/
@Bean
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
return builder.build();
}
}
关闭池
import javax.annotation.PreDestroy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.pool.PoolStats;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component //交给spring容器管理
public class HttpClientClose extends Thread{
@Autowired
private PoolingHttpClientConnectionManager manage;
private volatile boolean shutdown; //开关 volatitle表示多线程可变数据,一个线程修改,其他线程立即修改
public HttpClientClose() {
///System.out.println("执行构造方法,实例化对象");
//线程开启启动
this.start();
}
@Override
public void run() {
try {
//如果服务没有关闭,执行线程
while(!shutdown) {
synchronized (this) {
wait(5000); //等待5秒
//System.out.println("线程开始执行,关闭超时链接");
//关闭超时的链接
PoolStats stats = manage.getTotalStats();
int av = stats.getAvailable(); //获取可用的线程数量
int pend = stats.getPending(); //获取阻塞的线程数量
int lea = stats.getLeased(); //获取当前正在使用的链接数量
int max = stats.getMax();
//System.out.println("max/"+max+": av/"+av+": pend/"+pend+": lea/"+lea);
manage.closeExpiredConnections();
}
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
super.run();
}
//关闭清理无效连接的线程
@PreDestroy //容器关闭时执行该方法.
public void shutdown() {
shutdown = true;
synchronized (this) {
//System.out.println("关闭全部链接!!");
notifyAll(); //全部从等待中唤醒.执行关闭操作;
}
}
}
使用
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.http.NameValuePair;
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.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service
public class HttpClientService {
@Autowired
private CloseableHttpClient httpClient; // 请求的API
@Autowired
private RequestConfig requestConfig; // 控制请求的超时时间
/*
* 业务分析: 1. 参数说明: 1).url的地址 2).Map<String,String> 3).封装字符集 2.返回值:String类型的JSON数据
* 3. get请求分析 id = 1 name = tomcat url1:http://xxx.xx.com/xx?id=1&name=tomcat
* url2:http://xxx.xx.com/xx
*/
public String doGet(String url, Map<String, String> params, String charset) {
// 1.判断用户是否传递了字符集
if (StringUtils.isEmpty(charset)) {
charset = "UTF-8";
}
// 2.判断用户是否传递了参数
if (params != null) { // 如果有参数则需要字符串的拼接
url += "?"; // http://xxx.xx.com/xx?
for (Map.Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
url += key + "=" + value + "&";
}
// 去除多余的&
url = url.substring(0, url.length() - 1);
}
//3.定义请求对象 发起请求
HttpGet httpGet = new HttpGet(url);
//4.设定请求的超时时间
httpGet.setConfig(requestConfig);
//5.发起请求
try {
CloseableHttpResponse response = httpClient.execute(httpGet);
int status = response.getStatusLine().getStatusCode();
if(status == 200) {
//表示请求正常
String result = EntityUtils.toString(response.getEntity(),charset);
return result;
}else {
throw new RuntimeException("请求状态异常:"+status+":"+url);
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public String doGet(String url) {
return doGet(url, null, null);
}
public String doGet(String url,Map<String,String> params) {
return doGet(url, params, null);
}
// 实现httpClient POST提交
public String doPost(String url, Map<String, String> params, String charset) {
String result = null;
// 1.定义请求类型
HttpPost post = new HttpPost(url);
post.setConfig(requestConfig); // 定义超时时间
// 2.判断字符集是否为null
if (StringUtils.isEmpty(charset)) {
charset = "UTF-8";
}
// 3.判断用户是否传递参数
if (params != null) {
// 3.2准备List集合信息
List<NameValuePair> parameters = new ArrayList<>();
// 3.3将数据封装到List集合中
for (Map.Entry<String, String> entry : params.entrySet()) {
parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
// 3.1模拟表单提交
try {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, charset); // 采用u8编码
// 3.4将实体对象封装到请求对象中
post.setEntity(formEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
// 4.发送请求
try {
CloseableHttpResponse response = httpClient.execute(post);
// 4.1判断返回值状态
if (response.getStatusLine().getStatusCode() == 200) {
// 4.2表示请求成功
result = EntityUtils.toString(response.getEntity(), charset);
} else {
System.out.println("获取状态码信息:" + response.getStatusLine().getStatusCode());
throw new RuntimeException();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
public String doPost(String url) {
return doPost(url, null, null);
}
public String doPost(String url, Map<String, String> params) {
return doPost(url, params, null);
}
public String doPost(String url, String charset) {
return doPost(url, null, charset);
}
// 实现httpClient POST提交
public String doPostString(String url, String jsonParam, Map<String,String> headers, String charset) {
String result = null;
// 1.定义请求类型
HttpPost post = new HttpPost(url);
post.setConfig(requestConfig); // 定义超时时间
post.setHeader("Content-type","application/json");
// 2.判断字符集是否为null
if (StringUtils.isEmpty(charset)) {
charset = "UTF-8";
}
if (headers != null){
for (Map.Entry<String, String> head : headers.entrySet()) {
post.setHeader(head.getKey(),head.getValue());
}
}
// 3.判断用户是否传递参数
if (StringUtils.isNotBlank(jsonParam)) {
// 3.1模拟表单提交
try {
StringEntity stringEntity = new StringEntity(jsonParam,charset);
stringEntity.setContentEncoding(charset); //设置编码格式
// 发送Json格式的数据请求
stringEntity.setContentType("application/json");
post.setEntity(stringEntity);
} catch (Exception e) {
e.printStackTrace();
}
}
// 4.发送请求
try {
CloseableHttpResponse response = httpClient.execute(post);
// 4.1判断返回值状态
if (response.getStatusLine().getStatusCode() == 200) {
// 4.2表示请求成功
result = EntityUtils.toString(response.getEntity(), charset);
} else {
System.out.println("获取状态码信息:" + response.getStatusLine().getStatusCode());
throw new RuntimeException();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}
测试
@Autowired
private HttpClientService httpClientService;
@Test
public void test2() {
Map<String,String> params = new HashMap<>();
params.put("id", "12");
params.put("name", "完蛋了!!");
String result = httpClientService.doGet("http://www.baidu.com", params, null);
System.out.println(result);
}