wangyunpeng 1 неделя назад
Родитель
Сommit
ff563d4581

+ 0 - 15
core/src/main/java/com/tzld/ad/config/AppConfig.java

@@ -1,15 +0,0 @@
-package com.tzld.ad.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.client.RestTemplate;
-
-@Configuration
-public class AppConfig {  
-  
-    @Bean
-    public RestTemplate restTemplate() {
-        return new RestTemplate();  
-    }
-
-}

+ 24 - 19
core/src/main/java/com/tzld/ad/job/adPut/AdPutTencentAlarmJob.java

@@ -20,21 +20,19 @@ import com.tzld.ad.util.OdpsUtil;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import com.xxl.job.core.handler.annotation.XxlJob;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.CollectionUtils;
-import org.springframework.web.client.RestTemplate;
 
 
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.math.MathContext;
 import java.math.MathContext;
 import java.net.URLDecoder;
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.nio.charset.StandardCharsets;
 import java.util.*;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 @Slf4j
 @Slf4j
@@ -51,8 +49,14 @@ public class AdPutTencentAlarmJob {
     private AdPutTencentExtMapper adPutTencentExtMapper;
     private AdPutTencentExtMapper adPutTencentExtMapper;
     @Autowired
     @Autowired
     private AdOwnRedisUtils adOwnRedisUtils;
     private AdOwnRedisUtils adOwnRedisUtils;
-    @Autowired
-    private RestTemplate restTemplate;
+
+    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+    private static final OkHttpClient httpClient = new OkHttpClient.Builder()
+            .connectTimeout(30, TimeUnit.SECONDS)
+            .readTimeout(30, TimeUnit.SECONDS)
+            .writeTimeout(30, TimeUnit.SECONDS)
+            .build();
 
 
     @ApolloJsonValue("${partner.creative.rootSourceId.robot.config:{\"棱镜\":\"https://open.feishu.cn/open-apis/bot/v2/hook/b55e2b97-84d4-4b77-9bd6-c3a62f23b986\",\"鲸禾\":\"https://open.feishu.cn/open-apis/bot/v2/hook/d467841e-1ea4-458a-acbd-577d8c1692c0\",\"像素\":\"https://open.feishu.cn/open-apis/bot/v2/hook/1fe05cc1-4b20-48e5-bc72-2781952e1aa5\"}}")
     @ApolloJsonValue("${partner.creative.rootSourceId.robot.config:{\"棱镜\":\"https://open.feishu.cn/open-apis/bot/v2/hook/b55e2b97-84d4-4b77-9bd6-c3a62f23b986\",\"鲸禾\":\"https://open.feishu.cn/open-apis/bot/v2/hook/d467841e-1ea4-458a-acbd-577d8c1692c0\",\"像素\":\"https://open.feishu.cn/open-apis/bot/v2/hook/1fe05cc1-4b20-48e5-bc72-2781952e1aa5\"}}")
     private Map<String, String> creativeCheckPartnerRobotConfig;
     private Map<String, String> creativeCheckPartnerRobotConfig;
@@ -154,18 +158,19 @@ public class AdPutTencentAlarmJob {
     }
     }
 
 
     private String sendMsg(String url, String jsonString) {
     private String sendMsg(String url, String jsonString) {
-        // 创建请求头
-        HttpHeaders headers = new HttpHeaders();
-        headers.setContentType(MediaType.APPLICATION_JSON);
-
-        // 创建HttpEntity
-        HttpEntity<String> request = new HttpEntity<>(jsonString, headers);
-
-        // 发送POST请求
-        ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
-
-        // 返回响应体
-        return response.getBody();
+        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonString);
+        Request request = new Request.Builder()
+                .url(url)
+                .post(body)
+                .addHeader("Content-Type", "application/json")
+                .build();
+
+        try (Response response = httpClient.newCall(request).execute()) {
+            return response.body() != null ? response.body().string() : null;
+        } catch (IOException e) {
+            log.error("sendMsg error, url:{}, jsonString:{}", url, jsonString, e);
+            return null;
+        }
     }
     }
 
 
 
 

+ 69 - 85
core/src/main/java/com/tzld/ad/service/adput/impl/AdPutTencentCommonServiceImpl.java

@@ -34,15 +34,8 @@ import com.tzld.ad.service.platform.MqService;
 import com.tzld.ad.util.*;
 import com.tzld.ad.util.*;
 import com.tzld.ad.util.adPut.AdPutTencentUtil;
 import com.tzld.ad.util.adPut.AdPutTencentUtil;
 import com.tzld.ad.util.adPut.TextFileSplitter;
 import com.tzld.ad.util.adPut.TextFileSplitter;
+import okhttp3.*;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.ContentType;
-import org.apache.http.entity.mime.MultipartEntityBuilder;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeanUtils;
@@ -69,9 +62,13 @@ public class AdPutTencentCommonServiceImpl implements AdPutTencentCommonService
 
 
     private final static Logger log = LoggerFactory.getLogger(AdPutTencentCommonServiceImpl.class);
     private final static Logger log = LoggerFactory.getLogger(AdPutTencentCommonServiceImpl.class);
 
 
-    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
+    private static final OkHttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
 
 
-    private static final HttpClient httpClient = HttpClients.createDefault();
+    private static final OkHttpClient httpClient = new OkHttpClient.Builder()
+            .connectTimeout(60, TimeUnit.SECONDS)
+            .readTimeout(60, TimeUnit.SECONDS)
+            .writeTimeout(60, TimeUnit.SECONDS)
+            .build();
 
 
     @Resource
     @Resource
     private LoghubService loghubService;
     private LoghubService loghubService;
