目录
1、引入依赖
2、yml配置http参数
3、核心参数配置类
4、API封装
5、连接池自动管理配置--参考官方提供方案
6、测试案例
文章简单做个记录,SpringBoot与HttpClient整合步骤
org.apache.httpcomponents
httpcore
4.4.10
org.apache.httpcomponents
httpclient
4.5.6
#http设置
http:
#最大连接数
maxTotal: 100
defaultMaxPerRoute: 20
#连接超时时间
connectTimeout: 1000
#从连接池中获取到连接的最长时间
connectionRequestTimeout: 500
#数据传输的最长时间
socketTimeout: 10000
#提交请求前测试连接是否可用
staleConnectionCheckEnabled: true
package com.essm.config;
/**
* HttpClient配置类
*
* @author :HUANG ZHI XUE
* @date :Create in 2020-09-07
*/
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.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 2020/9/7
* hzx
*
* HttpClient配置类
*/
@Configuration
@ConfigurationProperties(prefix = "http", ignoreUnknownFields = true)
public class HttpClientConfig {
private Integer maxTotal;
private Integer defaultMaxPerRoute;
private Integer connectTimeout;
private Integer connectionRequestTimeout;
private Integer socketTimeout;
private boolean staleConnectionCheckEnabled;
/**
* 首先实例化一个连接池管理器,设置最大连接数、并发连接数
*
* @return
*/
@Bean(name = "httpClientConnectionManager")
public PoolingHttpClientConnectionManager getHttpClientConnectionManager() {
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager();
//最大连接数
httpClientConnectionManager.setMaxTotal(maxTotal);
//并发数
httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
return httpClientConnectionManager;
}
/**
* 实例化连接池,设置连接池管理器。
* 这里需要以参数形式注入上面实例化的连接池管理器
*
* @param httpClientConnectionManager
* @return
*/
@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的连接信息
* 这里还可以设置proxy,cookieSpec等属性。有需要的话可以在此设置
*
* @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();
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
public Integer getDefaultMaxPerRoute() {
return defaultMaxPerRoute;
}
public void setDefaultMaxPerRoute(Integer defaultMaxPerRoute) {
this.defaultMaxPerRoute = defaultMaxPerRoute;
}
public Integer getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Integer getConnectionRequestTimeout() {
return connectionRequestTimeout;
}
public void setConnectionRequestTimeout(Integer connectionRequestTimeout) {
this.connectionRequestTimeout = connectionRequestTimeout;
}
public Integer getSocketTimeout() {
return socketTimeout;
}
public void setSocketTimeout(Integer socketTimeout) {
this.socketTimeout = socketTimeout;
}
public boolean isStaleConnectionCheckEnabled() {
return staleConnectionCheckEnabled;
}
public void setStaleConnectionCheckEnabled(boolean staleConnectionCheckEnabled) {
this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
}
}
package com.essm.config;
import com.essm.entity.JsonUtils;
import org.apache.http.HttpHost;
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.client.utils.URIBuilder;
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.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* HttpClient api封装
*
* @author :HUANG ZHI XUE
* @date :Create in 2020-09-07
*/
@Component
public class HttpAPIService {
@Autowired
private CloseableHttpClient httpClient;
@Autowired
private RequestConfig config;
/**
* 不带参数的get请求,如果状态码为200,则返回body,如果不为200,则返回null
*
* @param url
* @return
* @throws Exception
*/
public String doGet(String url) throws Exception {
// 声明 http get 请求
HttpGet httpGet = new HttpGet(url);
// 装载配置信息
httpGet.setConfig(config);
// 发起请求
try (CloseableHttpResponse response = this.httpClient.execute(httpGet)) {
// 判断状态码是否为200
if (response.getStatusLine().getStatusCode() == 200) {
// 返回响应体的内容
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
return null;
}
/**
* 带参数的get请求,如果状态码为200,则返回body,如果不为200,则返回null
*
* @param url
* @return
* @throws Exception
*/
public String doGet(String url, Map map) throws Exception {
URIBuilder uriBuilder = new URIBuilder(url);
if (map != null) {
// 遍历map,拼接请求参数
for (Map.Entry entry : map.entrySet()) {
uriBuilder.setParameter(entry.getKey(), entry.getValue().toString());
}
}
// 调用不带参数的get请求
return this.doGet(uriBuilder.build().toString());
}
/**
* 带map参数的post请求
*
* @param url
* @param map
* @return string json串
* @throws Exception
*/
public String doPostByMapParm(String url, Map map) throws Exception {
// 声明httpPost请求
HttpPost httpPost = new HttpPost(url);
// 加入配置信息
httpPost.setConfig(config);
// 判断map是否为空,不为空则进行遍历,封装from表单对象
if (map != null) {
List list = new ArrayList<>();
for (Map.Entry entry : map.entrySet()) {
list.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
}
// 构造from表单对象
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
// 把表单放到post里
httpPost.setEntity(urlEncodedFormEntity);
}
// 发起请求
try(CloseableHttpResponse response = this.httpClient.execute(httpPost)) {
if (response.getStatusLine().getStatusCode() == 200) {
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
return null;
}
/**
* 带json参数的post请求,用的最多,因为map可以转为json
*
* @param url 请求地址host+path
* @param json json字符串
* @return string json串
* @throws Exception
*/
public String doPostByJsonParm(String url, String json) throws Exception {
//设置请求路径,请求格式,配置信息
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
httpPost.setConfig(config);
//格式化请求数据并设值
StringEntity se = new StringEntity(json);
se.setContentType("text/json");
httpPost.setEntity(se);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
//返回信息
if (response.getStatusLine().getStatusCode() == 200) {
return EntityUtils.toString(response.getEntity(), "UTF-8");
}
}
return null;
}
/**
* 不带参数post请求
*
* @param url
* @return string json串
* @throws Exception
*/
public String doPost(String url) throws Exception {
return this.doPostByMapParm(url, null);
}
}
package com.essm.config;
import org.apache.http.conn.HttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 连接池自动关闭管理
*
* @author :HUANG ZHI XUE
* @date :Create in 2020-09-07
*/
@Component
public class IdleConnectionEvictor extends Thread {
@Autowired
private HttpClientConnectionManager connMgr;
private volatile boolean shutdown;
public IdleConnectionEvictor() {
super();
super.start();
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// 关闭失效的连接
connMgr.closeExpiredConnections();
connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
// 结束
}
}
//关闭清理无效连接的线程
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
/**
* 通过HttpClient调用它方接口
*
* @return 返回响应结果
*/
public GenericDTO synHttpClientToOther(GenericDTO reqDto) {
GenericDTO rspDto = new GenericDTO<>();
//格式化请求参数
String parameter = JsonUtils.toJSON(reqDto);
//调用它方接口
try {
String result = httpAPIService.doPostByJsonParm(host + path, parameter);
//不为kong则,转成对象返回
if (StringUtils.isNotEmpty(result)) {
//转成对象
rspDto = JsonUtils.toBean(result, GenericDTO.class);
rspDto.setBody(JsonUtils.toBean(rspDto.getBody(), GetNonStandardPersonAddrRspDTO.class));
}
} catch (Exception e) {
e.printStackTrace();
}
return rspDto;
}