From 323766a218b51ec3e47565c50781a0f15a986b62 Mon Sep 17 00:00:00 2001 From: D <3066417822@qq.com> Date: Wed, 17 Apr 2024 01:38:36 +0800 Subject: [PATCH] updall httpClient and pool --- doc/支付系统订单状态图.drawio | 231 ++++++++----- doc/限流逻辑.drawio | 12 +- .../common/utils/http/HttpClientUtil.java | 324 ++++++++++++++++++ .../framework/config/ThreadPoolConfig.java | 71 +++- 4 files changed, 522 insertions(+), 116 deletions(-) create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpClientUtil.java diff --git a/doc/支付系统订单状态图.drawio b/doc/支付系统订单状态图.drawio index 090dedc..38be5c9 100644 --- a/doc/支付系统订单状态图.drawio +++ b/doc/支付系统订单状态图.drawio @@ -1,178 +1,219 @@ - + - - + + - + - + - + - - + + - + - + - + - - + + - + - + + - + - - + + - - + + - + - + - + - + - - + + - + - - - - + + + - + - + - - + + - + - - - - - - - - - - - - + - - + + - + - + - - - - + - + + + + + + - + + + + + + + + + + + + + + + - + - - - - - - + + + - + - + - - + + - + - - - - + + - + - + - - + + - + - - - - - - - - - - - - + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/限流逻辑.drawio b/doc/限流逻辑.drawio index 436ae4e..7ad47d0 100644 --- a/doc/限流逻辑.drawio +++ b/doc/限流逻辑.drawio @@ -1,6 +1,6 @@ - + @@ -8,28 +8,28 @@ - + - + - + - + - + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpClientUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpClientUtil.java new file mode 100644 index 0000000..954701f --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpClientUtil.java @@ -0,0 +1,324 @@ +package com.ruoyi.common.utils.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +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.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.util.PublicSuffixMatcher; +import org.apache.http.conn.util.PublicSuffixMatcherLoader; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson2.JSON; +import com.ruoyi.common.utils.spring.SpringUtils; + +public class HttpClientUtil { + + private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class); + /** + * 默认参数设置 + * setConnectTimeout:设置连接超时时间,单位毫秒。 + * setConnectionRequestTimeout:设置从connect Manager获取Connection 超时时间,单位毫秒。 + * setSocketTimeout:请求获取数据的超时时间,单位毫秒。访问一个接口,多少时间内无法返回数据,就直接放弃此次调用。 暂时定义15分钟 + */ + private static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(600000) + .setConnectTimeout(600000) + .setConnectionRequestTimeout(600000).build(); + + private static CloseableHttpClient client = SpringUtils.getBean("closeableHttpClient"); + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + */ + public static String sendHttpPost(String httpUrl) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + return sendHttpPost(httpPost); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param params 参数(格式:key1=value1&key2=value2) + */ + public static String sendHttpPost(String httpUrl, String params) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + try { + // 设置参数 + StringEntity stringEntity = new StringEntity(params, "UTF-8"); + stringEntity.setContentType("application/x-www-form-urlencoded"); + httpPost.setEntity(stringEntity); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + public static String sendHttpPost(String httpUrl, Object object) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + String jsonString = JSON.toJSONString(object); + httpPost.setHeader("Accept", ContentType.APPLICATION_JSON.getMimeType()); + httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); + log.debug(jsonString); + try { + + // 设置参数 + StringEntity stringEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON); + + httpPost.setEntity(stringEntity); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + public static String sendHttpPost(String httpUrl, Object data, Map headersMap) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + String jsonString = JSON.toJSONString(data); + httpPost.setHeader("Accept", ContentType.APPLICATION_JSON.getMimeType()); + httpPost.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType()); + for (String keySet : headersMap.keySet()) { + httpPost.setHeader(keySet, headersMap.get(keySet)); + } + log.debug(jsonString); + try { + // 设置参数 + StringEntity stringEntity = new StringEntity(jsonString, ContentType.APPLICATION_JSON); + + httpPost.setEntity(stringEntity); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + /** + * 发送 post请求 + * + * @param httpUrl 地址 + * @param maps 参数 + */ + public static String sendHttpPost(String httpUrl, Map maps) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + // 创建参数队列 + List nameValuePairs = new ArrayList(); + for (String key : maps.keySet()) { + nameValuePairs.add(new BasicNameValuePair(key, maps.get(key))); + } + try { + httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8")); + } catch (Exception e) { + e.printStackTrace(); + } + return sendHttpPost(httpPost); + } + + /** + * 发送 get请求 + * + * @param httpUrl + */ + public static String sendHttpGet(String httpUrl) { + HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求 + return sendHttpGet(httpGet); + } + + /** + * 发送 get请求Https + * + * @param httpUrl + */ + public static String sendHttpsGet(String httpUrl) { + HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求 + return sendHttpsGet(httpGet); + } + + /** + * 发送Post请求 + * + * @param httpPost + * @return + */ + private static String sendHttpPost(HttpPost httpPost) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 创建默认的httpClient实例 + // httpClient = HttpClients.createDefault(); + httpPost.setConfig(requestConfig); + // 执行请求 + long execStart = System.currentTimeMillis(); + response = client.execute(httpPost); + long execEnd = System.currentTimeMillis(); + log.debug("=================执行post请求耗时:" + (execEnd - execStart) + "ms"); + long getStart = System.currentTimeMillis(); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, "UTF-8"); + long getEnd = System.currentTimeMillis(); + log.debug("=================获取响应结果耗时:" + (getEnd - getStart) + "ms"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // 关闭连接,释放资源 + if (response != null) { + response.close(); + } + if (httpClient != null) { + httpClient.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return responseContent; + } + + /** + * 发送Get请求 + * + * @param httpGet + * @return + */ + private static String sendHttpGet(HttpGet httpGet) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 创建默认的httpClient实例. + + httpGet.setConfig(requestConfig); + // 执行请求 + response = client.execute(httpGet); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // 关闭连接,释放资源 + if (response != null) { + response.close(); + } + if (httpClient != null) { + httpClient.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return responseContent; + } + + /** + * 发送Get请求Https + * + * @param httpGet + * @return + */ + private static String sendHttpsGet(HttpGet httpGet) { + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + HttpEntity entity = null; + String responseContent = null; + try { + // 创建默认的httpClient实例. + PublicSuffixMatcher publicSuffixMatcher = PublicSuffixMatcherLoader + .load(new URL(httpGet.getURI().toString())); + DefaultHostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(publicSuffixMatcher); + httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build(); + httpGet.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpGet); + entity = response.getEntity(); + responseContent = EntityUtils.toString(entity, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // 关闭连接,释放资源 + if (response != null) { + response.close(); + } + if (httpClient != null) { + httpClient.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return responseContent; + } + + /** + * 发送xml数据 + * + * @param url + * @param xmlData + * @return + * @throws ClientProtocolException + * @throws IOException + */ + public static HttpResponse sendXMLDataByPost(String url, String xmlData) + throws ClientProtocolException, IOException { + + HttpPost httppost = new HttpPost(url); + StringEntity entity = new StringEntity(xmlData); + httppost.setEntity(entity); + httppost.setHeader("Content-Type", "text/xml;charset=UTF-8"); + HttpResponse response = client.execute(httppost); + return response; + } + + /** + * 获得响应HTTP实体内容 + * + * @param response + * @return + * @throws IOException + * @throws UnsupportedEncodingException + */ + public static String getHttpEntityContent(HttpResponse response) throws IOException, UnsupportedEncodingException { + HttpEntity entity = response.getEntity(); + if (entity != null) { + InputStream is = entity.getContent(); + BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8")); + String line = br.readLine(); + StringBuilder sb = new StringBuilder(); + while (line != null) { + sb.append(line + "\n"); + line = br.readLine(); + } + return sb.toString(); + } + return ""; + } + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java index 7840141..8f06930 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java @@ -1,22 +1,39 @@ package com.ruoyi.framework.config; -import com.ruoyi.common.utils.Threads; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; +import javax.net.ssl.SSLContext; + +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +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.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContextBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import com.ruoyi.common.utils.Threads; + /** * 线程池配置 * * @author ruoyi **/ @Configuration -public class ThreadPoolConfig -{ +public class ThreadPoolConfig { // 核心线程池大小 private int corePoolSize = 50; @@ -30,8 +47,7 @@ public class ThreadPoolConfig private int keepAliveSeconds = 300; @Bean(name = "threadPoolTaskExecutor") - public ThreadPoolTaskExecutor threadPoolTaskExecutor() - { + protected ThreadPoolTaskExecutor threadPoolTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(maxPoolSize); executor.setCorePoolSize(corePoolSize); @@ -46,18 +62,43 @@ public class ThreadPoolConfig * 执行周期性或定时任务 */ @Bean(name = "scheduledExecutorService") - protected ScheduledExecutorService scheduledExecutorService() - { + protected ScheduledExecutorService scheduledExecutorService() { return new ScheduledThreadPoolExecutor(corePoolSize, new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), - new ThreadPoolExecutor.CallerRunsPolicy()) - { + new ThreadPoolExecutor.CallerRunsPolicy()) { @Override - protected void afterExecute(Runnable r, Throwable t) - { + protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); Threads.printException(r, t); } }; } + + @Bean(name = "closeableHttpClient") + protected CloseableHttpClient closeableHttpClient() throws Exception { + SSLContextBuilder sslContextBuilder = new SSLContextBuilder(); + sslContextBuilder.loadTrustMaterial(null, new TrustStrategy() { + // 信任所有 + @Override + public boolean isTrusted(X509Certificate[] chain, + String authType) throws CertificateException { + return true; + } + }); + SSLContext sslContext = sslContextBuilder.build(); + SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, + new String[] { "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }, + null, NoopHostnameVerifier.INSTANCE); + Registry register = null; + register = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.INSTANCE) + .register("https", socketFactory).build(); + HttpClientBuilder custom = HttpClients.custom(); + PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(register); + pool.setMaxTotal(maxPoolSize); + // // 默认的每个路由的最大连接数 + pool.setDefaultMaxPerRoute(corePoolSize); + custom.setConnectionManager(pool); + return custom.build(); + } }