@@ -234,57 +231,49 @@ public class AdPutTencentCommonServiceImpl implements AdPutTencentCommonService
     public String uploadVideoMaterial(List<AdPutTencentMaterialUploadHandle> adPutTencentMaterialUploadHandles) {
     public String uploadVideoMaterial(List<AdPutTencentMaterialUploadHandle> adPutTencentMaterialUploadHandles) {
         SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
         SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
         adPutTencentMaterialUploadHandles.forEach(adPutTencentMaterialUploadHandle -> {
         adPutTencentMaterialUploadHandles.forEach(adPutTencentMaterialUploadHandle -> {
-            HttpPost httpPost = new HttpPost("https://api.e.qq.com/v3.0/videos/add?access_token=" + getAccessToken(useAccountId) +
+            String url = "https://api.e.qq.com/v3.0/videos/add?access_token=" + getAccessToken(useAccountId) +
                     "&timestamp=" + getTimestamp() +
                     "&timestamp=" + getTimestamp() +
-                    "&nonce=" + getNonce());
+                    "&nonce=" + getNonce();
             // 去重
             // 去重
             // 上传素材
             // 上传素材
             if (StringUtils.isNotBlank(adPutTencentMaterialUploadHandle.getVideoAfterPath())) {
             if (StringUtils.isNotBlank(adPutTencentMaterialUploadHandle.getVideoAfterPath())) {
                 File aliYunOssFile = getAliYunOssFile(BUCKET, adPutTencentMaterialUploadHandle.getVideoAfterPath());
                 File aliYunOssFile = getAliYunOssFile(BUCKET, adPutTencentMaterialUploadHandle.getVideoAfterPath());
 
 
-                // 设置 parameters(这里只设置 JSON 部分的参数,因为文件上传需要特殊处理)
-                MultipartEntityBuilder builder = MultipartEntityBuilder.create();
-                builder.addTextBody("account_id", useAccountId);
                 try {
                 try {
-                    builder.addTextBody("signature", FileMD5Calculator.getFileMD5(aliYunOssFile));
-                } catch (IOException | NoSuchAlgorithmException e) {
-                    throw new RuntimeException(e);
-                }
-
-                String description = df.format(new Date()) + "_" + adPutTencentMaterialUploadHandle.getVideoTitle() + "_" +
-                        adPutTencentMaterialUploadHandle.getDesc() + "_" + adPutTencentMaterialUploadHandle.getVideoId() + "_" + adPutTencentMaterialUploadHandle.getId();
-                builder.addTextBody("description", description, ContentType.APPLICATION_JSON);
-
-
-                // 注意:文件上传需要使用不同的方法添加到 MultipartEntityBuilder 中
-//                builder.addBinaryBody("video_file", aliYunOssFile, ContentType.DEFAULT_BINARY, new String("测试视频001.mp4".getBytes(StandardCharsets.UTF_8)));
-                builder.addBinaryBody("video_file", aliYunOssFile);
-                HttpEntity multipart = builder.build();
-                httpPost.setEntity(multipart);
-
-                HttpResponse response = null;
-                try {
-                    response = httpClient.execute(httpPost);
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-                HttpEntity responseEntity = response.getEntity();
-
-                // 读取响应内容并返回
-                try {
-                    String responseStr = EntityUtils.toString(responseEntity, "UTF-8");
-                    log.info("uploadVideoMaterial process data:" + JSON.toJSONString(adPutTencentMaterialUploadHandle) + ",upload tencent response:" + responseStr);
-                    JSONObject tencentResponse = JSONObject.parseObject(responseStr);
-                    adPutTencentMaterialUploadHandle.setMaterialName(description);
-                    adPutTencentMaterialUploadHandle.setResponse(responseStr);
-                    if (tencentResponse.containsKey("code") && tencentResponse.getInteger("code") == 0) {
-                        adPutTencentMaterialUploadHandle.setMaterialId(JSONObject.parseObject(tencentResponse.getString("data")).getLong("video_id"));
-                        adPutTencentMaterialUploadHandle.setProcesseNode(2);
-                    } else {
-                        adPutTencentMaterialUploadHandle.setProcesseNode(3);
+                    // 构建Multipart请求体
+                    MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
+                    builder.addFormDataPart("account_id", useAccountId);
+                    builder.addFormDataPart("signature", FileMD5Calculator.getFileMD5(aliYunOssFile));
+
+                    String description = df.format(new Date()) + "_" + adPutTencentMaterialUploadHandle.getVideoTitle() + "_" +
+                            adPutTencentMaterialUploadHandle.getDesc() + "_" + adPutTencentMaterialUploadHandle.getVideoId() + "_" + adPutTencentMaterialUploadHandle.getId();
+                    builder.addFormDataPart("description", description);
+
+                    // 添加视频文件
+                    MediaType mediaType = MediaType.parse("application/octet-stream");
+                    builder.addFormDataPart("video_file", aliYunOssFile.getName(), RequestBody.create(mediaType, aliYunOssFile));
+
+                    RequestBody requestBody = builder.build();
+                    Request request = new Request.Builder()
+                            .url(url)
+                            .post(requestBody)
+                            .build();
+
+                    try (Response response = httpClient.newCall(request).execute()) {
+                        String responseStr = response.body() != null ? response.body().string() : "";
+                        log.info("uploadVideoMaterial process data:" + JSON.toJSONString(adPutTencentMaterialUploadHandle) + ",upload tencent response:" + responseStr);
+                        JSONObject tencentResponse = JSONObject.parseObject(responseStr);
+                        adPutTencentMaterialUploadHandle.setMaterialName(description);
+                        adPutTencentMaterialUploadHandle.setResponse(responseStr);
+                        if (tencentResponse.containsKey("code") && tencentResponse.getInteger("code") == 0) {
+                            adPutTencentMaterialUploadHandle.setMaterialId(JSONObject.parseObject(tencentResponse.getString("data")).getLong("video_id"));
+                            adPutTencentMaterialUploadHandle.setProcesseNode(2);
+                        } else {
+                            adPutTencentMaterialUploadHandle.setProcesseNode(3);
+                        }
+                        adPutTencentMaterialUploadHandleMapper.updateByPrimaryKeySelective(adPutTencentMaterialUploadHandle);
                     }
                     }
-                    adPutTencentMaterialUploadHandleMapper.updateByPrimaryKeySelective(adPutTencentMaterialUploadHandle);
-                } catch (IOException e) {
+                } catch (IOException | NoSuchAlgorithmException e) {
                     throw new RuntimeException(e);
                     throw new RuntimeException(e);
                 }
                 }
                 aliYunOssFile.delete();
                 aliYunOssFile.delete();
@@ -485,41 +474,36 @@ public class AdPutTencentCommonServiceImpl implements AdPutTencentCommonService
 
 
             for (File file : files) {
             for (File file : files) {
                 System.out.println(file.getName() + "--------------size:" + getFileSizeInMB(file));
                 System.out.println(file.getName() + "--------------size:" + getFileSizeInMB(file));
-                // 设置 parameters(这里只设置 JSON 部分的参数,因为文件上传需要特殊处理)
-                MultipartEntityBuilder builder = MultipartEntityBuilder.create();
-                builder.addTextBody("account_id", accountId);
-                builder.addTextBody("audience_id", audienceId);
-                builder.addTextBody("user_id_type", userIdType);
-                builder.addTextBody("open_app_id", open_app_id);
-                try {
-                    builder.addTextBody("signature", FileMD5Calculator.getFileMD5(file));
-                } catch (IOException | NoSuchAlgorithmException e) {
-                    throw new RuntimeException(e);
-                }
-
-                HttpPost httpPost = new HttpPost("https://api.e.qq.com/v3.0/custom_audience_files/add?access_token=" + getAccessToken(accountId) +
+                
+                String url = "https://api.e.qq.com/v3.0/custom_audience_files/add?access_token=" + getAccessToken(accountId) +
                         "&timestamp=" + getTimestamp() +
                         "&timestamp=" + getTimestamp() +
-                        "&nonce=" + getNonce());
+                        "&nonce=" + getNonce();
 
 
-                // 注意:文件上传需要使用不同的方法添加到 MultipartEntityBuilder 中
-                builder.addBinaryBody("file", file);
-                HttpEntity multipart = builder.build();
-                httpPost.setEntity(multipart);
-
-                HttpResponse response = null;
                 try {
                 try {
-                    response = httpClient.execute(httpPost);
-                } catch (IOException e) {
-                    throw new RuntimeException(e);
-                }
-                HttpEntity responseEntity = response.getEntity();
-
-                // 读取响应内容并返回
-                try {
-                    String responseStr = EntityUtils.toString(responseEntity, "UTF-8");
-                    aliYunOssFile.delete();
-                    customAudienceFileIds.add(AdPutTencentUtil.getAdPutTencentCreateCrowdFileByResponse(responseStr));
-                } catch (IOException e) {
+                    // 构建Multipart请求体
+                    MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
+                    builder.addFormDataPart("account_id", accountId);
+                    builder.addFormDataPart("audience_id", audienceId);
+                    builder.addFormDataPart("user_id_type", userIdType);
+                    builder.addFormDataPart("open_app_id", open_app_id);
+                    builder.addFormDataPart("signature", FileMD5Calculator.getFileMD5(file));
+
+                    // 添加文件
+                    MediaType mediaType = MediaType.parse("application/octet-stream");
+                    builder.addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file));
+
+                    RequestBody requestBody = builder.build();
+                    Request request = new Request.Builder()
+                            .url(url)
+                            .post(requestBody)
+                            .build();
+
+                    try (Response response = httpClient.newCall(request).execute()) {
+                        String responseStr = response.body() != null ? response.body().string() : "";
+                        aliYunOssFile.delete();
+                        customAudienceFileIds.add(AdPutTencentUtil.getAdPutTencentCreateCrowdFileByResponse(responseStr));
+                    }
+                } catch (IOException | NoSuchAlgorithmException e) {
                     throw new RuntimeException(e);
                     throw new RuntimeException(e);
                 }
                 }
             }
             }

+ 2 - 2
core/src/main/java/com/tzld/ad/service/adput/impl/AdPutTencentUserActionAddServiceImpl.java

@@ -17,7 +17,7 @@ import com.tzld.ad.service.AdOwnRedisUtils;
 import com.tzld.ad.service.adput.AdPutTencentUserActionAddService;
 import com.tzld.ad.service.adput.AdPutTencentUserActionAddService;
 import com.tzld.ad.util.DateTimeUtils;
 import com.tzld.ad.util.DateTimeUtils;
 import com.tzld.ad.util.HttpClientUtil;
 import com.tzld.ad.util.HttpClientUtil;
-import com.tzld.ad.util.HttpPoolClient;
+import com.tzld.ad.util.OkHttpPoolClient;
 import com.tzld.ad.util.adPut.AdPutTencentUtil;
 import com.tzld.ad.util.adPut.AdPutTencentUtil;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringUtils;
@@ -36,7 +36,7 @@ public class AdPutTencentUserActionAddServiceImpl implements AdPutTencentUserAct
 
 
     private final static Logger log = LoggerFactory.getLogger(AdPutTencentUserActionAddServiceImpl.class);
     private final static Logger log = LoggerFactory.getLogger(AdPutTencentUserActionAddServiceImpl.class);
 
 
-    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
+    private static final OkHttpPoolClient httpPoolClientDefault = HttpClientUtil.create(30000, 30000, 2000, 5000, 5, 30000);
 
 
     @Resource
     @Resource
     private AdPutTencentCommonServiceImpl adPutTencentCommonService;
     private AdPutTencentCommonServiceImpl adPutTencentCommonService;

+ 2 - 2
core/src/main/java/com/tzld/ad/service/aigc/AigcApiService.java

@@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.tzld.ad.model.aigc.GoogleLLMResult;
 import com.tzld.ad.model.aigc.GoogleLLMResult;
 import com.tzld.ad.util.HttpClientUtil;
 import com.tzld.ad.util.HttpClientUtil;
-import com.tzld.ad.util.HttpPoolClient;
+import com.tzld.ad.util.OkHttpPoolClient;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -18,7 +18,7 @@ import java.util.Optional;
 @Component
 @Component
 public class AigcApiService {
 public class AigcApiService {
 
 
-    private static final HttpPoolClient httpPoolClient = HttpClientUtil.create(5000, 120000, 200, 500, 0, 5000);
+    private static final OkHttpPoolClient httpPoolClient = HttpClientUtil.create(5000, 120000, 200, 500, 0, 5000);
 
 
     public String gpt(String model, String prompt, JSONObject responseFormat, List<String> imageList) {
     public String gpt(String model, String prompt, JSONObject responseFormat, List<String> imageList) {
         if (StringUtils.isEmpty(model) || StringUtils.isEmpty(prompt)) {
         if (StringUtils.isEmpty(model) || StringUtils.isEmpty(prompt)) {

+ 28 - 23
core/src/main/java/com/tzld/ad/service/feishu/FeiShuService.java

@@ -1,37 +1,35 @@
 package com.tzld.ad.service.feishu;
 package com.tzld.ad.service.feishu;
 
 
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
+import okhttp3.*;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.http.converter.StringHttpMessageConverter;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
 
 
 import javax.annotation.PostConstruct;
 import javax.annotation.PostConstruct;
-import javax.annotation.Resource;
-import java.nio.charset.StandardCharsets;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
 
 
 /**
 /**
- * 飞书机器人发送信息组件
+ * 飞书机器人发送信息组件 (基于OkHttp实现)
  */
  */
 @Component
 @Component
 public class FeiShuService {
 public class FeiShuService {
 
 
     private static final Logger log = LoggerFactory.getLogger(FeiShuService.class);
     private static final Logger log = LoggerFactory.getLogger(FeiShuService.class);
 
 
-    //https://open.feishu.cn/open-apis/bot/v2/hook/6df5a1cb-5308-4d0f-b0e7-a1ef25a363e9
-    private RestTemplate restTemplate;
+    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+    private OkHttpClient httpClient;
 
 
 
 
     @PostConstruct
     @PostConstruct
     public void init() {
     public void init() {
-        restTemplate = new RestTemplate();
-        // 设置restemplate编码为utf-8
-        restTemplate.getMessageConverters().set(1,new StringHttpMessageConverter(StandardCharsets.UTF_8));
+        httpClient = new OkHttpClient.Builder()
+                .connectTimeout(30, TimeUnit.SECONDS)
+                .readTimeout(30, TimeUnit.SECONDS)
+                .writeTimeout(30, TimeUnit.SECONDS)
+                .build();
     }
     }
     /**
     /**
      * 发送机器人消息
      * 发送机器人消息
@@ -42,15 +40,22 @@ public class FeiShuService {
      */
      */
     public String sendMsg(String text, String url) {
     public String sendMsg(String text, String url) {
         log.info("FeiShuService.sendMsg, text:{}, url:{}", text, url);
         log.info("FeiShuService.sendMsg, text:{}, url:{}", text, url);
-        // 创建请求头
-        HttpHeaders headers = new HttpHeaders();
-        MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8");
-        headers.setContentType(type);
-        HttpEntity<String> httpEntity = new HttpEntity<>(text, headers);
-        // 发送POST请求
-        String rsp = restTemplate.postForObject(url, httpEntity, String.class);
-        log.info("FeiShuService.sendMsg, rsp:{}", rsp);
-        return rsp;
+        
+        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, text);
+        Request request = new Request.Builder()
+                .url(url)
+                .post(body)
+                .addHeader("Content-Type", "application/json;charset=UTF-8")
+                .build();
+        
+        try (Response response = httpClient.newCall(request).execute()) {
+            String rsp = response.body() != null ? response.body().string() : null;
+            log.info("FeiShuService.sendMsg, rsp:{}", rsp);
+            return rsp;
+        } catch (IOException e) {
+            log.error("FeiShuService.sendMsg error, url:{}, text:{}", url, text, e);
+            return null;
+        }
     }
     }
 
 
 
 

+ 13 - 13
core/src/main/java/com/tzld/ad/util/HttpClientUtil.java

@@ -43,34 +43,34 @@ public class HttpClientUtil {
      */
      */
     private static final int DEFAULT_CONNECTION_WAIT_TIMEOUT = 300;
     private static final int DEFAULT_CONNECTION_WAIT_TIMEOUT = 300;
 
 
-    private static final Map<String, HttpPoolClient> CREATED_HTTP_CLIENTS = new HashMap<>();
+    private static final Map<String, OkHttpPoolClient> CREATED_HTTP_CLIENTS = new HashMap<>();
 
 
     private static final Lock LOCK = new ReentrantLock();
     private static final Lock LOCK = new ReentrantLock();
 
 
     private HttpClientUtil() {
     private HttpClientUtil() {
     }
     }
 
 
-    public static HttpPoolClient useDefault() {
+    public static OkHttpPoolClient useDefault() {
         return createCached(DEFAULT_SHARED_KEY);
         return createCached(DEFAULT_SHARED_KEY);
     }
     }
 
 
 
 
-    public static HttpPoolClient createCached(String cachedKey) {
-        HttpPoolClient httpPoolClient = CREATED_HTTP_CLIENTS.get(cachedKey);
-        if (httpPoolClient != null) {
-            return httpPoolClient;
+    public static OkHttpPoolClient createCached(String cachedKey) {
+        OkHttpPoolClient httpClient = CREATED_HTTP_CLIENTS.get(cachedKey);
+        if (httpClient != null) {
+            return httpClient;
         }
         }
         LOCK.lock();
         LOCK.lock();
         try {
         try {
-            httpPoolClient = CREATED_HTTP_CLIENTS.get(cachedKey);
-            if (httpPoolClient == null) {
-                httpPoolClient = create(DEFAULT_CONNECTION_TIMEOUT, DEFAULT_SOCKET_TIMEOUT, DEFAULT_DEFAULT_MAX_PER_ROUTE, DEFAULT_DEFAULT_MAX_TOTAL, DEFAULT_RETRY_COUNT, DEFAULT_CONNECTION_WAIT_TIMEOUT);
-                CREATED_HTTP_CLIENTS.put(cachedKey, httpPoolClient);
+            httpClient = CREATED_HTTP_CLIENTS.get(cachedKey);
+            if (httpClient == null) {
+                httpClient = create(DEFAULT_CONNECTION_TIMEOUT, DEFAULT_SOCKET_TIMEOUT, DEFAULT_DEFAULT_MAX_PER_ROUTE, DEFAULT_DEFAULT_MAX_TOTAL, DEFAULT_RETRY_COUNT, DEFAULT_CONNECTION_WAIT_TIMEOUT);
+                CREATED_HTTP_CLIENTS.put(cachedKey, httpClient);
             }
             }
         } finally {
         } finally {
             LOCK.unlock();
             LOCK.unlock();
         }
         }
-        return httpPoolClient;
+        return httpClient;
     }
     }
 
 
     /**
     /**
@@ -84,7 +84,7 @@ public class HttpClientUtil {
      * @param connectionWaitTimeout 连接等待超市时间 ms
      * @param connectionWaitTimeout 连接等待超市时间 ms
      * @return httpclient instance
      * @return httpclient instance
      */
      */
-    public static HttpPoolClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal, int retryCount, int connectionWaitTimeout) {
-        return HttpPoolClient.create(connectTimeout, socketTimeout, maxPerRoute, maxTotal, retryCount, connectionWaitTimeout);
+    public static OkHttpPoolClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal, int retryCount, int connectionWaitTimeout) {
+        return OkHttpPoolClient.create(connectTimeout, socketTimeout, maxPerRoute, maxTotal, retryCount, connectionWaitTimeout);
     }
     }
 }
 }

+ 0 - 292
core/src/main/java/com/tzld/ad/util/HttpPoolClient.java

@@ -1,292 +0,0 @@
-package com.tzld.ad.util;
-
-import com.google.common.collect.Lists;
-import org.apache.commons.collections4.MapUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.*;
-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.DefaultHttpRequestRetryHandler;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.NoHttpResponseException;
-import org.apache.http.ssl.SSLContexts;
-import org.apache.http.util.EntityUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.MDC;
-
-import javax.net.ssl.SSLContext;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import javax.net.ssl.SSLException;
-
-/**
- * http client
- * @author supeng
- */
-public class HttpPoolClient {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(HttpPoolClient.class);
-
-    private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1,
-            new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> LOGGER.error(" monitor push reject task error={}", e.toString()));
-
-    private static final List<HttpClientConnectionManager> HTTP_CLIENT_CONNECTION_MANAGERS = Lists.newArrayList();
-
-    static {
-        // 定期清理过期和空闲连接(每 30 秒执行一次)
-        SCHEDULED_CLOSED_EXECUTOR.scheduleAtFixedRate(() -> {
-            try {
-                HTTP_CLIENT_CONNECTION_MANAGERS.forEach(manager -> {
-                    // 清理过期连接
-                    manager.closeExpiredConnections();
-                    // 清理空闲超过 30 秒的连接
-                    manager.closeIdleConnections(30, TimeUnit.SECONDS);
-                });
-                LOGGER.debug("HTTP connection pool cleanup completed");
-            } catch (Exception e) {
-                LOGGER.error("HTTP connection pool cleanup error", e);
-            }
-        }, 30, 30, TimeUnit.SECONDS);
-    }
-
-    private CloseableHttpClient closeableHttpClient;
-
-    private HttpPoolClient(CloseableHttpClient closeableHttpClient) {
-        this.closeableHttpClient = closeableHttpClient;
-    }
-
-    private static HttpRequestInterceptor getInterceptor() {
-        HttpRequestInterceptor requestInterceptor = (request, context) -> {
-            try {
-                String missSpanId = MDC.get("missSpanId");
-                String missTraceId = MDC.get("request-id");
-                if (missTraceId != null && !"".equals(missTraceId.trim())) {
-                    request.setHeader("request-id", missTraceId);
-                }
-                if (missSpanId != null && !"".equals(missSpanId.trim())) {
-                    request.setHeader("missSpanId", missSpanId);
-                }
-            } catch (Exception e) {
-                LOGGER.error(e.getMessage(), e);
-            }
-        };
-        return requestInterceptor;
-    }
-
-
-    public Optional<String> get(String url) {
-        HttpGet httpGet = new HttpGet(url);
-        return request(httpGet);
-    }
-    public Optional<String> get(String url, Map<String, String> headers) {
-        HttpGet httpGet = new HttpGet(url);
-        if (MapUtils.isNotEmpty(headers)) {
-            for (Map.Entry<String, String> entry : headers.entrySet()) {
-                httpGet.addHeader(entry.getKey(), entry.getValue());
-            }
-        }
-        return request(httpGet);
-    }
-
-
-    public Optional<String> post(String url) {
-        HttpPost httpPost = new HttpPost(url);
-        return request(httpPost);
-    }
-
-
-    public Optional<String> postJson(String url, String json) {
-        HttpPost httpPost = new HttpPost(url);
-        if (StringUtils.isBlank(json)) {
-            return request(httpPost);
-        }
-        StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8);
-        entity.setContentEncoding("UTF-8");
-        entity.setContentType("application/json");
-        httpPost.setEntity(entity);
-        return request(httpPost);
-    }
-
-    public Optional<String> postJson(String url, String json, Map<String, String> headers) {
-        HttpPost httpPost = new HttpPost(url);
-        if (StringUtils.isBlank(json)) {
-            return request(httpPost);
-        }
-        StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8);
-        entity.setContentEncoding("UTF-8");
-        entity.setContentType("application/json");
-        httpPost.setEntity(entity);
-
-        // 添加请求头
-        if (MapUtils.isNotEmpty(headers)) {
-            for (Map.Entry<String, String> entry : headers.entrySet()) {
-                String key = entry.getKey();
-                String value = entry.getValue();
-                httpPost.addHeader(key, value);
-            }
-        }
-
-        return request(httpPost);
-    }
-
-    public Optional<String> request(HttpRequestBase request) {
-
-        if (LOGGER.isDebugEnabled()) {
-            String path = request.getURI().toString();
-            LOGGER.debug("http request url = {} ", path);
-        }
-        HttpEntity entity = null;
-        try {
-            CloseableHttpResponse response = request((HttpUriRequest) request);
-            if (response == null) {
-                throw new RuntimeException("call api exception no response");
-            }
-            entity = response.getEntity();
-            String content = null;
-            if (entity != null) {
-                content = EntityUtils.toString(entity, "UTF-8");
-            }
-            int httpStatus = response.getStatusLine().getStatusCode();
-            if (httpStatus == HttpStatus.SC_OK) {
-                return Optional.ofNullable(content);
-            }
-            String path = request.getURI().toString();
-            LOGGER.error("http call api {} fail response status {} content {}", path, httpStatus, content);
-//            throw new HttpServiceException(httpStatus, content);
-        } catch (Exception e) {
-//            if (e instanceof TimeoutException) {
-//                throw (TimeoutException) e;
-//            }
-//            if (e instanceof HttpServiceException) {
-//                throw (HttpServiceException) e;
-//            }
-            throw new RuntimeException(e.getMessage(), e);
-        } finally {
-            if (request != null) {
-                request.abort();
-            }
-            EntityUtils.consumeQuietly(entity);
-        }
-        return null;
-    }
-
-
-    public CloseableHttpResponse request(HttpUriRequest request) {
-        try {
-            CloseableHttpResponse execute = closeableHttpClient.execute(request);
-            return execute;
-        } catch (Exception e) {
-            String path = request.getURI().toString();
-            if (e instanceof SocketTimeoutException) {
-                LOGGER.error(String.format("http timeout request url = %s .", path));
-//                throw new TimeoutException();
-            } else {
-            }
-            throw new RuntimeException(String.format("http exception request url = %s ", path), e);
-        }
-    }
-
-    /**
-     * @param connectTimeout 连接超时时间 ms
-     * @param socketTimeout  读超时时间(等待数据超时时间)ms
-     * @param maxPerRoute    每个路由的最大连接数
-     * @param maxTotal       最大连接数
-     * @param retryCount     重试次数
-     * @return httpclient instance
-     */
-    protected static HttpPoolClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal, int retryCount, int connectionWaitTimeout) {
-        try {
-            RequestConfig requestConfig = RequestConfig.custom()
-                    .setConnectTimeout(connectTimeout)
-                    .setSocketTimeout(socketTimeout)
-                    .setConnectionRequestTimeout(connectionWaitTimeout)
-                    .build();
-
-            CloseableHttpClient client = HttpClientBuilder.create()
-                    .setDefaultRequestConfig(requestConfig)
-                    .setConnectionManager(createConnectionManager(maxPerRoute, maxTotal))
-                    // 自定义重试处理器,针对 NoHttpResponseException 进行重试
-                    .setRetryHandler((exception, executionCount, context) -> {
-                        if (executionCount >= retryCount) {
-                            LOGGER.warn("Retry count exceeded: {}", executionCount);
-                            return false;
-                        }
-                        // 针对 NoHttpResponseException 进行重试
-                        if (exception instanceof NoHttpResponseException) {
-                            LOGGER.warn("NoHttpResponseException occurred, retry count: {}, error: {}",
-                                    executionCount, exception.getMessage());
-                            return true;
-                        }
-                        // 针对其他 IO 异常不重试
-                        if (exception instanceof InterruptedIOException) {
-                            LOGGER.warn("InterruptedIOException, no retry");
-                            return false;
-                        }
-                        if (exception instanceof UnknownHostException) {
-                            LOGGER.warn("UnknownHostException, no retry");
-                            return false;
-                        }
-                        if (exception instanceof SSLException) {
-                            LOGGER.warn("SSLException, no retry");
-                            return false;
-                        }
-                        // 其他异常使用默认策略
-                        return executionCount < retryCount;
-                    })
-                    .addInterceptorFirst(getInterceptor())
-                    // 自动清理过期连接
-                    .evictExpiredConnections()
-                    // 自动清理空闲超过 30 秒的连接
-                    .evictIdleConnections(30, TimeUnit.SECONDS)
-                    .build();
-            return new HttpPoolClient(client);
-        } catch (Throwable e) {
-            LOGGER.error("create HttpPoolClient exception", e);
-            throw new RuntimeException("create HttpPoolClient exception");
-        }
-    }
-
-    private static PoolingHttpClientConnectionManager createConnectionManager(int maxPerRoute, int maxTotal) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
-        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build();
-        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
-                .register("http", PlainConnectionSocketFactory.getSocketFactory())
-                .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
-        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
-        cm.setDefaultMaxPerRoute(maxPerRoute);
-        cm.setMaxTotal(maxTotal);
-        // 设置连接在空闲 20 秒后进行失效检查(关键配置)
-        cm.setValidateAfterInactivity(20000);
-        HTTP_CLIENT_CONNECTION_MANAGERS.add(cm);
-        LOGGER.info("Created HTTP connection pool: maxPerRoute={}, maxTotal={}, validateAfterInactivity=20s",
-                maxPerRoute, maxTotal);
-        return cm;
-    }
-
-}

+ 271 - 0
core/src/main/java/com/tzld/ad/util/OkHttpPoolClient.java

@@ -0,0 +1,271 @@
+package com.tzld.ad.util;
+
+import okhttp3.*;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于OkHttp的HTTP连接池客户端
+ *
+ * @author supeng
+ */
+public class OkHttpPoolClient {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpPoolClient.class);
+
+    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+    private static final ConcurrentHashMap<String, OkHttpPoolClient> CLIENT_CACHE = new ConcurrentHashMap<>();
+
+    private final OkHttpClient client;
+
+    private OkHttpPoolClient(OkHttpClient client) {
+        this.client = client;
+    }
+
+    /**
+     * 创建OkHttpPoolClient实例
+     *
+     * @param connectTimeout        连接超时时间 ms
+     * @param readTimeout           读超时时间 ms
+     * @param maxPerRoute           每个路由的最大连接数(OkHttp使用connectionPool)
+     * @param maxTotal              最大连接数
+     * @param retryCount            重试次数
+     * @param connectionWaitTimeout 连接等待超时时间 ms
+     * @return OkHttpPoolClient实例
+     */
+    public static OkHttpPoolClient create(int connectTimeout, int readTimeout,
+                                          int maxPerRoute, int maxTotal,
+                                          int retryCount, int connectionWaitTimeout) {
+        String cacheKey = String.format("%d_%d_%d_%d_%d_%d",
+                connectTimeout, readTimeout, maxPerRoute, maxTotal, retryCount, connectionWaitTimeout);
+
+        return CLIENT_CACHE.computeIfAbsent(cacheKey, key -> {
+            OkHttpClient.Builder builder = new OkHttpClient.Builder()
+                    .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
+                    .readTimeout(readTimeout, TimeUnit.MILLISECONDS)
+                    .writeTimeout(readTimeout, TimeUnit.MILLISECONDS)
+                    .connectionPool(new ConnectionPool(maxTotal, 5, TimeUnit.MINUTES))
+                    .retryOnConnectionFailure(retryCount > 0)
+                    .addInterceptor(chain -> {
+                        Request.Builder requestBuilder = chain.request().newBuilder();
+                        try {
+                            String missSpanId = MDC.get("missSpanId");
+                            String missTraceId = MDC.get("request-id");
+                            if (StringUtils.isNotBlank(missTraceId)) {
+                                requestBuilder.addHeader("request-id", missTraceId);
+                            }
+                            if (StringUtils.isNotBlank(missSpanId)) {
+                                requestBuilder.addHeader("missSpanId", missSpanId);
+                            }
+                        } catch (Exception e) {
+                            LOGGER.error(e.getMessage(), e);
+                        }
+                        return chain.proceed(requestBuilder.build());
+                    });
+
+            // 配置SSL信任所有证书
+            try {
+                TrustManager[] trustAllCerts = new TrustManager[]{
+                        new X509TrustManager() {
+                            @Override
+                            public void checkClientTrusted(X509Certificate[] chain, String authType) {
+                            }
+
+                            @Override
+                            public void checkServerTrusted(X509Certificate[] chain, String authType) {
+                            }
+
+                            @Override
+                            public X509Certificate[] getAcceptedIssuers() {
+                                return new X509Certificate[]{};
+                            }
+                        }
+                };
+
+                SSLContext sslContext = SSLContext.getInstance("TLS");
+                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+                SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+                builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
+                builder.hostnameVerifier((hostname, session) -> true);
+            } catch (Exception e) {
+                LOGGER.error("Failed to configure SSL", e);
+            }
+
+            LOGGER.info("Created OkHttpPoolClient: connectTimeout={}ms, readTimeout={}ms, maxConnections={}",
+                    connectTimeout, readTimeout, maxTotal);
+
+            return new OkHttpPoolClient(builder.build());
+        });
+    }
+
+    /**
+     * GET请求
+     */
+    public Optional<String> get(String url) {
+        return get(url, null);
+    }
+
+    /**
+     * GET请求带请求头
+     */
+    public Optional<String> get(String url, Map<String, String> headers) {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("http get request url = {}", url);
+        }
+
+        Request.Builder requestBuilder = new Request.Builder().url(url).get();
+
+        if (MapUtils.isNotEmpty(headers)) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                requestBuilder.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
+
+        return executeRequest(requestBuilder.build(), url);
+    }
+
+    /**
+     * POST请求
+     */
+    public Optional<String> post(String url) {
+        return postJson(url, null);
+    }
+
+    /**
+     * POST JSON请求
+     */
+    public Optional<String> postJson(String url, String json) {
+        return postJson(url, json, null);
+    }
+
+    /**
+     * POST JSON请求带请求头
+     */
+    public Optional<String> postJson(String url, String json, Map<String, String> headers) {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("http post request url = {}", url);
+        }
+
+        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, json != null ? json : "");
+        Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
+
+        if (MapUtils.isNotEmpty(headers)) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                requestBuilder.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
+
+        return executeRequest(requestBuilder.build(), url);
+    }
+
+    /**
+     * 执行HTTP请求
+     */
+    private Optional<String> executeRequest(Request request, String url) {
+        try (Response response = client.newCall(request).execute()) {
+            int statusCode = response.code();
+            ResponseBody responseBody = response.body();
+            String content = responseBody != null ? responseBody.string() : null;
+
+            if (statusCode == 200) {
+                return Optional.ofNullable(content);
+            }
+
+            LOGGER.error("http call api {} fail response status {} content {}", url, statusCode, content);
+            return Optional.empty();
+        } catch (IOException e) {
+            LOGGER.error("http request error, url={}", url, e);
+            throw new RuntimeException("http request error: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 文件上传请求(Multipart)
+     *
+     * @param url      请求URL
+     * @param parts    多部分内容
+     * @param headers  请求头
+     * @return 响应内容
+     */
+    public Optional<String> postMultipart(String url, Map<String, Object> parts, Map<String, String> headers) {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("http post multipart request url = {}", url);
+        }
+
+        MultipartBody.Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
+
+        if (MapUtils.isNotEmpty(parts)) {
+            for (Map.Entry<String, Object> entry : parts.entrySet()) {
+                String key = entry.getKey();
+                Object value = entry.getValue();
+
+                if (value instanceof String) {
+                    bodyBuilder.addFormDataPart(key, (String) value);
+                } else if (value instanceof byte[]) {
+                    bodyBuilder.addFormDataPart(key, null, RequestBody.create(MediaType.parse("application/octet-stream"), (byte[]) value));
+                } else if (value instanceof java.io.File) {
+                    java.io.File file = (java.io.File) value;
+                    MediaType mediaType = MediaType.parse("application/octet-stream");
+                    bodyBuilder.addFormDataPart(key, file.getName(), RequestBody.create(mediaType, file));
+                } else if (value instanceof MultipartPart) {
+                    MultipartPart part = (MultipartPart) value;
+                    bodyBuilder.addFormDataPart(key, part.getFilename(),
+                            RequestBody.create(part.getMediaType(), part.getData()));
+                }
+            }
+        }
+
+        Request.Builder requestBuilder = new Request.Builder().url(url).post(bodyBuilder.build());
+
+        if (MapUtils.isNotEmpty(headers)) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                requestBuilder.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
+
+        return executeRequest(requestBuilder.build(), url);
+    }
+
+    /**
+     * 多部分内容封装类
+     */
+    public static class MultipartPart {
+        private final String filename;
+        private final byte[] data;
+        private final MediaType mediaType;
+
+        public MultipartPart(String filename, byte[] data, MediaType mediaType) {
+            this.filename = filename;
+            this.data = data;
+            this.mediaType = mediaType;
+        }
+
+        public String getFilename() {
+            return filename;
+        }
+
+        public byte[] getData() {
+            return data;
+        }
+
+        public MediaType getMediaType() {
+            return mediaType;
+        }
+    }
+}

+ 0 - 216
core/src/main/java/com/tzld/ad/util/adPut/HttpPoolAdClient.java

@@ -1,216 +0,0 @@
-package com.tzld.ad.util.adPut;
-
-import com.google.common.collect.Lists;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.*;
-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.DefaultHttpRequestRetryHandler;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.ssl.SSLContexts;
-import org.apache.http.util.EntityUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.MDC;
-
-import javax.net.ssl.SSLContext;
-import java.io.IOException;
-import java.net.SocketTimeoutException;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * http client
- *
- * @author supeng
- */
-public class HttpPoolAdClient {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(HttpPoolAdClient.class);
-
-    private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1,
-            new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> LOGGER.error(" monitor push reject task error={}", e.toString()));
-
-    private static final List<HttpClientConnectionManager> HTTP_CLIENT_CONNECTION_MANAGERS = Lists.newArrayList();
-
-    static {
-        SCHEDULED_CLOSED_EXECUTOR.schedule(() -> HTTP_CLIENT_CONNECTION_MANAGERS.forEach(HttpClientConnectionManager::closeExpiredConnections), 5, TimeUnit.SECONDS);
-    }
-
-    private CloseableHttpClient closeableHttpClient;
-
-    private HttpPoolAdClient(CloseableHttpClient closeableHttpClient) {
-        this.closeableHttpClient = closeableHttpClient;
-    }
-
-    private static HttpRequestInterceptor getInterceptor() {
-        HttpRequestInterceptor requestInterceptor = (request, context) -> {
-            try {
-                String missSpanId = MDC.get("missSpanId");
-                String missTraceId = MDC.get("request-id");
-                if (missTraceId != null && !"".equals(missTraceId.trim())) {
-                    request.setHeader("request-id", missTraceId);
-                }
-                if (missSpanId != null && !"".equals(missSpanId.trim())) {
-                    request.setHeader("missSpanId", missSpanId);
-                }
-            } catch (Exception e) {
-                LOGGER.error(e.getMessage(), e);
-            }
-        };
-        return requestInterceptor;
-    }
-
-
-    public Optional<String> get(String url) {
-        HttpGet httpGet = new HttpGet(url);
-        return request(httpGet);
-    }
-
-    public Optional<String> post(String url) {
-        HttpPost httpPost = new HttpPost(url);
-        return request(httpPost);
-    }
-
-
-    public Optional<String> postJson(String url, String json) {
-        HttpPost httpPost = new HttpPost(url);
-        if (StringUtils.isBlank(json)) {
-            return request(httpPost);
-        }
-        StringEntity entity = new StringEntity(json, Charset.forName("UTF-8"));
-        entity.setContentEncoding("UTF-8");
-        entity.setContentType("application/json");
-        httpPost.setEntity(entity);
-        return request(httpPost);
-    }
-
-    public Optional<String> request(HttpRequestBase httpRequestBase) {
-        int retries = 0;
-        final int maxRetries = 5;
-        long retryDelayMillis = 1000; // 1秒作为重试之间的等待时间
-
-
-        // 由于类型不匹配的问题,这里我们假设 httpRequestBase 已经被正确处理或转换
-        HttpUriRequest httpUriRequest = (HttpUriRequest) httpRequestBase; // 注意:这是不安全的转换
-
-        while (retries < maxRetries) {
-            try (CloseableHttpResponse response = request(httpUriRequest)) {
-                HttpEntity entity = response.getEntity();
-                String content = null;
-                if (entity != null) {
-                    content = EntityUtils.toString(entity, "UTF-8");
-                }
-
-                int httpStatus = response.getStatusLine().getStatusCode();
-                if (httpStatus == HttpStatus.SC_OK) {
-                    return Optional.ofNullable(content);
-                }
-
-                // 日志记录失败响应
-                URI uri = httpUriRequest.getURI();
-                LOGGER.error("HTTP call to {} failed with status {} and content {}", uri, httpStatus, content);
-
-                retries++;
-
-                // 在每次重试前增加等待时间
-                if (retries < maxRetries) {
-                    try {
-                        Thread.sleep(retryDelayMillis);
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                        LOGGER.error("Retry wait interrupted", e);
-                        return Optional.empty(); // 或者抛出一个异常
-                    }
-                }
-
-            } catch (IOException e) {
-                // 处理所有 IO 异常
-                LOGGER.error("Error during HTTP request", e);
-                retries++;
-
-                // 在这里也可以基于异常类型决定是否继续重试
-
-                // 如果需要,在每次重试前增加等待时间(已经在上面处理了)
-            }
-
-            // 注意:不需要在循环内部再次检查 retries >= maxRetries,因为循环条件已经保证了这一点
-        }
-
-        // 所有重试都失败了
-        LOGGER.error("Max retries reached for HTTP request");
-        return Optional.empty();
-    }
-
-
-    public CloseableHttpResponse request(HttpUriRequest request) {
-        try {
-            CloseableHttpResponse execute = closeableHttpClient.execute(request);
-            return execute;
-        } catch (Exception e) {
-            String path = request.getURI().toString();
-            if (e instanceof SocketTimeoutException) {
-                LOGGER.error(String.format("http timeout request url = %s .", path));
-//                throw new TimeoutException();
-            } else {
-            }
-            throw new RuntimeException(String.format("http exception request url = %s ", path), e);
-        }
-    }
-
-    /**
-     * @param connectTimeout 连接超时时间 ms
-     * @param socketTimeout  读超时时间(等待数据超时时间)ms
-     * @param maxPerRoute    每个路由的最大连接数
-     * @param maxTotal       最大连接数
-     * @param retryCount     重试次数
-     * @return httpclient instance
-     */
-    protected static HttpPoolAdClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal, int retryCount, int connectionWaitTimeout) {
-        try {
-            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).setConnectionRequestTimeout(connectionWaitTimeout).build();
-            CloseableHttpClient client = HttpClientBuilder.create()
-                    .setDefaultRequestConfig(requestConfig)
-                    .setConnectionManager(createConnectionManager(maxPerRoute, maxTotal))
-                    .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).addInterceptorFirst(getInterceptor()).build();
-            return new HttpPoolAdClient(client);
-        } catch (Throwable e) {
-            LOGGER.error("create HttpPoolClient exception", e);
-            throw new RuntimeException("create HttpPoolClient exception");
-        }
-    }
-
-    private static PoolingHttpClientConnectionManager createConnectionManager(int maxPerRoute, int maxTotal) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
-        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build();
-        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
-                .register("http", PlainConnectionSocketFactory.getSocketFactory())
-                .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
-        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
-        cm.setDefaultMaxPerRoute(maxPerRoute);
-        cm.setMaxTotal(maxTotal);
-        HTTP_CLIENT_CONNECTION_MANAGERS.add(cm);
-        return cm;
-    }
-
-}

