From 9af9d61535de779149d332b23ee8f8ddd7e33cbf Mon Sep 17 00:00:00 2001 From: FLYPHT <1035748121@qq.com> Date: Tue, 6 Sep 2022 13:38:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E6=B7=BB=E5=8A=A0Ht?= =?UTF-8?q?tpUtil=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- smtweb-framework/core/pom.xml | 10 + .../cc/smtweb/framework/core/common/SwConsts.java | 2 +- .../cc/smtweb/framework/core/util/HttpUtil.java | 458 +++++++++++++++++++++ 3 files changed, 469 insertions(+), 1 deletion(-) create mode 100644 smtweb-framework/core/src/main/java/cc/smtweb/framework/core/util/HttpUtil.java diff --git a/smtweb-framework/core/pom.xml b/smtweb-framework/core/pom.xml index f277f76..4e524ba 100644 --- a/smtweb-framework/core/pom.xml +++ b/smtweb-framework/core/pom.xml @@ -34,6 +34,16 @@ org.springframework.boot spring-boot-starter-web + + org.apache.httpcomponents + httpclient + 4.5.13 + + + org.apache.httpcomponents + httpcore + 4.4.15 + com.fasterxml.jackson.core diff --git a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/common/SwConsts.java b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/common/SwConsts.java index 77453e2..d76fb3d 100644 --- a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/common/SwConsts.java +++ b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/common/SwConsts.java @@ -6,7 +6,7 @@ package cc.smtweb.framework.core.common; public interface SwConsts { class SysParam { //开发调试模式 - public static final boolean SYS_DEBUG = true; + public static boolean SYS_DEBUG = true; //系统启动完成 public static boolean SYS_STARTED = false; //运行的项目,多个用半角逗号分隔 diff --git a/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/util/HttpUtil.java b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/util/HttpUtil.java new file mode 100644 index 0000000..0e47993 --- /dev/null +++ b/smtweb-framework/core/src/main/java/cc/smtweb/framework/core/util/HttpUtil.java @@ -0,0 +1,458 @@ +package cc.smtweb.framework.core.util; + +import cc.smtweb.framework.core.common.SwMap; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.*; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.HttpClientConnectionManager; +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.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.LaxRedirectStrategy; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.TrustStrategy; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * Created by Akmm at 2017/7/4 16:58 + * http辅助类,支持http/https + */ +@Slf4j +public class HttpUtil { + private static final String HTTP = "http"; + private static final String HTTPS = "https"; + private static SSLConnectionSocketFactory sslsf = null; + private static PoolingHttpClientConnectionManager cm = null; + private static SSLContextBuilder builder = null; + private static RequestConfig requestConfig = null; + + private static final Integer MAX_TOTAL = 200; //连接池最大连接数 + private static final Integer MAX_PER_ROUTE = 100; //单个路由默认最大连接数 + private static final Integer REQ_TIMEOUT = 10 * 1000; //请求超时时间ms + private static final Integer CONN_TIMEOUT = 10 * 1000; //连接超时时间ms + private static final Integer SOCK_TIMEOUT = 5 * 60 * 1000; //读取超时时间ms + private static HttpClientConnectionMonitorThread thread; //HTTP链接管理器线程 + + + static { + try { + builder = new SSLContextBuilder(); + // 全部信任 不做身份鉴定 + builder.loadTrustMaterial(null, new TrustStrategy() { + @Override + public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + return true; + } + }); + sslsf = new SSLConnectionSocketFactory(builder.build(), new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE); + Registry registry = RegistryBuilder.create() + .register(HTTP, new PlainConnectionSocketFactory()) + .register(HTTPS, sslsf) + .build(); + cm = new PoolingHttpClientConnectionManager(registry); + cm.setMaxTotal(MAX_TOTAL);//max connection + cm.setDefaultMaxPerRoute(MAX_PER_ROUTE); + thread = new HttpClientConnectionMonitorThread(cm); + + requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(REQ_TIMEOUT) //从连接池中获取连接的超时时间 + //与服务器连接超时时间:httpclient会创建一个异步线程用以创建socket连接,此处设置该socket的连接超时时间 + .setConnectTimeout(CONN_TIMEOUT) + .setSocketTimeout(SOCK_TIMEOUT) //socket读数据超时时间:从服务器获取响应数据的超时时间 + .build(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * http调用 + * + * @param url 请求地址 + * @param paras 参数,name,value形式 + * @return + * @throws Exception + */ + public static SwMap post(String url, String... paras) throws Exception { + SwMap map = new SwMap(); + int n = 0; + while (n < paras.length) { + map.put(paras[n++], paras[n++]); + } + return post(url, map); + } + + public static SwMap post(String url, Map paras) throws Exception { + String json_resp = post(url, null, paras, null); + if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; + return (SwMap) JsonUtil.parseMap(json_resp); + } + + /** + * Post 请求 + * + * @param url 请求url + * @param paras json 格式参数 + * @return + * @throws Exception + */ + public static SwMap post(String url, SwMap paras) throws Exception { + return post(url, paras, false); + } + + /** + * Post 请求 + * + * @param url 请求url + * @param paras json 参数 + * @param encode json 是否加密传输 + * @return + * @throws Exception + */ + public static SwMap post(String url, SwMap paras, boolean encode) throws Exception { + return post(url, paras, encode, null); + } + + public static SwMap post(String url, SwMap paras, boolean encode, String charset) throws Exception { + if (StringUtils.isEmpty(charset)) charset = "UTF-8"; + String param = JsonUtil.encodeString(paras); + if (encode) param = Base64.encodeBase64String(param.getBytes(charset)); + StringEntity entity = new StringEntity(param, charset);//解决中文乱码问题 + entity.setContentEncoding(charset); + entity.setContentType("application/json"); + String json_resp = post(url, null, null, entity, charset); + if (encode && !json_resp.startsWith("{")) {//加密传输时,解密 + json_resp = new String(Base64.decodeBase64(json_resp),charset); + } + if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; + return (SwMap)JsonUtil.parseMap(json_resp); + } + + /** + * 加密请求 + * + * @param url + * @param paras + * @param encode + * @return + * @throws Exception + */ + public static SwMap post(String url, Map paras, boolean encode) throws Exception { + return post(url, paras, encode, null); + } + + public static SwMap post(String url, Map paras, boolean encode, String charset) throws Exception { + String json_resp = post(url, null, paras, null, charset); + if (encode) { + json_resp = new String(Base64.decodeBase64(json_resp),charset); + } + if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; + return (SwMap)JsonUtil.parseMap(json_resp); + } + + + public static SwMap post(String url,Map header, Map paras) throws Exception { + String json_resp = post(url, header, paras, null); + if (StringUtils.isEmpty(json_resp) || !json_resp.startsWith("{")) return null; + return (SwMap) JsonUtil.parseMap(json_resp); + } + + /** + * httpClient post请求 + * + * @param url 请求url + * @param header 头部信息 + * @param param 请求参数 form提交适用 + * @param entity 请求实体 json/xml提交适用 + * @return 可能为空 需要处理 + * @throws Exception + */ + public static String post(String url, Map header, Map param, HttpEntity entity) throws Exception { + return post(url, header, param, entity, null); + } + public static String post(String url, Map header, Map param, HttpEntity entity, String charset) throws Exception { + return postEx(url,header,param,entity,charset,null); + } + public static String postEx(String url, Map header, Map param, HttpEntity entity, String charset, Consumer headerWorker) throws Exception { + if (StringUtils.isEmpty(charset)) charset = "UTF-8"; + String result = ""; + CloseableHttpClient httpClient = null; + HttpResponse httpResponse = null; + try { + httpClient = getHttpClient(); + HttpPost httpPost = getHttpPost(url); + // 设置头信息 + if (header!=null && header.size()>0) { + for (Map.Entry entry : header.entrySet()) { + httpPost.addHeader(entry.getKey(), entry.getValue()); + } + } + // 设置请求参数 + if (param!=null && param.size()>0) { + List formparams = new ArrayList<>(); + for (Map.Entry entry : param.entrySet()) { + //给参数赋值 + formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(formparams, charset); + httpPost.setEntity(urlEncodedFormEntity); + } + // 设置实体 优先级高 + if (entity != null) { + httpPost.setEntity(entity); + } + httpResponse = httpClient.execute(httpPost); + int statusCode = httpResponse.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + if(headerWorker!=null){ + headerWorker.accept(httpResponse.getAllHeaders()); + } + HttpEntity resEntity = httpResponse.getEntity(); + result = EntityUtils.toString(resEntity, charset); + EntityUtils.consume(resEntity); + } else { + result = readHttpResponse(httpResponse); + } + } catch (Exception e) { + log.error("POST_ERROR:",e); + } finally { + if (httpClient != null) { + httpClient.close(); + } + if (httpResponse != null) { + HttpEntity httpEntity = httpResponse.getEntity(); + if (httpEntity != null) { + EntityUtils.consume(httpEntity); + } + } + } + return result; + } + + /** + * httpClient post请求 + * + * @param url 请求url + * @param header 头部信息 + * @return 可能为空 需要处理 + * @throws Exception + */ + public static String get(String url, Map header) throws Exception { + String result = ""; + CloseableHttpClient httpClient = null; + HttpResponse httpResponse = null; + try { + httpClient = HttpUtil.getHttpClient(); + HttpGet httpGet = new HttpGet(url); + httpGet.setConfig(requestConfig); + // 设置头信息 + if (header!=null && header.size()>0) { + for (Map.Entry entry : header.entrySet()) { + httpGet.addHeader(entry.getKey(), entry.getValue()); + } + } + httpResponse = httpClient.execute(httpGet); + int statusCode = httpResponse.getStatusLine().getStatusCode(); + if (statusCode == HttpStatus.SC_OK) { + HttpEntity resEntity = httpResponse.getEntity(); + result = EntityUtils.toString(resEntity); + EntityUtils.consume(resEntity); + } else { + result = readHttpResponse(httpResponse); + } + } finally { + if (httpClient != null) { + httpClient.close(); + } + if (httpResponse != null) { + HttpEntity httpEntity = httpResponse.getEntity(); + if (httpEntity != null) { + EntityUtils.consume(httpEntity); + } + } + } + return result; + } + + public static CloseableHttpClient getHttpClient() throws Exception { +// thread = new HttpClientConnectionMonitorThread(cm); + CloseableHttpClient httpClient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .setConnectionManager(cm) + .setConnectionManagerShared(true) + .disableAutomaticRetries() //关闭自动处理重定向 + .setRedirectStrategy(new LaxRedirectStrategy())//利用LaxRedirectStrategy处理POST重定向问题 + .setDefaultRequestConfig(requestConfig) + .build(); + + return httpClient; + } + + public static HttpPost getHttpPost(String url) { + HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + return httpPost; + } + + private static String readHttpResponse(HttpResponse httpResponse) + throws ParseException, IOException { + StringBuilder builder = new StringBuilder(); + // 获取响应消息实体 + HttpEntity entity = httpResponse.getEntity(); + // 响应状态 + builder.append("status:" + httpResponse.getStatusLine()); + builder.append("headers:"); + HeaderIterator iterator = httpResponse.headerIterator(); + while (iterator.hasNext()) { + builder.append("\t" + iterator.next()); + } + // 判断响应实体是否为空 + if (entity != null) { + String responseString = EntityUtils.toString(entity); + builder.append("response length:" + responseString.length()); + builder.append("response content:" + responseString.replace("\r\n", "")); + } + return builder.toString(); + } + + public static void main(String[] args) throws Exception { + + +// //用线程池发送请求 +// ExecutorService executor = Executors.newFixedThreadPool(3); +// +// Thread t1 = new Thread(new Runnable() { +// @Override +// public void run() { +// for (int i = 0; i < 100; i++) { +// HttpPost post = getHttpPost("http://127.0.0.1:8080/qhmz/receiveBankData.do"); +// System.out.println("请求第【" + (i + 1) + "】次:【receiveBankData】"); +// try { +// CloseableHttpClient httpclient = UtilHttp.getHttpClient(); +// CloseableHttpResponse response2 = httpclient.execute(post); +// System.out.println("请求第【" + (i + 1) + "】次:【" + post.getURI() + "】,结果" + response2.getStatusLine()); +// httpclient.close(); +// EntityUtils.consume(response2.getEntity()); +// } catch (Exception e) { +// System.out.println("请求第【" + (i + 1) + "】次:【" + post.getURI() + "】" + UtilPub.getOrigMsg(e)); +// } +// +// } +// } +// }); +// Thread t2 = new Thread(new Runnable() { +// @Override +// public void run() { +// for (int i = 0; i < 100; i++) { +// HttpPost post = getHttpPost("http://127.0.0.1:8080/qhmz/cust/ebank/biz/service.do"); +// System.out.println("请求第【" + (i + 1) + "】次:【service】"); +// try { +// CloseableHttpClient httpclient = UtilHttp.getHttpClient(); +// CloseableHttpResponse response2 = httpclient.execute(post); +// System.out.println("请求第【" + (i + 1) + "】次:【" + post.getURI() + "】,结果" + response2.getStatusLine()); +// httpclient.close(); +// EntityUtils.consume(response2.getEntity()); +// } catch (Exception e) { +// System.out.println("请求第【" + (i + 1) + "】次:【" + post.getURI() + "】" + UtilPub.getOrigMsg(e)); +// } +// +// } +// } +// }); +// Thread t3 = new Thread(new Runnable() { +// @Override +// public void run() { +// for (int i = 0; i < 100; i++) { +// HttpPost post = getHttpPost("http://127.0.0.1:8080/qhmz/cust/ebank/biz/isSupBank.do"); +// System.out.println("请求第【" + (i + 1) + "】次:【isSupBank】"); +// try { +// CloseableHttpClient httpclient = UtilHttp.getHttpClient(); +// CloseableHttpResponse response2 = httpclient.execute(post); +// System.out.println("请求第【" + (i + 1) + "】次:【" + post.getURI() + "】,结果" + response2.getStatusLine()); +// httpclient.close(); +// EntityUtils.consume(response2.getEntity()); +// } catch (Exception e) { +// System.out.println("请求第【" + (i + 1) + "】次:【" + post.getURI() + "】" + UtilPub.getOrigMsg(e)); +// } +// +// } +// } +// }); +// executor.execute(t1); +// executor.execute(t2); +// executor.execute(t3); +// executor.shutdown(); + } + + /** + *

Description: 使用管理器,管理HTTP连接池 无效链接定期清理功能

+ * + * @author andy 2017年8月28日 + */ + public static class HttpClientConnectionMonitorThread extends Thread { + + private final HttpClientConnectionManager connManager; + private volatile boolean shutdown; + + public HttpClientConnectionMonitorThread(HttpClientConnectionManager connManager) { + super(); + this.setName("http-connection-monitor"); + this.setDaemon(true); + this.connManager = connManager; + this.start(); + } + + @Override + public void run() { + try { + while (!shutdown) { + synchronized (this) { + wait(5000); // 等待5秒 + // 关闭过期的链接 + connManager.closeExpiredConnections(); + // 选择关闭 空闲30秒的链接 + connManager.closeIdleConnections(30, TimeUnit.SECONDS); + } + } + } catch (InterruptedException ex) { + } + } + + /** + * 方法描述: 停止 管理器 清理无效链接 (该方法当前暂时关闭) + * + * @author andy 2017年8月28日 下午1:45:18 + */ + @Deprecated + public void shutDownMonitor() { + synchronized (this) { + shutdown = true; + notifyAll(); + } + } + + } + +}