diff --git a/.gitee/ISSUE_TEMPLATE.md b/.gitee/ISSUE_TEMPLATE.md
index cdae693d35..a0b60ba750 100644
--- a/.gitee/ISSUE_TEMPLATE.md
+++ b/.gitee/ISSUE_TEMPLATE.md
@@ -1,4 +1,4 @@
-强烈建议大家到 `github` 相关页面提交问题,方便统一查询管理,具体页面地址:https://github.com/Wechat-Group/WxJava/issues
+强烈建议大家到 `github` 相关页面提交问题,方便统一查询管理,具体页面地址:https://github.com/binarywang/WxJava/issues
当然如果必须在这里提问,请务必按以下格式填写,谢谢配合~
diff --git a/.github/agents/my-agent.agent.md b/.github/agents/my-agent.agent.md
new file mode 100644
index 0000000000..bd1b4572eb
--- /dev/null
+++ b/.github/agents/my-agent.agent.md
@@ -0,0 +1,16 @@
+---
+# Fill in the fields below to create a basic custom agent for your repository.
+# The Copilot CLI can be used for local testing: https://gh.io/customagents/cli
+# To make this agent available, merge this file into the default repository branch.
+# For format details, see: https://gh.io/customagents/config
+
+name: 全部用中文
+description: 需要用中文,包括PR标题和分析总结过程
+---
+
+# My Agent
+
+- 1、请使用中文输出思考过程和总结,包括PR标题,提交commit信息也要使用中文;
+- 2、生成代码时需要提供必要的单元测试代码;
+- 3、实现接口时请严格按照官方文档编写代码,严禁瞎编乱造、臆想并实现不存在的接口;
+- 4、新增加的代码如果标记作者信息,请注意不要把作者名设为binarywang或者其他无关人员,要改为 GitHub Copilot。
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000000..cad29d96d9
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,202 @@
+# Copilot Instruction
+请始终使用中文生成 Pull Request 的标题、描述和提交信息
+
+
+# WxJava - 微信 Java SDK 开发说明
+
+WxJava 是一个支持多种微信平台的完整 Java SDK,包含公众号、小程序、微信支付、企业微信、开放平台、视频号、企点等多种功能模块。
+
+**请始终优先参考本说明,只有在遇到与此内容不一致的意外信息时,才退而使用搜索或 bash 命令。**
+
+## 高效开发指南
+
+### 前置条件与环境准备
+- **Java 要求**:JDK 8+(项目最低目标为 Java 8)
+- **Maven**:推荐 Maven 3.6+(已验证 Maven 3.9.11)
+- **IDE**:推荐使用 IntelliJ IDEA(项目针对 IDEA 优化)
+
+### 引导、构建与校验
+克隆仓库后按顺序执行以下命令:
+
+```bash
+# 1. 基础编译(请勿中断 - 约需 4-5 分钟)
+mvn clean compile -DskipTests=true --no-transfer-progress
+# 超时时间:建议设置 8 分钟以上。实际时间:约 4 分钟
+
+# 2. 完整打包(请勿中断 - 约需 2-3 分钟)
+mvn clean package -DskipTests=true --no-transfer-progress
+# 超时时间:建议设置 5 分钟以上。实际时间:约 2 分钟
+
+# 3. 代码质量校验(请勿中断 - 约需 45-60 秒)
+mvn checkstyle:check --no-transfer-progress
+# 超时时间:建议设置 3 分钟以上。实际时间:约 50 秒
+```
+
+重要时间说明:
+- 绝对不要中断任意 Maven 构建命令
+- 编译阶段耗时最长(约 4 分钟),原因是项目包含 34 个模块
+- 后续构建会更快,因为存在增量编译
+- 始终使用 `--no-transfer-progress` 以减少日志噪音
+
+### 测试结构
+- **测试框架**:TestNG(非 JUnit)
+- **测试文件**:共有 298 个测试文件
+- **默认行为**:pom.xml 中默认禁用测试(`
-
-
-
- |
- ||
-
-
-
- |
- ||
-
-
-
- |
-
-
-
-
- |
-
-
-
-
- |
-
|
-
- |
- ||
+ * {@link me.chanjar.weixin.cp.api.WxCpService#setMaxRetryTimes(int)}
+ * {@link me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl#setMaxRetryTimes(int)}
+ *
+ */
+ private int maxRetryTimes = 5;
+
+ /**
+ * http 请求重试间隔
+ *
+ * {@link me.chanjar.weixin.cp.api.WxCpService#setRetrySleepMillis(int)}
+ * {@link me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl#setRetrySleepMillis(int)}
+ *
+ */
+ private int retrySleepMillis = 1000;
+ }
+
+ public enum StorageType {
+ /**
+ * 内存
+ */
+ memory,
+ /**
+ * jedis
+ */
+ jedis,
+ /**
+ * redisson
+ */
+ redisson,
+ /**
+ * redistemplate
+ */
+ redistemplate
+ }
+
+ public enum HttpClientType {
+ /**
+ * HttpClient
+ */
+ HTTP_CLIENT,
+ /**
+ * OkHttp
+ */
+ OK_HTTP,
+ /**
+ * JoddHttp
+ */
+ JODD_HTTP
+ }
+}
diff --git a/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpTpMultiRedisProperties.java b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpTpMultiRedisProperties.java
new file mode 100644
index 0000000000..b94711216f
--- /dev/null
+++ b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpTpMultiRedisProperties.java
@@ -0,0 +1,48 @@
+package com.binarywang.spring.starter.wxjava.cp.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * Redis配置.
+ *
+ * @author yl
+ * created on 2023/10/16
+ */
+@Data
+@NoArgsConstructor
+public class WxCpTpMultiRedisProperties implements Serializable {
+ private static final long serialVersionUID = -5924815351660074401L;
+
+ /**
+ * 主机地址.
+ */
+ private String host;
+
+ /**
+ * 端口号.
+ */
+ private int port = 6379;
+
+ /**
+ * 密码.
+ */
+ private String password;
+
+ /**
+ * 超时.
+ */
+ private int timeout = 2000;
+
+ /**
+ * 数据库.
+ */
+ private int database = 0;
+
+ private Integer maxActive;
+ private Integer maxIdle;
+ private Integer maxWaitMillis;
+ private Integer minIdle;
+}
diff --git a/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpTpSingleProperties.java b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpTpSingleProperties.java
new file mode 100644
index 0000000000..02a52657db
--- /dev/null
+++ b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/properties/WxCpTpSingleProperties.java
@@ -0,0 +1,43 @@
+package com.binarywang.spring.starter.wxjava.cp.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 企业微信企业相关配置属性
+ *
+ * @author yl
+ * created on 2023/10/16
+ */
+@Data
+@NoArgsConstructor
+public class WxCpTpSingleProperties implements Serializable {
+ private static final long serialVersionUID = -7502823825007859418L;
+ /**
+ * 微信企业号 corpId
+ */
+ private String corpId;
+ /**
+ * 微信企业号 服务商 providerSecret
+ */
+ private String providerSecret;
+ /**
+ * 微信企业号应用 token
+ */
+ private String token;
+
+ private String encodingAESKey;
+
+ /**
+ * 微信企业号 第三方 应用 ID
+ */
+ private String suiteId;
+ /**
+ * 微信企业号应用
+ */
+ private String suiteSecret;
+
+
+}
diff --git a/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/service/WxCpTpMultiServices.java b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/service/WxCpTpMultiServices.java
new file mode 100644
index 0000000000..c0a9faf51e
--- /dev/null
+++ b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/service/WxCpTpMultiServices.java
@@ -0,0 +1,29 @@
+package com.binarywang.spring.starter.wxjava.cp.service;
+
+
+import me.chanjar.weixin.cp.tp.service.WxCpTpService;
+
+/**
+ * 企业微信 {@link WxCpTpService} 所有实例存放类.
+ *
+ * @author yl
+ * created on 2023/10/16
+ */
+public interface WxCpTpMultiServices {
+ /**
+ * 通过租户 Id 获取 WxCpTpService
+ *
+ * @param tenantId 租户 Id
+ * @return WxCpTpService
+ */
+ WxCpTpService getWxCpTpService(String tenantId);
+
+ void addWxCpTpService(String tenantId, WxCpTpService wxCpService);
+
+ /**
+ * 根据租户 Id,从列表中移除一个 WxCpTpService 实例
+ *
+ * @param tenantId 租户 Id
+ */
+ void removeWxCpTpService(String tenantId);
+}
diff --git a/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/service/WxCpTpMultiServicesImpl.java b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/service/WxCpTpMultiServicesImpl.java
new file mode 100644
index 0000000000..84b381230c
--- /dev/null
+++ b/spring-boot-starters/wx-java-cp-tp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/cp/service/WxCpTpMultiServicesImpl.java
@@ -0,0 +1,44 @@
+package com.binarywang.spring.starter.wxjava.cp.service;
+
+
+import me.chanjar.weixin.cp.tp.service.WxCpTpService;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 企业微信 {@link WxCpTpMultiServices} 默认实现
+ *
+ * @author yl
+ * created on 2023/10/16
+ */
+public class WxCpTpMultiServicesImpl implements WxCpTpMultiServices {
+ private final Map+ * 使用单个 WxMaService 实例管理多个租户配置,通过 switchover 切换租户。 + * 相比 {@link WxMaMultiServicesImpl},此实现共享 HTTP 客户端,节省资源。 + *
+ *+ * 注意:由于使用 ThreadLocal 切换配置,在异步或多线程场景需要特别注意线程上下文切换。 + *
+ * + * @author Binary Wang + * created on 2026/1/9 + */ +@RequiredArgsConstructor +public class WxMaMultiServicesSharedImpl implements WxMaMultiServices { + private final WxMaService sharedWxMaService; + + @Override + public WxMaService getWxMaService(String tenantId) { + if (tenantId == null) { + return null; + } + // 使用 switchover 检查配置是否存在,保持与隔离模式 API 行为一致(不存在时返回 null) + if (!sharedWxMaService.switchover(tenantId)) { + return null; + } + return sharedWxMaService; + } + + @Override + public void removeWxMaService(String tenantId) { + if (tenantId != null) { + sharedWxMaService.removeConfig(tenantId); + } + } + + /** + * 添加租户配置到共享的 WxMaService 实例 + * + * @param tenantId 租户 ID + * @param wxMaService 要添加配置的 WxMaService(仅使用其配置,不使用其实例) + */ + public void addWxMaService(String tenantId, WxMaService wxMaService) { + if (tenantId != null && wxMaService != null) { + sharedWxMaService.addConfig(tenantId, wxMaService.getWxMaConfig()); + } + } +} diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md index 82f6bdd8b1..cbf0b53925 100644 --- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md @@ -10,12 +10,13 @@ ``` 2. 添加配置(application.properties) ```properties - # 公众号配置(必填) + # 小程序配置(必填) wx.miniapp.appid = appId wx.miniapp.secret = @secret wx.miniapp.token = @token wx.miniapp.aesKey = @aesKey wx.miniapp.msgDataFormat = @msgDataFormat # 消息格式,XML或者JSON. + wx.miniapp.use-stable-access-token=@useStableAccessToken # 存储配置redis(可选) # 注意: 指定redis.host值后不会使用容器注入的redis连接(JedisPool) wx.miniapp.config-storage.type = Jedis # 配置类型: Memory(默认), Jedis, RedisTemplate diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml index 6983904416..25d5f66758 100644 --- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml @@ -4,7 +4,7 @@+ * 使用单个 WxMpService 实例管理多个租户配置,通过 switchover 切换租户。 + * 相比 {@link WxMpMultiServicesImpl},此实现共享 HTTP 客户端,节省资源。 + *
+ *+ * 注意:由于使用 ThreadLocal 切换配置,在异步或多线程场景需要特别注意线程上下文切换。 + *
+ * + * @author Binary Wang + * created on 2026/1/9 + */ +@RequiredArgsConstructor +public class WxMpMultiServicesSharedImpl implements WxMpMultiServices { + private final WxMpService sharedWxMpService; + + @Override + public WxMpService getWxMpService(String tenantId) { + if (tenantId == null) { + return null; + } + // 使用 switchover 检查配置是否存在,保持与隔离模式 API 行为一致(不存在时返回 null) + if (!sharedWxMpService.switchover(tenantId)) { + return null; + } + return sharedWxMpService; + } + + @Override + public void removeWxMpService(String tenantId) { + if (tenantId != null) { + sharedWxMpService.removeConfigStorage(tenantId); + } + } + + /** + * 添加租户配置到共享的 WxMpService 实例 + * + * @param tenantId 租户 ID + * @param wxMpService 要添加配置的 WxMpService(仅使用其配置,不使用其实例) + */ + public void addWxMpService(String tenantId, WxMpService wxMpService) { + if (tenantId != null && wxMpService != null) { + sharedWxMpService.addConfigStorage(tenantId, wxMpService.getWxMpConfigStorage()); + } + } +} diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md b/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md index 3e14f499d9..091912cfad 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md @@ -27,7 +27,7 @@ #wx.mp.config-storage.redis.sentinel-ips=127.0.0.1:16379,127.0.0.1:26379 #wx.mp.config-storage.redis.sentinel-name=mymaster # http客户端配置 - wx.mp.config-storage.http-client-type=httpclient # http客户端类型: HttpClient(默认), OkHttp, JoddHttp + wx.mp.config-storage.http-client-type=HttpComponents # http客户端类型: HttpComponents(Apache HttpClient 5.x,推荐), HttpClient(Apache HttpClient 4.x), OkHttp, JoddHttp wx.mp.config-storage.http-proxy-host= wx.mp.config-storage.http-proxy-port= wx.mp.config-storage.http-proxy-username= diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml index a784de838c..9e95574bc2 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@
+ * {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setMaxRetryTimes(int)}
+ * {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
+ *
+ */
+ private int maxRetryTimes = 5;
+
+ /**
+ * http 请求重试间隔
+ *
+ * {@link me.chanjar.weixin.mp.api.impl.BaseWxMpServiceImpl#setRetrySleepMillis(int)}
+ * {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
+ *
+ */
+ private int retrySleepMillis = 1000;
+
+ /**
+ * 连接超时时间,单位毫秒
+ */
+ private int connectionTimeout = 5000;
+
+ /**
+ * 读数据超时时间,即socketTimeout,单位毫秒
+ */
+ private int soTimeout = 5000;
+
+ /**
+ * 从连接池获取链接的超时时间,单位毫秒
+ */
+ private int connectionRequestTimeout = 5000;
+ }
+
+ public enum StorageType {
+ /**
+ * 内存
+ */
+ memory,
+ /**
+ * jedis
+ */
+ jedis,
+ /**
+ * redisson
+ */
+ redisson,
+ /**
+ * redisTemplate
+ */
+ redistemplate
+ }
+
+}
diff --git a/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenMultiRedisProperties.java b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenMultiRedisProperties.java
new file mode 100644
index 0000000000..ae6d5368d7
--- /dev/null
+++ b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenMultiRedisProperties.java
@@ -0,0 +1,57 @@
+package com.binarywang.spring.starter.wxjava.open.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 微信开放平台多账号Redis配置.
+ *
+ * @author Binary Wang
+ */
+@Data
+@NoArgsConstructor
+public class WxOpenMultiRedisProperties implements Serializable {
+ private static final long serialVersionUID = -5924815351660074401L;
+
+ /**
+ * 主机地址.
+ */
+ private String host = "127.0.0.1";
+
+ /**
+ * 端口号.
+ */
+ private int port = 6379;
+
+ /**
+ * 密码.
+ */
+ private String password;
+
+ /**
+ * 超时.
+ */
+ private int timeout = 2000;
+
+ /**
+ * 数据库.
+ */
+ private int database = 0;
+
+ /**
+ * sentinel ips
+ */
+ private String sentinelIps;
+
+ /**
+ * sentinel name
+ */
+ private String sentinelName;
+
+ private Integer maxActive;
+ private Integer maxIdle;
+ private Integer maxWaitMillis;
+ private Integer minIdle;
+}
diff --git a/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenSingleProperties.java b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenSingleProperties.java
new file mode 100644
index 0000000000..116da323dc
--- /dev/null
+++ b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenSingleProperties.java
@@ -0,0 +1,49 @@
+package com.binarywang.spring.starter.wxjava.open.properties;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 微信开放平台单个应用配置.
+ *
+ * @author Binary Wang
+ */
+@Data
+@NoArgsConstructor
+public class WxOpenSingleProperties implements Serializable {
+ private static final long serialVersionUID = 1980986361098922525L;
+
+ /**
+ * 设置微信开放平台的appid.
+ */
+ private String appId;
+
+ /**
+ * 设置微信开放平台的app secret.
+ */
+ private String secret;
+
+ /**
+ * 设置微信开放平台的token.
+ */
+ private String token;
+
+ /**
+ * 设置微信开放平台的EncodingAESKey.
+ */
+ private String aesKey;
+
+ /**
+ * 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
+ * 例如:http://proxy.company.com:8080
+ */
+ private String apiHostUrl;
+
+ /**
+ * 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
+ * 例如:http://proxy.company.com:8080/oauth/token
+ */
+ private String accessTokenUrl;
+}
diff --git a/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/service/WxOpenMultiServices.java b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/service/WxOpenMultiServices.java
new file mode 100644
index 0000000000..9228071a10
--- /dev/null
+++ b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/service/WxOpenMultiServices.java
@@ -0,0 +1,26 @@
+package com.binarywang.spring.starter.wxjava.open.service;
+
+
+import me.chanjar.weixin.open.api.WxOpenService;
+
+/**
+ * 微信开放平台 {@link WxOpenService} 所有实例存放类.
+ *
+ * @author binarywang
+ */
+public interface WxOpenMultiServices {
+ /**
+ * 通过租户 Id 获取 WxOpenService
+ *
+ * @param tenantId 租户 Id
+ * @return WxOpenService
+ */
+ WxOpenService getWxOpenService(String tenantId);
+
+ /**
+ * 根据租户 Id,从列表中移除一个 WxOpenService 实例
+ *
+ * @param tenantId 租户 Id
+ */
+ void removeWxOpenService(String tenantId);
+}
diff --git a/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/service/WxOpenMultiServicesImpl.java b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/service/WxOpenMultiServicesImpl.java
new file mode 100644
index 0000000000..76fb139e6c
--- /dev/null
+++ b/spring-boot-starters/wx-java-open-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/service/WxOpenMultiServicesImpl.java
@@ -0,0 +1,35 @@
+package com.binarywang.spring.starter.wxjava.open.service;
+
+import me.chanjar.weixin.open.api.WxOpenService;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 微信开放平台 {@link WxOpenMultiServices} 默认实现
+ *
+ * @author Binary Wang
+ */
+public class WxOpenMultiServicesImpl implements WxOpenMultiServices {
+ private final Map+ * 注意:configKey 是配置文件中定义的 key(如 wx.pay.configs.<configKey>.xxx), + * 而不是 appId。如果使用 appId 作为配置 key,则可以直接传入 appId。 + *
+ * + * @param configKey 配置标识(配置文件中 wx.pay.configs 下的 key) + * @return WxPayService + */ + WxPayService getWxPayService(String configKey); + + /** + * 根据配置标识,从列表中移除一个 WxPayService 实例. + *+ * 注意:configKey 是配置文件中定义的 key(如 wx.pay.configs.<configKey>.xxx), + * 而不是 appId。如果使用 appId 作为配置 key,则可以直接传入 appId。 + *
+ * + * @param configKey 配置标识(配置文件中 wx.pay.configs 下的 key) + */ + void removeWxPayService(String configKey); +} diff --git a/spring-boot-starters/wx-java-pay-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/service/WxPayMultiServicesImpl.java b/spring-boot-starters/wx-java-pay-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/service/WxPayMultiServicesImpl.java new file mode 100644 index 0000000000..459fe3b6c0 --- /dev/null +++ b/spring-boot-starters/wx-java-pay-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/service/WxPayMultiServicesImpl.java @@ -0,0 +1,92 @@ +package com.binarywang.spring.starter.wxjava.pay.service; + +import com.binarywang.spring.starter.wxjava.pay.properties.WxPayMultiProperties; +import com.binarywang.spring.starter.wxjava.pay.properties.WxPaySingleProperties; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 微信支付多服务管理实现类. + * + * @author Binary Wang + */ +@Slf4j +public class WxPayMultiServicesImpl implements WxPayMultiServices { + private final Map+ * 本示例展示了如何使用 wx-java-pay-multi-spring-boot-starter 来管理多个公众号的支付配置。 + *
+ * + * @author Binary Wang + */ +@Slf4j +@Service +public class WxPayMultiExample { + + @Autowired + private WxPayMultiServices wxPayMultiServices; + + /** + * 示例1:根据appId创建支付订单. + *+ * 适用场景:系统需要支持多个公众号,根据用户所在的公众号动态选择支付配置 + *
+ * + * @param appId 公众号appId + * @param openId 用户的openId + * @param totalFee 支付金额(分) + * @param body 商品描述 + * @return JSAPI支付参数 + */ + public WxPayUnifiedOrderV3Result.JsapiResult createJsapiOrder(String appId, String openId, + Integer totalFee, String body) { + try { + // 根据appId获取对应的WxPayService + WxPayService wxPayService = wxPayMultiServices.getWxPayService(appId); + + if (wxPayService == null) { + log.error("未找到appId对应的微信支付配置: {}", appId); + throw new IllegalArgumentException("未找到appId对应的微信支付配置"); + } + + // 构建支付请求 + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); + request.setOutTradeNo(generateOutTradeNo()); + request.setDescription(body); + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(totalFee)); + request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(openId)); + request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl()); + + // 调用微信支付API创建订单 + WxPayUnifiedOrderV3Result.JsapiResult result = + wxPayService.createOrderV3(TradeTypeEnum.JSAPI, request); + + log.info("创建JSAPI支付订单成功,appId: {}, outTradeNo: {}", appId, request.getOutTradeNo()); + return result; + + } catch (Exception e) { + log.error("创建JSAPI支付订单失败,appId: {}", appId, e); + throw new RuntimeException("创建支付订单失败", e); + } + } + + /** + * 示例2:服务商模式 - 为不同子商户创建订单. + *+ * 适用场景:服务商为多个子商户提供支付服务 + *
+ * + * @param configKey 配置标识(在配置文件中定义) + * @param subOpenId 子商户用户的openId + * @param totalFee 支付金额(分) + * @param body 商品描述 + * @return JSAPI支付参数 + */ + public WxPayUnifiedOrderV3Result.JsapiResult createPartnerOrder(String configKey, String subOpenId, + Integer totalFee, String body) { + try { + // 根据配置标识获取WxPayService + WxPayService wxPayService = wxPayMultiServices.getWxPayService(configKey); + + if (wxPayService == null) { + log.error("未找到配置: {}", configKey); + throw new IllegalArgumentException("未找到配置"); + } + + // 获取子商户信息 + String subAppId = wxPayService.getConfig().getSubAppId(); + String subMchId = wxPayService.getConfig().getSubMchId(); + log.info("使用服务商模式,子商户appId: {}, 子商户号: {}", subAppId, subMchId); + + // 构建支付请求 + WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); + request.setOutTradeNo(generateOutTradeNo()); + request.setDescription(body); + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(totalFee)); + request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(subOpenId)); + request.setNotifyUrl(wxPayService.getConfig().getNotifyUrl()); + + // 调用微信支付API创建订单 + WxPayUnifiedOrderV3Result.JsapiResult result = + wxPayService.createOrderV3(TradeTypeEnum.JSAPI, request); + + log.info("创建服务商支付订单成功,配置: {}, outTradeNo: {}", configKey, request.getOutTradeNo()); + return result; + + } catch (Exception e) { + log.error("创建服务商支付订单失败,配置: {}", configKey, e); + throw new RuntimeException("创建支付订单失败", e); + } + } + + /** + * 示例3:查询订单状态. + *+ * 适用场景:查询不同公众号的订单支付状态 + *
+ * + * @param appId 公众号appId + * @param outTradeNo 商户订单号 + * @return 订单状态 + */ + public String queryOrderStatus(String appId, String outTradeNo) { + try { + WxPayService wxPayService = wxPayMultiServices.getWxPayService(appId); + + if (wxPayService == null) { + log.error("未找到appId对应的微信支付配置: {}", appId); + throw new IllegalArgumentException("未找到appId对应的微信支付配置"); + } + + // 查询订单 + WxPayOrderQueryV3Result result = wxPayService.queryOrderV3(null, outTradeNo); + String tradeState = result.getTradeState(); + + log.info("查询订单状态成功,appId: {}, outTradeNo: {}, 状态: {}", appId, outTradeNo, tradeState); + return tradeState; + + } catch (Exception e) { + log.error("查询订单状态失败,appId: {}, outTradeNo: {}", appId, outTradeNo, e); + throw new RuntimeException("查询订单失败", e); + } + } + + /** + * 示例4:申请退款. + *+ * 适用场景:为不同公众号的订单申请退款 + *
+ * + * @param appId 公众号appId + * @param outTradeNo 商户订单号 + * @param refundFee 退款金额(分) + * @param totalFee 订单总金额(分) + * @param reason 退款原因 + * @return 退款单号 + */ + public String refund(String appId, String outTradeNo, Integer refundFee, + Integer totalFee, String reason) { + try { + WxPayService wxPayService = wxPayMultiServices.getWxPayService(appId); + + if (wxPayService == null) { + log.error("未找到appId对应的微信支付配置: {}", appId); + throw new IllegalArgumentException("未找到appId对应的微信支付配置"); + } + + // 构建退款请求 + com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request request = + new com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request(); + request.setOutTradeNo(outTradeNo); + request.setOutRefundNo(generateRefundNo()); + request.setReason(reason); + request.setNotifyUrl(wxPayService.getConfig().getRefundNotifyUrl()); + + com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request.Amount amount = + new com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request.Amount(); + amount.setRefund(refundFee); + amount.setTotal(totalFee); + amount.setCurrency("CNY"); + request.setAmount(amount); + + // 调用微信支付API申请退款 + WxPayRefundV3Result result = wxPayService.refundV3(request); + + log.info("申请退款成功,appId: {}, outTradeNo: {}, outRefundNo: {}", + appId, outTradeNo, request.getOutRefundNo()); + return request.getOutRefundNo(); + + } catch (Exception e) { + log.error("申请退款失败,appId: {}, outTradeNo: {}", appId, outTradeNo, e); + throw new RuntimeException("申请退款失败", e); + } + } + + /** + * 示例5:动态管理配置. + *+ * 适用场景:需要在运行时更新配置(如证书更新后需要重新加载) + *
+ * + * @param configKey 配置标识 + */ + public void reloadConfig(String configKey) { + try { + // 移除缓存的WxPayService实例 + wxPayMultiServices.removeWxPayService(configKey); + log.info("移除配置成功,下次获取时将重新创建: {}", configKey); + + // 下次调用 getWxPayService 时会重新创建实例 + WxPayService wxPayService = wxPayMultiServices.getWxPayService(configKey); + if (wxPayService != null) { + log.info("重新加载配置成功: {}", configKey); + } + + } catch (Exception e) { + log.error("重新加载配置失败: {}", configKey, e); + throw new RuntimeException("重新加载配置失败", e); + } + } + + /** + * 生成商户订单号. + * + * @return 商户订单号 + */ + private String generateOutTradeNo() { + return "ORDER_" + System.currentTimeMillis(); + } + + /** + * 生成商户退款单号. + * + * @return 商户退款单号 + */ + private String generateRefundNo() { + return "REFUND_" + System.currentTimeMillis(); + } +} diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml index b24d3ce7cf..ecdb925730 100644 --- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@+ * 仅设置文件参数名和上传数据,额外表单字段将为 {@code null}。 + * + * @param name 参数名,如:media + * @param data 上传数据 + * @deprecated 请使用包含 formFields 参数的构造函数或静态工厂方法 {@link #fromFile(String, File)}、{@link #fromBytes(String, String, byte[])} + */ + @Deprecated + public CommonUploadParam(@NotNull String name, @NotNull CommonUploadData data) { + this(name, data, null); + } + /** * 从文件构造 * @@ -43,7 +66,7 @@ public class CommonUploadParam implements Serializable { */ @SneakyThrows public static CommonUploadParam fromFile(String name, File file) { - return new CommonUploadParam(name, CommonUploadData.fromFile(file)); + return new CommonUploadParam(name, CommonUploadData.fromFile(file), null); } /** @@ -55,11 +78,32 @@ public static CommonUploadParam fromFile(String name, File file) { */ @SneakyThrows public static CommonUploadParam fromBytes(String name, @Nullable String fileName, byte[] bytes) { - return new CommonUploadParam(name, new CommonUploadData(fileName, new ByteArrayInputStream(bytes), bytes.length)); + return new CommonUploadParam(name, new CommonUploadData(fileName, new ByteArrayInputStream(bytes), bytes.length), null); + } + + /** + * 添加额外的表单字段 + * + * @param fieldName 表单字段名 + * @param fieldValue 表单字段值 + * @return 当前对象,支持链式调用 + */ + public CommonUploadParam addFormField(String fieldName, String fieldValue) { + if (fieldName == null || fieldName.trim().isEmpty()) { + throw new IllegalArgumentException("表单字段名不能为空"); + } + if (fieldValue == null) { + throw new IllegalArgumentException("表单字段值不能为null"); + } + if (this.formFields == null) { + this.formFields = new HashMap<>(); + } + this.formFields.put(fieldName, fieldValue); + return this; } @Override public String toString() { - return String.format("{name:%s, data:%s}", name, data); + return String.format("{name:%s, data:%s, formFields:%s}", name, data, formFields); } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/oauth2/WxOAuth2AccessToken.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/oauth2/WxOAuth2AccessToken.java index c08a49063d..b339844ad6 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/oauth2/WxOAuth2AccessToken.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/oauth2/WxOAuth2AccessToken.java @@ -7,7 +7,10 @@ import java.io.Serializable; /** - * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 + * OAuth2 AccessToken + *
+ * 参考:{@code https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842} + *
* * @author Daniel Qian */ @@ -36,8 +39,10 @@ public class WxOAuth2AccessToken implements Serializable { private Integer snapshotUser; /** - * https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11513156443eZYea&version=&lang=zh_CN. * 本接口在scope参数为snsapi_base时不再提供unionID字段。 + *+ * 参考:{@code https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11513156443eZYea&version=&lang=zh_CN} + *
*/ @SerializedName("unionid") private String unionId; diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java index cd700be7c1..5427d5cada 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java @@ -16,7 +16,7 @@ public class WxMinishopImageUploadCustomizeResult implements Serializable { private WxMinishopPicFileCustomizeResult imgInfo; public static WxMinishopImageUploadCustomizeResult fromJson(String json) { - JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject(); + JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); WxMinishopImageUploadCustomizeResult result = new WxMinishopImageUploadCustomizeResult(); result.setErrcode(jsonObject.get(WxConsts.ERR_CODE).getAsNumber().toString()); if (result.getErrcode().equals("0")) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java index 324232d0ee..9c2cbaf3ba 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java @@ -21,7 +21,7 @@ public class WxMinishopImageUploadResult implements Serializable { public static WxMinishopImageUploadResult fromJson(String json) { - JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject(); + JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject(); WxMinishopImageUploadResult result = new WxMinishopImageUploadResult(); result.setErrcode(jsonObject.get(WxConsts.ERR_CODE).getAsNumber().toString()); if (result.getErrcode().equals("0")) { diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java index ea1e9e7c68..356d1dbbf9 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxCpErrorMsgEnum.java @@ -453,7 +453,7 @@ public enum WxCpErrorMsgEnum { */ CODE_60008(60008, "部门已存在;部门ID或者部门名称已存在"), /** - * 部门名称含有非法字符;不能含有 \\:?*“< >| 等字符. + * {@code 部门名称含有非法字符;不能含有 \\:?*"< >| 等字符.} */ CODE_60009(60009, "部门名称含有非法字符;不能含有 \\ :?*“< >| 等字符"), /** @@ -521,7 +521,7 @@ public enum WxCpErrorMsgEnum { */ CODE_60124(60124, "无效的父部门id;父部门不存在通讯录中"), /** - * 非法部门名字;不能为空,且不能超过64字节,且不能含有\\:*?”< >|等字符. + * {@code 非法部门名字;不能为空,且不能超过64字节,且不能含有\\:*?"< >|等字符.} */ CODE_60125(60125, "非法部门名字;不能为空,且不能超过64字节,且不能含有\\:*?”< >|等字符"), /** diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java index b45fba3411..1aab7f1f20 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java @@ -12,11 +12,13 @@ /** * 微信错误码. + ** 请阅读: * 公众平台:全局返回码说明 * 企业微信:全局错误码 + *
* - * @author Daniel Qian & Binary Wang + * @author Daniel Qian, Binary Wang */ @Data @NoArgsConstructor diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java index 1bb3f6472b..3f380543b0 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java @@ -46,23 +46,23 @@ public enum WxMaErrorMsgEnum { */ CODE_40003(40003, "openid 不正确"), /** - *
* 无效媒体文件类型
- * 对应操作:uploadTempMedia
+ *
+ * 对应操作:{@code uploadTempMedia}
* 对应地址:
- * POST https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
+ * {@code POST https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE}
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/uploadTempMedia.html
- *
+ *
*/
CODE_40004(40004, "无效媒体文件类型"),
/**
- *
* 无效媒体文件 ID.
- * 对应操作:getTempMedia
+ *
+ * 对应操作:{@code getTempMedia}
* 对应地址:
- * GET https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
+ * {@code GET https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID}
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/getTempMedia.html
- *
+ *
*/
CODE_40007(40007, "无效媒体文件 ID"),
/**
@@ -99,29 +99,29 @@ public enum WxMaErrorMsgEnum {
*/
CODE_41028(41028, "form_id 不正确,或者过期"),
/**
- *
* code 或 template_id 不正确.
- * 对应操作:code2Session, sendUniformMessage, sendTemplateMessage
+ *
+ * 对应操作:{@code code2Session}, {@code sendUniformMessage}, {@code sendTemplateMessage}
* 对应地址:
- * GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
+ * {@code GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code}
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
* https://developers.weixin.qq.com/miniprogram/dev/api/open-api/template-message/sendTemplateMessage.html
- *
+ *
*/
CODE_41029(41029, "请求的参数不正确"),
/**
- *
* form_id 已被使用,或者所传page页面不存在,或者小程序没有发布
- * 对应操作:sendUniformMessage, getWXACodeUnlimit
+ *
+ * 对应操作:{@code sendUniformMessage}, {@code getWXACodeUnlimit}
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
* POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
- * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACodeUnlimit.html
- *
+ * https://developers.weixin.qq.com/miniprogram/dev/api/open-api/qr-code/getWXACodeUnlimit.html
+ *
*/
CODE_41030(41030, "请求的参数不正确"),
/**
@@ -138,13 +138,13 @@ public enum WxMaErrorMsgEnum {
*/
CODE_45009(45009, "调用分钟频率受限"),
/**
- *
* 频率限制,每个用户每分钟100次.
- * 对应操作:code2Session
+ *
+ * 对应操作:{@code code2Session}
* 对应地址:
- * GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
+ * {@code GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code}
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/code2Session.html
- *
+ *
*/
CODE_45011(45011, "频率限制,每个用户每分钟100次"),
/**
@@ -190,12 +190,13 @@ public enum WxMaErrorMsgEnum {
*/
CODE_45072(45072, "command字段取值不对"),
/**
- *
* 下发输入状态,需要之前30秒内跟用户有过消息交互.
- * 对应操作:customerTyping
+ *
+ * 对应操作:{@code customerTyping}
* 对应地址:
* POST https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/customer-message/customerTyping.html
+ *
*/
CODE_45080(45080, "下发输入状态,需要之前30秒内跟用户有过消息交互"),
/**
@@ -686,7 +687,7 @@ public enum WxMaErrorMsgEnum {
/**
* 89252
- * 法人&企业信息一致性校验中 front checking
+ * {@code 法人&企业信息一致性校验中 front checking}
*/
CODE_89252(89252, "法人&企业信息一致性校验中"),
@@ -837,6 +838,34 @@ public enum WxMaErrorMsgEnum {
*/
CODE_89424(89424, "授权次数到达上限"),
+ /**
+ * 微信小程序虚拟支付错误码
+ *
+ * @see 虚拟支付 API 文档
+ */
+ CODE_268490001(268490001, "openid错误"),
+ CODE_268490002(268490002, "请求参数字段错误,具体看errmsg"),
+ CODE_268490003(268490003, "签名错误"),
+ CODE_268490004(268490004, "重复操作(赠送和代币支付和充值广告金相关接口会返回,表示之前的操作已经成功)"),
+ CODE_268490005(268490005, "订单已经通过cancel_currency_pay接口退款,不支持再退款"),
+ CODE_268490006(268490006, "代币的退款/支付操作金额不足"),
+ CODE_268490007(268490007, "图片或文字存在敏感内容,禁止使用"),
+ CODE_268490008(268490008, "代币未发布,不允许进行代币操作"),
+ CODE_268490009(268490009, "用户session_key不存在或已过期,请重新登录"),
+ CODE_268490011(268490011, "数据生成中,请稍后调用本接口获取"),
+ CODE_268490012(268490012, "批量任务运行中,请等待完成后才能再次运行"),
+ CODE_268490013(268490013, "禁止对核销状态的单进行退款"),
+ CODE_268490014(268490014, "退款操作进行中,稍后可以使用相同参数重试"),
+ CODE_268490015(268490015, "频率限制"),
+ CODE_268490016(268490016, "退款的left_fee字段与实际不符,请通过query_order接口查询确认"),
+ CODE_268490018(268490018, "广告金充值账户行业id不匹配"),
+ CODE_268490019(268490019, "广告金充值账户id已绑定其他appid"),
+ CODE_268490020(268490020, "广告金充值账户主体名称错误"),
+ CODE_268490021(268490021, "账户未完成进件"),
+ CODE_268490022(268490022, "广告金充值账户无效"),
+ CODE_268490023(268490023, "广告金余额不足"),
+ CODE_268490024(268490024, "广告金充值金额必须大于0"),
+
;
private final int code;
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxOpenErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxOpenErrorMsgEnum.java
index 28fb5de8ad..ba910e988b 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxOpenErrorMsgEnum.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxOpenErrorMsgEnum.java
@@ -527,7 +527,7 @@ public enum WxOpenErrorMsgEnum {
CODE_40099(40099, "invalid code, this code has consumed."),
/**
- * invalid DateInfo, Make Sure OldDateInfoType==NewDateInfoType && NewBeginTime<=OldBeginTime && OldEndTime<= NewEndTime
+ * {@code invalid DateInfo, Make Sure OldDateInfoType==NewDateInfoType && NewBeginTime<=OldBeginTime && OldEndTime<= NewEndTime}
*/
CODE_40100(40100, "invalid DateInfo, Make Sure OldDateInfoType==NewDateInfoType && NewBeginTime<=OldBeginTime && OldEndTime<= NewEndTime"),
@@ -572,7 +572,7 @@ public enum WxOpenErrorMsgEnum {
CODE_40108(40108, "invalid client version"),
/**
- * too many code size, must <= 100
+ * {@code too many code size, must <= 100}
*/
CODE_40109(40109, "too many code size, must <= 100"),
@@ -702,7 +702,7 @@ public enum WxOpenErrorMsgEnum {
CODE_40135(40135, "invalid not supply bonus, can not change card_id which supply bonus to be not supply"),
/**
- * invalid use DepositCodeMode, make sure sku.quantity>DepositCode.quantity
+ * {@code invalid use DepositCodeMode, make sure sku.quantity>DepositCode.quantity}
*/
CODE_40136(40136, "invalid use DepositCodeMode, make sure sku.quantity>DepositCode.quantity"),
@@ -1082,7 +1082,7 @@ public enum WxOpenErrorMsgEnum {
CODE_40211(40211, "invalid scope_data"),
/**
- * paegs 当中存在不合法的query,query格式遵循URL标准,即k1=v1&k2=v2 invalid query
+ * {@code paegs 当中存在不合法的query,query格式遵循URL标准,即k1=v1&k2=v2 invalid query}
*/
CODE_40212(40212, "paegs 当中存在不合法的query,query格式遵循URL标准,即k1=v1&k2=v2"),
@@ -4242,7 +4242,7 @@ public enum WxOpenErrorMsgEnum {
CODE_71005(71005, "limit exe count"),
/**
- * limit coin count, 1 <= coin_count <= 100000
+ * {@code limit coin count, 1 <= coin_count <= 100000}
*/
CODE_71006(71006, "limit coin count, 1 <= coin_count <= 100000"),
@@ -4347,7 +4347,7 @@ public enum WxOpenErrorMsgEnum {
CODE_72018(72018, "duplicate order id, invoice had inserted to user"),
/**
- * limit msg operation card list size, must <= 5
+ * {@code limit msg operation card list size, must <= 5}
*/
CODE_72019(72019, "limit msg operation card list size, must <= 5"),
@@ -6432,7 +6432,7 @@ public enum WxOpenErrorMsgEnum {
CODE_88009(88009, "reply is not exists"),
/**
- * count range error. cout <= 0 or count > 50
+ * {@code count range error. cout <= 0 or count > 50}
*/
CODE_88010(88010, "count range error. cout <= 0 or count > 50"),
@@ -6682,7 +6682,7 @@ public enum WxOpenErrorMsgEnum {
CODE_89251(89251, "模板消息已下发,待法人人脸核身校验"),
/**
- * 法人&企业信息一致性校验中 front checking
+ * {@code 法人&企业信息一致性校验中 front checking}
*/
CODE_89253(89253, "法人&企业信息一致性校验中"),
@@ -7257,7 +7257,7 @@ public enum WxOpenErrorMsgEnum {
CODE_200021(200021, "场景描述 sceneDesc 参数错误"),
/**
- * 禁止创建/更新商品(如商品创建功能被封禁) 或 禁止编辑&更新房间
+ * {@code 禁止创建/更新商品(如商品创建功能被封禁) 或 禁止编辑&更新房间}
*/
CODE_300001(300001, "禁止创建/更新商品(如商品创建功能被封禁) 或 禁止编辑&更新房间"),
@@ -8382,7 +8382,7 @@ public enum WxOpenErrorMsgEnum {
CODE_9300003(9300003, "begin_time must less than end_time"),
/**
- * end_time - begin_time > 1year
+ * {@code end_time - begin_time > 1year}
*/
CODE_9300004(9300004, "end_time - begin_time > 1year"),
@@ -8397,7 +8397,7 @@ public enum WxOpenErrorMsgEnum {
CODE_9300006(9300006, "invalid activity status"),
/**
- * gift_num must >0 and <=15
+ * {@code gift_num must >0 and <=15}
*/
CODE_9300007(9300007, "gift_num must >0 and <=15"),
@@ -8412,7 +8412,7 @@ public enum WxOpenErrorMsgEnum {
CODE_9300009(9300009, "activity can not finish"),
/**
- * card_info_list must >= 2
+ * {@code card_info_list must >= 2}
*/
CODE_9300010(9300010, "card_info_list must >= 2"),
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java
index 2c9a4d7526..a93cbe1e99 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java
@@ -1,11 +1,15 @@
package me.chanjar.weixin.common.executor;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
import java.io.IOException;
@@ -34,15 +38,19 @@ public void execute(String uri, CommonUploadParam data, ResponseHandler
* @param requestHttp 请求信息
* @return 执行器
*/
- @SuppressWarnings({"rawtypes", "unchecked"})
- public static RequestExecutor create(RequestHttp requestHttp) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new CommonUploadRequestExecutorApacheImpl(requestHttp);
+ return new CommonUploadRequestExecutorApacheImpl(
+ (RequestHttp) requestHttp);
case JODD_HTTP:
- return new CommonUploadRequestExecutorJoddHttpImpl(requestHttp);
+ return new CommonUploadRequestExecutorJoddHttpImpl((RequestHttp) requestHttp);
case OK_HTTP:
- return new CommonUploadRequestExecutorOkHttpImpl(requestHttp);
+ return new CommonUploadRequestExecutorOkHttpImpl((RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new CommonUploadRequestExecutorHttpComponentsImpl(
+ (RequestHttp) requestHttp);
default:
throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java
index 6a3c05dd21..dba92e27da 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java
@@ -8,10 +8,10 @@
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
+import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
@@ -28,8 +28,7 @@
* @author 广州跨界
* created on 2024/01/11
*/
-public class CommonUploadRequestExecutorApacheImpl
- extends CommonUploadRequestExecutor {
+public class CommonUploadRequestExecutorApacheImpl extends CommonUploadRequestExecutor {
public CommonUploadRequestExecutorApacheImpl(RequestHttp requestHttp) {
super(requestHttp);
@@ -45,26 +44,30 @@ public String execute(String uri, CommonUploadParam param, WxType wxType) throws
if (param != null) {
CommonUploadData data = param.getData();
InnerStreamBody part = new InnerStreamBody(data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFileName(), data.getLength());
- HttpEntity entity = MultipartEntityBuilder
+ MultipartEntityBuilder entityBuilder = MultipartEntityBuilder
.create()
.addPart(param.getName(), part)
- .setMode(HttpMultipartMode.RFC6532)
- .build();
+ .setMode(HttpMultipartMode.RFC6532);
+
+ // 添加额外的表单字段
+ if (param.getFormFields() != null && !param.getFormFields().isEmpty()) {
+ for (java.util.Map.Entry entry : param.getFormFields().entrySet()) {
+ entityBuilder.addTextBody(entry.getKey(), entry.getValue(), ContentType.TEXT_PLAIN.withCharset("UTF-8"));
+ }
+ }
+
+ HttpEntity entity = entityBuilder.build();
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- if (responseContent == null || responseContent.isEmpty()) {
- throw new WxErrorException(String.format("上传失败,服务器响应空 url:%s param:%s", uri, param));
- }
- WxError error = WxError.fromJson(responseContent, wxType);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
- }
- return responseContent;
- } finally {
- httpPost.releaseConnection();
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ if (StringUtils.isEmpty(responseContent)) {
+ throw new WxErrorException(String.format("上传失败,服务器响应空 url:%s param:%s", uri, param));
+ }
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
}
+ return responseContent;
}
/**
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorHttpComponentsImpl.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorHttpComponentsImpl.java
new file mode 100644
index 0000000000..f79e4cd96f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorHttpComponentsImpl.java
@@ -0,0 +1,83 @@
+package me.chanjar.weixin.common.executor;
+
+import lombok.Getter;
+import me.chanjar.weixin.common.bean.CommonUploadData;
+import me.chanjar.weixin.common.bean.CommonUploadParam;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.InputStreamBody;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Apache HttpComponents 通用文件上传器
+ */
+public class CommonUploadRequestExecutorHttpComponentsImpl extends CommonUploadRequestExecutor {
+
+ public CommonUploadRequestExecutorHttpComponentsImpl(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public String execute(String uri, CommonUploadParam param, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (param != null) {
+ CommonUploadData data = param.getData();
+ InnerStreamBody part = new InnerStreamBody(data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFileName(), data.getLength());
+ MultipartEntityBuilder entityBuilder = MultipartEntityBuilder
+ .create()
+ .addPart(param.getName(), part)
+ .setMode(HttpMultipartMode.EXTENDED);
+
+ // 添加额外的表单字段
+ if (param.getFormFields() != null && !param.getFormFields().isEmpty()) {
+ for (java.util.Map.Entry entry : param.getFormFields().entrySet()) {
+ entityBuilder.addTextBody(entry.getKey(), entry.getValue(), ContentType.TEXT_PLAIN.withCharset("UTF-8"));
+ }
+ }
+
+ HttpEntity entity = entityBuilder.build();
+ httpPost.setEntity(entity);
+ }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ if (StringUtils.isEmpty(responseContent)) {
+ throw new WxErrorException(String.format("上传失败,服务器响应空 url:%s param:%s", uri, param));
+ }
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return responseContent;
+ }
+
+ /**
+ * 内部流 请求体
+ */
+ @Getter
+ public static class InnerStreamBody extends InputStreamBody {
+
+ private final long contentLength;
+
+ public InnerStreamBody(final InputStream in, final ContentType contentType, final String filename, long contentLength) {
+ super(in, contentType, filename);
+ this.contentLength = contentLength;
+ }
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorJoddHttpImpl.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorJoddHttpImpl.java
index 36e8660f77..182820d076 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorJoddHttpImpl.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorJoddHttpImpl.java
@@ -39,6 +39,14 @@ public String execute(String uri, CommonUploadParam param, WxType wxType) throws
}
request.withConnectionProvider(requestHttp.getRequestHttpClient());
request.form(param.getName(), new CommonUploadParamToUploadableAdapter(param.getData()));
+
+ // 添加额外的表单字段
+ if (param.getFormFields() != null && !param.getFormFields().isEmpty()) {
+ for (java.util.Map.Entry entry : param.getFormFields().entrySet()) {
+ request.form(entry.getKey(), entry.getValue());
+ }
+ }
+
HttpResponse response = request.send();
response.charset(StandardCharsets.UTF_8.name());
String responseContent = response.bodyText();
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorOkHttpImpl.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorOkHttpImpl.java
index 40a4622b89..6a0343980f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorOkHttpImpl.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorOkHttpImpl.java
@@ -31,10 +31,18 @@ public CommonUploadRequestExecutorOkHttpImpl(RequestHttp entry : param.getFormFields().entrySet()) {
+ bodyBuilder.addFormDataPart(entry.getKey(), entry.getValue());
+ }
+ }
+
+ RequestBody body = bodyBuilder.build();
Request request = new Request.Builder().url(uri).post(body).build();
try (Response response = requestHttp.getRequestHttpClient().newCall(request).execute()) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java
index 19d4046c92..d531a2a307 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java
@@ -29,7 +29,7 @@ public void setValue(String key, String value, int expire, TimeUnit timeUnit) {
@Override
public Long getExpire(String key) {
- return redisTemplate.getExpire(key);
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
@Override
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java
index 22cdab3f92..03bec013dd 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java
@@ -8,7 +8,6 @@
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -24,7 +23,7 @@
* created on 2019/6/27 14:06
*/
public class OcrDiscernApacheHttpRequestExecutor extends OcrDiscernRequestExecutor {
- public OcrDiscernApacheHttpRequestExecutor(RequestHttp requestHttp) {
+ public OcrDiscernApacheHttpRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -43,15 +42,11 @@ public String execute(String uri, File file, WxType wxType) throws WxErrorExcept
.build();
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- WxError error = WxError.fromJson(responseContent, wxType);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
- }
- return responseContent;
- } finally {
- httpPost.releaseConnection();
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
}
+ return responseContent;
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernHttpComponentsRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..2d02c965a8
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernHttpComponentsRequestExecutor.java
@@ -0,0 +1,46 @@
+package me.chanjar.weixin.common.requestexecuter.ocr;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class OcrDiscernHttpComponentsRequestExecutor extends OcrDiscernRequestExecutor {
+ public OcrDiscernHttpComponentsRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public String execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (file != null) {
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addBinaryBody("file", file)
+ .setMode(HttpMultipartMode.EXTENDED)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return responseContent;
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java
index 870f77d2ed..542ab4a378 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java
@@ -5,6 +5,8 @@
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.ResponseHandler;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.CloseableHttpClient;
import java.io.File;
import java.io.IOException;
@@ -18,7 +20,7 @@
public abstract class OcrDiscernRequestExecutor implements RequestExecutor {
protected RequestHttp requestHttp;
- public OcrDiscernRequestExecutor(RequestHttp requestHttp) {
+ public OcrDiscernRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}
@@ -27,12 +29,17 @@ public void execute(String uri, File data, ResponseHandler handler, WxTy
handler.handle(this.execute(uri, data, wxType));
}
- public static RequestExecutor create(RequestHttp requestHttp) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new OcrDiscernApacheHttpRequestExecutor(requestHttp);
+ return new OcrDiscernApacheHttpRequestExecutor(
+ (RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new OcrDiscernHttpComponentsRequestExecutor(
+ (RequestHttp) requestHttp);
default:
- return null;
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOcrService.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOcrService.java
index 39a8a93754..d0aeef8491 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOcrService.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/service/WxOcrService.java
@@ -12,7 +12,9 @@
/**
* 基于小程序或 H5 的身份证、银行卡、行驶证 OCR 识别.
- * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21516712284rHWMX
+ *
+ * 参考:{@code https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21516712284rHWMX}
+ *
*
* @author Binary Wang
* created on 2019-06-22
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java
index e3d9ab8351..24ea58ef38 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/session/InternalSessionManager.java
@@ -7,13 +7,12 @@ public interface InternalSessionManager {
/**
* Return the active Session, associated with this Manager, with the
- * specified session id (if any); otherwise return null.
+ * specified session id (if any); otherwise return {@code null}.
*
* @param id The session id for the session to be returned
+ * @return the session or null
* @throws IllegalStateException if a new session cannot be
* instantiated for any reason
- * @throws java.io.IOException if an input/output error occurs while
- * processing this request
*/
InternalSession findSession(String id);
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
index 73b6cff368..d3f8d00406 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
@@ -2,7 +2,6 @@
import com.google.common.collect.Lists;
import me.chanjar.weixin.common.annotation.Required;
-import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java
index 983d9a668f..b8fb42e0e9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java
@@ -1,5 +1,6 @@
package me.chanjar.weixin.common.util;
+import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
/**
@@ -17,7 +18,7 @@ public class DataUtils {
public static E handleDataWithSecret(E data) {
E dataForLog = data;
if(data instanceof String && StringUtils.contains((String)data, "&secret=")){
- dataForLog = (E) StringUtils.replaceAll((String)data,"&secret=\\w+&","&secret=******&");
+ dataForLog = (E) RegExUtils.replaceAll((String)data,"&secret=\\w+&","&secret=******&");
}
return dataForLog;
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java
index bbb11992bc..a9017c0d16 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/RandomUtils.java
@@ -4,12 +4,24 @@ public class RandomUtils {
private static final String RANDOM_STR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- private static final java.util.Random RANDOM = new java.util.Random();
+ private static volatile java.util.Random random;
+
+ private static java.util.Random getRandom() {
+ if (random == null) {
+ synchronized (RandomUtils.class) {
+ if (random == null) {
+ random = new java.util.Random();
+ }
+ }
+ }
+ return random;
+ }
public static String getRandomStr() {
StringBuilder sb = new StringBuilder();
+ java.util.Random r = getRandom();
for (int i = 0; i < 16; i++) {
- sb.append(RANDOM_STR.charAt(RANDOM.nextInt(RANDOM_STR.length())));
+ sb.append(RANDOM_STR.charAt(r.nextInt(RANDOM_STR.length())));
}
return sb.toString();
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
index fc3579d45c..1886209f98 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/SignUtils.java
@@ -25,6 +25,7 @@ public class SignUtils {
*
* @param message 签名数据
* @param key 签名密钥
+ * @return 签名结果
*/
public static String createHmacSha256Sign(String message, String key) {
try {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
index facf564e32..67faf319f4 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
@@ -65,7 +65,7 @@ private static Object element2MapOrString(Element element) {
final List names = names(nodes);
// 判断节点下有无非文本节点(非Text和CDATA),如无,直接取Text文本内容
- if (names.size() < 1) {
+ if (names.isEmpty()) {
return element.getText();
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java
index 9b9f776768..43cc54b43d 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/SHA1.java
@@ -29,7 +29,10 @@ public static String gen(String... arr) {
}
/**
- * 用&串接arr参数,生成sha1 digest.
+ * {@code 用&串接arr参数,生成sha1 digest.}
+ *
+ * @param arr 参数数组
+ * @return sha1摘要
*/
public static String genWithAmple(String... arr) {
if (StringUtils.isAnyEmpty(arr)) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
index f02d087b7d..50362636fc 100755
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
@@ -1,6 +1,5 @@
package me.chanjar.weixin.common.util.crypto;
-import com.google.common.base.CharMatcher;
import lombok.AllArgsConstructor;
import lombok.Data;
import me.chanjar.weixin.common.error.WxRuntimeException;
@@ -38,6 +37,19 @@ public class WxCryptUtil {
private static final Base64 BASE64 = new Base64();
private static final Charset CHARSET = StandardCharsets.UTF_8;
+ private static volatile Random random;
+
+ private static Random getRandom() {
+ if (random == null) {
+ synchronized (WxCryptUtil.class) {
+ if (random == null) {
+ random = new Random();
+ }
+ }
+ }
+ return random;
+ }
+
private static final ThreadLocal BUILDER_LOCAL = ThreadLocal.withInitial(() -> {
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
@@ -110,10 +122,10 @@ private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) {
*/
private static String genRandomStr() {
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- Random random = new Random();
+ Random r = getRandom();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++) {
- int number = random.nextInt(base.length());
+ int number = r.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
@@ -185,6 +197,7 @@ public EncryptContext encryptContext(String plainText) {
/**
* 对明文进行加密.
*
+ * @param randomStr 随机字符串
* @param plainText 需要加密的明文
* @return 加密后base64编码的字符串
*/
@@ -321,14 +334,28 @@ public String decrypt(String cipherText) {
byte[] bytes = PKCS7Encoder.decode(original);
// 分离16位随机字符串,网络字节序和AppId
+ if (bytes == null || bytes.length < 20) {
+ throw new WxRuntimeException("解密后数据长度异常,可能为错误的密文或EncodingAESKey");
+ }
byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
int xmlLength = bytesNetworkOrder2Number(networkOrder);
- xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
- fromAppid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
+ // 长度边界校验,避免非法长度导致的越界/参数异常
+ int startIndex = 20;
+ int endIndex = startIndex + xmlLength;
+ if (xmlLength < 0 || endIndex > bytes.length) {
+ throw new WxRuntimeException("解密后数据格式非法:消息长度不正确,可能为错误的密文或EncodingAESKey");
+ }
+
+ xmlContent = new String(Arrays.copyOfRange(bytes, startIndex, endIndex), CHARSET);
+ fromAppid = new String(Arrays.copyOfRange(bytes, endIndex, bytes.length), CHARSET);
} catch (Exception e) {
- throw new WxRuntimeException(e);
+ if (e instanceof WxRuntimeException) {
+ throw (WxRuntimeException) e;
+ } else {
+ throw new WxRuntimeException(e);
+ }
}
// appid不相同的情况 暂时忽略这段判断
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
index ed5ec17bc9..8304742524 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
@@ -1,13 +1,18 @@
package me.chanjar.weixin.common.util.http;
-import java.io.File;
-import java.io.IOException;
-
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
+
+import java.io.File;
+import java.io.IOException;
/**
* 下载媒体文件请求执行器.
@@ -30,16 +35,21 @@ public void execute(String uri, String data, ResponseHandler handler, WxTy
handler.handle(this.execute(uri, data, wxType));
}
- public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp, File tmpDirFile) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+ return new ApacheMediaDownloadRequestExecutor(
+ (RequestHttp) requestHttp, tmpDirFile);
case JODD_HTTP:
- return new JoddHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+ return new JoddHttpMediaDownloadRequestExecutor((RequestHttp) requestHttp, tmpDirFile);
case OK_HTTP:
- return new OkHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+ return new OkHttpMediaDownloadRequestExecutor((RequestHttp) requestHttp, tmpDirFile);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsMediaDownloadRequestExecutor(
+ (RequestHttp) requestHttp, tmpDirFile);
default:
- return null;
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpClientType.java
similarity index 59%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpClientType.java
index eff5907f7a..a4e22be9b4 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpClientType.java
@@ -3,17 +3,21 @@
/**
* Created by ecoolper on 2017/4/28.
*/
-public enum HttpType {
+public enum HttpClientType {
/**
* jodd-http.
*/
JODD_HTTP,
/**
- * apache httpclient.
+ * apache httpclient 4.x.
*/
APACHE_HTTP,
/**
* okhttp.
*/
- OK_HTTP
+ OK_HTTP,
+ /**
+ * apache httpclient 5.x.
+ */
+ HTTP_COMPONENTS
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
index 11b1209460..e45294b503 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
@@ -1,10 +1,10 @@
package me.chanjar.weixin.common.util.http;
-import jodd.http.HttpResponse;
import me.chanjar.weixin.common.error.WxErrorException;
-import okhttp3.Response;
-import org.apache.http.Header;
-import org.apache.http.client.methods.CloseableHttpResponse;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpResponseProxy;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsResponseProxy;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpResponseProxy;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpResponseProxy;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
@@ -14,68 +14,33 @@
/**
*
- * 三种http框架的response代理类,方便提取公共方法
+ * http 框架的 response 代理类,方便提取公共方法
* Created by Binary Wang on 2017-8-3.
*
*
* @author Binary Wang
*/
-public class HttpResponseProxy {
+public interface HttpResponseProxy {
- private CloseableHttpResponse apacheHttpResponse;
- private HttpResponse joddHttpResponse;
- private Response okHttpResponse;
-
- public HttpResponseProxy(CloseableHttpResponse apacheHttpResponse) {
- this.apacheHttpResponse = apacheHttpResponse;
- }
-
- public HttpResponseProxy(HttpResponse joddHttpResponse) {
- this.joddHttpResponse = joddHttpResponse;
+ static ApacheHttpResponseProxy from(org.apache.http.client.methods.CloseableHttpResponse response) {
+ return new ApacheHttpResponseProxy(response);
}
- public HttpResponseProxy(Response okHttpResponse) {
- this.okHttpResponse = okHttpResponse;
- }
-
- public String getFileName() throws WxErrorException {
- //由于对象只能由一个构造方法实现,因此三个response对象必定且只有一个不为空
- if (this.apacheHttpResponse != null) {
- return this.getFileName(this.apacheHttpResponse);
- }
-
- if (this.joddHttpResponse != null) {
- return this.getFileName(this.joddHttpResponse);
- }
-
- if (this.okHttpResponse != null) {
- return this.getFileName(this.okHttpResponse);
- }
-
- //cannot happen
- return null;
+ static HttpComponentsResponseProxy from(org.apache.hc.client5.http.impl.classic.CloseableHttpResponse response) {
+ return new HttpComponentsResponseProxy(response);
}
- private String getFileName(CloseableHttpResponse response) throws WxErrorException {
- Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
- if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
- throw new WxErrorException("无法获取到文件名,Content-disposition为空");
- }
-
- return extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+ static JoddHttpResponseProxy from(jodd.http.HttpResponse response) {
+ return new JoddHttpResponseProxy(response);
}
- private String getFileName(HttpResponse response) throws WxErrorException {
- String content = response.header("Content-disposition");
- return extractFileNameFromContentString(content);
+ static OkHttpResponseProxy from(okhttp3.Response response) {
+ return new OkHttpResponseProxy(response);
}
- private String getFileName(Response response) throws WxErrorException {
- String content = response.header("Content-disposition");
- return extractFileNameFromContentString(content);
- }
+ String getFileName() throws WxErrorException;
- public static String extractFileNameFromContentString(String content) throws WxErrorException {
+ static String extractFileNameFromContentString(String content) throws WxErrorException {
if (content == null || content.isEmpty()) {
throw new WxErrorException("无法获取到文件名,content为空");
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java
index d07873f3c4..f03932984f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java
@@ -10,8 +10,9 @@
/**
* 输入流数据.
- *
+ *
* InputStreamData
+ *
*
* @author zichuan.zhou91@gmail.com
* created on 2022/2/15
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
index de4be21709..22c426ca54 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
@@ -1,11 +1,16 @@
package me.chanjar.weixin.common.util.http;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheMediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMediaInputStreamUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaInputStreamUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
import java.io.IOException;
@@ -18,7 +23,7 @@
public abstract class MediaInputStreamUploadRequestExecutor implements RequestExecutor {
protected RequestHttp requestHttp;
- public MediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ public MediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}
@@ -27,16 +32,21 @@ public void execute(String uri, InputStreamData data, ResponseHandler create(RequestHttp requestHttp) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheMediaInputStreamUploadRequestExecutor(requestHttp);
+ return new ApacheMediaInputStreamUploadRequestExecutor(
+ (RequestHttp) requestHttp);
case JODD_HTTP:
- return new JoddHttpMediaInputStreamUploadRequestExecutor(requestHttp);
+ return new JoddHttpMediaInputStreamUploadRequestExecutor((RequestHttp) requestHttp);
case OK_HTTP:
- return new OkHttpMediaInputStreamUploadRequestExecutor(requestHttp);
+ return new OkHttpMediaInputStreamUploadRequestExecutor((RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsMediaInputStreamUploadRequestExecutor(
+ (RequestHttp) requestHttp);
default:
- return null;
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
index 83d0c099b3..2d16e714e9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
@@ -1,13 +1,18 @@
package me.chanjar.weixin.common.util.http;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.service.WxService;
import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
import java.io.File;
import java.io.IOException;
@@ -25,7 +30,7 @@
public abstract class MediaUploadRequestExecutor implements RequestExecutor {
protected RequestHttp requestHttp;
- public MediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public MediaUploadRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}
@@ -34,16 +39,21 @@ public void execute(String uri, File data, ResponseHandler
handler.handle(this.execute(uri, data, wxType));
}
- public static RequestExecutor create(RequestHttp requestHttp) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheMediaUploadRequestExecutor(requestHttp);
+ return new ApacheMediaUploadRequestExecutor(
+ (RequestHttp) requestHttp);
case JODD_HTTP:
- return new JoddHttpMediaUploadRequestExecutor(requestHttp);
+ return new JoddHttpMediaUploadRequestExecutor((RequestHttp) requestHttp);
case OK_HTTP:
- return new OkHttpMediaUploadRequestExecutor(requestHttp);
+ return new OkHttpMediaUploadRequestExecutor((RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsMediaUploadRequestExecutor(
+ (RequestHttp) requestHttp);
default:
- return null;
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java
index e94b2d8d6a..0e8684a1db 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java
@@ -1,11 +1,16 @@
package me.chanjar.weixin.common.util.http;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadCustomizeResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheMinishopMediaUploadRequestCustomizeExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMinishopMediaUploadRequestCustomizeExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMinishopMediaUploadRequestCustomizeExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMinishopMediaUploadRequestCustomizeExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
import java.io.File;
import java.io.IOException;
@@ -16,13 +21,12 @@ public abstract class MinishopUploadRequestCustomizeExecutor implements Re
protected String uploadType;
protected String imgUrl;
- public MinishopUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+ public MinishopUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
this.requestHttp = requestHttp;
this.respType = respType;
if (imgUrl == null || imgUrl.isEmpty()) {
this.uploadType = "0";
- }
- else {
+ } else {
this.uploadType = "1";
this.imgUrl = imgUrl;
}
@@ -33,16 +37,21 @@ public void execute(String uri, File data, ResponseHandler create(RequestHttp requestHttp, String respType, String imgUrl) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp, String respType, String imgUrl) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheMinishopMediaUploadRequestCustomizeExecutor(requestHttp, respType, imgUrl);
+ return new ApacheMinishopMediaUploadRequestCustomizeExecutor(
+ (RequestHttp) requestHttp, respType, imgUrl);
case JODD_HTTP:
- return new JoddHttpMinishopMediaUploadRequestCustomizeExecutor(requestHttp, respType, imgUrl);
+ return new JoddHttpMinishopMediaUploadRequestCustomizeExecutor((RequestHttp) requestHttp, respType, imgUrl);
case OK_HTTP:
- return new OkHttpMinishopMediaUploadRequestCustomizeExecutor(requestHttp, respType, imgUrl);
+ return new OkHttpMinishopMediaUploadRequestCustomizeExecutor((RequestHttp) requestHttp, respType, imgUrl);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsMinishopMediaUploadRequestCustomizeExecutor(
+ (RequestHttp) requestHttp, respType, imgUrl);
default:
- return null;
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java
index ee4608edf3..e6018a7791 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java
@@ -1,11 +1,16 @@
package me.chanjar.weixin.common.util.http;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheMinishopMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMinishopMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpMinishopMediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpMinishopMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
import java.io.File;
import java.io.IOException;
@@ -13,7 +18,7 @@
public abstract class MinishopUploadRequestExecutor implements RequestExecutor {
protected RequestHttp requestHttp;
- public MinishopUploadRequestExecutor(RequestHttp requestHttp) {
+ public MinishopUploadRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}
@@ -22,16 +27,21 @@ public void execute(String uri, File data, ResponseHandler create(RequestHttp requestHttp) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheMinishopMediaUploadRequestExecutor(requestHttp);
+ return new ApacheMinishopMediaUploadRequestExecutor(
+ (RequestHttp) requestHttp);
case JODD_HTTP:
- return new JoddHttpMinishopMediaUploadRequestExecutor(requestHttp);
+ return new JoddHttpMinishopMediaUploadRequestExecutor((RequestHttp) requestHttp);
case OK_HTTP:
- return new OkHttpMinishopMediaUploadRequestExecutor(requestHttp);
+ return new OkHttpMinishopMediaUploadRequestExecutor((RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsMinishopMediaUploadRequestExecutor(
+ (RequestHttp) requestHttp);
default:
- return null;
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
index b7bc850f8f..36be78b8ae 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
@@ -26,6 +26,6 @@ public interface RequestHttp {
*
* @return HttpType
*/
- HttpType getRequestType();
+ HttpClientType getRequestType();
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
index 266fd226e7..a880a9323c 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
@@ -1,11 +1,16 @@
package me.chanjar.weixin.common.util.http;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsSimpleGetRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor;
+import okhttp3.OkHttpClient;
import java.io.IOException;
@@ -27,16 +32,21 @@ public void execute(String uri, String data, ResponseHandler handler, Wx
handler.handle(this.execute(uri, data, wxType));
}
+ @SuppressWarnings("unchecked")
public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheSimpleGetRequestExecutor(requestHttp);
+ return new ApacheSimpleGetRequestExecutor(
+ (RequestHttp) requestHttp);
case JODD_HTTP:
- return new JoddHttpSimpleGetRequestExecutor(requestHttp);
+ return new JoddHttpSimpleGetRequestExecutor((RequestHttp) requestHttp);
case OK_HTTP:
- return new OkHttpSimpleGetRequestExecutor(requestHttp);
+ return new OkHttpSimpleGetRequestExecutor((RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsSimpleGetRequestExecutor(
+ (RequestHttp) requestHttp);
default:
- throw new IllegalArgumentException("非法请求参数");
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
index 0366b156af..2cc086cd0f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
@@ -1,11 +1,16 @@
package me.chanjar.weixin.common.util.http;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsSimplePostRequestExecutor;
import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor;
+import okhttp3.OkHttpClient;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -18,7 +23,7 @@
public abstract class SimplePostRequestExecutor implements RequestExecutor {
protected RequestHttp requestHttp;
- public SimplePostRequestExecutor(RequestHttp requestHttp) {
+ public SimplePostRequestExecutor(RequestHttp requestHttp) {
this.requestHttp = requestHttp;
}
@@ -28,16 +33,21 @@ public void execute(String uri, String data, ResponseHandler handler, Wx
handler.handle(this.execute(uri, data, wxType));
}
- public static RequestExecutor create(RequestHttp requestHttp) {
+ @SuppressWarnings("unchecked")
+ public static RequestExecutor create(RequestHttp, ?> requestHttp) {
switch (requestHttp.getRequestType()) {
case APACHE_HTTP:
- return new ApacheSimplePostRequestExecutor(requestHttp);
+ return new ApacheSimplePostRequestExecutor(
+ (RequestHttp) requestHttp);
case JODD_HTTP:
- return new JoddHttpSimplePostRequestExecutor(requestHttp);
+ return new JoddHttpSimplePostRequestExecutor((RequestHttp) requestHttp);
case OK_HTTP:
- return new OkHttpSimplePostRequestExecutor(requestHttp);
+ return new OkHttpSimplePostRequestExecutor((RequestHttp) requestHttp);
+ case HTTP_COMPONENTS:
+ return new HttpComponentsSimplePostRequestExecutor(
+ (RequestHttp) requestHttp);
default:
- throw new IllegalArgumentException("非法请求参数");
+ throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType());
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheBasicResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheBasicResponseHandler.java
new file mode 100644
index 0000000000..a91fc383ca
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheBasicResponseHandler.java
@@ -0,0 +1,9 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.impl.client.BasicResponseHandler;
+
+public class ApacheBasicResponseHandler extends BasicResponseHandler {
+
+ public static final ApacheBasicResponseHandler INSTANCE = new ApacheBasicResponseHandler();
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
index 0d5073de14..5b13e7cc17 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
@@ -21,36 +21,66 @@ public interface ApacheHttpClientBuilder {
/**
* 代理服务器地址.
+ *
+ * @param httpProxyHost 代理服务器地址
+ * @return ApacheHttpClientBuilder
*/
ApacheHttpClientBuilder httpProxyHost(String httpProxyHost);
/**
* 代理服务器端口.
+ *
+ * @param httpProxyPort 代理服务器端口
+ * @return ApacheHttpClientBuilder
*/
ApacheHttpClientBuilder httpProxyPort(int httpProxyPort);
/**
* 代理服务器用户名.
+ *
+ * @param httpProxyUsername 代理服务器用户名
+ * @return ApacheHttpClientBuilder
*/
ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername);
/**
* 代理服务器密码.
+ *
+ * @param httpProxyPassword 代理服务器密码
+ * @return ApacheHttpClientBuilder
*/
ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword);
/**
* 重试策略.
+ *
+ * @param httpRequestRetryHandler 重试处理器
+ * @return ApacheHttpClientBuilder
*/
- ApacheHttpClientBuilder httpRequestRetryHandler(HttpRequestRetryHandler httpRequestRetryHandler );
+ ApacheHttpClientBuilder httpRequestRetryHandler(HttpRequestRetryHandler httpRequestRetryHandler);
/**
* 超时时间.
+ *
+ * @param keepAliveStrategy 保持连接策略
+ * @return ApacheHttpClientBuilder
*/
ApacheHttpClientBuilder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy);
/**
* ssl连接socket工厂.
+ *
+ * @param sslConnectionSocketFactory SSL连接Socket工厂
+ * @return ApacheHttpClientBuilder
*/
ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory);
+
+ /**
+ * 支持的TLS协议版本.
+ * Supported TLS protocol versions.
+ *
+ * @param supportedProtocols 支持的协议版本数组
+ * @return ApacheHttpClientBuilder
+ */
+ ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
index 6a136600e5..b3ebf350be 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
@@ -117,6 +117,13 @@ public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFac
return this;
}
+ @Override
+ public ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols) {
+ // This implementation doesn't use the supportedProtocols parameter as it relies on the provided SSLConnectionSocketFactory
+ // Users should configure the SSLConnectionSocketFactory with desired protocols before setting it
+ return this;
+ }
+
/**
* 获取链接的超时时间设置,默认3000ms
*
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpResponseProxy.java
new file mode 100644
index 0000000000..06439d3879
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpResponseProxy.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import org.apache.http.Header;
+import org.apache.http.client.methods.CloseableHttpResponse;
+
+public class ApacheHttpResponseProxy implements HttpResponseProxy {
+
+ private final CloseableHttpResponse httpResponse;
+
+ public ApacheHttpResponseProxy(CloseableHttpResponse closeableHttpResponse) {
+ this.httpResponse = closeableHttpResponse;
+ }
+
+ @Override
+ public String getFileName() throws WxErrorException {
+ Header[] contentDispositionHeader = this.httpResponse.getHeaders("Content-disposition");
+ if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
+ throw new WxErrorException("无法获取到文件名,Content-disposition为空");
+ }
+
+ return HttpResponseProxy.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
index e2f4611439..554dc8df7b 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
@@ -28,7 +28,7 @@
* created on 2017/5/5
*/
public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor {
- public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+ public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
super(requestHttp, tmpDirFile);
}
@@ -58,7 +58,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
}
}
- String fileName = new HttpResponseProxy(response).getFileName();
+ String fileName = HttpResponseProxy.from(response).getFileName();
if (StringUtils.isBlank(fileName)) {
fileName = String.valueOf(System.currentTimeMillis());
}
@@ -68,11 +68,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
baseName = String.valueOf(System.currentTimeMillis());
}
- return FileUtils.createTmpFile(inputStream, baseName, FilenameUtils.getExtension(fileName),
- super.tmpDirFile);
-
- } finally {
- httpGet.releaseConnection();
+ return FileUtils.createTmpFile(inputStream, baseName, FilenameUtils.getExtension(fileName), super.tmpDirFile);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
index ef09812cb2..43a5d604b0 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
@@ -10,7 +10,6 @@
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
@@ -26,7 +25,7 @@
* created on 2022/02/15
*/
public class ApacheMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
- public ApacheMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ public ApacheMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -45,15 +44,11 @@ public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxTy
.build();
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- WxError error = WxError.fromJson(responseContent, wxType);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
- }
- return WxMediaUploadResult.fromJson(responseContent);
- } finally {
- httpPost.releaseConnection();
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
}
+ return WxMediaUploadResult.fromJson(responseContent);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java
index ca33b8641f..5d3eae174f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java
@@ -1,7 +1,7 @@
package me.chanjar.weixin.common.util.http.apache;
-import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
@@ -9,7 +9,6 @@
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -22,7 +21,7 @@
* Created by ecoolper on 2017/5/5.
*/
public class ApacheMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
- public ApacheMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public ApacheMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -41,15 +40,11 @@ public WxMediaUploadResult execute(String uri, File file, WxType wxType) throws
.build();
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- WxError error = WxError.fromJson(responseContent, wxType);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
- }
- return WxMediaUploadResult.fromJson(responseContent);
- } finally {
- httpPost.releaseConnection();
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
}
+ return WxMediaUploadResult.fromJson(responseContent);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java
index 9af02af5d0..48fafc3401 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java
@@ -10,7 +10,6 @@
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -24,7 +23,7 @@
*/
@Slf4j
public class ApacheMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor {
- public ApacheMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+ public ApacheMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
super(requestHttp, respType, imgUrl);
}
@@ -58,16 +57,12 @@ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxTyp
.build();
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- WxError error = WxError.fromJson(responseContent, wxType);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
- }
- log.info("responseContent: " + responseContent);
- return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
- } finally {
- httpPost.releaseConnection();
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
}
+ log.info("responseContent: {}", responseContent);
+ return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java
index 7adc6a2cfa..f76d4e8642 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java
@@ -5,13 +5,11 @@
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -25,7 +23,7 @@
*/
@Slf4j
public class ApacheMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor {
- public ApacheMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public ApacheMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -44,16 +42,12 @@ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType)
.build();
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- WxError error = WxError.fromJson(responseContent, wxType);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
- }
- log.info("responseContent: " + responseContent);
- return WxMinishopImageUploadResult.fromJson(responseContent);
- } finally {
- httpPost.releaseConnection();
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
}
+ log.info("responseContent: {}", responseContent);
+ return WxMinishopImageUploadResult.fromJson(responseContent);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
index be0784b076..08ccf1b252 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
@@ -6,7 +6,6 @@
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
@@ -19,7 +18,7 @@
* created on 2017/5/4
*/
public class ApacheSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
- public ApacheSimpleGetRequestExecutor(RequestHttp requestHttp) {
+ public ApacheSimpleGetRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -37,12 +36,8 @@ public String execute(String uri, String queryParam, WxType wxType) throws WxErr
httpGet.setConfig(config);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- return handleResponse(wxType, responseContent);
- } finally {
- httpGet.releaseConnection();
- }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpGet, Utf8ResponseHandler.INSTANCE);
+ return handleResponse(wxType, responseContent);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java
index 52c8caaf3d..65af81690d 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java
@@ -4,15 +4,15 @@
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
-import org.apache.http.Consts;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
/**
* .
@@ -21,7 +21,7 @@
* created on 2017/5/4
*/
public class ApacheSimplePostRequestExecutor extends SimplePostRequestExecutor {
- public ApacheSimplePostRequestExecutor(RequestHttp requestHttp) {
+ public ApacheSimplePostRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -34,17 +34,12 @@ public String execute(String uri, String postEntity, WxType wxType) throws WxErr
}
if (postEntity != null) {
- StringEntity entity = new StringEntity(postEntity, Consts.UTF_8);
- entity.setContentType("application/json; charset=utf-8");
+ StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8));
httpPost.setEntity(entity);
}
- try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
- String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
- return this.handleResponse(wxType, responseContent);
- } finally {
- httpPost.releaseConnection();
- }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ return this.handleResponse(wxType, responseContent);
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ByteArrayResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ByteArrayResponseHandler.java
new file mode 100644
index 0000000000..776b7e32f1
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ByteArrayResponseHandler.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.impl.client.AbstractResponseHandler;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+public class ByteArrayResponseHandler extends AbstractResponseHandler {
+
+ public static final ByteArrayResponseHandler INSTANCE = new ByteArrayResponseHandler();
+
+ @Override
+ public byte[] handleEntity(HttpEntity entity) throws IOException {
+ return EntityUtils.toByteArray(entity);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
index 4c06f5168e..ef7120b768 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
@@ -25,17 +25,13 @@
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import javax.annotation.concurrent.NotThreadSafe;
import javax.net.ssl.SSLContext;
-import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -59,7 +55,7 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
* 设置为负数是使用系统默认设置(非3000ms的默认值,而是httpClient的默认设置).
*
*/
- private int connectionRequestTimeout = -1;
+ private int connectionRequestTimeout = 3000;
/**
* 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用
@@ -97,6 +93,12 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
*/
private String userAgent;
+ /**
+ * 支持的TLS协议版本,默认支持现代TLS版本
+ * Supported TLS protocol versions, defaults to modern TLS versions
+ */
+ private String[] supportedProtocols = {"TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1"};
+
/**
* 自定义请求拦截器
*/
@@ -183,6 +185,12 @@ public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFac
return this;
}
+ @Override
+ public ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols) {
+ this.supportedProtocols = supportedProtocols;
+ return this;
+ }
+
public IdleConnectionMonitorThread getIdleConnectionMonitorThread() {
return this.idleConnectionMonitorThread;
}
@@ -261,7 +269,7 @@ private SSLConnectionSocketFactory buildSSLConnectionSocketFactory() {
return new SSLConnectionSocketFactory(
sslcontext,
- new String[]{"TLSv1"},
+ this.supportedProtocols,
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
index 5c72744cb0..1568362611 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
@@ -1,33 +1,23 @@
package me.chanjar.weixin.common.util.http.apache;
-import java.io.IOException;
-import java.io.InputStream;
-
import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
-import org.apache.http.util.EntityUtils;
+import org.apache.http.impl.client.AbstractResponseHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
/**
* 输入流响应处理器.
*
- * @author Daniel Qian
+ * @author altusea
*/
-public class InputStreamResponseHandler implements ResponseHandler {
+public class InputStreamResponseHandler extends AbstractResponseHandler {
+
public static final ResponseHandler INSTANCE = new InputStreamResponseHandler();
- private static final int STATUS_CODE_300 = 300;
@Override
- public InputStream handleResponse(final HttpResponse response) throws IOException {
- final StatusLine statusLine = response.getStatusLine();
- final HttpEntity entity = response.getEntity();
- if (statusLine.getStatusCode() >= STATUS_CODE_300) {
- EntityUtils.consume(entity);
- throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
- }
- return entity == null ? null : entity.getContent();
+ public InputStream handleEntity(HttpEntity entity) throws IOException {
+ return entity.getContent();
}
-
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java
index 035726d44f..40d96e3ca1 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java
@@ -1,33 +1,24 @@
package me.chanjar.weixin.common.util.http.apache;
-import org.apache.http.Consts;
import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
+import org.apache.http.impl.client.AbstractResponseHandler;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
/**
- * copy from {@link org.apache.http.impl.client.BasicResponseHandler}
+ * Utf8ResponseHandler
*
- * @author Daniel Qian
+ * @author altusea
*/
-public class Utf8ResponseHandler implements ResponseHandler {
+public class Utf8ResponseHandler extends AbstractResponseHandler {
public static final ResponseHandler INSTANCE = new Utf8ResponseHandler();
@Override
- public String handleResponse(final HttpResponse response) throws IOException {
- final StatusLine statusLine = response.getStatusLine();
- final HttpEntity entity = response.getEntity();
- if (statusLine.getStatusCode() >= 300) {
- EntityUtils.consume(entity);
- throw new HttpResponseException(statusLine.getStatusCode(), statusLine.toString());
- }
- return entity == null ? null : EntityUtils.toString(entity, Consts.UTF_8);
+ public String handleEntity(HttpEntity entity) throws IOException {
+ return EntityUtils.toString(entity, StandardCharsets.UTF_8);
}
-
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/BasicResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/BasicResponseHandler.java
new file mode 100644
index 0000000000..f69e14a240
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/BasicResponseHandler.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler;
+
+/**
+ * ApacheBasicResponseHandler
+ *
+ * @author altusea
+ */
+public class BasicResponseHandler extends BasicHttpClientResponseHandler {
+
+ public static final BasicHttpClientResponseHandler INSTANCE = new BasicHttpClientResponseHandler();
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/ByteArrayResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/ByteArrayResponseHandler.java
new file mode 100644
index 0000000000..e4a314f866
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/ByteArrayResponseHandler.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+
+import java.io.IOException;
+
+/**
+ * ByteArrayResponseHandler
+ *
+ * @author altusea
+ */
+public class ByteArrayResponseHandler extends AbstractHttpClientResponseHandler {
+
+ public static final ByteArrayResponseHandler INSTANCE = new ByteArrayResponseHandler();
+
+ @Override
+ public byte[] handleEntity(HttpEntity entity) throws IOException {
+ return EntityUtils.toByteArray(entity);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/DefaultHttpComponentsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/DefaultHttpComponentsClientBuilder.java
new file mode 100644
index 0000000000..4915e31a16
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/DefaultHttpComponentsClientBuilder.java
@@ -0,0 +1,249 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.HttpRequestRetryStrategy;
+import org.apache.hc.client5.http.auth.AuthScope;
+import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
+import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
+import org.apache.hc.client5.http.ssl.TrustAllStrategy;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequestInterceptor;
+import org.apache.hc.core5.http.HttpResponseInterceptor;
+import org.apache.hc.core5.http.io.SocketConfig;
+import org.apache.hc.core5.ssl.SSLContexts;
+
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.net.ssl.SSLContext;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * DefaultApacheHttpClientBuilder
+ *
+ * @author altusea
+ */
+@Slf4j
+@Data
+@NotThreadSafe
+public class DefaultHttpComponentsClientBuilder implements HttpComponentsClientBuilder {
+
+ private final AtomicBoolean prepared = new AtomicBoolean(false);
+
+ /**
+ * 获取链接的超时时间设置
+ *
+ * 设置为零时不超时,一直等待.
+ * 设置为负数是使用系统默认设置(非3000ms的默认值,而是httpClient的默认设置).
+ *
+ */
+ private int connectionRequestTimeout = 3000;
+
+ /**
+ * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用
+ *
+ * 设置为零时不超时,一直等待.
+ * 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置).
+ *
+ */
+ private int connectionTimeout = 5000;
+ /**
+ * 默认NIO的socket超时设置,默认5000ms.
+ */
+ private int soTimeout = 5000;
+ /**
+ * 空闲链接的超时时间,默认60000ms.
+ *
+ * 超时的链接将在下一次空闲链接检查是被销毁
+ *
+ */
+ private int idleConnTimeout = 60000;
+ /**
+ * 检查空间链接的间隔周期,默认60000ms.
+ */
+ private int checkWaitTime = 60000;
+ /**
+ * 每路的最大链接数,默认10
+ */
+ private int maxConnPerHost = 10;
+ /**
+ * 最大总连接数,默认50
+ */
+ private int maxTotalConn = 50;
+ /**
+ * 自定义httpclient的User Agent
+ */
+ private String userAgent;
+
+ /**
+ * 自定义请求拦截器
+ */
+ private List requestInterceptors = new ArrayList<>();
+
+ /**
+ * 自定义响应拦截器
+ */
+ private List responseInterceptors = new ArrayList<>();
+
+ /**
+ * 自定义重试策略
+ */
+ private HttpRequestRetryStrategy httpRequestRetryStrategy;
+
+ /**
+ * 自定义KeepAlive策略
+ */
+ private ConnectionKeepAliveStrategy connectionKeepAliveStrategy;
+
+ private String httpProxyHost;
+ private int httpProxyPort;
+ private String httpProxyUsername;
+ private char[] httpProxyPassword;
+ /**
+ * 持有client对象,仅初始化一次,避免多service实例的时候造成重复初始化的问题
+ */
+ private CloseableHttpClient closeableHttpClient;
+
+ private DefaultHttpComponentsClientBuilder() {
+ }
+
+ public static DefaultHttpComponentsClientBuilder get() {
+ return SingletonHolder.INSTANCE;
+ }
+
+ @Override
+ public HttpComponentsClientBuilder httpProxyHost(String httpProxyHost) {
+ this.httpProxyHost = httpProxyHost;
+ return this;
+ }
+
+ @Override
+ public HttpComponentsClientBuilder httpProxyPort(int httpProxyPort) {
+ this.httpProxyPort = httpProxyPort;
+ return this;
+ }
+
+ @Override
+ public HttpComponentsClientBuilder httpProxyUsername(String httpProxyUsername) {
+ this.httpProxyUsername = httpProxyUsername;
+ return this;
+ }
+
+ @Override
+ public HttpComponentsClientBuilder httpProxyPassword(char[] httpProxyPassword) {
+ this.httpProxyPassword = httpProxyPassword;
+ return this;
+ }
+
+ @Override
+ public HttpComponentsClientBuilder httpRequestRetryStrategy(HttpRequestRetryStrategy httpRequestRetryStrategy) {
+ this.httpRequestRetryStrategy = httpRequestRetryStrategy;
+ return this;
+ }
+
+ @Override
+ public HttpComponentsClientBuilder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy) {
+ this.connectionKeepAliveStrategy = keepAliveStrategy;
+ return this;
+ }
+
+ private synchronized void prepare() {
+ if (prepared.get()) {
+ return;
+ }
+
+ SSLContext sslcontext;
+ try {
+ sslcontext = SSLContexts.custom()
+ .loadTrustMaterial(TrustAllStrategy.INSTANCE) // 忽略对服务器端证书的校验
+ .build();
+ } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
+ log.error("构建 SSLContext 时发生异常!", e);
+ throw new RuntimeException(e);
+ }
+
+ PoolingHttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create()
+ .setTlsSocketStrategy(new DefaultClientTlsStrategy(sslcontext, NoopHostnameVerifier.INSTANCE))
+ .setMaxConnTotal(this.maxTotalConn)
+ .setMaxConnPerRoute(this.maxConnPerHost)
+ .setDefaultSocketConfig(SocketConfig.custom()
+ .setSoTimeout(this.soTimeout, TimeUnit.MILLISECONDS)
+ .build())
+ .setDefaultConnectionConfig(ConnectionConfig.custom()
+ .setConnectTimeout(this.connectionTimeout, TimeUnit.MILLISECONDS)
+ .build())
+ .build();
+
+ HttpClientBuilder httpClientBuilder = HttpClients.custom()
+ .setConnectionManager(connManager)
+ .setConnectionManagerShared(true)
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectionRequestTimeout(this.connectionRequestTimeout, TimeUnit.MILLISECONDS)
+ .build()
+ );
+
+ // 设置重试策略,没有则使用默认
+ httpClientBuilder.setRetryStrategy(ObjectUtils.defaultIfNull(httpRequestRetryStrategy, NoopRetryStrategy.INSTANCE));
+
+ // 设置KeepAliveStrategy,没有使用默认
+ if (connectionKeepAliveStrategy != null) {
+ httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy);
+ }
+
+ if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) {
+ // 使用代理服务器 需要用户认证的代理服务器
+ BasicCredentialsProvider provider = new BasicCredentialsProvider();
+ provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort),
+ new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword));
+ httpClientBuilder.setDefaultCredentialsProvider(provider);
+ httpClientBuilder.setProxy(new HttpHost(this.httpProxyHost, this.httpProxyPort));
+ }
+
+ if (StringUtils.isNotBlank(this.userAgent)) {
+ httpClientBuilder.setUserAgent(this.userAgent);
+ }
+
+ //添加自定义的请求拦截器
+ requestInterceptors.forEach(httpClientBuilder::addRequestInterceptorFirst);
+
+ //添加自定义的响应拦截器
+ responseInterceptors.forEach(httpClientBuilder::addResponseInterceptorLast);
+
+ this.closeableHttpClient = httpClientBuilder.build();
+ prepared.set(true);
+ }
+
+ @Override
+ public CloseableHttpClient build() {
+ if (!prepared.get()) {
+ prepare();
+ }
+ return this.closeableHttpClient;
+ }
+
+ /**
+ * DefaultApacheHttpClientBuilder 改为单例模式,并持有唯一的CloseableHttpClient(仅首次调用创建)
+ */
+ private static class SingletonHolder {
+ private static final DefaultHttpComponentsClientBuilder INSTANCE = new DefaultHttpComponentsClientBuilder();
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsClientBuilder.java
new file mode 100644
index 0000000000..66cd58e15f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsClientBuilder.java
@@ -0,0 +1,51 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.HttpRequestRetryStrategy;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+
+/**
+ * httpclient build interface.
+ *
+ * @author altusea
+ */
+public interface HttpComponentsClientBuilder {
+
+ /**
+ * 构建httpclient实例.
+ *
+ * @return new instance of CloseableHttpClient
+ */
+ CloseableHttpClient build();
+
+ /**
+ * 代理服务器地址.
+ */
+ HttpComponentsClientBuilder httpProxyHost(String httpProxyHost);
+
+ /**
+ * 代理服务器端口.
+ */
+ HttpComponentsClientBuilder httpProxyPort(int httpProxyPort);
+
+ /**
+ * 代理服务器用户名.
+ */
+ HttpComponentsClientBuilder httpProxyUsername(String httpProxyUsername);
+
+ /**
+ * 代理服务器密码.
+ */
+ HttpComponentsClientBuilder httpProxyPassword(char[] httpProxyPassword);
+
+ /**
+ * 重试策略.
+ */
+ HttpComponentsClientBuilder httpRequestRetryStrategy(HttpRequestRetryStrategy httpRequestRetryStrategy);
+
+ /**
+ * 超时时间.
+ */
+ HttpComponentsClientBuilder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy);
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaDownloadRequestExecutor.java
new file mode 100644
index 0000000000..26fbed93f3
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaDownloadRequestExecutor.java
@@ -0,0 +1,79 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * ApacheMediaDownloadRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor {
+
+ public HttpComponentsMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+ super(requestHttp, tmpDirFile);
+ }
+
+ @Override
+ public File execute(String uri, String queryParam, WxType wxType) throws WxErrorException, IOException {
+ if (queryParam != null) {
+ if (uri.indexOf('?') == -1) {
+ uri += '?';
+ }
+ uri += uri.endsWith("?") ? queryParam : '&' + queryParam;
+ }
+
+ HttpGet httpGet = new HttpGet(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpGet.setConfig(config);
+ }
+
+ try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
+ InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+ Header[] contentTypeHeader = response.getHeaders("Content-Type");
+ if (contentTypeHeader != null && contentTypeHeader.length > 0) {
+ if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) {
+ // application/json; encoding=utf-8 下载媒体文件出错
+ String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+ throw new WxErrorException(WxError.fromJson(responseContent, wxType));
+ }
+ }
+
+ String fileName = HttpResponseProxy.from(response).getFileName();
+ if (StringUtils.isBlank(fileName)) {
+ fileName = String.valueOf(System.currentTimeMillis());
+ }
+
+ String baseName = FilenameUtils.getBaseName(fileName);
+ if (StringUtils.isBlank(fileName) || baseName.length() < 3) {
+ baseName = String.valueOf(System.currentTimeMillis());
+ }
+
+ return FileUtils.createTmpFile(inputStream, baseName, FilenameUtils.getExtension(fileName), super.tmpDirFile);
+ } catch (HttpException httpException) {
+ throw new ClientProtocolException(httpException.getMessage(), httpException);
+ }
+ }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaInputStreamUploadRequestExecutor.java
new file mode 100644
index 0000000000..4853b1572b
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaInputStreamUploadRequestExecutor.java
@@ -0,0 +1,54 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.InputStreamData;
+import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+
+/**
+ * 文件输入流上传.
+ *
+ * @author altusea
+ */
+public class HttpComponentsMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
+
+ public HttpComponentsMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (data != null) {
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addBinaryBody("media", data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFilename())
+ .setMode(HttpMultipartMode.EXTENDED)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return WxMediaUploadResult.fromJson(responseContent);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaUploadRequestExecutor.java
new file mode 100644
index 0000000000..e65d855d52
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaUploadRequestExecutor.java
@@ -0,0 +1,53 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ApacheMediaUploadRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
+
+ public HttpComponentsMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public WxMediaUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (file != null) {
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addBinaryBody("media", file)
+ .setMode(HttpMultipartMode.EXTENDED)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return WxMediaUploadResult.fromJson(responseContent);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestCustomizeExecutor.java
new file mode 100644
index 0000000000..711f538309
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestCustomizeExecutor.java
@@ -0,0 +1,71 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadCustomizeResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.MinishopUploadRequestCustomizeExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ApacheMinishopMediaUploadRequestCustomizeExecutor
+ *
+ * @author altusea
+ */
+@Slf4j
+public class HttpComponentsMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor {
+
+ public HttpComponentsMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+ super(requestHttp, respType, imgUrl);
+ }
+
+ @Override
+ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (this.uploadType.equals("0")) {
+ if (file == null) {
+ throw new WxErrorException("上传文件为空");
+ }
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addBinaryBody("media", file)
+ .addTextBody("resp_type", this.respType)
+ .addTextBody("upload_type", this.uploadType)
+ .setMode(HttpMultipartMode.EXTENDED)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ else {
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addTextBody("resp_type", this.respType)
+ .addTextBody("upload_type", this.uploadType)
+ .addTextBody("img_url", this.imgUrl)
+ .setMode(org.apache.hc.client5.http.entity.mime.HttpMultipartMode.EXTENDED)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ log.info("responseContent: {}", responseContent);
+ return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestExecutor.java
new file mode 100644
index 0000000000..72c1f2765f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestExecutor.java
@@ -0,0 +1,56 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ApacheMinishopMediaUploadRequestExecutor
+ *
+ * @author altusea
+ */
+@Slf4j
+public class HttpComponentsMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor {
+
+ public HttpComponentsMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (file != null) {
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addBinaryBody("media", file)
+ .setMode(HttpMultipartMode.EXTENDED)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ log.info("responseContent: {}", responseContent);
+ return WxMinishopImageUploadResult.fromJson(responseContent);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsResponseProxy.java
new file mode 100644
index 0000000000..d55ff0735f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsResponseProxy.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.Header;
+
+public class HttpComponentsResponseProxy implements HttpResponseProxy {
+
+ private final CloseableHttpResponse response;
+
+ public HttpComponentsResponseProxy(CloseableHttpResponse closeableHttpResponse) {
+ this.response = closeableHttpResponse;
+ }
+
+ @Override
+ public String getFileName() throws WxErrorException {
+ Header[] contentDispositionHeader = this.response.getHeaders("Content-disposition");
+ if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
+ throw new WxErrorException("无法获取到文件名,Content-disposition为空");
+ }
+
+ return HttpResponseProxy.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimpleGetRequestExecutor.java
new file mode 100644
index 0000000000..0d212fe7e2
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimpleGetRequestExecutor.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+
+/**
+ * ApacheSimpleGetRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
+
+ public HttpComponentsSimpleGetRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public String execute(String uri, String queryParam, WxType wxType) throws WxErrorException, IOException {
+ if (queryParam != null) {
+ if (uri.indexOf('?') == -1) {
+ uri += '?';
+ }
+ uri += uri.endsWith("?") ? queryParam : '&' + queryParam;
+ }
+ HttpGet httpGet = new HttpGet(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpGet.setConfig(config);
+ }
+
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpGet, Utf8ResponseHandler.INSTANCE);
+ return handleResponse(wxType, responseContent);
+ }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimplePostRequestExecutor.java
new file mode 100644
index 0000000000..45d2ca9f6e
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimplePostRequestExecutor.java
@@ -0,0 +1,45 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * ApacheSimplePostRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsSimplePostRequestExecutor extends SimplePostRequestExecutor {
+
+ public HttpComponentsSimplePostRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public String execute(String uri, String postEntity, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+
+ if (postEntity != null) {
+ StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8));
+ httpPost.setEntity(entity);
+ }
+
+ String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+ return this.handleResponse(wxType, responseContent);
+ }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/InputStreamResponseHandler.java
new file mode 100644
index 0000000000..27308151f7
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/InputStreamResponseHandler.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * InputStreamResponseHandler
+ *
+ * @author altusea
+ */
+public class InputStreamResponseHandler extends AbstractHttpClientResponseHandler {
+
+ public static final HttpClientResponseHandler INSTANCE = new InputStreamResponseHandler();
+
+ @Override
+ public InputStream handleEntity(HttpEntity entity) throws IOException {
+ return entity.getContent();
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/NoopRetryStrategy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/NoopRetryStrategy.java
new file mode 100644
index 0000000000..9b4e3bc384
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/NoopRetryStrategy.java
@@ -0,0 +1,34 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.HttpRequestRetryStrategy;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.TimeValue;
+
+import java.io.IOException;
+
+/**
+ * NoopRetryStrategy
+ *
+ * @author altusea
+ */
+public class NoopRetryStrategy implements HttpRequestRetryStrategy {
+
+ public static final HttpRequestRetryStrategy INSTANCE = new NoopRetryStrategy();
+
+ @Override
+ public boolean retryRequest(HttpRequest request, IOException exception, int execCount, HttpContext context) {
+ return false;
+ }
+
+ @Override
+ public boolean retryRequest(HttpResponse response, int execCount, HttpContext context) {
+ return false;
+ }
+
+ @Override
+ public TimeValue getRetryInterval(HttpResponse response, int execCount, HttpContext context) {
+ return TimeValue.ZERO_MILLISECONDS;
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/Utf8ResponseHandler.java
new file mode 100644
index 0000000000..81699ef57b
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/Utf8ResponseHandler.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.ParseException;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utf8ResponseHandler
+ *
+ * @author altusea
+ */
+public class Utf8ResponseHandler extends AbstractHttpClientResponseHandler {
+
+ public static final HttpClientResponseHandler INSTANCE = new Utf8ResponseHandler();
+
+ @Override
+ public String handleEntity(HttpEntity entity) throws IOException {
+ try {
+ return EntityUtils.toString(entity, StandardCharsets.UTF_8);
+ } catch (final ParseException ex) {
+ throw new ClientProtocolException(ex);
+ }
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
index 920cf2d03b..bc2fbc17f3 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
@@ -4,7 +4,6 @@
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
@@ -28,7 +27,7 @@
* created on 2017/5/5
*/
public class JoddHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor {
- public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+ public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
super(requestHttp, tmpDirFile);
}
@@ -56,7 +55,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
throw new WxErrorException(WxError.fromJson(response.bodyText(), wxType));
}
- String fileName = new HttpResponseProxy(response).getFileName();
+ String fileName = HttpResponseProxy.from(response).getFileName();
if (StringUtils.isBlank(fileName)) {
return null;
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
index 311b7c49c5..915db21c65 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
@@ -25,7 +25,7 @@
* created on 2022/02/15
*/
public class JoddHttpMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
- public JoddHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ public JoddHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
index 876caa29fb..1ed59a71da 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
@@ -4,7 +4,6 @@
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxError;
@@ -23,7 +22,7 @@
* created on 2017/5/5
*/
public class JoddHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
- public JoddHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public JoddHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java
index 1d6f24fa2a..66074d8103 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java
@@ -22,7 +22,7 @@
*/
@Slf4j
public class JoddHttpMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor {
- public JoddHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+ public JoddHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
super(requestHttp, respType, imgUrl);
}
@@ -51,7 +51,7 @@ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxTyp
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
- log.info("responseContent: " + responseContent);
+ log.info("responseContent: {}", responseContent);
return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java
index 4cb9c50ee0..c7c35dd798 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java
@@ -5,12 +5,10 @@
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
@@ -26,7 +24,7 @@
*/
@Slf4j
public class JoddHttpMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor {
- public JoddHttpMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public JoddHttpMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -46,7 +44,7 @@ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType)
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
- log.info("responseContent: " + responseContent);
+ log.info("responseContent: {}", responseContent);
return WxMinishopImageUploadResult.fromJson(responseContent);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpResponseProxy.java
new file mode 100644
index 0000000000..1bda38a497
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpResponseProxy.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.common.util.http.jodd;
+
+import jodd.http.HttpResponse;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+
+public class JoddHttpResponseProxy implements HttpResponseProxy {
+
+ private final HttpResponse response;
+
+ public JoddHttpResponseProxy(HttpResponse httpResponse) {
+ this.response = httpResponse;
+ }
+
+ @Override
+ public String getFileName() throws WxErrorException {
+ String content = response.header("Content-disposition");
+ return HttpResponseProxy.extractFileNameFromContentString(content);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
index 869ea8c04e..ed8288b04f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
@@ -4,7 +4,6 @@
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.RequestHttp;
@@ -20,7 +19,7 @@
* created on 2017/5/4
*/
public class JoddHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
- public JoddHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
+ public JoddHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
index 654378271c..095493c75e 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
@@ -19,7 +19,7 @@
* created on 2017/5/4
*/
public class JoddHttpSimplePostRequestExecutor extends SimplePostRequestExecutor {
- public JoddHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
+ public JoddHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
index dda52e2f7b..0610d3f51c 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
@@ -25,7 +25,7 @@
*/
@Slf4j
public class OkHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor {
- public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+ public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
super(requestHttp, tmpDirFile);
}
@@ -51,7 +51,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
throw new WxErrorException(WxError.fromJson(response.body().string(), wxType));
}
- String fileName = new HttpResponseProxy(response).getFileName();
+ String fileName = HttpResponseProxy.from(response).getFileName();
if (StringUtils.isBlank(fileName)) {
return null;
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
index 613bd7ecfa..c30cc619aa 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
@@ -20,7 +20,7 @@
* created on 2022/02/15
*/
public class OkHttpMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
- public OkHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ public OkHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
index 1b5241ff70..6a7b0b794d 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
@@ -18,7 +18,7 @@
* created on 2017/5/5
*/
public class OkHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor {
- public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java
index a8b76321ca..a2c78f423b 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java
@@ -18,7 +18,7 @@
*/
@Slf4j
public class OkHttpMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor {
- public OkHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+ public OkHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
super(requestHttp, respType, imgUrl);
}
@@ -50,7 +50,7 @@ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxTyp
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
- log.info("responseContent: " + responseContent);
+ log.info("responseContent: {}", responseContent);
return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java
index 5c40b1f6ba..f2df3c7e73 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java
@@ -1,12 +1,10 @@
package me.chanjar.weixin.common.util.http.okhttp;
import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
import me.chanjar.weixin.common.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import okhttp3.*;
@@ -22,7 +20,7 @@
*/
@Slf4j
public class OkHttpMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor {
- public OkHttpMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+ public OkHttpMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
@@ -43,7 +41,7 @@ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType)
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
- log.info("responseContent: " + responseContent);
+ log.info("responseContent: {}", responseContent);
return WxMinishopImageUploadResult.fromJson(responseContent);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpResponseProxy.java
new file mode 100644
index 0000000000..95c290735c
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpResponseProxy.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.common.util.http.okhttp;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import okhttp3.Response;
+
+public class OkHttpResponseProxy implements HttpResponseProxy {
+
+ private final Response response;
+
+ public OkHttpResponseProxy(Response response) {
+ this.response = response;
+ }
+
+ @Override
+ public String getFileName() throws WxErrorException {
+ String content = this.response.header("Content-disposition");
+ return HttpResponseProxy.extractFileNameFromContentString(content);
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
index 2a41ea0508..d475222872 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
@@ -17,7 +17,7 @@
* created on 2017/5/4
*/
public class OkHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor {
- public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
+ public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
index a289f362e3..3044f29d60 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
@@ -18,7 +18,7 @@
*/
@Slf4j
public class OkHttpSimplePostRequestExecutor extends SimplePostRequestExecutor {
- public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
+ public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
super(requestHttp);
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java
index 061a3cb2ee..caa07d0eaf 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java
@@ -10,17 +10,16 @@
* @author niefy
*/
public class GsonParser {
- private static final JsonParser JSON_PARSER = new JsonParser();
public static JsonObject parse(String json) {
- return JSON_PARSER.parse(json).getAsJsonObject();
+ return new JsonParser().parse(json).getAsJsonObject();
}
public static JsonObject parse(Reader json) {
- return JSON_PARSER.parse(json).getAsJsonObject();
+ return new JsonParser().parse(json).getAsJsonObject();
}
public static JsonObject parse(JsonReader json) {
- return JSON_PARSER.parse(json).getAsJsonObject();
+ return new JsonParser().parse(json).getAsJsonObject();
}
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java
index ff260c16fb..8f3dafe48a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxGsonBuilder.java
@@ -1,5 +1,7 @@
package me.chanjar.weixin.common.util.json;
+import com.google.gson.ExclusionStrategy;
+import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import me.chanjar.weixin.common.bean.WxAccessToken;
@@ -7,6 +9,9 @@
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+
+import java.io.File;
import java.util.Objects;
/**
@@ -25,8 +30,24 @@ public class WxGsonBuilder {
INSTANCE.registerTypeAdapter(WxMediaUploadResult.class, new WxMediaUploadResultAdapter());
INSTANCE.registerTypeAdapter(WxNetCheckResult.class, new WxNetCheckResultGsonAdapter());
+ INSTANCE.setExclusionStrategies(new ExclusionStrategy() {
+ @Override
+ public boolean shouldSkipField(FieldAttributes fieldAttributes) {
+ return false;
+ }
+
+ @Override
+ public boolean shouldSkipClass(Class> aClass) {
+ return aClass == File.class || aClass == ApacheHttpClientBuilder.class;
+ }
+ });
}
+ /**
+ * 创建Gson实例
+ *
+ * @return Gson实例
+ */
public static Gson create() {
if (Objects.isNull(GSON_INSTANCE)) {
synchronized (INSTANCE) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
index 50d3b0d630..5e7f9b41d9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
@@ -1,11 +1,3 @@
-/*
- * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
- *
- * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
- * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
- * arose from modification of the original source, or other redistribution of this source
- * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
- */
package me.chanjar.weixin.common.util.json;
import com.google.gson.*;
@@ -14,6 +6,7 @@
import me.chanjar.weixin.common.bean.menu.WxMenuRule;
import java.lang.reflect.Type;
+import java.util.Optional;
/**
@@ -21,96 +14,111 @@
*/
public class WxMenuGsonAdapter implements JsonSerializer, JsonDeserializer {
+ // JSON字段常量定义
+ private static final String FIELD_BUTTON = "button";
+ private static final String FIELD_MATCH_RULE = "matchrule";
+ private static final String FIELD_SUB_BUTTON = "sub_button";
+ private static final String FIELD_MENU = "menu";
+
+ // 菜单按钮字段常量
+ private static final String FIELD_TYPE = "type";
+ private static final String FIELD_NAME = "name";
+ private static final String FIELD_KEY = "key";
+ private static final String FIELD_URL = "url";
+ private static final String FIELD_MEDIA_ID = "media_id";
+ private static final String FIELD_ARTICLE_ID = "article_id";
+ private static final String FIELD_APP_ID = "appid";
+ private static final String FIELD_PAGE_PATH = "pagepath";
+
+ // 菜单规则字段常量
+ private static final String FIELD_TAG_ID = "tag_id";
+ private static final String FIELD_SEX = "sex";
+ private static final String FIELD_COUNTRY = "country";
+ private static final String FIELD_PROVINCE = "province";
+ private static final String FIELD_CITY = "city";
+ private static final String FIELD_CLIENT_PLATFORM_TYPE = "client_platform_type";
+ private static final String FIELD_LANGUAGE = "language";
+
@Override
public JsonElement serialize(WxMenu menu, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
-
JsonArray buttonArray = new JsonArray();
- for (WxMenuButton button : menu.getButtons()) {
- JsonObject buttonJson = convertToJson(button);
- buttonArray.add(buttonJson);
- }
- json.add("button", buttonArray);
-
+ Optional.ofNullable(menu.getButtons())
+ .ifPresent(buttons -> buttons.stream()
+ .map(this::convertToJson)
+ .forEach(buttonArray::add));
+ json.add(FIELD_BUTTON, buttonArray);
if (menu.getMatchRule() != null) {
- json.add("matchrule", convertToJson(menu.getMatchRule()));
+ json.add(FIELD_MATCH_RULE, convertToJson(menu.getMatchRule()));
}
-
return json;
}
protected JsonObject convertToJson(WxMenuButton button) {
JsonObject buttonJson = new JsonObject();
- buttonJson.addProperty("type", button.getType());
- buttonJson.addProperty("name", button.getName());
- buttonJson.addProperty("key", button.getKey());
- buttonJson.addProperty("url", button.getUrl());
- buttonJson.addProperty("media_id", button.getMediaId());
- buttonJson.addProperty("article_id", button.getArticleId());
- buttonJson.addProperty("appid", button.getAppId());
- buttonJson.addProperty("pagepath", button.getPagePath());
- if (button.getSubButtons() != null && button.getSubButtons().size() > 0) {
+ addPropertyIfNotNull(buttonJson, FIELD_TYPE, button.getType());
+ addPropertyIfNotNull(buttonJson, FIELD_NAME, button.getName());
+ addPropertyIfNotNull(buttonJson, FIELD_KEY, button.getKey());
+ addPropertyIfNotNull(buttonJson, FIELD_URL, button.getUrl());
+ addPropertyIfNotNull(buttonJson, FIELD_MEDIA_ID, button.getMediaId());
+ addPropertyIfNotNull(buttonJson, FIELD_ARTICLE_ID, button.getArticleId());
+ addPropertyIfNotNull(buttonJson, FIELD_APP_ID, button.getAppId());
+ addPropertyIfNotNull(buttonJson, FIELD_PAGE_PATH, button.getPagePath());
+ if (button.getSubButtons() != null && !button.getSubButtons().isEmpty()) {
JsonArray buttonArray = new JsonArray();
- for (WxMenuButton sub_button : button.getSubButtons()) {
- buttonArray.add(convertToJson(sub_button));
- }
- buttonJson.add("sub_button", buttonArray);
+ button.getSubButtons().stream()
+ .map(this::convertToJson)
+ .forEach(buttonArray::add);
+ buttonJson.add(FIELD_SUB_BUTTON, buttonArray);
}
return buttonJson;
}
protected JsonObject convertToJson(WxMenuRule menuRule) {
JsonObject matchRule = new JsonObject();
- matchRule.addProperty("tag_id", menuRule.getTagId());
- matchRule.addProperty("sex", menuRule.getSex());
- matchRule.addProperty("country", menuRule.getCountry());
- matchRule.addProperty("province", menuRule.getProvince());
- matchRule.addProperty("city", menuRule.getCity());
- matchRule.addProperty("client_platform_type", menuRule.getClientPlatformType());
- matchRule.addProperty("language", menuRule.getLanguage());
+ addPropertyIfNotNull(matchRule, FIELD_TAG_ID, menuRule.getTagId());
+ addPropertyIfNotNull(matchRule, FIELD_SEX, menuRule.getSex());
+ addPropertyIfNotNull(matchRule, FIELD_COUNTRY, menuRule.getCountry());
+ addPropertyIfNotNull(matchRule, FIELD_PROVINCE, menuRule.getProvince());
+ addPropertyIfNotNull(matchRule, FIELD_CITY, menuRule.getCity());
+ addPropertyIfNotNull(matchRule, FIELD_CLIENT_PLATFORM_TYPE, menuRule.getClientPlatformType());
+ addPropertyIfNotNull(matchRule, FIELD_LANGUAGE, menuRule.getLanguage());
return matchRule;
}
- @Deprecated
- private WxMenuRule convertToRule(JsonObject json) {
- WxMenuRule menuRule = new WxMenuRule();
- //变态的微信接口,这里居然反人类的使用和序列化时不一样的名字
- //menuRule.setTagId(GsonHelper.getString(json,"tag_id"));
- menuRule.setTagId(GsonHelper.getString(json, "group_id"));
- menuRule.setSex(GsonHelper.getString(json, "sex"));
- menuRule.setCountry(GsonHelper.getString(json, "country"));
- menuRule.setProvince(GsonHelper.getString(json, "province"));
- menuRule.setCity(GsonHelper.getString(json, "city"));
- menuRule.setClientPlatformType(GsonHelper.getString(json, "client_platform_type"));
- menuRule.setLanguage(GsonHelper.getString(json, "language"));
- return menuRule;
+ private void addPropertyIfNotNull(JsonObject obj, String key, String value) {
+ if (value != null) {
+ obj.addProperty(key, value);
+ }
}
@Override
public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
- /*
- * 操蛋的微信
- * 创建菜单时是 { button : ... }
- * 查询菜单时是 { menu : { button : ... } }
- * 现在企业号升级为企业微信后,没有此问题,因此需要单独处理
- */
- JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray();
- return this.buildMenuFromJson(buttonsJson);
+ JsonObject root = json.getAsJsonObject();
+ JsonArray buttonsJson = null;
+ if (root.has(FIELD_MENU)) {
+ JsonObject menuObj = root.getAsJsonObject(FIELD_MENU);
+ buttonsJson = menuObj.getAsJsonArray(FIELD_BUTTON);
+ } else if (root.has(FIELD_BUTTON)) {
+ buttonsJson = root.getAsJsonArray(FIELD_BUTTON);
+ }
+ if (buttonsJson == null) {
+ throw new JsonParseException("No button array found in menu JSON");
+ }
+ return buildMenuFromJson(buttonsJson);
}
protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
WxMenu menu = new WxMenu();
- for (int i = 0; i < buttonsJson.size(); i++) {
- JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
+ for (JsonElement btnElem : buttonsJson) {
+ JsonObject buttonJson = btnElem.getAsJsonObject();
WxMenuButton button = convertFromJson(buttonJson);
menu.getButtons().add(button);
- if (buttonJson.get("sub_button") == null || buttonJson.get("sub_button").isJsonNull()) {
- continue;
- }
- JsonArray sub_buttonsJson = buttonJson.get("sub_button").getAsJsonArray();
- for (int j = 0; j < sub_buttonsJson.size(); j++) {
- JsonObject sub_buttonJson = sub_buttonsJson.get(j).getAsJsonObject();
- button.getSubButtons().add(convertFromJson(sub_buttonJson));
+ if (buttonJson.has(FIELD_SUB_BUTTON) && buttonJson.get(FIELD_SUB_BUTTON).isJsonArray()) {
+ JsonArray sub_buttonsJson = buttonJson.getAsJsonArray(FIELD_SUB_BUTTON);
+ for (JsonElement subBtnElem : sub_buttonsJson) {
+ button.getSubButtons().add(convertFromJson(subBtnElem.getAsJsonObject()));
+ }
}
}
return menu;
@@ -118,14 +126,14 @@ protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
protected WxMenuButton convertFromJson(JsonObject json) {
WxMenuButton button = new WxMenuButton();
- button.setName(GsonHelper.getString(json, "name"));
- button.setKey(GsonHelper.getString(json, "key"));
- button.setUrl(GsonHelper.getString(json, "url"));
- button.setType(GsonHelper.getString(json, "type"));
- button.setMediaId(GsonHelper.getString(json, "media_id"));
- button.setArticleId(GsonHelper.getString(json, "article_id"));
- button.setAppId(GsonHelper.getString(json, "appid"));
- button.setPagePath(GsonHelper.getString(json, "pagepath"));
+ button.setName(GsonHelper.getString(json, FIELD_NAME));
+ button.setKey(GsonHelper.getString(json, FIELD_KEY));
+ button.setUrl(GsonHelper.getString(json, FIELD_URL));
+ button.setType(GsonHelper.getString(json, FIELD_TYPE));
+ button.setMediaId(GsonHelper.getString(json, FIELD_MEDIA_ID));
+ button.setArticleId(GsonHelper.getString(json, FIELD_ARTICLE_ID));
+ button.setAppId(GsonHelper.getString(json, FIELD_APP_ID));
+ button.setPagePath(GsonHelper.getString(json, FIELD_PAGE_PATH));
return button;
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java
index 65c15fbc38..61492cbc7a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java
@@ -20,7 +20,7 @@ public WxNetCheckResult deserialize(JsonElement json, Type typeOfT, JsonDeserial
JsonArray dnssJson = json.getAsJsonObject().get("dns").getAsJsonArray();
List dnsInfoList = new ArrayList<>();
- if (dnssJson != null && dnssJson.size() > 0) {
+ if (dnssJson != null && !dnssJson.isEmpty()) {
for (int i = 0; i < dnssJson.size(); i++) {
JsonObject buttonJson = dnssJson.get(i).getAsJsonObject();
WxNetCheckResult.WxNetCheckDnsInfo dnsInfo = new WxNetCheckResult.WxNetCheckDnsInfo();
@@ -32,7 +32,7 @@ public WxNetCheckResult deserialize(JsonElement json, Type typeOfT, JsonDeserial
JsonArray pingsJson = json.getAsJsonObject().get("ping").getAsJsonArray();
List pingInfoList = new ArrayList<>();
- if (pingsJson != null && pingsJson.size() > 0) {
+ if (pingsJson != null && !pingsJson.isEmpty()) {
for (int i = 0; i < pingsJson.size(); i++) {
JsonObject pingJson = pingsJson.get(i).getAsJsonObject();
WxNetCheckResult.WxNetCheckPingInfo pingInfo = new WxNetCheckResult.WxNetCheckPingInfo();
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java
index 214b4547b0..3f5ce4d692 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java
@@ -1,16 +1,11 @@
package me.chanjar.weixin.common.util.locks;
import lombok.Getter;
-import org.springframework.data.redis.connection.RedisStringCommands;
-import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
-import org.springframework.data.redis.core.types.Expiration;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
+import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@@ -66,19 +61,20 @@ public void lockInterruptibly() throws InterruptedException {
@Override
public boolean tryLock() {
String value = valueThreadLocal.get();
- if (value == null || value.length() == 0) {
+ if (value == null || value.isEmpty()) {
value = UUID.randomUUID().toString();
valueThreadLocal.set(value);
}
- final byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
- final byte[] valueBytes = value.getBytes(StandardCharsets.UTF_8);
- List