+ 98 - 55
core/src/main/java/com/tzld/ad/util/feishu/FeishuExcelUtil.java

@@ -5,32 +5,43 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
 import com.tzld.ad.util.MapBuilder;
 import com.tzld.ad.util.MapBuilder;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
 import org.springframework.data.util.Pair;
 import org.springframework.data.util.Pair;
-import org.springframework.http.*;
-import org.springframework.web.client.RestTemplate;
 
 
+import java.io.IOException;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 @Slf4j
 @Slf4j
 public class FeishuExcelUtil {
 public class FeishuExcelUtil {
 
 
+    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
+
+    private static final OkHttpClient httpClient = new OkHttpClient.Builder()
+            .connectTimeout(30, TimeUnit.SECONDS)
+            .readTimeout(30, TimeUnit.SECONDS)
+            .writeTimeout(30, TimeUnit.SECONDS)
+            .build();
+
     public static void feishuSheetDelete(String sheetToken,
     public static void feishuSheetDelete(String sheetToken,
                                    String sheetId,
                                    String sheetId,
                                    int rowNum,
                                    int rowNum,
                                    int startRowIndex,
                                    int startRowIndex,
-                                   HttpHeaders httpHeaders,
-                                   RestTemplate restTemplate,
+                                   Map<String, String> headers,
                                    List<String> dateStrList) {
                                    List<String> dateStrList) {
-        HttpEntity<Object> queryEntity = new HttpEntity<>(httpHeaders);
+        Map<String, String> queryEntity = headers;
         int deleteRowNum = rowNum < 20 ? startRowIndex + dateStrList.size() * rowNum : startRowIndex + (rowNum * 2);
         int deleteRowNum = rowNum < 20 ? startRowIndex + dateStrList.size() * rowNum : startRowIndex + (rowNum * 2);
-        ResponseEntity<String> queryResponseEntity = restTemplate.exchange(
-                String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values/%s!A"
-                        + startRowIndex + ":A" + deleteRowNum, sheetToken, sheetId),
-                HttpMethod.GET, queryEntity, String.class);
-        JSONArray values = JSON.parseObject(queryResponseEntity.getBody())
+        
+        String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values/%s!A"
+                + startRowIndex + ":A" + deleteRowNum, sheetToken, sheetId);
+        
+        String responseBody = doGet(url, queryEntity);
+        if (responseBody == null) return;
+        
+        JSONArray values = JSON.parseObject(responseBody)
                 .getJSONObject("data")
                 .getJSONObject("data")
                 .getJSONObject("valueRange")
                 .getJSONObject("valueRange")
                 .getJSONArray("values");
                 .getJSONArray("values");
@@ -53,19 +64,16 @@ public class FeishuExcelUtil {
             int delNum = 0;
             int delNum = 0;
             do {
             do {
                 // 删除当前日期已存在的旧数据
                 // 删除当前日期已存在的旧数据
-                httpHeaders.setContentType(MediaType.APPLICATION_JSON);
-                HttpEntity<Object> deleteEntity = new HttpEntity<>(
-                        String.format("{\n" +
+                String deleteUrl = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken);
+                String jsonBody = String.format("{\n" +
                                 "    \"dimension\": {\n" +
                                 "    \"dimension\": {\n" +
                                 "        \"sheetId\": \"%s\",\n" +
                                 "        \"sheetId\": \"%s\",\n" +
                                 "        \"majorDimension\": \"ROWS\",\n" +
                                 "        \"majorDimension\": \"ROWS\",\n" +
                                 "        \"startIndex\": %s,\n" +
                                 "        \"startIndex\": %s,\n" +
                                 "        \"endIndex\": %s\n" +
                                 "        \"endIndex\": %s\n" +
                                 "    }\n" +
                                 "    }\n" +
-                                "}", sheetId, startRowIndex, Math.min(startRowIndex + 4000, count - delNum + startRowIndex) - 1),
-                        httpHeaders);
-                restTemplate.exchange(String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken),
-                        HttpMethod.DELETE, deleteEntity, String.class);
+                                "}", sheetId, startRowIndex, Math.min(startRowIndex + 4000, count - delNum + startRowIndex) - 1);
+                doDelete(deleteUrl, jsonBody, headers);
                 delNum = Math.min(delNum + 4000, count);
                 delNum = Math.min(delNum + 4000, count);
             } while (delNum < count);
             } while (delNum < count);
         }
         }
@@ -74,31 +82,29 @@ public class FeishuExcelUtil {
     public static void feishuSheetInsert(String sheetToken,
     public static void feishuSheetInsert(String sheetToken,
                                    String sheetId,
                                    String sheetId,
                                    Integer startRowIndex,
                                    Integer startRowIndex,
-                                   HttpHeaders httpHeaders,
-                                   RestTemplate restTemplate,
+                                   Map<String, String> headers,
                                    List<List<List<Object>>> partitions) {
                                    List<List<List<Object>>> partitions) {
         int startRow = startRowIndex;
         int startRow = startRowIndex;
         for (List<List<Object>> partition : partitions) {
         for (List<List<Object>> partition : partitions) {
             // 插入数据
             // 插入数据
-            HttpEntity<Object> postEntity = new HttpEntity<>(MapBuilder
+            String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values_prepend", sheetToken);
+            @SuppressWarnings("unchecked")
+            Map<String, Object> bodyMap = (Map<String, Object>) (Map<?, Object>) MapBuilder
                     .builder()
                     .builder()
                     .put("valueRange", MapBuilder
                     .put("valueRange", MapBuilder
                             .builder()
                             .builder()
                             .put("range", String.format("%s!A" + startRow + ":CI", sheetId) + (partition.size() + startRow - 1))
                             .put("range", String.format("%s!A" + startRow + ":CI", sheetId) + (partition.size() + startRow - 1))
                             .put("values", partition)
                             .put("values", partition)
                             .build())
                             .build())
-                    .build(), httpHeaders);
-            ResponseEntity<String> response = restTemplate.exchange(String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values_prepend",
-                            sheetToken),
-                    HttpMethod.POST, postEntity, String.class);
-            JSONObject responseJSON = JSONObject.parseObject(response.getBody());
-            if (0 != responseJSON.getInteger("code")) {
+                    .build();
+            String response = doPost(url, JSON.toJSONString(bodyMap), headers);
+            JSONObject responseJSON = JSONObject.parseObject(response);
+            if (responseJSON != null && 0 != responseJSON.getInteger("code")) {
                 log.error("doSendFeishuSheet write error :{}", responseJSON.getString("msg"));
                 log.error("doSendFeishuSheet write error :{}", responseJSON.getString("msg"));
             }
             }
             // 设置行高
             // 设置行高
-            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
-            HttpEntity<Object> putEntity = new HttpEntity<>(
-                    String.format("{\n" +
+            String putUrl = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken);
+            String putBody = String.format("{\n" +
                             "    \"dimension\": {\n" +
                             "    \"dimension\": {\n" +
                             "        \"sheetId\": \"%s\",\n" +
                             "        \"sheetId\": \"%s\",\n" +
                             "        \"majorDimension\": \"ROWS\",\n" +
                             "        \"majorDimension\": \"ROWS\",\n" +
@@ -108,10 +114,8 @@ public class FeishuExcelUtil {
                             "    \"dimensionProperties\":{\n" +
                             "    \"dimensionProperties\":{\n" +
                             "        \"fixedSize\":27\n" +
                             "        \"fixedSize\":27\n" +
                             "    }\n" +
                             "    }\n" +
-                            "}", sheetId, startRow, Math.min(startRow + 4000, startRow + partition.size()) - 1),
-                    httpHeaders);
-            restTemplate.exchange(String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken),
-                    HttpMethod.PUT, putEntity, String.class);
+                            "}", sheetId, startRow, Math.min(startRow + 4000, startRow + partition.size()) - 1);
+            doPut(putUrl, putBody, headers);
             startRow += partition.size();
             startRow += partition.size();
         }
         }
     }
     }
@@ -120,13 +124,14 @@ public class FeishuExcelUtil {
                                   String sheetId,
                                   String sheetId,
                                   int rowNum,
                                   int rowNum,
                                   Integer startRowIndex,
                                   Integer startRowIndex,
-                                  HttpHeaders httpHeaders,
-                                  RestTemplate restTemplate,
+                                  Map<String, String> headers,
                                   List<Pair<String, Map<Object, Object>>> styles) {
                                   List<Pair<String, Map<Object, Object>>> styles) {
         Integer startRow = startRowIndex;
         Integer startRow = startRowIndex;
         do {
         do {
             for (Pair<String, Map<Object, Object>> style : styles) {
             for (Pair<String, Map<Object, Object>> style : styles) {
-                HttpEntity<Map<Object, Object>> styleEntity = new HttpEntity<>(MapBuilder
+                String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/style", sheetToken);
+                @SuppressWarnings("unchecked")
+                Map<String, Object> bodyMap = (Map<String, Object>) (Map<?, Object>) MapBuilder
                         .builder()
                         .builder()
                         .put("appendStyle",
                         .put("appendStyle",
                                 MapBuilder
                                 MapBuilder
@@ -137,14 +142,8 @@ public class FeishuExcelUtil {
                                         .put("style", style.getSecond())
                                         .put("style", style.getSecond())
                                         .build()
                                         .build()
                         )
                         )
-                        .build(), httpHeaders);
-                restTemplate.exchange(
-                        String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/style",
-                                sheetToken),
-                        HttpMethod.PUT,
-                        styleEntity,
-                        String.class
-                );
+                        .build();
+                doPut(url, JSON.toJSONString(bodyMap), headers);
             }
             }
             startRow += 4000;
             startRow += 4000;
         } while (startRow < rowNum);
         } while (startRow < rowNum);
@@ -154,15 +153,16 @@ public class FeishuExcelUtil {
                                    String sheetId,
                                    String sheetId,
                                    int rowNum,
                                    int rowNum,
                                    Integer startRowIndex,
                                    Integer startRowIndex,
-                                   HttpHeaders httpHeaders,
-                                   RestTemplate restTemplate,
+                                   Map<String, String> headers,
                                    List<Pair<String, List<Pair<String, String>>>> thanks) {
                                    List<Pair<String, List<Pair<String, String>>>> thanks) {
         Integer startRow = startRowIndex;
         Integer startRow = startRowIndex;
         do {
         do {
             for (Pair<String, List<Pair<String, String>>> thank : thanks) {
             for (Pair<String, List<Pair<String, String>>> thank : thanks) {
                 List<String> keyList = thank.getSecond().stream().map(Pair::getFirst).collect(Collectors.toList());
                 List<String> keyList = thank.getSecond().stream().map(Pair::getFirst).collect(Collectors.toList());
                 List<String> colorList = thank.getSecond().stream().map(Pair::getSecond).collect(Collectors.toList());
                 List<String> colorList = thank.getSecond().stream().map(Pair::getSecond).collect(Collectors.toList());
-                HttpEntity<Map<Object, Object>> styleEntity = new HttpEntity<>(MapBuilder
+                String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dataValidation", sheetToken);
+                @SuppressWarnings("unchecked")
+                Map<String, Object> bodyMap = (Map<String, Object>) (Map<?, Object>) MapBuilder
                         .builder()
                         .builder()
                         .put("range", String.format("%s!%s" + startRow + ":%s", sheetId,
                         .put("range", String.format("%s!%s" + startRow + ":%s", sheetId,
                                 thank.getFirst(), thank.getFirst())
                                 thank.getFirst(), thank.getFirst())
@@ -175,16 +175,59 @@ public class FeishuExcelUtil {
                                         .put("colors", colorList)
                                         .put("colors", colorList)
                                         .build()
                                         .build()
                                 ).build())
                                 ).build())
-                        .build(), httpHeaders);
-                restTemplate.exchange(
-                        String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dataValidation",
-                                sheetToken),
-                        HttpMethod.POST,
-                        styleEntity,
-                        String.class
-                );
+                        .build();
+                doPost(url, JSON.toJSONString(bodyMap), headers);
             }
             }
             startRow += 4000;
             startRow += 4000;
         } while (startRow < rowNum);
         } while (startRow < rowNum);
     }
     }
+
+    // HTTP Helper Methods
+
+    private static String doGet(String url, Map<String, String> headers) {
+        Request.Builder requestBuilder = new Request.Builder().url(url).get();
+        if (headers != null) {
+            headers.forEach(requestBuilder::addHeader);
+        }
+        return executeRequest(requestBuilder.build());
+    }
+
+    private static String doPost(String url, String jsonBody, Map<String, String> headers) {
+        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonBody != null ? jsonBody : "");
+        Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
+        if (headers != null) {
+            headers.forEach(requestBuilder::addHeader);
+        }
+        requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
+        return executeRequest(requestBuilder.build());
+    }
+
+    private static String doPut(String url, String jsonBody, Map<String, String> headers) {
+        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonBody != null ? jsonBody : "");
+        Request.Builder requestBuilder = new Request.Builder().url(url).put(body);
+        if (headers != null) {
+            headers.forEach(requestBuilder::addHeader);
+        }
+        requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
+        return executeRequest(requestBuilder.build());
+    }
+
+    private static String doDelete(String url, String jsonBody, Map<String, String> headers) {
+        RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonBody != null ? jsonBody : "");
+        Request.Builder requestBuilder = new Request.Builder().url(url).delete(body);
+        if (headers != null) {
+            headers.forEach(requestBuilder::addHeader);
+        }
+        requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
+        return executeRequest(requestBuilder.build());
+    }
+
+    private static String executeRequest(Request request) {
+        try (Response response = httpClient.newCall(request).execute()) {
+            return response.body() != null ? response.body().string() : null;
+        } catch (IOException e) {
+            log.error("HTTP request error, url:{}", request.url(), e);
+            return null;
+        }
+    }
 }
 }

+ 0 - 20
pom.xml

@@ -112,26 +112,6 @@
             <version>1.18.12</version>
             <version>1.18.12</version>
         </dependency>
         </dependency>
 
 
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-            <version>4.5.14</version> <!-- 使用最新版本 -->
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpmime</artifactId>
-            <version>4.5.14</version>
-        </dependency>
-
-        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
-        <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpcore</artifactId>
-            <version>4.4.16</version>
-        </dependency>
-
         <dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <artifactId>guava</artifactId>