diff --git a/.github/agents/my-agent.agent.md b/.github/agents/my-agent.agent.md
new file mode 100644
index 0000000000..dcce85fd88
--- /dev/null
+++ b/.github/agents/my-agent.agent.md
@@ -0,0 +1,13 @@
+---
+# 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
+
+请使用中文输出思考过程和总结,包括PR标题,提交commit信息也要使用中文
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- * 三种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/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
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
+ * 设置为零时不超时,一直等待. + * 设置为负数是使用系统默认设置(非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+ * 获取企业配置的「联系我」二维码和「联系我」小程序插件列表。不包含临时会话。 + * 注意,该接口仅可获取2021年7月10日以后创建的「联系我」 + *+ * + * 文档地址: 获取企业已配置的「联系我」列表 + * + * @param startTime 「联系我」创建起始时间戳, 默认为90天前 + * @param endTime 「联系我」创建结束时间戳, 默认为当前时间 + * @param cursor 分页查询使用的游标,为上次请求返回的 next_cursor + * @param limit 每次查询的分页大小,默认为100条,最多支持1000条 + * @return contact way configId + * @throws WxErrorException the wx error exception + */ + WxCpContactWayList listContactWay(Long startTime, Long endTime, String cursor, Long limit) throws WxErrorException; + /** * 更新企业已配置的「联系我」方式 * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpGroupRobotService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpGroupRobotService.java index e396ed58ac..c1a8d56255 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpGroupRobotService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpGroupRobotService.java @@ -70,6 +70,23 @@ public interface WxCpGroupRobotService { */ void sendMarkdown(String webhookUrl, String content) throws WxErrorException; + /** + * 发送markdown_v2类型的消息 + * + * @param content markdown内容,最长不超过4096个字节,必须是utf8编码 + * @throws WxErrorException 异常 + */ + void sendMarkdownV2(String content) throws WxErrorException; + + /** + * 发送markdown_v2类型的消息 + * + * @param webhookUrl webhook地址 + * @param content markdown内容,最长不超过4096个字节,必须是utf8编码 + * @throws WxErrorException 异常 + */ + void sendMarkdownV2(String webhookUrl, String content) throws WxErrorException; + /** * 发送image类型的消息 * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java new file mode 100644 index 0000000000..f68092918f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java @@ -0,0 +1,67 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.intelligentrobot.*; + +/** + * 企业微信智能机器人接口 + * 官方文档: https://developer.work.weixin.qq.com/document/path/101039 + * + * @author Binary Wang + */ +public interface WxCpIntelligentRobotService { + + /** + * 创建智能机器人 + * + * @param request 创建请求参数 + * @return 创建结果 + * @throws WxErrorException 微信接口异常 + */ + WxCpIntelligentRobotCreateResponse createRobot(WxCpIntelligentRobotCreateRequest request) throws WxErrorException; + + /** + * 删除智能机器人 + * + * @param robotId 机器人ID + * @throws WxErrorException 微信接口异常 + */ + void deleteRobot(String robotId) throws WxErrorException; + + /** + * 更新智能机器人 + * + * @param request 更新请求参数 + * @throws WxErrorException 微信接口异常 + */ + void updateRobot(WxCpIntelligentRobotUpdateRequest request) throws WxErrorException; + + /** + * 查询智能机器人 + * + * @param robotId 机器人ID + * @return 机器人信息 + * @throws WxErrorException 微信接口异常 + */ + WxCpIntelligentRobot getRobot(String robotId) throws WxErrorException; + + /** + * 智能机器人会话 + * + * @param request 聊天请求参数 + * @return 聊天响应 + * @throws WxErrorException 微信接口异常 + */ + WxCpIntelligentRobotChatResponse chat(WxCpIntelligentRobotChatRequest request) throws WxErrorException; + + /** + * 重置智能机器人会话 + * + * @param robotId 机器人ID + * @param userid 用户ID + * @param sessionId 会话ID + * @throws WxErrorException 微信接口异常 + */ + void resetSession(String robotId, String userid, String sessionId) throws WxErrorException; + +} \ No newline at end of file diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java index 86b342f2fc..5a53829dc0 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java @@ -75,6 +75,19 @@ public interface WxCpKfService { */ WxCpKfServicerOpResp addServicer(String openKfid, List
* 获取打卡数据
- * API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262
+ * 文档地址
*
*
* @param openCheckinDataType 打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡
@@ -50,7 +50,7 @@ List
* 获取打卡规则
- * API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263
+ * 文档地址
*
*
* @param datetime 需要获取规则的当天日期
@@ -64,7 +64,7 @@ List
* 获取企业所有打卡规则
- * API doc : https://work.weixin.qq.com/api/doc/90000/90135/93384
+ * 文档地址
*
*
* @return 打卡规则列表 crop checkin option
@@ -82,7 +82,7 @@ List
@@ -57,12 +68,7 @@ public WxMediaUploadResult upload(String mediaType, String filename, String url)
, this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD + mediaType),
new InputStreamData(inputStream, filename));
} finally {
- if (inputStream != null) {
- try {
- inputStream.close();
- } catch (IOException e) {
- }
- }
+ IOUtils.closeQuietly(inputStream);
if (conn != null) {
conn.disconnect();
}
@@ -119,4 +125,20 @@ public String uploadImg(File file) throws WxErrorException {
return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), url, file)
.getUrl();
}
+
+ @Override
+ public String uploadByUrl(MediaUploadByUrlReq req) throws WxErrorException {
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPLOAD_BY_URL);
+ String responseContent = this.mainService.post(url, req.toJson());
+ return GsonHelper.getString(GsonParser.parse(responseContent), "jobid");
+ }
+
+ @Override
+ public MediaUploadByUrlResult uploadByUrl(String jobId) throws WxErrorException {
+ final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_UPLOAD_BY_URL_RESULT);
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("jobid", jobId);
+ String post = this.mainService.post(url, jsonObject.toString());
+ return MediaUploadByUrlResult.fromJson(post);
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java
index 3fc9d8218f..341bc97eab 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java
@@ -11,7 +11,6 @@
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Oa.*;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java
index 5ede317fbb..cdf559ad7a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java
@@ -11,6 +11,7 @@
import me.chanjar.weixin.cp.api.WxCpMsgAuditService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.msgaudit.*;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import org.apache.commons.lang3.StringUtils;
@@ -35,20 +36,59 @@
public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService {
private final WxCpService cpService;
+ /**
+ * SDK初始化有效期,根据企微文档为7200秒
+ */
+ private static final int SDK_EXPIRES_TIME = 7200;
+
@Override
public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, String passwd,
@NonNull long timeout) throws Exception {
- String configPath = cpService.getWxCpConfigStorage().getMsgAuditLibPath();
+ // 获取或初始化SDK
+ long sdk = this.initSdk();
+
+ long slice = Finance.NewSlice();
+ long ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice);
+ if (ret != 0) {
+ Finance.FreeSlice(slice);
+ throw new WxErrorException("getchatdata err ret " + ret);
+ }
+
+ // 拉取会话存档
+ String content = Finance.GetContentFromSlice(slice);
+ Finance.FreeSlice(slice);
+ WxCpChatDatas chatDatas = WxCpChatDatas.fromJson(content);
+ if (chatDatas.getErrCode().intValue() != 0) {
+ throw new WxErrorException(chatDatas.toJson());
+ }
+
+ chatDatas.setSdk(sdk);
+ return chatDatas;
+ }
+
+ /**
+ * 获取或初始化SDK,如果SDK已过期则重新初始化
+ *
+ * @return sdk id
+ * @throws WxErrorException 初始化失败时抛出异常
+ */
+ private synchronized long initSdk() throws WxErrorException {
+ WxCpConfigStorage configStorage = cpService.getWxCpConfigStorage();
+
+ // 检查SDK是否已缓存且未过期
+ if (!configStorage.isMsgAuditSdkExpired()) {
+ long cachedSdk = configStorage.getMsgAuditSdk();
+ if (cachedSdk > 0) {
+ return cachedSdk;
+ }
+ }
+
+ // SDK未初始化或已过期,需要重新初始化
+ String configPath = configStorage.getMsgAuditLibPath();
if (StringUtils.isEmpty(configPath)) {
throw new WxErrorException("请配置会话存档sdk文件的路径,不要配错了!!");
}
- /**
- * 完整的文件库路径:
- *
- * /www/osfile/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,
- * libWeWorkFinanceSdk_Java.so
- */
// 替换斜杠
String replacePath = configPath.replace("\\", "/");
// 获取最后一个斜杠的下标,用作分割路径
@@ -66,9 +106,9 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S
List libList = Arrays.asList(libFiles);
// 判断windows系统会话存档sdk中dll的加载,因为会互相依赖所以是有顺序的,否则会导致无法加载sdk #2598
- List osLib = new LinkedList();
- List fileLib = new ArrayList();
- libList.stream().forEach(s -> {
+ List osLib = new LinkedList<>();
+ List fileLib = new ArrayList<>();
+ libList.forEach(s -> {
if (s.contains("lib")) {
osLib.add(s);
} else {
@@ -79,36 +119,22 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S
Finance.loadingLibraries(osLib, prefixPath);
long sdk = Finance.NewSdk();
- //因为会话存档单独有个secret,优先使用会话存档的secret
- String msgAuditSecret = cpService.getWxCpConfigStorage().getMsgAuditSecret();
+ // 因为会话存档单独有个secret,优先使用会话存档的secret
+ String msgAuditSecret = configStorage.getMsgAuditSecret();
if (StringUtils.isEmpty(msgAuditSecret)) {
- msgAuditSecret = cpService.getWxCpConfigStorage().getCorpSecret();
+ msgAuditSecret = configStorage.getCorpSecret();
}
- long ret = Finance.Init(sdk, cpService.getWxCpConfigStorage().getCorpId(), msgAuditSecret);
+ long ret = Finance.Init(sdk, configStorage.getCorpId(), msgAuditSecret);
if (ret != 0) {
Finance.DestroySdk(sdk);
throw new WxErrorException("init sdk err ret " + ret);
}
- long slice = Finance.NewSlice();
- ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice);
- if (ret != 0) {
- Finance.FreeSlice(slice);
- Finance.DestroySdk(sdk);
- throw new WxErrorException("getchatdata err ret " + ret);
- }
-
- // 拉取会话存档
- String content = Finance.GetContentFromSlice(slice);
- Finance.FreeSlice(slice);
- WxCpChatDatas chatDatas = WxCpChatDatas.fromJson(content);
- if (chatDatas.getErrCode().intValue() != 0) {
- Finance.DestroySdk(sdk);
- throw new WxErrorException(chatDatas.toJson());
- }
+ // 缓存SDK
+ configStorage.updateMsgAuditSdk(sdk, SDK_EXPIRES_TIME);
+ log.debug("初始化会话存档SDK成功,sdk={}", sdk);
- chatDatas.setSdk(sdk);
- return chatDatas;
+ return sdk;
}
@Override
@@ -128,36 +154,27 @@ public WxCpChatModel getDecryptData(@NonNull long sdk, @NonNull WxCpChatDatas.Wx
* @throws Exception the exception
*/
public String decryptChatData(long sdk, WxCpChatDatas.WxCpChatData chatData, Integer pkcs1) throws Exception {
- /**
- * 企业获取的会话内容,使用企业自行配置的消息加密公钥进行加密,企业可用自行保存的私钥解开会话内容数据。
- * msgAuditPriKey 会话存档私钥不能为空
- */
+ // 企业获取的会话内容,使用企业自行配置的消息加密公钥进行加密,企业可用自行保存的私钥解开会话内容数据。
+ // msgAuditPriKey 会话存档私钥不能为空
String priKey = cpService.getWxCpConfigStorage().getMsgAuditPriKey();
if (StringUtils.isEmpty(priKey)) {
throw new WxErrorException("请配置会话存档私钥【msgAuditPriKey】");
}
String decryptByPriKey = WxCpCryptUtil.decryptPriKey(chatData.getEncryptRandomKey(), priKey, pkcs1);
- /**
- * 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
- */
+ // 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
long msg = Finance.NewSlice();
- /**
- * 解密会话存档内容
- * sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。
- * 此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。
- */
+ // 解密会话存档内容
+ // sdk不会要求用户传入rsa私钥,保证用户会话存档数据只有自己能够解密。
+ // 此处需要用户先用rsa私钥解密encrypt_random_key后,作为encrypt_key参数传入sdk来解密encrypt_chat_msg获取会话存档明文。
int ret = Finance.DecryptData(sdk, decryptByPriKey, chatData.getEncryptChatMsg(), msg);
if (ret != 0) {
Finance.FreeSlice(msg);
- Finance.DestroySdk(sdk);
throw new WxErrorException("msg err ret " + ret);
}
- /**
- * 明文
- */
+ // 明文
String plainText = Finance.GetContentFromSlice(msg);
Finance.FreeSlice(msg);
return plainText;
@@ -209,7 +226,6 @@ public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String pr
ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, mediaData);
if (ret != 0) {
Finance.FreeMediaData(mediaData);
- Finance.DestroySdk(sdk);
throw new WxErrorException("getmediadata err ret " + ret);
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
index 2a64f52bc7..d04a051c0e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
@@ -13,6 +13,8 @@
import me.chanjar.weixin.cp.bean.workbench.WxCpSecondVerificationInfo;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+import java.util.Optional;
+
import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.*;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.OAuth2.*;
@@ -74,9 +76,9 @@ public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErr
JsonObject jo = GsonParser.parse(responseText);
return WxCpOauth2UserInfo.builder()
- .userId(GsonHelper.getString(jo, "UserId"))
+ .userId(Optional.ofNullable(GsonHelper.getString(jo, "UserId")).orElse(GsonHelper.getString(jo, "userid")))
.deviceId(GsonHelper.getString(jo, "DeviceId"))
- .openId(GsonHelper.getString(jo, "OpenId"))
+ .openId(Optional.ofNullable(GsonHelper.getString(jo, "OpenId")).orElse(GsonHelper.getString(jo, "openid")))
.userTicket(GsonHelper.getString(jo, "user_ticket"))
.expiresIn(GsonHelper.getString(jo, "expires_in"))
.externalUserId(GsonHelper.getString(jo, "external_userid"))
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
index 53aaa00ca7..59cde79a93 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
@@ -140,7 +140,7 @@ public WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date e
if (filters != null && !filters.isEmpty()) {
JsonArray filterJsonArray = new JsonArray();
for (WxCpApprovalInfoQueryFilter filter : filters) {
- filterJsonArray.add(new JsonParser().parse(filter.toJson()));
+ filterJsonArray.add(JsonParser.parseString(filter.toJson()));
}
jsonObject.add("filters", filterJsonArray);
}
@@ -181,7 +181,7 @@ public WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date e
if (filters != null && !filters.isEmpty()) {
JsonArray filterJsonArray = new JsonArray();
for (WxCpApprovalInfoQueryFilter filter : filters) {
- filterJsonArray.add(new JsonParser().parse(filter.toJson()));
+ filterJsonArray.add(JsonParser.parseString(filter.toJson()));
}
jsonObject.add("filters", filterJsonArray);
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java
index 597851aae4..a41195ae84 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java
@@ -39,20 +39,18 @@ public WxCpBaseResp spaceRename(@NonNull WxCpSpaceRenameRequest request) throws
}
@Override
- public WxCpBaseResp spaceDismiss(@NonNull String userId, @NonNull String spaceId) throws WxErrorException {
+ public WxCpBaseResp spaceDismiss(@NonNull String spaceId) throws WxErrorException {
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(SPACE_DISMISS);
JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("userid", userId);
jsonObject.addProperty("spaceid", spaceId);
String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
return WxCpBaseResp.fromJson(responseContent);
}
@Override
- public WxCpSpaceInfo spaceInfo(@NonNull String userId, @NonNull String spaceId) throws WxErrorException {
+ public WxCpSpaceInfo spaceInfo(@NonNull String spaceId) throws WxErrorException {
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(SPACE_INFO);
JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("userid", userId);
jsonObject.addProperty("spaceid", spaceId);
String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
return WxCpSpaceInfo.fromJson(responseContent);
@@ -80,10 +78,9 @@ public WxCpBaseResp spaceSetting(@NonNull WxCpSpaceSettingRequest request) throw
}
@Override
- public WxCpSpaceShare spaceShare(@NonNull String userId, @NonNull String spaceId) throws WxErrorException {
+ public WxCpSpaceShare spaceShare(@NonNull String spaceId) throws WxErrorException {
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(SPACE_SHARE);
JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("userid", userId);
jsonObject.addProperty("spaceid", spaceId);
String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
return WxCpSpaceShare.fromJson(responseContent);
@@ -166,11 +163,9 @@ public WxCpBaseResp fileAclDel(@NonNull WxCpFileAclDelRequest request) throws Wx
}
@Override
- public WxCpBaseResp fileSetting(@NonNull String userId, @NonNull String fileId, @NonNull Integer authScope,
- Integer auth) throws WxErrorException {
+ public WxCpBaseResp fileSetting(@NonNull String fileId, @NonNull Integer authScope, Integer auth) throws WxErrorException {
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_SETTING);
JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("userid", userId);
jsonObject.addProperty("fileid", fileId);
jsonObject.addProperty("auth_scope", authScope);
if (auth != null) {
@@ -181,10 +176,9 @@ public WxCpBaseResp fileSetting(@NonNull String userId, @NonNull String fileId,
}
@Override
- public WxCpFileShare fileShare(@NonNull String userId, @NonNull String fileId) throws WxErrorException {
+ public WxCpFileShare fileShare(@NonNull String fileId) throws WxErrorException {
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_SHARE);
JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("userid", userId);
jsonObject.addProperty("fileid", fileId);
String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
return WxCpFileShare.fromJson(responseContent);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
index fac1689e08..bdb067f923 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
@@ -16,6 +16,7 @@
import org.apache.commons.lang3.StringUtils;
import java.util.List;
+import java.util.Objects;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.School.*;
@@ -98,7 +99,7 @@ public WxCpBaseResp updateStudent(@NonNull String studentUserId, String newStude
if (StringUtils.isNotEmpty(name)) {
jsonObject.addProperty("name", name);
}
- if (departments != null && departments.size() > 0) {
+ if (departments != null && !departments.isEmpty()) {
JsonArray jsonArray = new JsonArray();
for (Integer depart : departments) {
jsonArray.add(new JsonPrimitive(depart));
@@ -246,7 +247,7 @@ public String convertToOpenId(@NonNull String externalUserId) throws WxErrorExce
@Override
public WxCpDepartmentList listDepartment(Integer id) throws WxErrorException {
- String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST) + id;
+ String apiUrl = Objects.isNull(id) ? this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST) : String.format("%s?id=%s", this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), id);
String responseContent = this.cpService.get(apiUrl, null);
return WxCpDepartmentList.fromJson(responseContent);
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
index 7e69152a17..1042f88d67 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
@@ -1,21 +1,19 @@
package me.chanjar.weixin.cp.api.impl;
-
import me.chanjar.weixin.common.bean.WxAccessToken;
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.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
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.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
@@ -40,8 +38,8 @@ public HttpHost getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.APACHE_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.APACHE_HTTP;
}
@Override
@@ -61,13 +59,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
.setProxy(this.httpProxy).build();
httpGet.setConfig(config);
}
- String resultContent;
- try (CloseableHttpClient httpClient = getRequestHttpClient();
- CloseableHttpResponse response = httpClient.execute(httpGet)) {
- resultContent = new BasicResponseHandler().handleResponse(response);
- } finally {
- httpGet.releaseConnection();
- }
+ String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
WxError error = WxError.fromJson(resultContent, WxType.CP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..92fd2dbd9b
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java
@@ -0,0 +1,99 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import me.chanjar.weixin.common.bean.WxAccessToken;
+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.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+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;
+
+/**
+ * The type Wx cp service apache http client.
+ *
+ * @author altusea
+ */
+public class WxCpServiceHttpComponentsImpl extends BaseWxCpServiceImpl {
+
+ private CloseableHttpClient httpClient;
+ private HttpHost httpProxy;
+
+ @Override
+ public CloseableHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public HttpHost getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.HTTP_COMPONENTS;
+ }
+
+ @Override
+ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) {
+ return this.configStorage.getAccessToken();
+ }
+
+ synchronized (this.globalAccessTokenRefreshLock) {
+ String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
+ this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
+
+ try {
+ HttpGet httpGet = new HttpGet(url);
+ if (this.httpProxy != null) {
+ RequestConfig config = RequestConfig.custom()
+ .setProxy(this.httpProxy).build();
+ httpGet.setConfig(config);
+ }
+ String resultContent = getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(resultContent, WxType.CP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+
+ WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
+ this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
+ } catch (IOException e) {
+ throw new WxRuntimeException(e);
+ }
+ }
+ return this.configStorage.getAccessToken();
+ }
+
+ @Override
+ public void initHttp() {
+ HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+ apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
+ .httpProxyPort(this.configStorage.getHttpProxyPort())
+ .httpProxyUsername(this.configStorage.getHttpProxyUsername())
+ .httpProxyPassword(this.configStorage.getHttpProxyPassword().toCharArray());
+
+ if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+ this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
+ }
+
+ this.httpClient = apacheHttpClientBuilder.build();
+ }
+
+ @Override
+ public WxCpConfigStorage getWxCpConfigStorage() {
+ return this.configStorage;
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
index 661a0ed79f..f2a50db471 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
@@ -6,14 +6,12 @@
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
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.BasicResponseHandler;
-import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
@@ -55,13 +53,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
RequestConfig config = RequestConfig.custom().setProxy(getRequestHttpProxy()).build();
httpGet.setConfig(config);
}
- String resultContent;
- try (CloseableHttpClient httpClient = getRequestHttpClient();
- CloseableHttpResponse response = httpClient.execute(httpGet)) {
- resultContent = new BasicResponseHandler().handleResponse(response);
- } finally {
- httpGet.releaseConnection();
- }
+ String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
WxError error = WxError.fromJson(resultContent, WxType.CP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
index ec8a3624ac..5081341851 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
@@ -9,7 +9,7 @@
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.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
@@ -33,8 +33,8 @@ public ProxyInfo getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.JODD_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.JODD_HTTP;
}
@Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
index 73b933f646..511c440e64 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
@@ -5,7 +5,7 @@
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.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
@@ -36,8 +36,8 @@ public OkHttpProxyInfo getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.OK_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.OK_HTTP;
}
@Override
@@ -86,12 +86,12 @@ public void initHttp() {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.proxy(getRequestHttpProxy().getProxy());
//设置授权
- clientBuilder.authenticator(new Authenticator() {
+ clientBuilder.proxyAuthenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
return response.request().newBuilder()
- .header("Authorization", credential)
+ .header("Proxy-Authorization", credential)
.build();
}
});
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java
index e74173ee3f..4c17397ecd 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java
@@ -6,6 +6,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.cp.bean.workbench.WorkBenchKeyData;
import me.chanjar.weixin.cp.bean.workbench.WorkBenchList;
import me.chanjar.weixin.cp.constant.WxCpConsts;
@@ -33,6 +34,10 @@ public class WxCpAgentWorkBench implements Serializable {
* 用户的userid
*/
private String userId;
+ /**
+ * 用户的userIds
+ */
+ private List useridList;
/**
* 应用id
*/
@@ -58,6 +63,15 @@ public class WxCpAgentWorkBench implements Serializable {
* 参考示例:今日要闻
*/
private Boolean enableWebviewClick;
+ /**
+ * 高度。可以有两种选择:single_row与double_row。当为single_row时,高度为106px(如果隐藏标题则为147px)。
+ * 当为double_row时,高度固定为171px(如果隐藏标题则为212px)。默认值为double_row
+ */
+ private String height;
+ /**
+ * 是否要隐藏展示了应用名称的标题部分,默认值为false。
+ */
+ private Boolean hideTitle;
private List keyDataList;
@@ -93,6 +107,20 @@ public String toUserDataString() {
return userDataObject.toString();
}
+ /**
+ * 生成批量用户数据Json字符串
+ *
+ * @return the string
+ */
+ public String toBatchUserDataString() {
+ JsonObject userDataObject = new JsonObject();
+ userDataObject.addProperty("agentid", this.agentId);
+ JsonArray useridList = WxGsonBuilder.create().toJsonTree(this.useridList).getAsJsonArray();
+ userDataObject.add("userid_list", useridList);
+ this.handleBatch(userDataObject);
+ return userDataObject.toString();
+ }
+
/**
* 处理不用类型的工作台数据
*/
@@ -140,9 +168,13 @@ private void handle(JsonObject templateObject) {
webview.addProperty("url", this.url);
webview.addProperty("jump_url", this.jumpUrl);
webview.addProperty("pagepath", this.pagePath);
- if (null != this.enableWebviewClick) {
+ if (this.enableWebviewClick != null) {
webview.addProperty("enable_webview_click", this.enableWebviewClick);
}
+ webview.addProperty("height", this.height);
+ if (this.hideTitle != null) {
+ webview.addProperty("hide_title", this.hideTitle);
+ }
templateObject.add("webview", webview);
break;
}
@@ -152,4 +184,79 @@ private void handle(JsonObject templateObject) {
}
}
+ /**
+ * 处理不用类型的工作台数据
+ */
+ private void handleBatch(JsonObject templateObject) {
+ switch (this.getType()) {
+ case WxCpConsts.WorkBenchType.KEYDATA: {
+ JsonArray keyDataArray = new JsonArray();
+ JsonObject itemsObject = new JsonObject();
+ for (WorkBenchKeyData keyDataItem : this.keyDataList) {
+ JsonObject keyDataObject = new JsonObject();
+ keyDataObject.addProperty("key", keyDataItem.getKey());
+ keyDataObject.addProperty("data", keyDataItem.getData());
+ keyDataObject.addProperty("jump_url", keyDataItem.getJumpUrl());
+ keyDataObject.addProperty("pagepath", keyDataItem.getPagePath());
+ keyDataArray.add(keyDataObject);
+ }
+ itemsObject.add("items", keyDataArray);
+ JsonObject dataObject = new JsonObject();
+ dataObject.addProperty("type", WxCpConsts.WorkBenchType.KEYDATA);
+ dataObject.add("keydata", itemsObject);
+ templateObject.add("data", dataObject);
+ break;
+ }
+ case WxCpConsts.WorkBenchType.IMAGE: {
+ JsonObject image = new JsonObject();
+ image.addProperty("url", this.url);
+ image.addProperty("jump_url", this.jumpUrl);
+ image.addProperty("pagepath", this.pagePath);
+ JsonObject dataObject = new JsonObject();
+ dataObject.addProperty("type", WxCpConsts.WorkBenchType.IMAGE);
+ dataObject.add("image", image);
+ templateObject.add("data", dataObject);
+ break;
+ }
+ case WxCpConsts.WorkBenchType.LIST: {
+ JsonArray listArray = new JsonArray();
+ JsonObject itemsObject = new JsonObject();
+ for (WorkBenchList listItem : this.lists) {
+ JsonObject listObject = new JsonObject();
+ listObject.addProperty("title", listItem.getTitle());
+ listObject.addProperty("jump_url", listItem.getJumpUrl());
+ listObject.addProperty("pagepath", listItem.getPagePath());
+ listArray.add(listObject);
+ }
+ itemsObject.add("items", listArray);
+ JsonObject dataObject = new JsonObject();
+ dataObject.addProperty("type", WxCpConsts.WorkBenchType.LIST);
+ dataObject.add("list", itemsObject);
+ templateObject.add("data", dataObject);
+ break;
+ }
+ case WxCpConsts.WorkBenchType.WEBVIEW: {
+ JsonObject webview = new JsonObject();
+ webview.addProperty("url", this.url);
+ webview.addProperty("jump_url", this.jumpUrl);
+ webview.addProperty("pagepath", this.pagePath);
+ if (this.enableWebviewClick != null) {
+ webview.addProperty("enable_webview_click", this.enableWebviewClick);
+ }
+ webview.addProperty("height", this.height);
+ if (this.hideTitle != null) {
+ webview.addProperty("hide_title", this.hideTitle);
+ }
+ JsonObject dataObject = new JsonObject();
+ dataObject.addProperty("type", WxCpConsts.WorkBenchType.WEBVIEW);
+ dataObject.add("webview", webview);
+ templateObject.add("data", dataObject);
+ break;
+ }
+ default: {
+ //do nothing
+ }
+ }
+ }
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java
index 1f02307f87..810b437e38 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java
@@ -2,7 +2,6 @@
import com.google.gson.annotations.SerializedName;
import lombok.Data;
-import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import java.io.Serializable;
import java.util.List;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java
index 3a6a61902c..5da6a8fd5a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java
@@ -152,6 +152,13 @@ public static class ContactWay implements Serializable {
@SerializedName("unionid")
private String unionId;
+
+ /**
+ *非必填,是否开启同一外部企业客户只能添加同一个员工,默认为否,开启后,同一个企业的客户会优先添加到同一个跟进人
+ */
+ @SerializedName("is_exclusive")
+ private boolean isExclusive;
+
/**
*
* 非必填
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java
new file mode 100644
index 0000000000..aeaeeea439
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java
@@ -0,0 +1,69 @@
+package me.chanjar.weixin.cp.bean.external;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 「联系我」方式 列表返回对象
+ *
+ * @author imyzt
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@NoArgsConstructor
+public class WxCpContactWayList extends WxCpBaseResp implements Serializable {
+ private static final long serialVersionUID = -8697184659526210472L;
+
+ @SerializedName("contact_way")
+ private List contactWay;
+
+ /**
+ * 分页参数,用于查询下一个分页的数据,为空时表示没有更多的分页
+ */
+ @SerializedName("next_cursor")
+ private String nextCursor;
+
+ /**
+ * The type Contact way.
+ */
+ @Getter
+ @Setter
+ public static class ContactWay implements Serializable {
+ private static final long serialVersionUID = -8697184659526210472L;
+
+ /**
+ * 联系方式的配置id
+ */
+ @SerializedName("config_id")
+ private String configId;
+ }
+
+ /**
+ * From json wx cp contact way list.
+ *
+ * @param json the json
+ * @return the wx cp contact way list
+ */
+ public static WxCpContactWayList fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayList.class);
+ }
+
+ /**
+ * To json string.
+ *
+ * @return the string
+ */
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java
index 0e6d75bf0c..20d6b32442 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java
@@ -4,7 +4,6 @@
import lombok.Data;
import lombok.EqualsAndHashCode;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
-import me.chanjar.weixin.cp.bean.external.acquisition.WxCpCustomerAcquisitionInfo;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.io.Serializable;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java
index 79cb9a6932..6826413e13 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java
@@ -2,10 +2,7 @@
import com.google.gson.annotations.SerializedName;
import lombok.*;
-import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
-import me.chanjar.weixin.cp.bean.external.acquisition.WxCpCustomerAcquisitionInfo;
-import me.chanjar.weixin.cp.bean.external.acquisition.WxCpCustomerAcquisitionList;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.io.Serializable;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobot.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobot.java
new file mode 100644
index 0000000000..60d518cac3
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobot.java
@@ -0,0 +1,77 @@
+package me.chanjar.weixin.cp.bean.intelligentrobot;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 智能机器人信息
+ *
+ * @author Binary Wang
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxCpIntelligentRobot extends WxCpBaseResp implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 机器人ID
+ */
+ @SerializedName("robot_id")
+ private String robotId;
+
+ /**
+ * 机器人名称
+ */
+ @SerializedName("name")
+ private String name;
+
+ /**
+ * 机器人描述
+ */
+ @SerializedName("description")
+ private String description;
+
+ /**
+ * 机器人头像
+ */
+ @SerializedName("avatar")
+ private String avatar;
+
+ /**
+ * 机器人状态 0:停用 1:启用
+ */
+ @SerializedName("status")
+ private Integer status;
+
+ /**
+ * 创建时间
+ */
+ @SerializedName("create_time")
+ private Long createTime;
+
+ /**
+ * 更新时间
+ */
+ @SerializedName("update_time")
+ private Long updateTime;
+
+ /**
+ * From json wx cp intelligent robot.
+ *
+ * @param json the json
+ * @return the wx cp intelligent robot
+ */
+ public static WxCpIntelligentRobot fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobot.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotChatRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotChatRequest.java
new file mode 100644
index 0000000000..d94ea93623
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotChatRequest.java
@@ -0,0 +1,49 @@
+package me.chanjar.weixin.cp.bean.intelligentrobot;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 智能机器人聊天请求
+ *
+ * @author Binary Wang
+ */
+@Data
+public class WxCpIntelligentRobotChatRequest implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 机器人ID
+ */
+ @SerializedName("robot_id")
+ private String robotId;
+
+ /**
+ * 用户ID
+ */
+ @SerializedName("userid")
+ private String userid;
+
+ /**
+ * 消息内容
+ */
+ @SerializedName("message")
+ private String message;
+
+ /**
+ * 会话ID,可选,用于保持会话连续性
+ */
+ @SerializedName("session_id")
+ private String sessionId;
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ public static WxCpIntelligentRobotChatRequest fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobotChatRequest.class);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotChatResponse.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotChatResponse.java
new file mode 100644
index 0000000000..c7e56a4d03
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotChatResponse.java
@@ -0,0 +1,46 @@
+package me.chanjar.weixin.cp.bean.intelligentrobot;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 智能机器人聊天响应
+ *
+ * @author Binary Wang
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxCpIntelligentRobotChatResponse extends WxCpBaseResp implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 机器人回复内容
+ */
+ @SerializedName("reply")
+ private String reply;
+
+ /**
+ * 会话ID
+ */
+ @SerializedName("session_id")
+ private String sessionId;
+
+ /**
+ * 消息ID
+ */
+ @SerializedName("msg_id")
+ private String msgId;
+
+ public static WxCpIntelligentRobotChatResponse fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobotChatResponse.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotCreateRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotCreateRequest.java
new file mode 100644
index 0000000000..46dd5f609b
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotCreateRequest.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.cp.bean.intelligentrobot;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 创建智能机器人请求
+ *
+ * @author Binary Wang
+ */
+@Data
+public class WxCpIntelligentRobotCreateRequest implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 机器人名称
+ */
+ @SerializedName("name")
+ private String name;
+
+ /**
+ * 机器人描述
+ */
+ @SerializedName("description")
+ private String description;
+
+ /**
+ * 机器人头像
+ */
+ @SerializedName("avatar")
+ private String avatar;
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ public static WxCpIntelligentRobotCreateRequest fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobotCreateRequest.class);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotCreateResponse.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotCreateResponse.java
new file mode 100644
index 0000000000..449d91f7d3
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotCreateResponse.java
@@ -0,0 +1,34 @@
+package me.chanjar.weixin.cp.bean.intelligentrobot;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 创建智能机器人响应
+ *
+ * @author Binary Wang
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxCpIntelligentRobotCreateResponse extends WxCpBaseResp implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 机器人ID
+ */
+ @SerializedName("robot_id")
+ private String robotId;
+
+ public static WxCpIntelligentRobotCreateResponse fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobotCreateResponse.class);
+ }
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotUpdateRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotUpdateRequest.java
new file mode 100644
index 0000000000..027812a7e9
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotUpdateRequest.java
@@ -0,0 +1,55 @@
+package me.chanjar.weixin.cp.bean.intelligentrobot;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 更新智能机器人请求
+ *
+ * @author Binary Wang
+ */
+@Data
+public class WxCpIntelligentRobotUpdateRequest implements Serializable {
+ private static final long serialVersionUID = -1L;
+
+ /**
+ * 机器人ID
+ */
+ @SerializedName("robot_id")
+ private String robotId;
+
+ /**
+ * 机器人名称
+ */
+ @SerializedName("name")
+ private String name;
+
+ /**
+ * 机器人描述
+ */
+ @SerializedName("description")
+ private String description;
+
+ /**
+ * 机器人头像
+ */
+ @SerializedName("avatar")
+ private String avatar;
+
+ /**
+ * 机器人状态 0:停用 1:启用
+ */
+ @SerializedName("status")
+ private Integer status;
+
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ public static WxCpIntelligentRobotUpdateRequest fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobotUpdateRequest.class);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlReq.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlReq.java
new file mode 100644
index 0000000000..c5cb21bde5
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlReq.java
@@ -0,0 +1,58 @@
+package me.chanjar.weixin.cp.bean.media;
+
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 生成异步上传任务
+ * @author imyzt
+ * @date 2025/04/27
+ */
+@Data
+public class MediaUploadByUrlReq {
+
+ /**
+ * 场景值。1-客户联系入群欢迎语素材(目前仅支持1)。 注意:每个场景值有对应的使用范围,详见上面的「使用场景说明」
+ */
+ private Integer scene;
+
+ /**
+ * 媒体文件类型。目前仅支持video-视频,file-普通文件 不超过32字节。
+ */
+ private String type;
+
+ /**
+ * 文件名,标识文件展示的名称。比如,使用该media_id发消息时,展示的文件名由该字段控制。 不超过128字节。
+ */
+ private String filename;
+
+ /**
+ * 文件cdn url。url要求支持Range分块下载 不超过1024字节。 如果为腾讯云cos链接,则需要设置为「公有读」权限。
+ */
+ private String url;
+
+ /**
+ * 文件md5。对比从url下载下来的文件md5是否一致。 不超过32字节。
+ */
+ private String md5;
+
+ /**
+ * From json wx cp base resp.
+ *
+ * @param json the json
+ * @return the wx cp base resp
+ */
+ public static MediaUploadByUrlReq fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, MediaUploadByUrlReq.class);
+ }
+
+ /**
+ * To json string.
+ *
+ * @return the string
+ */
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlResult.java
new file mode 100644
index 0000000000..cc931eed39
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlResult.java
@@ -0,0 +1,82 @@
+package me.chanjar.weixin.cp.bean.media;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 异步上传企微素材
+ * @author imyzt
+ * @date 2025/4/27
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class MediaUploadByUrlResult extends WxCpBaseResp implements Serializable {
+
+ private static final long serialVersionUID = 330834334738622341L;
+
+ /**
+ * 任务状态。1-处理中,2-完成,3-异常失败
+ */
+ @SerializedName("status")
+ private Integer status;
+
+ @SerializedName("detail")
+ private Detail detail;
+
+ @Data
+ public static class Detail {
+
+ /**
+ * 任务失败返回码。当status为3时返回非0,其他返回0
+ * 830001 url非法 确认url是否支持Range分块下载
+ * 830003 url下载数据失败 确认url本身是否能正常访问
+ * 45001 文件大小超过限制 确认文件在5字节~200M范围内
+ * 301019 文件MD5不匹配 确认url对应的文件内容md5,跟所填的md5参数是否一致
+ * 注意: status=2时,此处微信并未返回任何值
+ */
+ @SerializedName("errcode")
+ private Integer errCode;
+
+ /**
+ * 注意: status=2时,此处微信并未返回任何值
+ */
+ @SerializedName("errmsg")
+ private String errMsg;
+
+ /**
+ * 媒体文件上传后获取的唯一标识,3天内有效。当status为2时返回。
+ */
+ @SerializedName("media_id")
+ private String mediaId;
+
+ /**
+ * 媒体文件创建的时间戳。当status为2时返回。
+ */
+ @SerializedName("created_at")
+ private String createdAt;
+ }
+
+ /**
+ * From json wx cp media upload by url result.
+ *
+ * @param json the json
+ * @return the wx cp media upload by url result
+ */
+ public static MediaUploadByUrlResult fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, MediaUploadByUrlResult.class);
+ }
+
+ /**
+ * To json string.
+ *
+ * @return the string
+ */
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java
index 6c889b6cec..97beeec189 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java
@@ -14,7 +14,6 @@
import java.util.List;
import static me.chanjar.weixin.cp.constant.WxCpConsts.GroupRobotMsgType.*;
-import static me.chanjar.weixin.cp.constant.WxCpConsts.GroupRobotMsgType.TEMPLATE_CARD;
/**
* 微信群机器人消息
@@ -253,6 +252,12 @@ public String toJson() {
messageJson.add("markdown", text);
break;
}
+ case MARKDOWN_V2: {
+ JsonObject text = new JsonObject();
+ text.addProperty("content", this.getContent());
+ messageJson.add("markdown_v2", text);
+ break;
+ }
case IMAGE: {
JsonObject text = new JsonObject();
text.addProperty("base64", this.getBase64());
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java
index 2ddf95d8da..0883651ae6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java
@@ -50,6 +50,9 @@ public static WxCpMessageSendResult fromJson(String json) {
@SerializedName("invalidtag")
private String invalidTag;
+ @SerializedName("unlicenseduser")
+ private String unlicensedUser;
+
@SerializedName("msgid")
private String msgId;
@@ -93,4 +96,13 @@ public List getInvalidPartyList() {
public List getInvalidTagList() {
return this.content2List(this.invalidTag);
}
+
+ /**
+ * Gets unlicensed user list.
+ *
+ * @return the unlicensed user list
+ */
+ public List getUnlicensedUserList() {
+ return this.content2List(this.unlicensedUser);
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
index 8b6b0689a7..122bc26272 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
@@ -403,7 +403,7 @@ public class WxCpTpXmlMessage implements Serializable {
* The Agent id.
*/
@XStreamAlias("AgentID")
- protected String agentID;
+ protected Integer agentID;
/**
* The Pic url.
@@ -793,4 +793,6 @@ public static WxCpTpXmlMessage fromEncryptedXml(String encryptedXml, WxCpTpConfi
log.debug("解密后的原始xml消息内容:{}", plainText);
return fromXml(plainText);
}
+
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
index 7193c7cf6f..798a5c8b00 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
@@ -118,7 +118,7 @@ public static class NotifyNode implements Serializable {
/**
* 抄送人userid
*/
- @XStreamAlias("ItemUserid")
+ @XStreamAlias("ItemUserId")
@XStreamConverter(value = XStreamCDataConverter.class)
private String itemUserId;
@@ -190,7 +190,7 @@ public static class Item implements Serializable {
/**
* 分支审批人userid
*/
- @XStreamAlias("ItemUserid")
+ @XStreamAlias("ItemUserId")
@XStreamConverter(value = XStreamCDataConverter.class)
private String itemUserId;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
index fb4213f504..c5e55220e5 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
@@ -92,7 +92,7 @@ public class WxCpXmlMessage implements Serializable {
private String content;
@XStreamAlias("MsgId")
- private Long msgId;
+ private String msgId;
@XStreamAlias("PicUrl")
@XStreamConverter(value = XStreamCDataConverter.class)
@@ -155,6 +155,18 @@ public class WxCpXmlMessage implements Serializable {
@XStreamConverter(value = XStreamCDataConverter.class)
private String memChangeCnt;
+ @XStreamAlias("MemChangeList")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ private String MemChangeList;
+
+ @XStreamAlias("LastMemVer")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ private String lastMemVer;
+
+ @XStreamAlias("CurMemVer")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ private String curMemVer;
+
@XStreamAlias("Source")
@XStreamConverter(value = XStreamCDataConverter.class)
private String source;
@@ -198,6 +210,13 @@ public class WxCpXmlMessage implements Serializable {
@XStreamAlias("SelectedItems")
private List selectedItems;
+ /**
+ * 异步任务id
+ */
+ @XStreamAlias("JobId")
+ @XStreamConverter(value = XStreamCDataConverter.class)
+ private String jobId;
+
/**
* 微信客服
* 调用拉取消息接口时,需要传此token,用于校验请求的合法性
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java
index fcbc578a59..e7c2267018 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java
@@ -6,10 +6,8 @@
/**
* The type Base builder.
- *
- * @param the type parameter
*/
-public class BaseBuilder {
+public abstract class BaseBuilder {
/**
* The Msg type.
*/
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
index d843cad6cf..21a29abf8f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
@@ -25,9 +25,6 @@ public class WxCpChatModel implements Serializable {
@SerializedName("action")
private String action;
- @SerializedName("send")
- private String send;
-
@SerializedName("from")
private String from;
@@ -205,6 +202,12 @@ public class WxCpChatModel implements Serializable {
@SerializedName("sphfeed")
private SphFeed sphFeed;
+ /**
+ * 音视频通话消息
+ */
+ @SerializedName("voiptext")
+ private VoipText voipText;
+
/**
* From json wx cp chat model.
*
@@ -606,7 +609,7 @@ public static class File implements Serializable {
private String sdkFileId;
@SerializedName("filesize")
- private Integer fileSize;
+ private Long fileSize;
/**
* From json file.
@@ -1336,4 +1339,40 @@ public String toJson() {
}
+ /**
+ * 音视频通话消息
+ */
+ @Getter
+ @Setter
+ public static class VoipText implements Serializable {
+ private static final long serialVersionUID = -5028321625140879571L;
+
+ @SerializedName("callduration")
+ private Integer callDuration;
+
+ @SerializedName("invitetype")
+ private Integer inviteType;
+
+ /**
+ * From json voip text.
+ *
+ * @param json the json
+ * @return the voip text
+ */
+ public static VoipText fromJson(String json) {
+ return WxCpGsonBuilder.create().fromJson(json, VoipText.class);
+ }
+
+ /**
+ * To json string.
+ *
+ * @return the string
+ */
+ public String toJson() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ }
+
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java
index 1a8d47c82e..c06a6d79e2 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java
@@ -24,7 +24,7 @@ public class WxCpCheckinDayData implements Serializable {
* The type Base info.
*/
@Data
- public class BaseInfo implements Serializable {
+ public static class BaseInfo implements Serializable {
private static final long serialVersionUID = 3679745559788648438L;
@@ -143,7 +143,7 @@ public class CheckinTime implements Serializable {
* The type Summary info.
*/
@Data
- public class SummaryInfo implements Serializable {
+ public static class SummaryInfo implements Serializable {
private static final long serialVersionUID = 3428576099259666595L;
/**
* checkin_count 当日打卡次数
@@ -186,7 +186,7 @@ public class SummaryInfo implements Serializable {
* The type Holiday infos.
*/
@Data
- public class HolidayInfos implements Serializable {
+ public static class HolidayInfos implements Serializable {
private static final long serialVersionUID = -6671577072585561527L;
/**
* sp_number 假勤相关信息
@@ -282,7 +282,7 @@ public class Data implements Serializable {
* The type Exception infos.
*/
@Data
- public class ExceptionInfos implements Serializable {
+ public static class ExceptionInfos implements Serializable {
private static final long serialVersionUID = -5987438373762518299L;
/**
* exception 校准状态类型:1-迟到;2-早退;3-缺卡;4-旷工;5-地点异常;6-设备异常
@@ -313,7 +313,7 @@ public class ExceptionInfos implements Serializable {
* The type Ot info.
*/
@Data
- public class OtInfo implements Serializable {
+ public static class OtInfo implements Serializable {
private static final long serialVersionUID = -6557759801572150175L;
/**
* ot_status 状态:0-无加班;1-正常;2-缺时长
@@ -344,7 +344,7 @@ public class OtInfo implements Serializable {
* The type Sp item.
*/
@Data
- public class SpItem implements Serializable {
+ public static class SpItem implements Serializable {
private static final long serialVersionUID = 2423158264958352024L;
/**
* type 类型:1-请假;2-补卡;3-出差;4-外出;100-外勤
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java
index f1c1a8580d..3bc542ccd0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java
@@ -151,6 +151,30 @@ public static class CheckinDate implements Serializable {
*/
@SerializedName("flex_off_duty_time")
private Integer flexOffDutyTime;
+
+ /**
+ * 是否允许弹性时间
+ */
+ @SerializedName("allow_flex")
+ private Boolean allowFlex;
+
+ /**
+ * 迟到规则
+ */
+ @SerializedName("late_rule")
+ private LateRule lateRule;
+
+ /**
+ * 最早可打卡时间限制
+ */
+ @SerializedName("max_allow_arrive_early")
+ private Integer maxAllowArriveEarly;
+
+ /**
+ * 最晚可打卡时间限制
+ */
+ @SerializedName("max_allow_arrive_late")
+ private Integer maxAllowArriveLate;
}
/**
@@ -160,6 +184,13 @@ public static class CheckinDate implements Serializable {
public static class CheckinTime implements Serializable {
private static final long serialVersionUID = -5507709858609705279L;
+
+ /**
+ * 时段id,为班次中某一堆上下班时间组合的id
+ */
+ @SerializedName("time_id")
+ private Integer timeId;
+
/**
* 上班时间,表示为距离当天0点的秒数。
*/
@@ -183,6 +214,60 @@ public static class CheckinTime implements Serializable {
*/
@SerializedName("remind_off_work_sec")
private Integer remindOffWorkSec;
+
+ /**
+ * 休息开始时间,仅单时段支持,距离0点的秒
+ */
+ @SerializedName("rest_begin_time")
+ private Integer restBeginTime;
+
+ /**
+ * 休息结束时间,仅单时段支持,距离0点的秒
+ */
+ @SerializedName("rest_end_time")
+ private Integer restEndTime;
+
+ /**
+ * 是否允许休息
+ */
+ @SerializedName("allow_rest")
+ private Boolean allowRest;
+
+ /**
+ * 最早可打卡时间,距离0点的秒数
+ */
+ @SerializedName("earliest_work_sec")
+ private Integer earliestWorkSec;
+
+ /**
+ * 最晚可打卡时间,距离0点的秒数
+ */
+ @SerializedName("latest_work_sec")
+ private Integer latestWorkSec;
+
+ /**
+ * 最早可下班打卡时间,距离0点的秒数
+ */
+ @SerializedName("earliest_off_work_sec")
+ private Integer earliestOffWorkSec;
+
+ /**
+ * 最晚可下班打卡时间,距离0点的秒数
+ */
+ @SerializedName("latest_off_work_sec")
+ private Integer latestOffWorkSec;
+
+ /**
+ * 上班无需打卡
+ */
+ @SerializedName("no_need_checkon")
+ private Boolean noNeedCheckon;
+
+ /**
+ * 下班无需打卡
+ */
+ @SerializedName("no_need_checkoff")
+ private Boolean noNeedCheckoff;
}
/**
@@ -438,6 +523,17 @@ public static class LateRule implements Serializable {
private static final long serialVersionUID = 5604969713950037053L;
+ /**
+ * 晚走的时间 距离最晚一个下班的时间单位:秒
+ */
+ @SerializedName("offwork_after_time")
+ private Integer offWorkAfterTime;
+
+ /**
+ * 第二天第一个班次允许迟到的弹性时间单位:秒
+ */
+ @SerializedName("onwork_flex_time")
+ private Integer onWorkFlexTime;
/**
* 是否允许超时下班(下班晚走次日晚到)允许时onwork_flex_time,offwork_after_time才有意义
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java
index af310439fc..1e8797cf7e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java
@@ -49,7 +49,7 @@ public class WxCpCheckinSchedule implements Serializable {
* The type User schedule.
*/
@Data
- public class UserSchedule implements Serializable {
+ public static class UserSchedule implements Serializable {
private static final long serialVersionUID = 9138985222324576857L;
/**
* scheduleList 个人排班表信息
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java
index bda77447fe..8cdccd9953 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java
@@ -53,6 +53,12 @@ public class WxCpCropCheckinOption extends WxCpCheckinGroupBase implements Seria
@SerializedName("ot_info")
private OtInfo otInfo;
+ /**
+ * 加班信息V2,新版API返回的加班信息结构
+ */
+ @SerializedName("ot_info_v2")
+ private OtInfoV2 otInfoV2;
+
/**
* 每月最多补卡次数,默认-1表示不限制
*/
@@ -418,4 +424,94 @@ public static class OtApplyInfo implements Serializable {
private Integer otNonworkingDaySpanDayTime;
}
+
+ /**
+ * 加班信息V2,新版API返回的加班信息结构
+ */
+ @Data
+ public static class OtInfoV2 implements Serializable {
+
+ private static final long serialVersionUID = 1610150484871066200L;
+
+ /**
+ * 工作日加班配置
+ */
+ @SerializedName("workdayconf")
+ private WorkdayConf workdayConf;
+
+ /**
+ * 非工作日加班配置
+ */
+ @SerializedName("restdayconf")
+ private RestdayConf restdayConf;
+
+ /**
+ * 节假日加班配置
+ */
+ @SerializedName("holidayconf")
+ private HolidayConf holidayConf;
+
+ /**
+ * 工作日加班配置
+ */
+ @Data
+ public static class WorkdayConf implements Serializable {
+ private static final long serialVersionUID = 1610150484871066201L;
+
+ /**
+ * 是否允许工作日加班,true为允许,false为不允许
+ */
+ @SerializedName("allow_ot")
+ private Boolean allowOt;
+
+ /**
+ * 加班类型
+ * 0:以加班申请核算打卡记录(根据打卡记录和加班申请核算),
+ * 1:以打卡时间为准(根据打卡时间计算),
+ * 2: 以加班申请审批为准(只根据加班申请计算)
+ */
+ @SerializedName("type")
+ private Integer type;
+ }
+
+ /**
+ * 非工作日加班配置
+ */
+ @Data
+ public static class RestdayConf implements Serializable {
+ private static final long serialVersionUID = 1610150484871066202L;
+
+ /**
+ * 是否允许非工作日加班,true为允许,false为不允许
+ */
+ @SerializedName("allow_ot")
+ private Boolean allowOt;
+
+ /**
+ * 加班类型
+ */
+ @SerializedName("type")
+ private Integer type;
+ }
+
+ /**
+ * 节假日加班配置
+ */
+ @Data
+ public static class HolidayConf implements Serializable {
+ private static final long serialVersionUID = 1610150484871066203L;
+
+ /**
+ * 是否允许节假日加班,true为允许,false为不允许
+ */
+ @SerializedName("allow_ot")
+ private Boolean allowOt;
+
+ /**
+ * 加班类型
+ */
+ @SerializedName("type")
+ private Integer type;
+ }
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequest.java
index 8aebb66003..30ae6497f8 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequest.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequest.java
@@ -44,7 +44,13 @@ public class WxCpOaApplyEventRequest implements Serializable {
private Integer chooseDepartment;
/**
- * 审批流程信息,用于指定审批申请的审批流程,支持单人审批、多人会签、多人或签,可能有多个审批节点,仅use_template_approver为0时生效。
+ * 审批流程信息(新版流程列表),用于指定审批申请的审批流程,支持单人审批、多人会签、多人或签,可能有多个审批节点,仅use_template_approver为0时生效。
+ */
+ @SerializedName("process")
+ private Process process;
+
+ /**
+ * 审批流程信息(旧版),用于指定审批申请的审批流程,支持单人审批、多人会签、多人或签,可能有多个审批节点,仅use_template_approver为0时生效。
*/
@SerializedName("approver")
private List approvers;
@@ -118,4 +124,46 @@ public static class ApplyData implements Serializable {
private List contents;
}
+ /**
+ * 审批流程信息(新版).
+ */
+ @Data
+ @Accessors(chain = true)
+ public static class Process implements Serializable {
+ private static final long serialVersionUID = 4758206091546930988L;
+
+ /**
+ * 审批流程节点列表,当use_template_approver为0时必填
+ */
+ @SerializedName("node_list")
+ private List nodeList;
+ }
+
+ /**
+ * 审批流程节点.
+ */
+ @Data
+ @Accessors(chain = true)
+ public static class ProcessNode implements Serializable {
+ private static final long serialVersionUID = 1758206091546930988L;
+
+ /**
+ * 节点类型:1-审批人,2-抄送人,3-抄送人
+ */
+ @SerializedName("type")
+ private Integer type;
+
+ /**
+ * 多人审批方式:1-全签,2-或签,3-依次审批
+ */
+ @SerializedName("apv_rel")
+ private Integer apvRel;
+
+ /**
+ * 审批节点审批人userid列表,若为多人会签、多人或签,需填写每个人的userid
+ */
+ @SerializedName("userid")
+ private String[] userIds;
+ }
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java
index 2a497d15fc..b926539008 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java
@@ -6,6 +6,7 @@
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
+import me.chanjar.weixin.cp.bean.oa.templatedata.TemplateTips;
import me.chanjar.weixin.cp.bean.oa.templatedata.TemplateTitle;
import me.chanjar.weixin.cp.bean.oa.templatedata.control.*;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
@@ -16,7 +17,7 @@
/**
* 审批模板详情
*
- * @author gyv12345 @163.com / Wang_Wong
+ * @author gyv12345@163.com / Wang_Wong
*/
@Data
@Builder
@@ -94,6 +95,9 @@ public static class TemplateConfig implements Serializable {
@SerializedName("vacation_list")
private TemplateVacation vacationList;
+ @SerializedName("tips")
+ private TemplateTips tips;
+
}
@Data
@@ -117,7 +121,7 @@ public static class TemplateOption implements Serializable {
/**
* 获取审批模板详情,value为list类型
- * https://developer.work.weixin.qq.com/document/path/91982
+ * 文档链接
*/
@SerializedName("value")
private List value;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java
index 158206867e..92ec8a43e8 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java
@@ -34,6 +34,9 @@ public class ContentValue implements Serializable {
private List departments;
+ @SerializedName("new_tips")
+ private NewTips newTips;
+
private List files;
private List children;
@@ -114,6 +117,68 @@ public static class Department implements Serializable {
private String name;
}
+ /**
+ * The type Tips.
+ */
+ @Data
+ public static class NewTips implements Serializable {
+ private static final long serialVersionUID = 1094978100200056100L;
+ @SerializedName("tips_content")
+ private List tipsContent;
+
+ /**
+ * The type tips_content.
+ */
+ @Data
+ public static class TipsContent implements Serializable {
+ private static final long serialVersionUID = 559432801311084797L;
+ @SerializedName("text")
+ private Text text;
+ private String lang;
+
+ /**
+ * The type sub_text.
+ */
+ @Data
+ public static class Text implements Serializable {
+ private static final long serialVersionUID = -70174360931158924L;
+ @SerializedName("sub_text")
+ private List subText;
+ }
+
+ /**
+ * The type sub_text.
+ */
+ @Data
+ public static class SubText implements Serializable {
+ private static final long serialVersionUID = -8226911175438019317L;
+ private Integer type;
+ private Content content;
+
+ @Data
+ public static class Content implements Serializable {
+ private static final long serialVersionUID = -6813250009451940525L;
+ @SerializedName("plain_text")
+ private PlainText plainText;
+ private Link link;
+
+ @Data
+ public static class PlainText implements Serializable {
+ private static final long serialVersionUID = -599377674188314118L;
+ private String content;
+ }
+
+ @Data
+ public static class Link implements Serializable {
+ private static final long serialVersionUID = 2784173996170990308L;
+ private String title;
+ private String url;
+ }
+ }
+ }
+ }
+ }
+
/**
* The type File.
*/
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java
index 0efbc5a772..0ad79538e4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java
@@ -65,6 +65,35 @@ public class WxCpMeeting implements Serializable, ToJson {
@SerializedName("agentid")
private Integer agentId;
+ /**
+ * 发起人所在部门
+ */
+ @SerializedName("main_department")
+ private Integer mainDepartment;
+
+ /**
+ * 会议的状态。
+ * 1:待开始
+ * 2:会议中
+ * 3:已结束
+ * 4:已取消
+ * 5:已过期
+ */
+ @SerializedName("status")
+ public Integer status;
+
+ /**
+ * 会议类型。
+ * 0:一次性会议
+ * 1:周期性会议
+ * 2:微信专属会议
+ * 3:Rooms 投屏会议
+ * 5:个人会议号会议
+ * 6:网络研讨会
+ */
+ @SerializedName("meeting_type")
+ private Integer meetingType;
+
/**
* 参与会议的成员。会议人数上限,以指定的「管理员」可预约的人数上限来校验,普通企业与会人员最多100;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java
index dfd200f2a8..21b8e88817 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java
@@ -1,15 +1,11 @@
package me.chanjar.weixin.cp.bean.oa.meeting;
-import com.google.common.base.Splitter;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
/**
* 为标签添加或移除用户结果对象类.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java
index 1a00baad0f..91ee8b7cde 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java
@@ -37,4 +37,6 @@ public class TemplateConfig implements Serializable {
@SerializedName("vacation_list")
private TemplateVacation vacationList;
+ private TemplateTips tips;
+
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java
index 32ada7b338..8b1605a5a1 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java
@@ -3,6 +3,7 @@
import lombok.Data;
import java.io.Serializable;
+import java.util.List;
/**
* The type Template options.
@@ -17,11 +18,8 @@ public class TemplateOptions implements Serializable {
private String key;
/**
- * 创建审批模板,value为对象类型
- * https://developer.work.weixin.qq.com/document/path/97437#%E9%99%845-%E5%8D%95%E9%80%89%E5%A4%9A%E9%80%89%E6%8E%A7%E4%BB%B6%EF%BC%88control%E5%8F%82%E6%95%B0%E4%B8%BAselector%EF%BC%89
- *
- * 获取审批模板详情,value为list类型
- * https://developer.work.weixin.qq.com/document/path/91982
+ * 创建审批模板,value为对象类型
+ * 获取审批模板详情,value为list类型
**/
- private TemplateTitle value;
+ private List value;
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTips.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTips.java
new file mode 100644
index 0000000000..58daeb007c
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTips.java
@@ -0,0 +1,18 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:40
+ */
+@Data
+public class TemplateTips {
+
+ @SerializedName("tips_content")
+ private List tipsContent;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsContent.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsContent.java
new file mode 100644
index 0000000000..939e6819a0
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsContent.java
@@ -0,0 +1,15 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:42
+ */
+@Data
+public class TemplateTipsContent {
+
+ private TemplateTipsText text;
+ private String lang;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubText.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubText.java
new file mode 100644
index 0000000000..ac4681038c
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubText.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:45
+ */
+@Data
+public class TemplateTipsSubText {
+ private Integer type;
+ private TemplateTipsSubTextContent content;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContent.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContent.java
new file mode 100644
index 0000000000..9c99b2688e
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContent.java
@@ -0,0 +1,16 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:46
+ */
+@Data
+public class TemplateTipsSubTextContent {
+ @SerializedName("plain_text")
+ private TemplateTipsSubTextContentPlainText plainText;
+ private TemplateTipsSubTextContentLink link;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentLink.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentLink.java
new file mode 100644
index 0000000000..4cd198409a
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentLink.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:49
+ */
+@Data
+public class TemplateTipsSubTextContentLink {
+ private String title;
+ private String url;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentPlainText.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentPlainText.java
new file mode 100644
index 0000000000..12969cdcdb
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentPlainText.java
@@ -0,0 +1,13 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @date 2025/1/16 09:47
+ * @version 1.0
+ */
+@Data
+public class TemplateTipsSubTextContentPlainText {
+ private String content;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsText.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsText.java
new file mode 100644
index 0000000000..100c5bb137
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsText.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author mrsiu@msn.com
+ * @date 2025/1/16 09:43
+ * @version 1.0
+ */
+@Data
+public class TemplateTipsText {
+ @SerializedName("sub_text")
+ private List subText;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java
index c9f15e6d74..1a078bea46 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java
@@ -59,7 +59,7 @@ public JsonObject toJson() {
}
// select_list
List options = this.getOptions();
- if (null != options && options.size() > 0) {
+ if (null != options && !options.isEmpty()) {
JsonArray optionJsonArray = new JsonArray();
for (CheckboxOption option : this.getOptions()) {
JsonObject tempObject = option.toJson();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java
index f279eb2274..b74346a938 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java
@@ -44,7 +44,7 @@ public JsonObject toJson() {
btnObject.addProperty("selected_id", this.selectedId);
}
- if (this.optionList != null && this.optionList.size() > 0) {
+ if (this.optionList != null && !this.optionList.isEmpty()) {
JsonArray optionJsonArray = new JsonArray();
for (TemplateCardButtonSelectionOption jump : this.getOptionList()) {
JsonObject tempObject = jump.toJson();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
index 36203aab11..8b968e540c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpConfigStorage.java
@@ -260,7 +260,36 @@ public interface WxCpConfigStorage {
/**
* 获取会话存档的secret
+ *
* @return msg audit secret
*/
String getMsgAuditSecret();
+
+ /**
+ * 获取会话存档SDK
+ * 会话存档SDK初始化后有效期为7200秒,无需每次重新初始化
+ *
+ * @return sdk id,如果未初始化或已过期返回0
+ */
+ long getMsgAuditSdk();
+
+ /**
+ * 检查会话存档SDK是否已过期
+ *
+ * @return true: 已过期, false: 未过期
+ */
+ boolean isMsgAuditSdkExpired();
+
+ /**
+ * 更新会话存档SDK
+ *
+ * @param sdk sdk id
+ * @param expiresInSeconds 过期时间(秒)
+ */
+ void updateMsgAuditSdk(long sdk, int expiresInSeconds);
+
+ /**
+ * 使会话存档SDK过期
+ */
+ void expireMsgAuditSdk();
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
index 72f143fc37..2cd37821b5 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
@@ -130,7 +130,7 @@ public interface WxCpTpConfigStorage {
* @return the aes key
*/
//第三方应用的EncodingAESKey,用来检查签名
- String getAesKey();
+ String getEncodingAESKey();
/**
* 企微服务商企业ID & 企业secret
@@ -146,6 +146,13 @@ public interface WxCpTpConfigStorage {
*/
String getCorpSecret();
+ /**
+ * Sets provider secret.
+ *
+ * @param providerSecret the provider secret
+ */
+ void setProviderSecret(String providerSecret);
+
/**
* 服务商secret
*
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java
index 780e722c30..a078e8cf9e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java
@@ -180,4 +180,17 @@ public boolean isAgentJsapiTicketExpired() {
Long expire = redisOps.getExpire(this.agentJsapiTicketKey);
return expire == null || expire < 2;
}
+
+ @Override
+ public String toString() {
+ return "AbstractWxCpInRedisConfigImpl{" +
+ "corpId='" + getCorpId() + '\'' +
+ ", agentId=" + getAgentId() +
+ ", keyPrefix='" + keyPrefix + '\'' +
+ ", accessTokenKey='" + accessTokenKey + '\'' +
+ ", jsapiTicketKey='" + jsapiTicketKey + '\'' +
+ ", agentJsapiTicketKey='" + agentJsapiTicketKey + '\'' +
+ ", lockKey='" + lockKey + '\'' +
+ '}';
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpTpInRedisConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpTpInRedisConfigImpl.java
new file mode 100644
index 0000000000..08eed33c16
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpTpInRedisConfigImpl.java
@@ -0,0 +1,431 @@
+package me.chanjar.weixin.cp.config.impl;
+
+
+import lombok.Builder;
+import lombok.NonNull;
+import lombok.Setter;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.redis.RedissonWxRedisOps;
+import me.chanjar.weixin.common.redis.WxRedisOps;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.cp.bean.WxCpProviderToken;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.redisson.api.RedissonClient;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * 企业微信各种固定、授权配置的Redisson存储实现
+ */
+public abstract class AbstractWxCpTpInRedisConfigImpl extends WxCpTpDefaultConfigImpl implements Serializable {
+ private static final long serialVersionUID = -5385639031981770319L;
+
+ public AbstractWxCpTpInRedisConfigImpl(@NonNull WxRedisOps wxRedisOps) {
+ this(wxRedisOps, null);
+ }
+
+ public AbstractWxCpTpInRedisConfigImpl(@NonNull WxRedisOps wxRedisOps, String keyPrefix) {
+ this.wxRedisOps = wxRedisOps;
+ this.keyPrefix = keyPrefix;
+ }
+ /**
+ * The constant LOCK_KEY.
+ */
+// lock key
+ protected static final String LOCK_KEY = "wechat_tp_lock:";
+ /**
+ * The constant LOCKER_PROVIDER_ACCESS_TOKEN.
+ */
+ protected static final String LOCKER_PROVIDER_ACCESS_TOKEN = "providerAccessTokenLock";
+ /**
+ * The constant LOCKER_SUITE_ACCESS_TOKEN.
+ */
+ protected static final String LOCKER_SUITE_ACCESS_TOKEN = "suiteAccessTokenLock";
+ /**
+ * The constant LOCKER_ACCESS_TOKEN.
+ */
+ protected static final String LOCKER_ACCESS_TOKEN = "accessTokenLock";
+ /**
+ * The constant LOCKER_CORP_JSAPI_TICKET.
+ */
+ protected static final String LOCKER_CORP_JSAPI_TICKET = "corpJsapiTicketLock";
+ /**
+ * The constant LOCKER_SUITE_JSAPI_TICKET.
+ */
+ protected static final String LOCKER_SUITE_JSAPI_TICKET = "suiteJsapiTicketLock";
+ @NonNull
+ private final WxRedisOps wxRedisOps;
+ private final String suiteAccessTokenKey = ":suiteAccessTokenKey:";
+ private final String suiteTicketKey = ":suiteTicketKey:";
+ private final String accessTokenKey = ":accessTokenKey:";
+ private final String authCorpJsApiTicketKey = ":authCorpJsApiTicketKey:";
+ private final String authSuiteJsApiTicketKey = ":authSuiteJsApiTicketKey:";
+ private final String providerTokenKey = ":providerTokenKey:";
+ /**
+ * redis里面key的统一前缀
+ */
+ @Setter
+ private String keyPrefix = "";
+ private volatile String baseApiUrl;
+ private volatile String httpProxyHost;
+ private volatile int httpProxyPort;
+ private volatile String httpProxyUsername;
+ private volatile String httpProxyPassword;
+ private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
+ private volatile File tmpDirFile;
+
+
+ @Override
+ public void setBaseApiUrl(String baseUrl) {
+ this.baseApiUrl = baseUrl;
+ }
+
+ @Override
+ public String getApiUrl(String path) {
+ if (baseApiUrl == null) {
+ baseApiUrl = "https://qyapi.weixin.qq.com";
+ }
+ return baseApiUrl + path;
+ }
+
+
+ /**
+ * 第三方应用的suite access token相关
+ */
+ @Override
+ public String getSuiteAccessToken() {
+ return wxRedisOps.getValue(keyWithPrefix(suiteAccessTokenKey));
+ }
+
+ @Override
+ public WxAccessToken getSuiteAccessTokenEntity() {
+ String suiteAccessToken = wxRedisOps.getValue(keyWithPrefix(suiteAccessTokenKey));
+ Long expireIn = wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey));
+ if (StringUtils.isBlank(suiteAccessToken) || expireIn == null || expireIn == 0 || expireIn == -2) {
+ return new WxAccessToken();
+ }
+
+ WxAccessToken suiteAccessTokenEntity = new WxAccessToken();
+ suiteAccessTokenEntity.setAccessToken(suiteAccessToken);
+ suiteAccessTokenEntity.setExpiresIn(Math.max(Math.toIntExact(expireIn), 0));
+ return suiteAccessTokenEntity;
+ }
+
+ @Override
+ public boolean isSuiteAccessTokenExpired() {
+ //remain time to live in seconds, or key not exist
+ return wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey)) == -2;
+ }
+
+ @Override
+ public void expireSuiteAccessToken() {
+ wxRedisOps.expire(keyWithPrefix(suiteAccessTokenKey), 0, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void updateSuiteAccessToken(WxAccessToken suiteAccessToken) {
+ updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn());
+ }
+
+ @Override
+ public void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) {
+ wxRedisOps.setValue(keyWithPrefix(suiteAccessTokenKey), suiteAccessToken, expiresInSeconds, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 第三方应用的suite ticket相关
+ */
+ @Override
+ public String getSuiteTicket() {
+ return wxRedisOps.getValue(keyWithPrefix(suiteTicketKey));
+ }
+
+ @Override
+ public boolean isSuiteTicketExpired() {
+ //remain time to live in seconds, or key not exist
+ return wxRedisOps.getExpire(keyWithPrefix(suiteTicketKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(suiteTicketKey)) == -2;
+ }
+
+ @Override
+ public void expireSuiteTicket() {
+ wxRedisOps.expire(keyWithPrefix(suiteTicketKey), 0, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void updateSuiteTicket(String suiteTicket, int expiresInSeconds) {
+ wxRedisOps.setValue(keyWithPrefix(suiteTicketKey), suiteTicket, expiresInSeconds, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 第三方应用的其他配置,来自于企微配置
+ */
+ @Override
+ public String getSuiteId() {
+ return suiteId;
+ }
+
+ @Override
+ public String getSuiteSecret() {
+ return suiteSecret;
+ }
+
+ // 第三方应用的token,用来检查应用的签名
+ @Override
+ public String getToken() {
+ return token;
+ }
+
+ //第三方应用的EncodingAESKey,用来检查签名
+ @Override
+ public String getEncodingAESKey() {
+ return encodingAESKey;
+ }
+
+
+ /**
+ * 企微服务商企业ID & 企业secret, 来自于企微配置
+ */
+ @Override
+ public String getCorpId() {
+ return corpId;
+ }
+
+ @Override
+ public String getProviderSecret() {
+ return providerSecret;
+ }
+
+ @Override
+ public void setProviderSecret(String providerSecret) {
+ this.providerSecret = providerSecret;
+ }
+
+ /**
+ * 授权企业的access token相关
+ */
+ @Override
+ public String getAccessToken(String authCorpId) {
+ return wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey);
+ }
+
+ @Override
+ public WxAccessToken getAccessTokenEntity(String authCorpId) {
+ String accessToken = wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey);
+ Long expire = wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey);
+ if (StringUtils.isBlank(accessToken) || expire == null || expire == 0 || expire == -2) {
+ return new WxAccessToken();
+ }
+
+ WxAccessToken accessTokenEntity = new WxAccessToken();
+ accessTokenEntity.setAccessToken(accessToken);
+ accessTokenEntity.setExpiresIn((int) ((expire - System.currentTimeMillis()) / 1000 + 200));
+ return accessTokenEntity;
+ }
+
+ @Override
+ public boolean isAccessTokenExpired(String authCorpId) {
+ //没有设置或者TTL为0,都是过期
+ return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == 0L
+ || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == -2;
+ }
+
+ @Override
+ public void expireAccessToken(String authCorpId) {
+ wxRedisOps.expire(keyWithPrefix(authCorpId) + accessTokenKey, 0, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void updateAccessToken(String authCorpId, String accessToken, int expiredInSeconds) {
+ wxRedisOps.setValue(keyWithPrefix(authCorpId) + accessTokenKey, accessToken, expiredInSeconds, TimeUnit.SECONDS);
+ }
+
+
+ /**
+ * 授权企业的js api ticket相关
+ */
+ @Override
+ public String getAuthCorpJsApiTicket(String authCorpId) {
+ return wxRedisOps.getValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey);
+ }
+
+ @Override
+ public boolean isAuthCorpJsApiTicketExpired(String authCorpId) {
+ //没有设置或TTL为0,都是过期
+ return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey) == 0L
+ || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey) == -2;
+ }
+
+ @Override
+ public void expireAuthCorpJsApiTicket(String authCorpId) {
+ wxRedisOps.expire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, 0, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void updateAuthCorpJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) {
+ wxRedisOps.setValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, jsApiTicket, expiredInSeconds,
+ TimeUnit.SECONDS);
+ }
+
+
+ /**
+ * 授权企业的第三方应用js api ticket相关
+ */
+ @Override
+ public String getAuthSuiteJsApiTicket(String authCorpId) {
+ return wxRedisOps.getValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey);
+ }
+
+ @Override
+ public boolean isAuthSuiteJsApiTicketExpired(String authCorpId) {
+ //没有设置或者TTL为0,都是过期
+ return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey) == 0L
+ || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey) == -2;
+ }
+
+ @Override
+ public void expireAuthSuiteJsApiTicket(String authCorpId) {
+ wxRedisOps.expire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, 0, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) {
+ wxRedisOps.setValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, jsApiTicket, expiredInSeconds,
+ TimeUnit.SECONDS);
+ }
+
+ @Override
+ public boolean isProviderTokenExpired() {
+ //remain time to live in seconds, or key not exist
+ return wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey)) == 0L || wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey)) == -2;
+ }
+
+ @Override
+ public void updateProviderToken(String providerToken, int expiredInSeconds) {
+ wxRedisOps.setValue(providerKeyWithPrefix(providerTokenKey), providerToken, expiredInSeconds, TimeUnit.SECONDS);
+ }
+
+ @Override
+ public String getProviderToken() {
+ return wxRedisOps.getValue(providerKeyWithPrefix(providerTokenKey));
+ }
+
+ @Override
+ public WxCpProviderToken getProviderTokenEntity() {
+ String providerToken = wxRedisOps.getValue(providerKeyWithPrefix(providerTokenKey));
+ Long expire = wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey));
+
+ if (StringUtils.isBlank(providerToken) || expire == null || expire == 0 || expire == -2) {
+ return new WxCpProviderToken();
+ }
+
+ WxCpProviderToken wxCpProviderToken = new WxCpProviderToken();
+ wxCpProviderToken.setProviderAccessToken(providerToken);
+ wxCpProviderToken.setExpiresIn(Math.max(Math.toIntExact(expire), 0));
+ return wxCpProviderToken;
+ }
+
+ @Override
+ public void expireProviderToken() {
+ wxRedisOps.expire(providerKeyWithPrefix(providerTokenKey), 0, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 网络代理相关
+ */
+ @Override
+ public String getHttpProxyHost() {
+ return this.httpProxyHost;
+ }
+
+ @Override
+ public int getHttpProxyPort() {
+ return this.httpProxyPort;
+ }
+
+ @Override
+ public String getHttpProxyUsername() {
+ return this.httpProxyUsername;
+ }
+
+ @Override
+ public String getHttpProxyPassword() {
+ return this.httpProxyPassword;
+ }
+
+ @Override
+ public File getTmpDirFile() {
+ return tmpDirFile;
+ }
+
+ @Override
+ public Lock getProviderAccessTokenLock() {
+ return getProviderLockByKey(String.join(":", this.corpId, LOCKER_PROVIDER_ACCESS_TOKEN));
+ }
+
+ @Override
+ public Lock getSuiteAccessTokenLock() {
+ return getLockByKey(LOCKER_SUITE_ACCESS_TOKEN);
+ }
+
+ @Override
+ public Lock getAccessTokenLock(String authCorpId) {
+ return getLockByKey(String.join(":", authCorpId, LOCKER_ACCESS_TOKEN));
+ }
+
+ @Override
+ public Lock getAuthCorpJsapiTicketLock(String authCorpId) {
+ return getLockByKey(String.join(":", authCorpId, LOCKER_CORP_JSAPI_TICKET));
+ }
+
+ @Override
+ public Lock getSuiteJsapiTicketLock(String authCorpId) {
+ return getLockByKey(String.join(":", authCorpId, LOCKER_SUITE_JSAPI_TICKET));
+ }
+
+ private Lock getLockByKey(String key) {
+ // 最终key的模式:(keyPrefix:)wechat_tp_lock:suiteId:(authCorpId):lockKey
+ // 其中keyPrefix目前不支持外部配置,authCorpId只有涉及到corpAccessToken, suiteJsapiTicket, authCorpJsapiTicket时才会拼上
+ return this.wxRedisOps.getLock(String.join(":", keyWithPrefix(LOCK_KEY + this.suiteId), key));
+ }
+
+ /**
+ * 单独处理provider,且不应和suite 有关系
+ */
+ private Lock getProviderLockByKey(String key) {
+ return this.wxRedisOps.getLock(String.join(":", providerKeyWithPrefix(LOCK_KEY), key));
+ }
+
+ @Override
+ public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
+ return this.apacheHttpClientBuilder;
+ }
+
+ @Override
+ public boolean autoRefreshToken() {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return WxCpGsonBuilder.create().toJson(this);
+ }
+
+ /**
+ * 一个provider 会有多个suite,需要唯一标识作为前缀
+ */
+ private String keyWithPrefix(String key) {
+ return keyPrefix + ":" + suiteId + ":" + key;
+ }
+
+ /**
+ * provider 应该独享一个key,且不和任何suite关联
+ * 一个provider 会有多个suite,不同的suite 都应该指向同一个provider 的数据
+ */
+ private String providerKeyWithPrefix(String key) {
+ return keyPrefix + ":" + corpId + ":" + key;
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java
index bef838c90d..b3d4834426 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java
@@ -18,6 +18,8 @@
* @author libo
*/
public class WxCpCorpGroupDefaultConfigImpl implements WxCpCorpGroupConfigStorage, Serializable {
+ private static final long serialVersionUID = -8392908346536154435L;
+
private final transient Map corpAccessTokenLocker = new ConcurrentHashMap<>();
private final Map corpAccessTokenMap = new HashMap<>();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java
index 8146b580d0..1ef05ba8b3 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java
@@ -23,6 +23,8 @@
*/
@Builder
public class WxCpCorpGroupRedissonConfigImpl implements WxCpCorpGroupConfigStorage, Serializable {
+ private static final long serialVersionUID = 1269450173683931930L;
+
private final transient Map corpAccessTokenLocker = new ConcurrentHashMap<>();
/**
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java
index 57647b3712..4bf13f24ea 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpDefaultConfigImpl.java
@@ -49,6 +49,11 @@ public class WxCpDefaultConfigImpl implements WxCpConfigStorage, Serializable {
private volatile String msgAuditSecret;
private volatile String msgAuditPriKey;
private volatile String msgAuditLibPath;
+ /**
+ * 会话存档SDK及其过期时间
+ */
+ private volatile long msgAuditSdk;
+ private volatile long msgAuditSdkExpiresTime;
private volatile String oauth2redirectUri;
private volatile String httpProxyHost;
private volatile int httpProxyPort;
@@ -444,10 +449,34 @@ public String getMsgAuditSecret() {
/**
* 设置会话存档secret
- * @param msgAuditSecret
+ *
+ * @param msgAuditSecret the msg audit secret
+ * @return this
*/
public WxCpDefaultConfigImpl setMsgAuditSecret(String msgAuditSecret) {
this.msgAuditSecret = msgAuditSecret;
return this;
}
+
+ @Override
+ public long getMsgAuditSdk() {
+ return this.msgAuditSdk;
+ }
+
+ @Override
+ public boolean isMsgAuditSdkExpired() {
+ return System.currentTimeMillis() > this.msgAuditSdkExpiresTime;
+ }
+
+ @Override
+ public synchronized void updateMsgAuditSdk(long sdk, int expiresInSeconds) {
+ this.msgAuditSdk = sdk;
+ // 预留200秒的时间
+ this.msgAuditSdkExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+ }
+
+ @Override
+ public void expireMsgAuditSdk() {
+ this.msgAuditSdkExpiresTime = 0;
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java
index 4225cff0af..15c0ff6727 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpRedisConfigImpl.java
@@ -50,6 +50,11 @@ public class WxCpRedisConfigImpl implements WxCpConfigStorage {
private volatile File tmpDirFile;
private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
private volatile String webhookKey;
+ /**
+ * 会话存档SDK及其过期时间(SDK是本地JVM变量,不适合存储到Redis)
+ */
+ private volatile long msgAuditSdk;
+ private volatile long msgAuditSdkExpiresTime;
/**
* Instantiates a new Wx cp redis config.
@@ -470,4 +475,26 @@ public String getWebhookKey() {
public String getMsgAuditSecret() {
return null;
}
+
+ @Override
+ public long getMsgAuditSdk() {
+ return this.msgAuditSdk;
+ }
+
+ @Override
+ public boolean isMsgAuditSdkExpired() {
+ return System.currentTimeMillis() > this.msgAuditSdkExpiresTime;
+ }
+
+ @Override
+ public synchronized void updateMsgAuditSdk(long sdk, int expiresInSeconds) {
+ this.msgAuditSdk = sdk;
+ // 预留200秒的时间
+ this.msgAuditSdkExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
+ }
+
+ @Override
+ public void expireMsgAuditSdk() {
+ this.msgAuditSdkExpiresTime = 0;
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java
index a4b8af4677..fc124251f5 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java
@@ -28,20 +28,32 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl
private final transient Map accessTokenLocker = new ConcurrentHashMap<>();
private final transient Map authCorpJsapiTicketLocker = new ConcurrentHashMap<>();
private final transient Map authSuiteJsapiTicketLocker = new ConcurrentHashMap<>();
- private volatile String corpId;
- private volatile String corpSecret;
+ /**
+ * 企微服务商企业ID & 企业secret,来自于企微配置
+ */
+ protected volatile String corpId;
/**
* 服务商secret
*/
- private volatile String providerSecret;
+ protected volatile String providerSecret;
private volatile String providerToken;
private volatile long providerTokenExpiresTime;
- private volatile String suiteId;
- private volatile String suiteSecret;
- private volatile String token;
+ /**
+ * 第三方应用的其他配置,来自于企微配置
+ */
+ protected volatile String suiteId;
+
+ protected volatile String suiteSecret;
+ /**
+ * 第三方应用的token,用来检查应用的签名
+ */
+ protected volatile String token;
private volatile String suiteAccessToken;
private volatile long suiteAccessTokenExpiresTime;
- private volatile String aesKey;
+ /**
+ * 第三方应用的EncodingAESKey,用来检查签名
+ */
+ protected volatile String encodingAESKey;
private volatile String suiteTicket;
private volatile long suiteTicketExpiresTime;
private volatile String oauth2redirectUri;
@@ -186,11 +198,10 @@ public String getSuiteId() {
/**
* Sets suite id.
*
- * @param corpId the corp id
+ * @param suiteId
*/
- @Deprecated
- public void setSuiteId(String corpId) {
- this.suiteId = corpId;
+ public void setSuiteId(String suiteId) {
+ this.suiteId = suiteId;
}
@Override
@@ -200,10 +211,7 @@ public String getSuiteSecret() {
/**
* Sets suite secret.
- *
- * @param corpSecret the corp secret
*/
- @Deprecated
public void setSuiteSecret(String corpSecret) {
this.suiteSecret = corpSecret;
}
@@ -218,24 +226,22 @@ public String getToken() {
*
* @param token the token
*/
- @Deprecated
public void setToken(String token) {
this.token = token;
}
@Override
- public String getAesKey() {
- return this.aesKey;
+ public String getEncodingAESKey() {
+ return this.encodingAESKey;
}
/**
- * Sets aes key.
+ * Sets aes key. encodingAESKey
*
- * @param aesKey the aes key
+ * @param encodingAESKey the aes key
*/
- @Deprecated
- public void setAesKey(String aesKey) {
- this.aesKey = aesKey;
+ public void setEncodingAESKey(String encodingAESKey) {
+ this.encodingAESKey = encodingAESKey;
}
@@ -249,24 +255,19 @@ public String getCorpId() {
*
* @param corpId the corp id
*/
- @Deprecated
public void setCorpId(String corpId) {
this.corpId = corpId;
}
@Override
public String getCorpSecret() {
- return this.corpSecret;
+ return this.providerSecret;
}
- /**
- * Sets corp secret.
- *
- * @param corpSecret the corp secret
- */
- @Deprecated
- public void setCorpSecret(String corpSecret) {
- this.corpSecret = corpSecret;
+
+ @Override
+ public void setProviderSecret(String providerSecret) {
+ this.providerSecret = providerSecret;
}
@Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpJedisConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpJedisConfigImpl.java
new file mode 100644
index 0000000000..045761256b
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpJedisConfigImpl.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.cp.config.impl;
+
+import lombok.NonNull;
+import me.chanjar.weixin.common.redis.JedisWxRedisOps;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.util.Pool;
+
+/**
+ * 基于 jedis 的实现
+ *
+ * @author yl
+ * created on 2023/04/23
+ */
+public class WxCpTpJedisConfigImpl extends AbstractWxCpTpInRedisConfigImpl {
+ private static final long serialVersionUID = -1869372247414407433L;
+
+ public WxCpTpJedisConfigImpl(Pool jedisPool) {
+ this(jedisPool, null);
+ }
+
+ public WxCpTpJedisConfigImpl(@NonNull Pool jedisPool, String keyPrefix) {
+ super(new JedisWxRedisOps(jedisPool), keyPrefix);
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedisTemplateConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedisTemplateConfigImpl.java
new file mode 100644
index 0000000000..0a94afc797
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedisTemplateConfigImpl.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.cp.config.impl;
+
+import lombok.Builder;
+import lombok.NonNull;
+import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
+import org.springframework.data.redis.core.StringRedisTemplate;
+
+/**
+ * 基于 RedisTemplate 的实现
+ *
+ * @author yl
+ * created on 2023/04/23
+ */
+public class WxCpTpRedisTemplateConfigImpl extends AbstractWxCpTpInRedisConfigImpl {
+ private static final long serialVersionUID = -1660004125413310620L;
+
+ public WxCpTpRedisTemplateConfigImpl(@NonNull StringRedisTemplate stringRedisTemplate) {
+ this(stringRedisTemplate, null);
+ }
+
+ public WxCpTpRedisTemplateConfigImpl(@NonNull StringRedisTemplate stringRedisTemplate, String keyPrefix) {
+ super(new RedisTemplateWxRedisOps(stringRedisTemplate), keyPrefix);
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
index 02193cfd33..fe8723a8a0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
@@ -1,444 +1,25 @@
package me.chanjar.weixin.cp.config.impl;
-
import lombok.Builder;
+import lombok.Data;
import lombok.NonNull;
-import lombok.Setter;
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.redis.WxRedisOps;
-import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
-import me.chanjar.weixin.cp.bean.WxCpProviderToken;
-import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
-import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.File;
-import java.io.Serializable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
+import me.chanjar.weixin.common.redis.RedissonWxRedisOps;
+import org.redisson.api.RedissonClient;
/**
- * 企业微信各种固定、授权配置的Redisson存储实现
+ * 基于Redisson的实现
+ *
+ * @author yuanqixun created on 2020 /5/13
+ * @author yl
*/
-@Builder
-public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializable {
- private static final long serialVersionUID = -5385639031981770319L;
-
- /**
- * The constant LOCK_KEY.
- */
-// lock key
- protected static final String LOCK_KEY = "wechat_tp_lock:";
- /**
- * The constant LOCKER_PROVIDER_ACCESS_TOKEN.
- */
- protected static final String LOCKER_PROVIDER_ACCESS_TOKEN = "providerAccessTokenLock";
- /**
- * The constant LOCKER_SUITE_ACCESS_TOKEN.
- */
- protected static final String LOCKER_SUITE_ACCESS_TOKEN = "suiteAccessTokenLock";
- /**
- * The constant LOCKER_ACCESS_TOKEN.
- */
- protected static final String LOCKER_ACCESS_TOKEN = "accessTokenLock";
- /**
- * The constant LOCKER_CORP_JSAPI_TICKET.
- */
- protected static final String LOCKER_CORP_JSAPI_TICKET = "corpJsapiTicketLock";
- /**
- * The constant LOCKER_SUITE_JSAPI_TICKET.
- */
- protected static final String LOCKER_SUITE_JSAPI_TICKET = "suiteJsapiTicketLock";
- @NonNull
- private final WxRedisOps wxRedisOps;
- private final String suiteAccessTokenKey = ":suiteAccessTokenKey:";
- private final String suiteTicketKey = ":suiteTicketKey:";
- private final String accessTokenKey = ":accessTokenKey:";
- private final String authCorpJsApiTicketKey = ":authCorpJsApiTicketKey:";
- private final String authSuiteJsApiTicketKey = ":authSuiteJsApiTicketKey:";
- private final String providerTokenKey = ":providerTokenKey:";
- /**
- * redis里面key的统一前缀
- */
- @Setter
- private String keyPrefix = "";
- private volatile String baseApiUrl;
- private volatile String httpProxyHost;
- private volatile int httpProxyPort;
- private volatile String httpProxyUsername;
- private volatile String httpProxyPassword;
- private volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
- private volatile File tmpDirFile;
- /**
- * 第三方应用的其他配置,来自于企微配置
- */
- private volatile String suiteId;
- private volatile String suiteSecret;
- /**
- * 第三方应用的token,用来检查应用的签名
- */
- private volatile String token;
- /**
- * 第三方应用的EncodingAESKey,用来检查签名
- */
- private volatile String aesKey;
- /**
- * 企微服务商企业ID & 企业secret,来自于企微配置
- */
- private volatile String corpId;
- private volatile String corpSecret;
- /**
- * 服务商secret
- */
- private volatile String providerSecret;
-
- @Override
- public void setBaseApiUrl(String baseUrl) {
- this.baseApiUrl = baseUrl;
- }
-
- @Override
- public String getApiUrl(String path) {
- if (baseApiUrl == null) {
- baseApiUrl = "https://qyapi.weixin.qq.com";
- }
- return baseApiUrl + path;
- }
-
-
- /**
- * 第三方应用的suite access token相关
- */
- @Override
- public String getSuiteAccessToken() {
- return wxRedisOps.getValue(keyWithPrefix(suiteAccessTokenKey));
- }
-
- @Override
- public WxAccessToken getSuiteAccessTokenEntity() {
- String suiteAccessToken = wxRedisOps.getValue(keyWithPrefix(suiteAccessTokenKey));
- Long expireIn = wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey));
- if (StringUtils.isBlank(suiteAccessToken) || expireIn == null || expireIn == 0 || expireIn == -2) {
- return new WxAccessToken();
- }
-
- WxAccessToken suiteAccessTokenEntity = new WxAccessToken();
- suiteAccessTokenEntity.setAccessToken(suiteAccessToken);
- suiteAccessTokenEntity.setExpiresIn(Math.max(Math.toIntExact(expireIn), 0));
- return suiteAccessTokenEntity;
- }
-
- @Override
- public boolean isSuiteAccessTokenExpired() {
- //remain time to live in seconds, or key not exist
- return wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(suiteAccessTokenKey)) == -2;
- }
-
- @Override
- public void expireSuiteAccessToken() {
- wxRedisOps.expire(keyWithPrefix(suiteAccessTokenKey), 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateSuiteAccessToken(WxAccessToken suiteAccessToken) {
- updateSuiteAccessToken(suiteAccessToken.getAccessToken(), suiteAccessToken.getExpiresIn());
- }
-
- @Override
- public void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(suiteAccessTokenKey), suiteAccessToken, expiresInSeconds, TimeUnit.SECONDS);
- }
-
- /**
- * 第三方应用的suite ticket相关
- */
- @Override
- public String getSuiteTicket() {
- return wxRedisOps.getValue(keyWithPrefix(suiteTicketKey));
- }
-
- @Override
- public boolean isSuiteTicketExpired() {
- //remain time to live in seconds, or key not exist
- return wxRedisOps.getExpire(keyWithPrefix(suiteTicketKey)) == 0L || wxRedisOps.getExpire(keyWithPrefix(suiteTicketKey)) == -2;
- }
-
- @Override
- public void expireSuiteTicket() {
- wxRedisOps.expire(keyWithPrefix(suiteTicketKey), 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateSuiteTicket(String suiteTicket, int expiresInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(suiteTicketKey), suiteTicket, expiresInSeconds, TimeUnit.SECONDS);
- }
-
- /**
- * 第三方应用的其他配置,来自于企微配置
- */
- @Override
- public String getSuiteId() {
- return suiteId;
- }
-
- @Override
- public String getSuiteSecret() {
- return suiteSecret;
- }
-
- // 第三方应用的token,用来检查应用的签名
- @Override
- public String getToken() {
- return token;
- }
-
- //第三方应用的EncodingAESKey,用来检查签名
- @Override
- public String getAesKey() {
- return aesKey;
- }
-
-
- /**
- * 企微服务商企业ID & 企业secret, 来自于企微配置
- */
- @Override
- public String getCorpId() {
- return corpId;
- }
-
- @Override
- public String getCorpSecret() {
- return corpSecret;
- }
-
- @Override
- public String getProviderSecret() {
- return providerSecret;
- }
-
- /**
- * 授权企业的access token相关
- */
- @Override
- public String getAccessToken(String authCorpId) {
- return wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey);
- }
-
- @Override
- public WxAccessToken getAccessTokenEntity(String authCorpId) {
- String accessToken = wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey);
- Long expire = wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey);
- if (StringUtils.isBlank(accessToken) || expire == null || expire == 0 || expire == -2) {
- return new WxAccessToken();
- }
-
- WxAccessToken accessTokenEntity = new WxAccessToken();
- accessTokenEntity.setAccessToken(accessToken);
- accessTokenEntity.setExpiresIn((int) ((expire - System.currentTimeMillis()) / 1000 + 200));
- return accessTokenEntity;
- }
-
- @Override
- public boolean isAccessTokenExpired(String authCorpId) {
- //没有设置或者TTL为0,都是过期
- return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == 0L
- || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == -2;
- }
-
- @Override
- public void expireAccessToken(String authCorpId) {
- wxRedisOps.expire(keyWithPrefix(authCorpId) + accessTokenKey, 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateAccessToken(String authCorpId, String accessToken, int expiredInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(authCorpId) + accessTokenKey, accessToken, expiredInSeconds, TimeUnit.SECONDS);
- }
-
-
- /**
- * 授权企业的js api ticket相关
- */
- @Override
- public String getAuthCorpJsApiTicket(String authCorpId) {
- return wxRedisOps.getValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey);
- }
-
- @Override
- public boolean isAuthCorpJsApiTicketExpired(String authCorpId) {
- //没有设置或TTL为0,都是过期
- return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey) == 0L
- || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey) == -2;
- }
-
- @Override
- public void expireAuthCorpJsApiTicket(String authCorpId) {
- wxRedisOps.expire(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateAuthCorpJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(authCorpId) + authCorpJsApiTicketKey, jsApiTicket, expiredInSeconds,
- TimeUnit.SECONDS);
- }
-
-
- /**
- * 授权企业的第三方应用js api ticket相关
- */
- @Override
- public String getAuthSuiteJsApiTicket(String authCorpId) {
- return wxRedisOps.getValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey);
- }
-
- @Override
- public boolean isAuthSuiteJsApiTicketExpired(String authCorpId) {
- //没有设置或者TTL为0,都是过期
- return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey) == 0L
- || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey) == -2;
- }
-
- @Override
- public void expireAuthSuiteJsApiTicket(String authCorpId) {
- wxRedisOps.expire(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, 0, TimeUnit.SECONDS);
- }
-
- @Override
- public void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) {
- wxRedisOps.setValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, jsApiTicket, expiredInSeconds,
- TimeUnit.SECONDS);
- }
-
- @Override
- public boolean isProviderTokenExpired() {
- //remain time to live in seconds, or key not exist
- return wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey)) == 0L || wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey)) == -2;
- }
-
- @Override
- public void updateProviderToken(String providerToken, int expiredInSeconds) {
- wxRedisOps.setValue(providerKeyWithPrefix(providerTokenKey), providerToken, expiredInSeconds, TimeUnit.SECONDS);
- }
-
- @Override
- public String getProviderToken() {
- return wxRedisOps.getValue(providerKeyWithPrefix(providerTokenKey));
- }
-
- @Override
- public WxCpProviderToken getProviderTokenEntity() {
- String providerToken = wxRedisOps.getValue(providerKeyWithPrefix(providerTokenKey));
- Long expire = wxRedisOps.getExpire(providerKeyWithPrefix(providerTokenKey));
-
- if (StringUtils.isBlank(providerToken) || expire == null || expire == 0 || expire == -2) {
- return new WxCpProviderToken();
- }
-
- WxCpProviderToken wxCpProviderToken = new WxCpProviderToken();
- wxCpProviderToken.setProviderAccessToken(providerToken);
- wxCpProviderToken.setExpiresIn(Math.max(Math.toIntExact(expire), 0));
- return wxCpProviderToken;
- }
-
- @Override
- public void expireProviderToken() {
- wxRedisOps.expire(providerKeyWithPrefix(providerTokenKey), 0, TimeUnit.SECONDS);
- }
-
- /**
- * 网络代理相关
- */
- @Override
- public String getHttpProxyHost() {
- return this.httpProxyHost;
- }
-
- @Override
- public int getHttpProxyPort() {
- return this.httpProxyPort;
- }
-
- @Override
- public String getHttpProxyUsername() {
- return this.httpProxyUsername;
- }
-
- @Override
- public String getHttpProxyPassword() {
- return this.httpProxyPassword;
- }
-
- @Override
- public File getTmpDirFile() {
- return tmpDirFile;
- }
-
- @Override
- public Lock getProviderAccessTokenLock() {
- return getProviderLockByKey(String.join(":", this.corpId, LOCKER_PROVIDER_ACCESS_TOKEN));
- }
-
- @Override
- public Lock getSuiteAccessTokenLock() {
- return getLockByKey(LOCKER_SUITE_ACCESS_TOKEN);
- }
-
- @Override
- public Lock getAccessTokenLock(String authCorpId) {
- return getLockByKey(String.join(":", authCorpId, LOCKER_ACCESS_TOKEN));
- }
-
- @Override
- public Lock getAuthCorpJsapiTicketLock(String authCorpId) {
- return getLockByKey(String.join(":", authCorpId, LOCKER_CORP_JSAPI_TICKET));
- }
-
- @Override
- public Lock getSuiteJsapiTicketLock(String authCorpId) {
- return getLockByKey(String.join(":", authCorpId, LOCKER_SUITE_JSAPI_TICKET));
- }
-
- private Lock getLockByKey(String key) {
- // 最终key的模式:(keyPrefix:)wechat_tp_lock:suiteId:(authCorpId):lockKey
- // 其中keyPrefix目前不支持外部配置,authCorpId只有涉及到corpAccessToken, suiteJsapiTicket, authCorpJsapiTicket时才会拼上
- return this.wxRedisOps.getLock(String.join(":", keyWithPrefix(LOCK_KEY + this.suiteId), key));
- }
-
- /**
- * 单独处理provider,且不应和suite 有关系
- */
- private Lock getProviderLockByKey(String key) {
- return this.wxRedisOps.getLock(String.join(":", providerKeyWithPrefix(LOCK_KEY), key));
- }
-
- @Override
- public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
- return this.apacheHttpClientBuilder;
- }
-
- @Override
- public boolean autoRefreshToken() {
- return false;
- }
-
- @Override
- public String toString() {
- return WxCpGsonBuilder.create().toJson(this);
- }
+public class WxCpTpRedissonConfigImpl extends AbstractWxCpTpInRedisConfigImpl {
+ private static final long serialVersionUID = -5674792341070783967L;
- /**
- * 一个provider 会有多个suite,需要唯一标识作为前缀
- */
- private String keyWithPrefix(String key) {
- return keyPrefix + ":" + suiteId + ":" + key;
+ public WxCpTpRedissonConfigImpl(@NonNull RedissonClient redissonClient) {
+ this(redissonClient, null);
}
- /**
- * provider 应该独享一个key,且不和任何suite关联
- * 一个provider 会有多个suite,不同的suite 都应该指向同一个provider 的数据
- */
- private String providerKeyWithPrefix(String key) {
- return keyPrefix + ":" + corpId + ":" + key;
+ public WxCpTpRedissonConfigImpl(@NonNull RedissonClient redissonClient, String keyPrefix) {
+ super(new RedissonWxRedisOps(redissonClient), keyPrefix);
}
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index b53f7549d7..91314e5872 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -130,6 +130,10 @@ interface WorkBench {
* The constant WORKBENCH_DATA_SET.
*/
String WORKBENCH_DATA_SET = "/cgi-bin/agent/set_workbench_data";
+ /**
+ * The constant WORKBENCH_BATCH_DATA_SET.
+ */
+ String WORKBENCH_BATCH_DATA_SET = "/cgi-bin/agent/batch_set_workbench_data";
}
/**
@@ -234,6 +238,12 @@ interface Media {
* The constant JSSDK_MEDIA_GET.
*/
String JSSDK_MEDIA_GET = "/cgi-bin/media/get/jssdk";
+
+ /** The constant GET_UPLOAD_BY_URL_RESULT. */
+ String GET_UPLOAD_BY_URL_RESULT = "/cgi-bin/media/get_upload_by_url_result";
+
+ /** The constant UPLOAD_BY_URL. */
+ String UPLOAD_BY_URL = "/cgi-bin/media/upload_by_url";
}
/**
@@ -691,7 +701,7 @@ interface School {
/**
* The constant DEPARTMENT_LIST.
*/
- String DEPARTMENT_LIST = "/cgi-bin/school/department/list?id=";
+ String DEPARTMENT_LIST = "/cgi-bin/school/department/list";
/**
* The constant GET_PAYMENT_RESULT.
@@ -845,6 +855,10 @@ interface Tp {
* The constant GET_PERMANENT_CODE.
*/
String GET_PERMANENT_CODE = "/cgi-bin/service/get_permanent_code";
+ /**
+ * The constant GET_V2_PERMANENT_CODE.
+ */
+ String GET_V2_PERMANENT_CODE = "/cgi-bin/service/v2/get_permanent_code";
/**
* The constant GET_SUITE_TOKEN.
*/
@@ -1085,6 +1099,10 @@ interface ExternalContact {
* The constant GET_CONTACT_WAY.
*/
String GET_CONTACT_WAY = "/cgi-bin/externalcontact/get_contact_way";
+ /**
+ * The constant LIST_CONTACT_WAY.
+ */
+ String LIST_CONTACT_WAY = "/cgi-bin/externalcontact/list_contact_way";
/**
* The constant UPDATE_CONTACT_WAY.
*/
@@ -1613,4 +1631,40 @@ interface IdConvert {
*/
String CONVERT_TMP_EXTERNAL_USER_ID = "/cgi-bin/idconvert/convert_tmp_external_userid";
}
+
+ /**
+ * 智能机器人相关接口
+ * 官方文档: https://developer.work.weixin.qq.com/document/path/101039
+ */
+ interface IntelligentRobot {
+ /**
+ * 创建智能机器人
+ */
+ String CREATE_ROBOT = "/cgi-bin/intelligent_robot/create";
+
+ /**
+ * 删除智能机器人
+ */
+ String DELETE_ROBOT = "/cgi-bin/intelligent_robot/delete";
+
+ /**
+ * 更新智能机器人
+ */
+ String UPDATE_ROBOT = "/cgi-bin/intelligent_robot/update";
+
+ /**
+ * 查询智能机器人
+ */
+ String GET_ROBOT = "/cgi-bin/intelligent_robot/get";
+
+ /**
+ * 智能机器人会话
+ */
+ String CHAT = "/cgi-bin/intelligent_robot/chat";
+
+ /**
+ * 重置智能机器人会话
+ */
+ String RESET_SESSION = "/cgi-bin/intelligent_robot/reset_session";
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
index 606dcea6d2..ff3f8e0e6c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
@@ -219,6 +219,11 @@ public static class EventType {
*/
public static final String CUSTOMER_ACQUISITION = "customer_acquisition";
+ /**
+ * 异步上传临时素材结果回调通知
+ */
+ public static final String UPLOAD_MEDIA_JOB_FINISH = "upload_media_job_finish";
+
}
/**
@@ -625,6 +630,11 @@ public static class GroupRobotMsgType {
*/
public static final String MARKDOWN = "markdown";
+ /**
+ * markdown_v2消息.
+ */
+ public static final String MARKDOWN_V2 = "markdown_v2";
+
/**
* 图文消息(点击跳转到外链).
*/
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java
index 5fb56cc157..9991073739 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java
@@ -17,7 +17,6 @@
import me.chanjar.weixin.cp.bean.corpgroup.WxCpCorpGroupCorpGetTokenReq;
import me.chanjar.weixin.cp.bean.corpgroup.WxCpMaTransferSession;
import me.chanjar.weixin.cp.config.WxCpCorpGroupConfigStorage;
-import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.corpgroup.service.WxCpCgService;
import me.chanjar.weixin.cp.corpgroup.service.WxCpLinkedCorpService;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java
index fde2c76bb2..13349c3d80 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java
@@ -1,6 +1,6 @@
package me.chanjar.weixin.cp.corpgroup.service.impl;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import org.apache.http.HttpHost;
@@ -25,8 +25,8 @@ public HttpHost getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.APACHE_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.APACHE_HTTP;
}
@Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceHttpComponentsImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..d5c60ad037
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceHttpComponentsImpl.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.cp.corpgroup.service.impl;
+
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+/**
+ * @author altusea
+ */
+public class WxCpCgServiceHttpComponentsImpl extends BaseWxCpCgServiceImpl {
+ private CloseableHttpClient httpClient;
+ private HttpHost httpProxy;
+
+ @Override
+ public CloseableHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public HttpHost getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.HTTP_COMPONENTS;
+ }
+
+ @Override
+ public void initHttp() {
+ HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+ apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
+ .httpProxyPort(this.configStorage.getHttpProxyPort())
+ .httpProxyUsername(this.configStorage.getHttpProxyUsername())
+ .httpProxyPassword(this.configStorage.getHttpProxyPassword().toCharArray());
+
+ if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+ this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
+ }
+
+ this.httpClient = apacheHttpClientBuilder.build();
+ }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
index a2417ec86d..94f0838a9d 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
@@ -205,12 +205,12 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map futures = new ArrayList<>();
+ final List> futures = new ArrayList<>();
for (final WxCpMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果
if (rule.isAsync()) {
@@ -228,9 +228,9 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map 0) {
+ if (!futures.isEmpty()) {
this.executorService.submit(() -> {
- for (Future future : futures) {
+ for (Future> future : futures) {
try {
future.get();
log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName());
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java
index 8887a23d5f..564be38692 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java
@@ -213,12 +213,12 @@ public WxCpXmlOutMessage route(final String suiteId, final WxCpTpXmlMessage wxMe
}
}
- if (matchRules.size() == 0) {
+ if (matchRules.isEmpty()) {
return null;
}
WxCpXmlOutMessage res = null;
- final List futures = new ArrayList<>();
+ final List> futures = new ArrayList<>();
for (final WxCpTpMessageRouterRule rule : matchRules) {
// 返回最后一个非异步的rule的执行结果
if (rule.isAsync()) {
@@ -236,9 +236,9 @@ public WxCpXmlOutMessage route(final String suiteId, final WxCpTpXmlMessage wxMe
}
}
- if (futures.size() > 0) {
+ if (!futures.isEmpty()) {
this.executorService.submit(() -> {
- for (Future future : futures) {
+ for (Future> future : futures) {
try {
future.get();
log.debug("End session access: async=true, sessionId={}", wxMessage.getSuiteId());
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java
index 78c52d5c36..10268bcb31 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java
@@ -6,8 +6,6 @@
import me.chanjar.weixin.cp.bean.WxCpTpTagIdListConvertResult;
import me.chanjar.weixin.cp.bean.WxCpTpUnionidToExternalUseridResult;
-import java.util.List;
-
/**
*
* 企业微信三方应用ID转换接口
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
index 5c433c0b49..b24be535da 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
@@ -8,6 +8,7 @@
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;
import me.chanjar.weixin.cp.bean.*;
+import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import java.util.List;
@@ -186,6 +187,8 @@ public interface WxCpTpService {
@Deprecated
WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException;
+ WxCpTpCorp getV2PermanentCode(String authCode) throws WxErrorException;
+
/**
* 获取企业永久授权码信息
*
@@ -200,6 +203,8 @@ public interface WxCpTpService {
*/
WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxErrorException;
+ WxCpTpPermanentCodeInfo getV2PermanentCodeInfo(String authCode) throws WxErrorException;
+
/**
*
* 获取预授权链接
@@ -343,9 +348,7 @@ public interface WxCpTpService {
* 获取WxCpTpConfigStorage 对象.
*
* @return WxCpTpConfigStorage wx cp tp config storage
- * @deprecated storage应该在service内部使用 ,提供这个接口,容易破坏这个封装
*/
- @Deprecated
WxCpTpConfigStorage getWxCpTpConfigStorage();
/**
@@ -527,6 +530,11 @@ public interface WxCpTpService {
*/
WxCpTpLicenseService getWxCpTpLicenseService();
+ WxCpTpXmlMessage fromEncryptedXml(String encryptedXml,
+ String timestamp, String nonce, String msgSignature);
+
+ String getVerifyDecrypt(String sVerifyEchoStr);
+
/**
* 获取应用的管理员列表
*
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
index aa874f8549..f8f554b81a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
@@ -25,8 +25,10 @@
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.cp.bean.*;
+import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.tp.service.*;
+import me.chanjar.weixin.cp.util.crypto.WxCpTpCryptUtil;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
@@ -91,6 +93,7 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ
private final WxSessionManager sessionManager = new StandardSessionManager();
+
/**
* 临时文件目录.
*/
@@ -104,7 +107,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc
return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
.equals(msgSignature);
} catch (Exception e) {
- log.error("Checking signature failed, and the reason is :" + e.getMessage());
+ log.error("Checking signature failed, and the reason is :{}", e.getMessage());
return false;
}
}
@@ -259,6 +262,18 @@ public WxCpTpCorp getPermanentCode(String authCode) throws WxErrorException {
return wxCpTpCorp;
}
+ @Override
+ public WxCpTpCorp getV2PermanentCode(String authCode) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("auth_code", authCode);
+
+ String result = post(configStorage.getApiUrl(GET_V2_PERMANENT_CODE), jsonObject.toString());
+ jsonObject = GsonParser.parse(result);
+ WxCpTpCorp wxCpTpCorp = WxCpTpCorp.fromJson(jsonObject.get("auth_corp_info").getAsJsonObject().toString());
+ wxCpTpCorp.setPermanentCode(jsonObject.get("permanent_code").getAsString());
+ return wxCpTpCorp;
+ }
+
@Override
public WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
@@ -267,6 +282,14 @@ public WxCpTpPermanentCodeInfo getPermanentCodeInfo(String authCode) throws WxEr
return WxCpTpPermanentCodeInfo.fromJson(result);
}
+ @Override
+ public WxCpTpPermanentCodeInfo getV2PermanentCodeInfo(String authCode) throws WxErrorException {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("auth_code", authCode);
+ String result = post(configStorage.getApiUrl(GET_V2_PERMANENT_CODE), jsonObject.toString());
+ return WxCpTpPermanentCodeInfo.fromJson(result);
+ }
+
@Override
@SneakyThrows
public String getPreAuthUrl(String redirectUri, String state) throws WxErrorException {
@@ -452,7 +475,7 @@ protected T executeInternal(RequestExecutor executor, String uri, E
if (error.getErrorCode() == WxCpErrorMsgEnum.CODE_42009.getCode()) {
// 强制设置wxCpTpConfigStorage它的suite access token过期了,这样在下一次请求里就会刷新suite access token
this.configStorage.expireSuiteAccessToken();
- if (this.getWxCpTpConfigStorage().autoRefreshToken()) {
+ if (this.configStorage.autoRefreshToken()) {
log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
return this.execute(executor, uri, data);
}
@@ -646,6 +669,27 @@ public void setWxCpTpUserService(WxCpTpUserService wxCpTpUserService) {
this.wxCpTpUserService = wxCpTpUserService;
}
+
+ /**
+ *
+ * @param encryptedXml the encrypted xml
+ * @param timestamp the timestamp
+ * @param nonce the nonce
+ * @param msgSignature the msg signature
+ * @return the wx cp tp xml message
+ */
+ @Override
+ public WxCpTpXmlMessage fromEncryptedXml(String encryptedXml,
+ String timestamp, String nonce, String msgSignature) {
+ return WxCpTpXmlMessage.fromEncryptedXml(encryptedXml,this.configStorage,timestamp,nonce,msgSignature);
+ }
+
+ @Override
+ public String getVerifyDecrypt(String sVerifyEchoStr) {
+ WxCpTpCryptUtil cryptUtil = new WxCpTpCryptUtil(this.configStorage);
+ return cryptUtil.decrypt(sVerifyEchoStr);
+ }
+
@Override
public WxCpTpAdmin getAdminList(String authCorpId, Integer agentId) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
@@ -764,4 +808,9 @@ public WxCpTpOAuth2Service getWxCpTpOAuth2Service() {
public void setWxCpTpOAuth2Service(WxCpTpOAuth2Service wxCpTpOAuth2Service) {
this.wxCpTpOAuth2Service = wxCpTpOAuth2Service;
}
+
+ @Override
+ public WxCpTpConfigStorage getWxCpTpConfigStorage() {
+ return this.configStorage;
+ }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java
index 7d0d80b452..6e14e6bbb9 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java
@@ -14,8 +14,6 @@
import me.chanjar.weixin.cp.tp.service.WxCpTpIdConvertService;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
-import java.util.List;
-
/**
* @author cocoa
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
index a128afd7e6..a287513331 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
@@ -1,27 +1,25 @@
package me.chanjar.weixin.cp.tp.service.impl;
-
import com.google.gson.JsonObject;
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.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
-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.StringEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
/**
* The type Wx cp tp service apache http client.
@@ -43,8 +41,8 @@ public HttpHost getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.APACHE_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.APACHE_HTTP;
}
@Override
@@ -65,23 +63,17 @@ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException
jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
- StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8);
+ StringEntity entity = new StringEntity(jsonObject.toString(), StandardCharsets.UTF_8);
httpPost.setEntity(entity);
- String resultContent;
- try (CloseableHttpClient httpclient = getRequestHttpClient();
- CloseableHttpResponse response = httpclient.execute(httpPost)) {
- resultContent = new BasicResponseHandler().handleResponse(response);
- } finally {
- httpPost.releaseConnection();
- }
+ String resultContent = getRequestHttpClient().execute(httpPost, ApacheBasicResponseHandler.INSTANCE);
WxError error = WxError.fromJson(resultContent, WxType.CP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
jsonObject = GsonParser.parse(resultContent);
String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
- Integer expiresIn = jsonObject.get("expires_in").getAsInt();
+ int expiresIn = jsonObject.get("expires_in").getAsInt();
this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
} catch (IOException e) {
throw new WxRuntimeException(e);
@@ -109,9 +101,9 @@ public void initHttp() {
this.httpClient = apacheHttpClientBuilder.build();
}
- @Override
- public WxCpTpConfigStorage getWxCpTpConfigStorage() {
- return this.configStorage;
- }
+// @Override
+// public WxCpTpConfigStorage getWxCpTpConfigStorage() {
+// return this.configStorage;
+// }
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceHttpComponentsImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..bba597a3ee
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceHttpComponentsImpl.java
@@ -0,0 +1,106 @@
+package me.chanjar.weixin.cp.tp.service.impl;
+
+import com.google.gson.JsonObject;
+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.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+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.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * The type Wx cp tp service apache http client.
+ *
+ * @author altusea
+ */
+public class WxCpTpServiceHttpComponentsImpl extends BaseWxCpTpServiceImpl {
+ private CloseableHttpClient httpClient;
+ private HttpHost httpProxy;
+
+ @Override
+ public CloseableHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public HttpHost getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.HTTP_COMPONENTS;
+ }
+
+ @Override
+ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) {
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ synchronized (this.globalSuiteAccessTokenRefreshLock) {
+ try {
+ HttpPost httpPost = new HttpPost(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN));
+ if (this.httpProxy != null) {
+ RequestConfig config = RequestConfig.custom()
+ .setProxy(this.httpProxy).build();
+ httpPost.setConfig(config);
+ }
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
+ jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
+ jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
+ StringEntity entity = new StringEntity(jsonObject.toString(), StandardCharsets.UTF_8);
+ httpPost.setEntity(entity);
+
+ String resultContent = getRequestHttpClient().execute(httpPost, BasicResponseHandler.INSTANCE);
+ WxError error = WxError.fromJson(resultContent, WxType.CP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ jsonObject = GsonParser.parse(resultContent);
+ String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
+ int expiresIn = jsonObject.get("expires_in").getAsInt();
+ this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
+ } catch (IOException e) {
+ throw new WxRuntimeException(e);
+ }
+ }
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ @Override
+ public void initHttp() {
+ HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+ apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
+ .httpProxyPort(this.configStorage.getHttpProxyPort())
+ .httpProxyUsername(this.configStorage.getHttpProxyUsername())
+ .httpProxyPassword(this.configStorage.getHttpProxyPassword().toCharArray());
+
+ if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+ this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
+ }
+
+ this.httpClient = apacheHttpClientBuilder.build();
+ }
+
+// @Override
+// public WxCpTpConfigStorage getWxCpTpConfigStorage() {
+// return this.configStorage;
+// }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceJoddHttpImpl.java
new file mode 100644
index 0000000000..9379f62e81
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceJoddHttpImpl.java
@@ -0,0 +1,104 @@
+package me.chanjar.weixin.cp.tp.service.impl;
+
+import com.google.gson.JsonObject;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.HttpRequest;
+import jodd.http.HttpResponse;
+import jodd.http.ProxyInfo;
+import jodd.http.net.SocketHttpConnectionProvider;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+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.HttpClientType;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+
+/**
+ * The type Wx cp service jodd http.
+ *
+ * @author someone
+ */
+public class WxCpTpServiceJoddHttpImpl extends BaseWxCpTpServiceImpl {
+ private HttpConnectionProvider httpClient;
+ private ProxyInfo httpProxy;
+
+ @Override
+ public HttpConnectionProvider getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public ProxyInfo getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.JODD_HTTP;
+ }
+
+ @Override
+ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) {
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ synchronized (this.globalSuiteAccessTokenRefreshLock) {
+ // 构建请求 URL
+ String url = this.configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN);
+
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
+ jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
+ jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
+ String jsonBody = jsonObject.toString();
+
+ if (this.httpProxy != null) {
+ httpClient.useProxy(this.httpProxy);
+ }
+ // 创建 POST 请求
+ HttpRequest request = HttpRequest
+ .post(url)
+ .contentType("application/json")
+ .body(jsonBody); // 使用 .body() 设置请求体
+
+ request.withConnectionProvider(httpClient);
+
+ // 发送请求
+ HttpResponse response = request.send();
+
+ // 解析响应
+ String resultContent = response.bodyText();
+ WxError error = WxError.fromJson(resultContent, WxType.CP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+
+ // 更新 access token
+ jsonObject = GsonParser.parse(resultContent);
+ String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
+ int expiresIn = jsonObject.get("expires_in").getAsInt();
+ this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
+ }
+
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ @Override
+ public void initHttp() {
+ if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+ httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(),
+ configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword());
+ }
+
+ httpClient = new SocketHttpConnectionProvider();
+ }
+//
+// @Override
+// public WxCpConfigStorage getWxCpConfigStorage() {
+// return this.configStorage;
+// }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java
new file mode 100644
index 0000000000..c4dab9cf20
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceOkHttpImpl.java
@@ -0,0 +1,130 @@
+package me.chanjar.weixin.cp.tp.service.impl;
+
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.WxAccessToken;
+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.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+import okhttp3.*;
+
+import java.io.IOException;
+
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.GET_TOKEN;
+
+/**
+ * The type Wx cp service ok http.
+ *
+ * @author someone
+ */
+@Slf4j
+public class WxCpTpServiceOkHttpImpl extends BaseWxCpTpServiceImpl {
+ private OkHttpClient httpClient;
+ private OkHttpProxyInfo httpProxy;
+
+ @Override
+ public OkHttpClient getRequestHttpClient() {
+ return httpClient;
+ }
+
+ @Override
+ public OkHttpProxyInfo getRequestHttpProxy() {
+ return httpProxy;
+ }
+
+ @Override
+ public HttpClientType getRequestType() {
+ return HttpClientType.OK_HTTP;
+ }
+
+ @Override
+ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException {
+ if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) {
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ synchronized (this.globalSuiteAccessTokenRefreshLock) {
+ // 得到 httpClient
+ OkHttpClient client = getRequestHttpClient();
+
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
+ jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
+ jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
+ String jsonBody = jsonObject.toString();
+
+ RequestBody requestBody = RequestBody.create(
+ MediaType.get("application/json; charset=utf-8"),
+ jsonBody
+ );
+
+ // 构建 POST 请求
+ Request request = new Request.Builder()
+ .url(this.configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN)) // URL 不包含查询参数
+ .post(requestBody) // 使用 POST 方法
+ .build();
+
+ String resultContent = null;
+ try (Response response = client.newCall(request).execute()) {
+ if (!response.isSuccessful()) {
+ throw new IOException("Unexpected response code: " + response);
+ }
+ resultContent = response.body().string();
+ } catch (IOException e) {
+ log.error("获取 suite token 失败: {}", e.getMessage(), e);
+ throw new WxRuntimeException("获取 suite token 失败", e);
+ }
+
+ WxError error = WxError.fromJson(resultContent, WxType.CP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+
+ jsonObject = GsonParser.parse(resultContent);
+ String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
+ int expiresIn = jsonObject.get("expires_in").getAsInt();
+ this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
+ }
+ return this.configStorage.getSuiteAccessToken();
+ }
+
+ @Override
+ public void initHttp() {
+ log.debug("WxCpServiceOkHttpImpl initHttp");
+ //设置代理
+ if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
+ httpProxy = OkHttpProxyInfo.httpProxy(configStorage.getHttpProxyHost(),
+ configStorage.getHttpProxyPort(),
+ configStorage.getHttpProxyUsername(),
+ configStorage.getHttpProxyPassword());
+ OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
+ clientBuilder.proxy(getRequestHttpProxy().getProxy());
+ //设置授权
+ clientBuilder.proxyAuthenticator(new Authenticator() {
+ @Override
+ public Request authenticate(Route route, Response response) throws IOException {
+ String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
+ return response.request().newBuilder()
+ .header("Proxy-Authorization", credential)
+ .build();
+ }
+ });
+ httpClient = clientBuilder.build();
+ } else {
+ httpClient = DefaultOkHttpClientBuilder.get().build();
+ }
+ }
+
+// @Override
+// public WxCpConfigStorage getWxCpConfigStorage() {
+// return this.configStorage;
+// }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java
index ac6097446a..4e9783e3e8 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpTpCryptUtil.java
@@ -23,7 +23,7 @@ public WxCpTpCryptUtil(WxCpTpConfigStorage wxCpTpConfigStorage) {
* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
* @param appidOrCorpid 公众平台corpId
*/
- String encodingAesKey = wxCpTpConfigStorage.getAesKey();
+ String encodingAesKey = wxCpTpConfigStorage.getEncodingAESKey();
String token = wxCpTpConfigStorage.getToken();
String corpId = wxCpTpConfigStorage.getCorpId();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
index e3a03ffab3..0e78465ead 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.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.cp.util.json;
import com.google.gson.*;
@@ -23,46 +15,44 @@
*/
public class WxCpChatGsonAdapter implements JsonSerializer, JsonDeserializer {
+ public static final String FIELD_CHAT_ID = "chatid";
+ public static final String FIELD_NAME = "name";
+ public static final String FIELD_OWNER = "owner";
+ public static final String FIELD_USER_LIST = "userlist";
+
@Override
public JsonElement serialize(WxCpChat chat, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
- if (chat.getId() != null) {
- json.addProperty("chatid", chat.getId());
- }
- if (chat.getName() != null) {
- json.addProperty("name", chat.getName());
- }
- if (chat.getOwner() != null) {
- json.addProperty("owner", chat.getOwner());
- }
- if (chat.getUsers() != null) {
+ addPropertyIfNotNull(json, FIELD_CHAT_ID, chat.getId());
+ addPropertyIfNotNull(json, FIELD_NAME, chat.getName());
+ addPropertyIfNotNull(json, FIELD_OWNER, chat.getOwner());
+ if (chat.getUsers() != null && !chat.getUsers().isEmpty()) {
JsonArray users = new JsonArray();
- for (String user : chat.getUsers()) {
- users.add(user);
- }
- json.add("userlist", users);
+ chat.getUsers().forEach(users::add);
+ json.add(FIELD_USER_LIST, users);
}
return json;
}
+ private void addPropertyIfNotNull(JsonObject json, String key, String value) {
+ if (value != null) {
+ json.addProperty(key, value);
+ }
+ }
+
@Override
public WxCpChat deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject chatJson = json.getAsJsonObject();
-
WxCpChat chat = new WxCpChat();
chat.setId(GsonHelper.getAsString(chatJson.get("chatid")));
chat.setName(GsonHelper.getAsString(chatJson.get("name")));
chat.setOwner(GsonHelper.getAsString(chatJson.get("owner")));
-
JsonArray usersJson = chatJson.getAsJsonArray("userlist");
- if (usersJson != null) {
+ if (usersJson != null && !usersJson.isEmpty()) {
List users = new ArrayList<>(usersJson.size());
+ usersJson.forEach(e -> users.add(e.getAsString()));
chat.setUsers(users);
- for (JsonElement userJson : usersJson) {
- users.add(userJson.getAsString());
- }
}
-
return chat;
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
index af9344b701..72d367c431 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.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.cp.util.json;
import com.google.gson.*;
@@ -13,6 +5,8 @@
import me.chanjar.weixin.cp.bean.WxCpDepart;
import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Objects;
/**
* WxCpDepart的gson适配器.
@@ -30,60 +24,47 @@ public class WxCpDepartGsonAdapter implements JsonSerializer, JsonDe
@Override
public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
- if (group.getId() != null) {
- json.addProperty(ID, group.getId());
- }
- if (group.getName() != null) {
- json.addProperty(NAME, group.getName());
- }
- if (group.getEnName() != null) {
- json.addProperty(EN_NAME, group.getEnName());
- }
- if (group.getDepartmentLeader() != null) {
+ addPropertyIfNotNull(json, ID, group.getId());
+ addPropertyIfNotNull(json, NAME, group.getName());
+ addPropertyIfNotNull(json, EN_NAME, group.getEnName());
+ if (group.getDepartmentLeader() != null && group.getDepartmentLeader().length > 0) {
JsonArray jsonArray = new JsonArray();
- for (String department : group.getDepartmentLeader()) {
- jsonArray.add(new JsonPrimitive(department));
- }
+ Arrays.stream(group.getDepartmentLeader()).filter(Objects::nonNull).forEach(jsonArray::add);
json.add(DEPARTMENT_LEADER, jsonArray);
}
- if (group.getParentId() != null) {
- json.addProperty(PARENT_ID, group.getParentId());
- }
- if (group.getOrder() != null) {
- json.addProperty(ORDER, String.valueOf(group.getOrder()));
- }
+ addPropertyIfNotNull(json, PARENT_ID, group.getParentId());
+ addPropertyIfNotNull(json, ORDER, group.getOrder());
return json;
}
+ private void addPropertyIfNotNull(JsonObject json, String key, Object value) {
+ if (value != null) {
+ if (value instanceof Number) {
+ json.addProperty(key, (Number) value);
+ } else {
+ json.addProperty(key, value.toString());
+ }
+ }
+ }
+
@Override
public WxCpDepart deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
WxCpDepart depart = new WxCpDepart();
JsonObject departJson = json.getAsJsonObject();
- if (departJson.get(ID) != null && !departJson.get(ID).isJsonNull()) {
- depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
- }
- if (departJson.get(NAME) != null && !departJson.get(NAME).isJsonNull()) {
- depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
- }
- if (departJson.get(EN_NAME) != null && !departJson.get(EN_NAME).isJsonNull()) {
- depart.setEnName(GsonHelper.getAsString(departJson.get(EN_NAME)));
- }
- if (departJson.getAsJsonArray(DEPARTMENT_LEADER) != null && !departJson.get(DEPARTMENT_LEADER).isJsonNull()) {
- JsonArray jsonArray = departJson.getAsJsonArray(DEPARTMENT_LEADER);
+ depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
+ depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
+ depart.setEnName(GsonHelper.getAsString(departJson.get(EN_NAME)));
+ JsonArray jsonArray = departJson.getAsJsonArray(DEPARTMENT_LEADER);
+ if (jsonArray != null && !jsonArray.isJsonNull()) {
String[] departments = new String[jsonArray.size()];
- int i = 0;
- for (JsonElement jsonElement : jsonArray) {
- departments[i++] = jsonElement.getAsString();
+ for (int i = 0; i < jsonArray.size(); i++) {
+ departments[i] = jsonArray.get(i).getAsString();
}
depart.setDepartmentLeader(departments);
}
- if (departJson.get(ORDER) != null && !departJson.get(ORDER).isJsonNull()) {
- depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
- }
- if (departJson.get(PARENT_ID) != null && !departJson.get(PARENT_ID).isJsonNull()) {
- depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
- }
+ depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
+ depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
return depart;
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java
index 7b53aa337a..48228a0686 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpGsonBuilder.java
@@ -1,9 +1,12 @@
package me.chanjar.weixin.cp.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.menu.WxMenu;
import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.json.WxErrorAdapter;
import me.chanjar.weixin.cp.bean.WxCpChat;
import me.chanjar.weixin.cp.bean.WxCpDepart;
@@ -11,6 +14,7 @@
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.bean.kf.WxCpKfGetCorpStatisticResp;
+import java.io.File;
import java.util.Objects;
/**
@@ -32,6 +36,18 @@ public class WxCpGsonBuilder {
INSTANCE.registerTypeAdapter(WxMenu.class, new WxCpMenuGsonAdapter());
INSTANCE.registerTypeAdapter(WxCpTag.class, new WxCpTagGsonAdapter());
INSTANCE.registerTypeAdapter(WxCpKfGetCorpStatisticResp.StatisticList.class, new StatisticListAdapter());
+
+ 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;
+ }
+ });
}
/**
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java
index 41a5b78400..2f830f7166 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.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.cp.util.json;
import com.google.gson.*;
@@ -21,19 +13,28 @@
*/
public class WxCpTagGsonAdapter implements JsonSerializer, JsonDeserializer {
+ private static final String TAG_ID = "tagid";
+ private static final String TAG_NAME = "tagname";
+
@Override
public JsonElement serialize(WxCpTag tag, Type typeOfSrc, JsonSerializationContext context) {
JsonObject o = new JsonObject();
- o.addProperty("tagid", tag.getId());
- o.addProperty("tagname", tag.getName());
+ addPropertyIfNotNull(o, TAG_ID, tag.getId());
+ addPropertyIfNotNull(o, TAG_NAME, tag.getName());
return o;
}
+ private void addPropertyIfNotNull(JsonObject obj, String key, String value) {
+ if (value != null) {
+ obj.addProperty(key, value);
+ }
+ }
+
@Override
public WxCpTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
- return new WxCpTag(GsonHelper.getString(jsonObject, "tagid"), GsonHelper.getString(jsonObject, "tagname"));
+ return new WxCpTag(GsonHelper.getString(jsonObject, TAG_ID), GsonHelper.getString(jsonObject, TAG_NAME));
}
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
index 0c32ba0060..1df32b8601 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
@@ -1,12 +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.cp.util.json;
import com.google.gson.*;
@@ -15,6 +6,8 @@
import me.chanjar.weixin.cp.bean.WxCpUser;
import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.stream.IntStream;
import static me.chanjar.weixin.cp.bean.WxCpUser.*;
@@ -31,66 +24,78 @@ public class WxCpUserGsonAdapter implements JsonDeserializer, JsonSeri
private static final String DEPARTMENT = "department";
private static final String EXTERNAL_CORP_NAME = "external_corp_name";
private static final String WECHAT_CHANNELS = "wechat_channels";
+ private static final String ORDER = "order";
+ private static final String POSITIONS = "positions";
+ private static final String USER_ID = "userid";
+ private static final String NEW_USER_ID = "new_userid";
+ private static final String NAME = "name";
+ private static final String POSITION = "position";
+ private static final String MOBILE = "mobile";
+ private static final String GENDER = "gender";
+ private static final String EMAIL = "email";
+ private static final String BIZ_MAIL = "biz_mail";
+ private static final String AVATAR = "avatar";
+ private static final String THUMB_AVATAR = "thumb_avatar";
+ private static final String ADDRESS = "address";
+ private static final String AVATAR_MEDIAID = "avatar_mediaid";
+ private static final String STATUS = "status";
+ private static final String ENABLE = "enable";
+ private static final String ALIAS = "alias";
+ private static final String IS_LEADER = "isleader";
+ private static final String IS_LEADER_IN_DEPT = "is_leader_in_dept";
+ private static final String HIDE_MOBILE = "hide_mobile";
+ private static final String ENGLISH_NAME = "english_name";
+ private static final String TELEPHONE = "telephone";
+ private static final String QR_CODE = "qr_code";
+ private static final String TO_INVITE = "to_invite";
+ private static final String OPEN_USER_ID = "open_userid";
+ private static final String MAIN_DEPARTMENT = "main_department";
+ private static final String DIRECT_LEADER = "direct_leader";
+ private static final String TYPE = "type";
+ private static final String VALUE = "value";
+ private static final String TEXT = "text";
+ private static final String WEB = "web";
+ private static final String MINIPROGRAM = "miniprogram";
+ private static final String URL = "url";
+ private static final String TITLE = "title";
+ private static final String APPID = "appid";
+ private static final String PAGE_PATH = "pagepath";
+ private static final String ATTRS = "attrs";
+ private static final String NICKNAME = "nickname";
@Override
public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject o = json.getAsJsonObject();
WxCpUser user = new WxCpUser();
- if (o.get(DEPARTMENT) != null) {
- JsonArray departJsonArray = o.get(DEPARTMENT).getAsJsonArray();
- Long[] departIds = new Long[departJsonArray.size()];
- int i = 0;
- for (JsonElement jsonElement : departJsonArray) {
- departIds[i++] = jsonElement.getAsLong();
- }
- user.setDepartIds(departIds);
- }
-
- if (o.get("order") != null) {
- JsonArray departJsonArray = o.get("order").getAsJsonArray();
- Integer[] orders = new Integer[departJsonArray.size()];
- int i = 0;
- for (JsonElement jsonElement : departJsonArray) {
- orders[i++] = jsonElement.getAsInt();
- }
- user.setOrders(orders);
- }
-
- if (o.get("positions") != null) {
- JsonArray positionJsonArray = o.get("positions").getAsJsonArray();
- String[] positions = new String[positionJsonArray.size()];
- int i = 0;
- for (JsonElement jsonElement : positionJsonArray) {
- positions[i++] = jsonElement.getAsString();
- }
- user.setPositions(positions);
- }
-
- user.setUserId(GsonHelper.getString(o, "userid"));
- user.setName(GsonHelper.getString(o, "name"));
- user.setPosition(GsonHelper.getString(o, "position"));
- user.setMobile(GsonHelper.getString(o, "mobile"));
- user.setGender(Gender.fromCode(GsonHelper.getString(o, "gender")));
- user.setEmail(GsonHelper.getString(o, "email"));
- user.setBizMail(GsonHelper.getString(o, "biz_mail"));
- user.setAvatar(GsonHelper.getString(o, "avatar"));
- user.setThumbAvatar(GsonHelper.getString(o, "thumb_avatar"));
- user.setAddress(GsonHelper.getString(o, "address"));
- user.setAvatarMediaId(GsonHelper.getString(o, "avatar_mediaid"));
- user.setStatus(GsonHelper.getInteger(o, "status"));
- user.setEnable(GsonHelper.getInteger(o, "enable"));
- user.setAlias(GsonHelper.getString(o, "alias"));
- user.setIsLeader(GsonHelper.getInteger(o, "isleader"));
- user.setIsLeaderInDept(GsonHelper.getIntArray(o, "is_leader_in_dept"));
- user.setHideMobile(GsonHelper.getInteger(o, "hide_mobile"));
- user.setEnglishName(GsonHelper.getString(o, "english_name"));
- user.setTelephone(GsonHelper.getString(o, "telephone"));
- user.setQrCode(GsonHelper.getString(o, "qr_code"));
- user.setToInvite(GsonHelper.getBoolean(o, "to_invite"));
- user.setOpenUserId(GsonHelper.getString(o, "open_userid"));
- user.setMainDepartment(GsonHelper.getString(o, "main_department"));
- user.setDirectLeader(GsonHelper.getStringArray(o, "direct_leader"));
+ user.setDepartIds(parseJsonArrayToLongArray(o, DEPARTMENT));
+ user.setOrders(parseJsonArrayToIntegerArray(o, ORDER));
+ user.setPositions(parseJsonArrayToStringArray(o, POSITIONS));
+
+ user.setUserId(GsonHelper.getString(o, USER_ID));
+ user.setName(GsonHelper.getString(o, NAME));
+ user.setPosition(GsonHelper.getString(o, POSITION));
+ user.setMobile(GsonHelper.getString(o, MOBILE));
+ user.setGender(Gender.fromCode(GsonHelper.getString(o, GENDER)));
+ user.setEmail(GsonHelper.getString(o, EMAIL));
+ user.setBizMail(GsonHelper.getString(o, BIZ_MAIL));
+ user.setAvatar(GsonHelper.getString(o, AVATAR));
+ user.setThumbAvatar(GsonHelper.getString(o, THUMB_AVATAR));
+ user.setAddress(GsonHelper.getString(o, ADDRESS));
+ user.setAvatarMediaId(GsonHelper.getString(o, AVATAR_MEDIAID));
+ user.setStatus(GsonHelper.getInteger(o, STATUS));
+ user.setEnable(GsonHelper.getInteger(o, ENABLE));
+ user.setAlias(GsonHelper.getString(o, ALIAS));
+ user.setIsLeader(GsonHelper.getInteger(o, IS_LEADER));
+ user.setIsLeaderInDept(GsonHelper.getIntArray(o, IS_LEADER_IN_DEPT));
+ user.setHideMobile(GsonHelper.getInteger(o, HIDE_MOBILE));
+ user.setEnglishName(GsonHelper.getString(o, ENGLISH_NAME));
+ user.setTelephone(GsonHelper.getString(o, TELEPHONE));
+ user.setQrCode(GsonHelper.getString(o, QR_CODE));
+ user.setToInvite(GsonHelper.getBoolean(o, TO_INVITE));
+ user.setOpenUserId(GsonHelper.getString(o, OPEN_USER_ID));
+ user.setMainDepartment(GsonHelper.getString(o, MAIN_DEPARTMENT));
+ user.setDirectLeader(GsonHelper.getStringArray(o, DIRECT_LEADER));
if (GsonHelper.isNotNull(o.get(EXTRA_ATTR))) {
this.buildExtraAttrs(o, user);
@@ -102,8 +107,9 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
JsonElement jsonElement = o.get(EXTERNAL_PROFILE).getAsJsonObject().get(WECHAT_CHANNELS);
if (jsonElement != null) {
JsonObject asJsonObject = jsonElement.getAsJsonObject();
- user.setWechatChannels(WechatChannels.builder().nickname(GsonHelper.getString(asJsonObject, "nickname")).status(GsonHelper.getInteger(asJsonObject, "status")).build());
+ user.setWechatChannels(WechatChannels.builder().nickname(GsonHelper.getString(asJsonObject, NICKNAME)).status(GsonHelper.getInteger(asJsonObject, STATUS)).build());
}
+
this.buildExternalAttrs(o, user);
}
@@ -112,29 +118,66 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
return user;
}
+ private Long[] parseJsonArrayToLongArray(JsonObject o, String key) {
+ JsonElement element = o.get(key);
+ if (element == null || !element.isJsonArray()) {
+ return null;
+ }
+ JsonArray jsonArray = element.getAsJsonArray();
+ return IntStream.range(0, jsonArray.size())
+ .mapToObj(i -> jsonArray.get(i).getAsLong())
+ .toArray(Long[]::new);
+ }
+
+ private Integer[] parseJsonArrayToIntegerArray(JsonObject o, String key) {
+ JsonElement element = o.get(key);
+ if (element == null || !element.isJsonArray()) {
+ return null;
+ }
+ JsonArray jsonArray = element.getAsJsonArray();
+ return IntStream.range(0, jsonArray.size())
+ .mapToObj(i -> jsonArray.get(i).getAsInt())
+ .toArray(Integer[]::new);
+ }
+
+ private String[] parseJsonArrayToStringArray(JsonObject o, String key) {
+ JsonElement element = o.get(key);
+ if (element == null || !element.isJsonArray()) {
+ return null;
+ }
+ JsonArray jsonArray = element.getAsJsonArray();
+ return IntStream.range(0, jsonArray.size())
+ .mapToObj(i -> jsonArray.get(i).getAsString())
+ .toArray(String[]::new);
+ }
+
private void buildExtraAttrs(JsonObject o, WxCpUser user) {
- JsonArray attrJsonElements = o.get(EXTRA_ATTR).getAsJsonObject().get("attrs").getAsJsonArray();
+ JsonArray attrJsonElements = o.get(EXTRA_ATTR).getAsJsonObject().get(ATTRS).getAsJsonArray();
for (JsonElement attrJsonElement : attrJsonElements) {
- final Integer type = GsonHelper.getInteger(attrJsonElement.getAsJsonObject(), "type");
+ final Integer type = GsonHelper.getInteger(attrJsonElement.getAsJsonObject(), TYPE);
final Attr attr = new Attr().setType(type)
- .setName(GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"));
+ .setName(GsonHelper.getString(attrJsonElement.getAsJsonObject(), NAME));
user.getExtAttrs().add(attr);
if (type == null) {
- attr.setTextValue(GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value"));
+ attr.setTextValue(GsonHelper.getString(attrJsonElement.getAsJsonObject(), VALUE));
continue;
}
switch (type) {
case 0: {
- attr.setTextValue(GsonHelper.getString(attrJsonElement.getAsJsonObject().get("text").getAsJsonObject(),
- "value"));
+ JsonElement textJsonElement = attrJsonElement.getAsJsonObject().get(TEXT);
+ if (textJsonElement != null && !textJsonElement.isJsonNull() && textJsonElement.isJsonObject()) {
+ attr.setTextValue(GsonHelper.getString(textJsonElement.getAsJsonObject(), VALUE));
+ } else {
+ attr.setTextValue(null); // Clear or set a default value to avoid stale data
+ }
break;
}
case 1: {
- final JsonObject web = attrJsonElement.getAsJsonObject().get("web").getAsJsonObject();
- attr.setWebTitle(GsonHelper.getString(web, "title"))
- .setWebUrl(GsonHelper.getString(web, "url"));
+ final JsonObject web = attrJsonElement.getAsJsonObject().get(WEB).getAsJsonObject();
+ attr.setWebTitle(GsonHelper.getString(web, TITLE))
+ .setWebUrl(GsonHelper.getString(web, URL));
break;
}
default://ignored
@@ -150,8 +193,8 @@ private void buildExternalAttrs(JsonObject o, WxCpUser user) {
JsonArray attrJsonElements = jsonElement.getAsJsonArray();
for (JsonElement element : attrJsonElements) {
- final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), "type");
- final String name = GsonHelper.getString(element.getAsJsonObject(), "name");
+ final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), TYPE);
+ final String name = GsonHelper.getString(element.getAsJsonObject(), NAME);
if (type == null) {
continue;
@@ -163,32 +206,32 @@ private void buildExternalAttrs(JsonObject o, WxCpUser user) {
.add(ExternalAttribute.builder()
.type(type)
.name(name)
- .value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value"))
+ .value(GsonHelper.getString(element.getAsJsonObject().get(TEXT).getAsJsonObject(), VALUE))
.build()
);
break;
}
case 1: {
- final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject();
+ final JsonObject web = element.getAsJsonObject().get(WEB).getAsJsonObject();
user.getExternalAttrs()
.add(ExternalAttribute.builder()
.type(type)
.name(name)
- .url(GsonHelper.getString(web, "url"))
- .title(GsonHelper.getString(web, "title"))
+ .url(GsonHelper.getString(web, URL))
+ .title(GsonHelper.getString(web, TITLE))
.build()
);
break;
}
case 2: {
- final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject();
+ final JsonObject miniprogram = element.getAsJsonObject().get(MINIPROGRAM).getAsJsonObject();
user.getExternalAttrs()
.add(ExternalAttribute.builder()
.type(type)
.name(name)
- .appid(GsonHelper.getString(miniprogram, "appid"))
- .pagePath(GsonHelper.getString(miniprogram, "pagepath"))
- .title(GsonHelper.getString(miniprogram, "title"))
+ .appid(GsonHelper.getString(miniprogram, APPID))
+ .pagePath(GsonHelper.getString(miniprogram, PAGE_PATH))
+ .title(GsonHelper.getString(miniprogram, TITLE))
.build()
);
break;
@@ -201,97 +244,75 @@ private void buildExternalAttrs(JsonObject o, WxCpUser user) {
@Override
public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationContext context) {
JsonObject o = new JsonObject();
- this.addProperty(o, "userid", user.getUserId());
- this.addProperty(o, "new_userid", user.getNewUserId());
- this.addProperty(o, "name", user.getName());
- if (user.getDepartIds() != null) {
- JsonArray jsonArray = new JsonArray();
- for (Long departId : user.getDepartIds()) {
- jsonArray.add(new JsonPrimitive(departId));
- }
- o.add("department", jsonArray);
- }
-
- if (user.getOrders() != null) {
- JsonArray jsonArray = new JsonArray();
- for (Integer order : user.getOrders()) {
- jsonArray.add(new JsonPrimitive(order));
- }
- o.add("order", jsonArray);
- }
+ addProperty(o, USER_ID, user.getUserId());
+ addProperty(o, NEW_USER_ID, user.getNewUserId());
+ addProperty(o, NAME, user.getName());
- this.addProperty(o, "position", user.getPosition());
-
- if (user.getPositions() != null) {
- JsonArray jsonArray = new JsonArray();
- for (String position : user.getPositions()) {
- jsonArray.add(new JsonPrimitive(position));
- }
- o.add("positions", jsonArray);
- }
+ addArrayProperty(o, DEPARTMENT, user.getDepartIds());
+ addArrayProperty(o, ORDER, user.getOrders());
+ addProperty(o, POSITION, user.getPosition());
+ addArrayProperty(o, POSITIONS, user.getPositions());
- this.addProperty(o, "mobile", user.getMobile());
+ addProperty(o, MOBILE, user.getMobile());
if (user.getGender() != null) {
- o.addProperty("gender", user.getGender().getCode());
+ o.addProperty(GENDER, user.getGender().getCode());
}
- this.addProperty(o, "email", user.getEmail());
- this.addProperty(o, "biz_mail", user.getBizMail());
- this.addProperty(o, "avatar", user.getAvatar());
- this.addProperty(o, "thumb_avatar", user.getThumbAvatar());
- this.addProperty(o, "address", user.getAddress());
- this.addProperty(o, "avatar_mediaid", user.getAvatarMediaId());
- this.addProperty(o, "status", user.getStatus());
- this.addProperty(o, "enable", user.getEnable());
- this.addProperty(o, "alias", user.getAlias());
- this.addProperty(o, "isleader", user.getIsLeader());
+ addProperty(o, EMAIL, user.getEmail());
+ addProperty(o, BIZ_MAIL, user.getBizMail());
+ addProperty(o, AVATAR, user.getAvatar());
+ addProperty(o, THUMB_AVATAR, user.getThumbAvatar());
+ addProperty(o, ADDRESS, user.getAddress());
+ addProperty(o, AVATAR_MEDIAID, user.getAvatarMediaId());
+ addProperty(o, STATUS, user.getStatus());
+ addProperty(o, ENABLE, user.getEnable());
+ addProperty(o, ALIAS, user.getAlias());
+ addProperty(o, IS_LEADER, user.getIsLeader());
if (user.getIsLeaderInDept() != null && user.getIsLeaderInDept().length > 0) {
JsonArray ary = new JsonArray();
- for (int item : user.getIsLeaderInDept()) {
- ary.add(item);
- }
- o.add("is_leader_in_dept", ary);
+ Arrays.stream(user.getIsLeaderInDept()).forEach(ary::add);
+ o.add(IS_LEADER_IN_DEPT, ary);
}
- this.addProperty(o, "hide_mobile", user.getHideMobile());
- this.addProperty(o, "english_name", user.getEnglishName());
- this.addProperty(o, "telephone", user.getTelephone());
- this.addProperty(o, "qr_code", user.getQrCode());
+ addProperty(o, HIDE_MOBILE, user.getHideMobile());
+ addProperty(o, ENGLISH_NAME, user.getEnglishName());
+ addProperty(o, TELEPHONE, user.getTelephone());
+ addProperty(o, QR_CODE, user.getQrCode());
if (user.getToInvite() != null) {
- o.addProperty("to_invite", user.getToInvite());
+ o.addProperty(TO_INVITE, user.getToInvite());
}
- this.addProperty(o, "main_department", user.getMainDepartment());
+ addProperty(o, MAIN_DEPARTMENT, user.getMainDepartment());
- if (user.getDirectLeader() != null && user.getDirectLeader().length > 0) {
- JsonArray ary = new JsonArray();
- for (String item : user.getDirectLeader()) {
- ary.add(item);
- }
- o.add("direct_leader", ary);
+ // Special handling for directLeader: include empty arrays to support WeChat Work API reset functionality
+ if (user.getDirectLeader() != null) {
+ JsonArray directLeaderArray = new JsonArray();
+ Arrays.stream(user.getDirectLeader()).forEach(directLeaderArray::add);
+ o.add(DIRECT_LEADER, directLeaderArray);
}
+
if (!user.getExtAttrs().isEmpty()) {
JsonArray attrsJsonArray = new JsonArray();
for (Attr attr : user.getExtAttrs()) {
- JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(),
- "name", attr.getName());
+ JsonObject attrJson = GsonHelper.buildJsonObject(TYPE, attr.getType(),
+ NAME, attr.getName());
attrsJsonArray.add(attrJson);
if (attr.getType() == null) {
- attrJson.addProperty("name", attr.getName());
- attrJson.addProperty("value", attr.getTextValue());
+ attrJson.addProperty(NAME, attr.getName());
+ attrJson.addProperty(VALUE, attr.getTextValue());
continue;
}
switch (attr.getType()) {
case 0:
- attrJson.add("text", GsonHelper.buildJsonObject("value", attr.getTextValue()));
+ attrJson.add(TEXT, GsonHelper.buildJsonObject(VALUE, attr.getTextValue()));
break;
case 1:
- attrJson.add("web", GsonHelper.buildJsonObject("url", attr.getWebUrl(), "title", attr.getWebTitle()));
+ attrJson.add(WEB, GsonHelper.buildJsonObject(URL, attr.getWebUrl(), TITLE, attr.getWebTitle()));
break;
default: //ignored
}
}
JsonObject attrsJson = new JsonObject();
- attrsJson.add("attrs", attrsJsonArray);
+ attrsJson.add(ATTRS, attrsJsonArray);
o.add(EXTRA_ATTR, attrsJson);
}
@@ -303,15 +324,15 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
this.addProperty(attrsJson, EXTERNAL_CORP_NAME, user.getExternalCorpName());
if (user.getWechatChannels() != null) {
- attrsJson.add(WECHAT_CHANNELS, GsonHelper.buildJsonObject("nickname", user.getWechatChannels().getNickname(),
- "status", user.getWechatChannels().getStatus()));
+ attrsJson.add(WECHAT_CHANNELS, GsonHelper.buildJsonObject(NICKNAME, user.getWechatChannels().getNickname(),
+ STATUS, user.getWechatChannels().getStatus()));
}
if (!user.getExternalAttrs().isEmpty()) {
JsonArray attrsJsonArray = new JsonArray();
for (ExternalAttribute attr : user.getExternalAttrs()) {
- JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(),
- "name", attr.getName());
+ JsonObject attrJson = GsonHelper.buildJsonObject(TYPE, attr.getType(),
+ NAME, attr.getName());
attrsJsonArray.add(attrJson);
@@ -321,14 +342,14 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
switch (attr.getType()) {
case 0:
- attrJson.add("text", GsonHelper.buildJsonObject("value", attr.getValue()));
+ attrJson.add(TEXT, GsonHelper.buildJsonObject(VALUE, attr.getValue()));
break;
case 1:
- attrJson.add("web", GsonHelper.buildJsonObject("url", attr.getUrl(), "title", attr.getTitle()));
+ attrJson.add(WEB, GsonHelper.buildJsonObject(URL, attr.getUrl(), TITLE, attr.getTitle()));
break;
case 2:
- attrJson.add("miniprogram", GsonHelper.buildJsonObject("appid", attr.getAppid(),
- "pagepath", attr.getPagePath(), "title", attr.getTitle()));
+ attrJson.add(MINIPROGRAM, GsonHelper.buildJsonObject(APPID, attr.getAppid(),
+ PAGE_PATH, attr.getPagePath(), TITLE, attr.getTitle()));
break;
default://忽略
}
@@ -340,15 +361,29 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
return o;
}
- private void addProperty(JsonObject object, String property, Integer value) {
- if (value != null) {
- object.addProperty(property, value);
+ private void addArrayProperty(JsonObject o, String key, Object[] array) {
+ if (array != null && array.length > 0) {
+ JsonArray jsonArray = new JsonArray();
+ Arrays.stream(array).forEach(item -> {
+ if (item instanceof Number) {
+ jsonArray.add((Number) item);
+ } else {
+ jsonArray.add(item.toString());
+ }
+ });
+ o.add(key, jsonArray);
}
}
- private void addProperty(JsonObject object, String property, String value) {
+ private void addProperty(JsonObject object, String property, Object value) {
if (value != null) {
- object.addProperty(property, value);
+ if (value instanceof Number) {
+ object.addProperty(property, (Number) value);
+ } else if (value instanceof Boolean) {
+ object.addProperty(property, (Boolean) value);
+ } else {
+ object.addProperty(property, value.toString());
+ }
}
}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
index c4753befd2..098a781c64 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
@@ -17,7 +17,7 @@ public class XStreamTransformer {
/**
* The constant CLASS_2_XSTREAM_INSTANCE.
*/
- protected static final Map CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();
+ protected static final Map, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();
/**
* xml -> pojo
@@ -53,7 +53,7 @@ public static T fromXml(Class clazz, InputStream is) {
* @param clz 类型
* @param xStream xml解析器
*/
- public static void register(Class clz, XStream xStream) {
+ public static void register(Class> clz, XStream xStream) {
CLASS_2_XSTREAM_INSTANCE.put(clz, xStream);
}
@@ -69,8 +69,8 @@ public static String toXml(Class clazz, T object) {
return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);
}
- private static Map configXStreamInstance() {
- Map map = new HashMap<>();
+ private static Map, XStream> configXStreamInstance() {
+ Map, XStream> map = new HashMap<>();
map.put(WxCpXmlMessage.class, configWxCpXmlMessage());
map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage());
map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage());
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java
index bd7599061d..1364ab5a13 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java
@@ -59,13 +59,13 @@ public void test() throws Exception {
/*
* 获取分享链接
*/
- WxCpFileShare fileShare = cpService.getOaWeDriveService().fileShare(uId, fileId2);
+ WxCpFileShare fileShare = cpService.getOaWeDriveService().fileShare(fileId2);
log.info("获取分享链接返回结果为:{}", fileShare.toJson());
/*
* 分享设置
*/
- WxCpBaseResp fileSetting = cpService.getOaWeDriveService().fileSetting(uId, fileId2, 2, 1);
+ WxCpBaseResp fileSetting = cpService.getOaWeDriveService().fileSetting(fileId2, 2, 1);
log.info("分享设置返回结果为:{}", fileSetting.toJson());
/*
@@ -200,13 +200,13 @@ public void test() throws Exception {
/*
* 获取邀请链接
*/
- WxCpSpaceShare spaceShare = cpService.getOaWeDriveService().spaceShare(uId, spId);
+ WxCpSpaceShare spaceShare = cpService.getOaWeDriveService().spaceShare(spId);
log.info("获取邀请链接信息为:{}", spaceShare.toJson());
/*
* 获取空间信息
*/
- WxCpSpaceInfo data = cpService.getOaWeDriveService().spaceInfo(uId, spId);
+ WxCpSpaceInfo data = cpService.getOaWeDriveService().spaceInfo(spId);
log.info("获取空间信息为:{}", data.toJson());
/*
@@ -252,7 +252,7 @@ public void test() throws Exception {
/*
* 获取空间信息
*/
- WxCpSpaceInfo spaceInfo = cpService.getOaWeDriveService().spaceInfo("WangKai", "s.ww45d3e188865aca30.652091685u4h");
+ WxCpSpaceInfo spaceInfo = cpService.getOaWeDriveService().spaceInfo("s.ww45d3e188865aca30.652091685u4h");
log.info("获取空间信息,spaceInfo信息为:{}", spaceInfo.toJson());
/*
@@ -279,7 +279,7 @@ public void test() throws Exception {
/*
* 解散空间
*/
- WxCpBaseResp thisResp = cpService.getOaWeDriveService().spaceDismiss("WangKai", spaceCreateData.getSpaceId());
+ WxCpBaseResp thisResp = cpService.getOaWeDriveService().spaceDismiss(spaceCreateData.getSpaceId());
log.info("解散成功:{}", thisResp.toJson());
}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java
index c2b1dad933..6b861cedec 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java
@@ -4,7 +4,7 @@
import me.chanjar.weixin.common.error.WxError;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.error.WxMpErrorMsgEnum;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.WxCpService;
@@ -92,7 +92,7 @@ public Object getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
+ public HttpClientType getRequestType() {
return null;
}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
index c629165ca4..4bd80928bd 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
@@ -4,6 +4,9 @@
import com.google.common.collect.Lists;
import com.google.inject.Inject;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -90,6 +93,20 @@ public void testGetContactWay() throws WxErrorException {
assertNotNull(contactWayInfo);
}
+ /**
+ * Test list contact way.
+ *
+ * @throws WxErrorException the wx error exception
+ */
+ @Test
+ public void testListContactWay() throws WxErrorException {
+ long startTime = LocalDateTime.now().minusDays(1).toEpochSecond(ZoneOffset.of("+8"));
+ long endTime = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
+ WxCpContactWayList wxCpContactWayList = this.wxCpService.getExternalContactService().listContactWay(startTime, endTime, null, 100L);
+ System.out.println(wxCpContactWayList.toJson());
+ assertNotNull(wxCpContactWayList);
+ }
+
/**
* Test update contact way.
*
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpGroupRobotServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpGroupRobotServiceImplTest.java
index 8e0d87d82c..f66580cc94 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpGroupRobotServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpGroupRobotServiceImplTest.java
@@ -64,6 +64,51 @@ public void testSendMarkDown() throws WxErrorException {
robotService.sendMarkdown(content);
}
+ /**
+ * Test send mark down v2.
+ *
+ * @throws WxErrorException the wx error exception
+ */
+ @Test
+ public void testSendMarkDownV2() throws WxErrorException {
+ String content = "# 一、标题\n" +
+ "## 二级标题\n" +
+ "### 三级标题\n" +
+ "# 二、字体\n" +
+ "*斜体*\n" +
+ "\n" +
+ "**加粗**\n" +
+ "# 三、列表 \n" +
+ "- 无序列表 1 \n" +
+ "- 无序列表 2\n" +
+ " - 无序列表 2.1\n" +
+ " - 无序列表 2.2\n" +
+ "1. 有序列表 1\n" +
+ "2. 有序列表 2\n" +
+ "# 四、引用\n" +
+ "> 一级引用\n" +
+ ">>二级引用\n" +
+ ">>>三级引用\n" +
+ "# 五、链接\n" +
+ "[这是一个链接](https://work.weixin.qq.com/api/doc)\n" +
+ "\n" +
+ "# 六、分割线\n" +
+ "\n" +
+ "---\n" +
+ "# 七、代码\n" +
+ "`这是行内代码`\n" +
+ "```\n" +
+ "这是独立代码块\n" +
+ "```\n" +
+ "\n" +
+ "# 八、表格\n" +
+ "| 姓名 | 文化衫尺寸 | 收货地址 |\n" +
+ "| :----- | :----: | -------: |\n" +
+ "| 张三 | S | 广州 |\n" +
+ "| 李四 | L | 深圳 |";
+ robotService.sendMarkdownV2(content);
+ }
+
/**
* Test send image.
*
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java
new file mode 100644
index 0000000000..2765b49916
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java
@@ -0,0 +1,88 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.api.ApiTestModule;
+import me.chanjar.weixin.cp.bean.intelligentrobot.*;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import javax.inject.Inject;
+
+/**
+ * 智能机器人接口测试
+ *
+ * @author Binary Wang
+ */
+@Test
+@Guice(modules = ApiTestModule.class)
+public class WxCpIntelligentRobotServiceImplTest {
+
+ @Inject
+ private WxCpService wxCpService;
+
+ @Test
+ public void testCreateRobot() {
+ // 测试创建智能机器人请求对象创建
+ WxCpIntelligentRobotCreateRequest request = new WxCpIntelligentRobotCreateRequest();
+ request.setName("测试机器人");
+ request.setDescription("这是一个测试的智能机器人");
+ request.setAvatar("avatar_url");
+
+ // 验证JSON序列化
+ String json = request.toJson();
+ assert json.contains("测试机器人");
+ assert json.contains("这是一个测试的智能机器人");
+
+ // 验证反序列化
+ WxCpIntelligentRobotCreateRequest fromJson = WxCpIntelligentRobotCreateRequest.fromJson(json);
+ assert fromJson.getName().equals("测试机器人");
+ }
+
+ @Test
+ public void testChatRequest() {
+ // 测试聊天请求对象创建
+ WxCpIntelligentRobotChatRequest request = new WxCpIntelligentRobotChatRequest();
+ request.setRobotId("robot123");
+ request.setUserid("user123");
+ request.setMessage("你好,机器人");
+ request.setSessionId("session123");
+
+ // 验证JSON序列化
+ String json = request.toJson();
+ assert json.contains("robot123");
+ assert json.contains("你好,机器人");
+
+ // 验证反序列化
+ WxCpIntelligentRobotChatRequest fromJson = WxCpIntelligentRobotChatRequest.fromJson(json);
+ assert fromJson.getRobotId().equals("robot123");
+ assert fromJson.getMessage().equals("你好,机器人");
+ }
+
+ @Test
+ public void testUpdateRequest() {
+ // 测试更新请求对象创建
+ WxCpIntelligentRobotUpdateRequest request = new WxCpIntelligentRobotUpdateRequest();
+ request.setRobotId("robot123");
+ request.setName("更新后的机器人");
+ request.setDescription("更新后的描述");
+ request.setStatus(1);
+
+ // 验证JSON序列化
+ String json = request.toJson();
+ assert json.contains("robot123");
+ assert json.contains("更新后的机器人");
+
+ // 验证反序列化
+ WxCpIntelligentRobotUpdateRequest fromJson = WxCpIntelligentRobotUpdateRequest.fromJson(json);
+ assert fromJson.getRobotId().equals("robot123");
+ assert fromJson.getName().equals("更新后的机器人");
+ assert fromJson.getStatus().equals(1);
+ }
+
+ @Test
+ public void testServiceIntegration() {
+ // 验证服务可以正确获取
+ assert this.wxCpService.getIntelligentRobotService() != null;
+ assert this.wxCpService.getIntelligentRobotService() instanceof WxCpIntelligentRobotServiceImpl;
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
index b964aad513..381a4c1454 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
@@ -7,6 +7,8 @@
import me.chanjar.weixin.cp.api.ApiTestModule;
import me.chanjar.weixin.cp.api.TestConstants;
import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlReq;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlResult;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
@@ -127,4 +129,38 @@ public void testGetJssdkFile() throws WxErrorException {
assertThat(file).isNotNull();
System.out.println(file);
}
+
+ /**
+ * Test upload media by url.
+ *
+ * @throws WxErrorException the wx error exception
+ */
+ @Test
+ public void testUploadMediaByUrl() throws WxErrorException {
+ MediaUploadByUrlReq req = new MediaUploadByUrlReq();
+ req.setScene(1);
+ req.setType("video");
+ req.setFilename("mov_bbb");
+ req.setUrl("https://www.w3school.com.cn/example/html5/mov_bbb.mp4");
+ req.setMd5("198918f40ecc7cab0fc4231adaf67c96");
+ String jobId = this.wxService.getMediaService().uploadByUrl(req);
+ System.out.println(jobId);
+ }
+
+ /**
+ * Test upload media by url.
+ *
+ * @throws WxErrorException the wx error exception
+ */
+ @Test
+ public void testUploadMediaByUrlResult() throws WxErrorException, InterruptedException {
+ String jobId = "job1745801375_5GIKWuFF3M7hcIkeSNMqs_W26xy5VeSWjLaLFTEdSfQ";
+ MediaUploadByUrlResult result = this.wxService.getMediaService().uploadByUrl(jobId);
+ System.out.println(result);
+ }
+
+ @Test
+ public void testUploadMediaJobFinishEvent() throws WxErrorException {
+ File file = this.wxService.getMediaService().getJssdkFile("....");
+ }
}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
index 708542f41d..860526bc68 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
@@ -80,6 +80,7 @@ public void testSendMessage() throws WxErrorException {
System.out.println(messageSendResult.getInvalidPartyList());
System.out.println(messageSendResult.getInvalidUserList());
System.out.println(messageSendResult.getInvalidTagList());
+ System.out.println(messageSendResult.getUnlicensedUserList());
}
/**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java
index a37a42ee68..f722a248d3 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java
@@ -8,6 +8,7 @@
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
import me.chanjar.weixin.cp.bean.oa.*;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
@@ -162,14 +163,252 @@ public void testGetCheckinOption() throws WxErrorException {
*/
@Test
public void testGetCropCheckinOption() throws WxErrorException {
-
- Date now = new Date();
List results = wxService.getOaService().getCropCheckinOption();
assertThat(results).isNotNull();
System.out.println("results ");
System.out.println(gson.toJson(results));
}
+ /**
+ * Test new ot_info_v2 structure deserialization.
+ */
+ @Test
+ public void testOtInfoV2Deserialization() {
+ // Test JSON with ot_info_v2 structure based on the new API response format
+ String jsonWithOtInfoV2 = "{\n" +
+ " \"groupid\": 1,\n" +
+ " \"groupname\": \"test group\",\n" +
+ " \"grouptype\": 0,\n" +
+ " \"ot_info_v2\": {\n" +
+ " \"workdayconf\": {\n" +
+ " \"allow_ot\": true,\n" +
+ " \"type\": 1\n" +
+ " },\n" +
+ " \"restdayconf\": {\n" +
+ " \"allow_ot\": false,\n" +
+ " \"type\": 0\n" +
+ " },\n" +
+ " \"holidayconf\": {\n" +
+ " \"allow_ot\": true,\n" +
+ " \"type\": 2\n" +
+ " }\n" +
+ " }\n" +
+ "}";
+
+ WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(jsonWithOtInfoV2, WxCpCropCheckinOption.class);
+ assertThat(option).isNotNull();
+ assertThat(option.getOtInfoV2()).isNotNull();
+ assertThat(option.getOtInfoV2().getWorkdayConf()).isNotNull();
+ assertThat(option.getOtInfoV2().getWorkdayConf().getAllowOt()).isTrue();
+ assertThat(option.getOtInfoV2().getWorkdayConf().getType()).isEqualTo(1);
+ assertThat(option.getOtInfoV2().getRestdayConf()).isNotNull();
+ assertThat(option.getOtInfoV2().getRestdayConf().getAllowOt()).isFalse();
+ assertThat(option.getOtInfoV2().getHolidayConf().getAllowOt()).isTrue();
+
+ System.out.println("Parsed ot_info_v2 structure:");
+ System.out.println(gson.toJson(option.getOtInfoV2()));
+ }
+
+ /**
+ * Test late_rule field deserialization in getCropCheckinOption response.
+ */
+ @Test
+ public void testLateRuleDeserialization() {
+ // Test JSON with late_rule structure based on the issue #3323
+ String jsonWithLateRule = "{\n" +
+ " \"grouptype\": 1,\n" +
+ " \"groupid\": 1,\n" +
+ " \"checkindate\": [\n" +
+ " {\n" +
+ " \"workdays\": [1, 2, 3, 4, 5],\n" +
+ " \"checkintime\": [\n" +
+ " {\n" +
+ " \"time_id\": 1,\n" +
+ " \"work_sec\": 32400,\n" +
+ " \"off_work_sec\": 64800,\n" +
+ " \"remind_work_sec\": 31800,\n" +
+ " \"remind_off_work_sec\": 64800,\n" +
+ " \"rest_begin_time\": 43200,\n" +
+ " \"rest_end_time\": 48600,\n" +
+ " \"allow_rest\": true,\n" +
+ " \"earliest_work_sec\": 21600,\n" +
+ " \"latest_work_sec\": 64740,\n" +
+ " \"earliest_off_work_sec\": 32460,\n" +
+ " \"latest_off_work_sec\": 107940,\n" +
+ " \"no_need_checkon\": false,\n" +
+ " \"no_need_checkoff\": false\n" +
+ " }\n" +
+ " ],\n" +
+ " \"noneed_offwork\": false,\n" +
+ " \"limit_aheadtime\": 0,\n" +
+ " \"flex_on_duty_time\": 0,\n" +
+ " \"flex_off_duty_time\": 0,\n" +
+ " \"allow_flex\": false,\n" +
+ " \"late_rule\": {\n" +
+ " \"offwork_after_time\": 3600,\n" +
+ " \"onwork_flex_time\": 3600,\n" +
+ " \"allow_offwork_after_time\": true,\n" +
+ " \"timerules\": [\n" +
+ " {\n" +
+ " \"offwork_after_time\": 18000,\n" +
+ " \"onwork_flex_time\": 3600\n" +
+ " },\n" +
+ " {\n" +
+ " \"offwork_after_time\": 21600,\n" +
+ " \"onwork_flex_time\": 7200\n" +
+ " }\n" +
+ " ]\n" +
+ " },\n" +
+ " \"max_allow_arrive_early\": 0,\n" +
+ " \"max_allow_arrive_late\": 0\n" +
+ " }\n" +
+ " ],\n" +
+ " \"groupname\": \"打卡\",\n" +
+ " \"need_photo\": false\n" +
+ "}";
+
+ WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(jsonWithLateRule, WxCpCropCheckinOption.class);
+ assertThat(option).isNotNull();
+ assertThat(option.getCheckinDate()).isNotNull();
+ assertThat(option.getCheckinDate().size()).isEqualTo(1);
+
+ WxCpCheckinGroupBase.CheckinDate checkinDate = option.getCheckinDate().get(0);
+ assertThat(checkinDate).isNotNull();
+ assertThat(checkinDate.getAllowFlex()).isFalse();
+ assertThat(checkinDate.getMaxAllowArriveEarly()).isEqualTo(0);
+ assertThat(checkinDate.getMaxAllowArriveLate()).isEqualTo(0);
+
+ // Test late_rule field
+ assertThat(checkinDate.getLateRule()).isNotNull();
+ assertThat(checkinDate.getLateRule().getOffWorkAfterTime()).isEqualTo(3600);
+ assertThat(checkinDate.getLateRule().getOnWorkFlexTime()).isEqualTo(3600);
+ assertThat(checkinDate.getLateRule().getAllowOffWorkAfterTime()).isTrue();
+ assertThat(checkinDate.getLateRule().getTimerules()).isNotNull();
+ assertThat(checkinDate.getLateRule().getTimerules().size()).isEqualTo(2);
+
+ // Test timerules
+ WxCpCheckinGroupBase.TimeRule firstRule = checkinDate.getLateRule().getTimerules().get(0);
+ assertThat(firstRule.getOffWorkAfterTime()).isEqualTo(18000);
+ assertThat(firstRule.getOnWorkFlexTime()).isEqualTo(3600);
+
+ // Test CheckinTime fields
+ assertThat(checkinDate.getCheckinTime()).isNotNull();
+ assertThat(checkinDate.getCheckinTime().size()).isEqualTo(1);
+
+ WxCpCheckinGroupBase.CheckinTime checkinTime = checkinDate.getCheckinTime().get(0);
+ assertThat(checkinTime.getTimeId()).isEqualTo(1);
+ assertThat(checkinTime.getRestBeginTime()).isEqualTo(43200);
+ assertThat(checkinTime.getRestEndTime()).isEqualTo(48600);
+ assertThat(checkinTime.getAllowRest()).isTrue();
+ assertThat(checkinTime.getEarliestWorkSec()).isEqualTo(21600);
+ assertThat(checkinTime.getLatestWorkSec()).isEqualTo(64740);
+ assertThat(checkinTime.getEarliestOffWorkSec()).isEqualTo(32460);
+ assertThat(checkinTime.getLatestOffWorkSec()).isEqualTo(107940);
+ assertThat(checkinTime.getNoNeedCheckon()).isFalse();
+ assertThat(checkinTime.getNoNeedCheckoff()).isFalse();
+
+ System.out.println("Successfully parsed late_rule and new checkintime fields:");
+ System.out.println(gson.toJson(option));
+ }
+
+ /**
+ * Test issue #3323 - full JSON from the issue report.
+ */
+ @Test
+ public void testIssue3323FullJson() {
+ // Full JSON from issue #3323
+ String issueJson = "{\n" +
+ " \"grouptype\": 1,\n" +
+ " \"groupid\": 1,\n" +
+ " \"checkindate\": [\n" +
+ " {\n" +
+ " \"workdays\": [\n" +
+ " 1,\n" +
+ " 2,\n" +
+ " 3,\n" +
+ " 4,\n" +
+ " 5\n" +
+ " ],\n" +
+ " \"checkintime\": [\n" +
+ " {\n" +
+ " \"time_id\": 1,\n" +
+ " \"work_sec\": 32400,\n" +
+ " \"off_work_sec\": 64800,\n" +
+ " \"remind_work_sec\": 31800,\n" +
+ " \"remind_off_work_sec\": 64800,\n" +
+ " \"rest_begin_time\": 43200,\n" +
+ " \"rest_end_time\": 48600,\n" +
+ " \"allow_rest\": true,\n" +
+ " \"earliest_work_sec\": 21600,\n" +
+ " \"latest_work_sec\": 64740,\n" +
+ " \"earliest_off_work_sec\": 32460,\n" +
+ " \"latest_off_work_sec\": 107940,\n" +
+ " \"no_need_checkon\": false,\n" +
+ " \"no_need_checkoff\": false\n" +
+ " }\n" +
+ " ],\n" +
+ " \"noneed_offwork\": false,\n" +
+ " \"limit_aheadtime\": 0,\n" +
+ " \"flex_on_duty_time\": 0,\n" +
+ " \"flex_off_duty_time\": 0,\n" +
+ " \"allow_flex\": false,\n" +
+ " \"late_rule\": {\n" +
+ " \"offwork_after_time\": 3600,\n" +
+ " \"onwork_flex_time\": 3600,\n" +
+ " \"allow_offwork_after_time\": true,\n" +
+ " \"timerules\": [\n" +
+ " {\n" +
+ " \"offwork_after_time\": 18000,\n" +
+ " \"onwork_flex_time\": 3600\n" +
+ " },\n" +
+ " {\n" +
+ " \"offwork_after_time\": 21600,\n" +
+ " \"onwork_flex_time\": 7200\n" +
+ " },\n" +
+ " {\n" +
+ " \"offwork_after_time\": 28800,\n" +
+ " \"onwork_flex_time\": 10800\n" +
+ " }\n" +
+ " ]\n" +
+ " },\n" +
+ " \"max_allow_arrive_early\": 0,\n" +
+ " \"max_allow_arrive_late\": 0\n" +
+ " }\n" +
+ " ],\n" +
+ " \"spe_workdays\": [],\n" +
+ " \"spe_offdays\": [],\n" +
+ " \"sync_holidays\": true,\n" +
+ " \"groupname\": \"打卡\",\n" +
+ " \"need_photo\": false,\n" +
+ " \"wifimac_infos\": [],\n" +
+ " \"note_can_use_local_pic\": true,\n" +
+ " \"allow_checkin_offworkday\": false,\n" +
+ " \"allow_apply_offworkday\": false,\n" +
+ " \"loc_infos\": []\n" +
+ " }";
+
+ WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(issueJson, WxCpCropCheckinOption.class);
+ assertThat(option).isNotNull();
+ assertThat(option.getGroupId()).isEqualTo(1);
+ assertThat(option.getGroupName()).isEqualTo("打卡");
+ assertThat(option.getCheckinDate()).isNotNull();
+ assertThat(option.getCheckinDate().size()).isEqualTo(1);
+
+ WxCpCheckinGroupBase.CheckinDate checkinDate = option.getCheckinDate().get(0);
+ assertThat(checkinDate.getLateRule()).isNotNull();
+ assertThat(checkinDate.getLateRule().getOffWorkAfterTime()).isEqualTo(3600);
+ assertThat(checkinDate.getLateRule().getOnWorkFlexTime()).isEqualTo(3600);
+ assertThat(checkinDate.getLateRule().getAllowOffWorkAfterTime()).isTrue();
+ assertThat(checkinDate.getLateRule().getTimerules()).isNotNull();
+ assertThat(checkinDate.getLateRule().getTimerules().size()).isEqualTo(3);
+
+ System.out.println("✓ Successfully parsed full JSON from issue #3323");
+ System.out.println("✓ Late Rule offwork_after_time: " + checkinDate.getLateRule().getOffWorkAfterTime());
+ System.out.println("✓ Late Rule onwork_flex_time: " + checkinDate.getLateRule().getOnWorkFlexTime());
+ System.out.println("✓ Late Rule allow_offwork_after_time: " + checkinDate.getLateRule().getAllowOffWorkAfterTime());
+ System.out.println("✓ Late Rule timerules count: " + checkinDate.getLateRule().getTimerules().size());
+ }
+
/**
* Test get approval info.
*
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImplTest.java
new file mode 100644
index 0000000000..da1cc25542
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImplTest.java
@@ -0,0 +1,139 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import com.google.gson.Gson;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.school.user.WxCpDepartmentList;
+import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
+import org.mockito.Mockito;
+import org.testng.annotations.Test;
+
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.School.DEPARTMENT_LIST;
+import static org.testng.Assert.assertEquals;
+
+public class WxCpSchoolUserServiceImplTest {
+
+
+ String allDeptListJson = "{\n" +
+ "\t\"errcode\": 0,\n" +
+ "\t\"errmsg\": \"ok\",\n" +
+ "\t\"departments\": [\n" +
+ "\t\t{\n" +
+ "\t\t\t\"name\": \"一年级\",\n" +
+ "\t\t\t\"parentid\": 1,\n" +
+ "\t\t\t\"id\": 2,\n" +
+ "\t\t\t\"type\":2,\n" +
+ "\t\t\t\"register_year\":2018,\n" +
+ "\t\t\t\"standard_grade\":1,\n" +
+ "\t\t\t\"order\":1,\n" +
+ "\t\t\t\"department_admins\": [\n" +
+ "\t\t\t\t{\n" +
+ "\t\t\t\t\t\"userid\": \"zhangsan\",\n" +
+ "\t\t\t\t\t\"type\": 1\n" +
+ "\t\t\t\t},\n" +
+ "\t\t\t\t{\n" +
+ "\t\t\t\t\t\"userid\": \"lisi\",\n" +
+ "\t\t\t\t\t\"type\": 2\n" +
+ "\t\t\t\t}\n" +
+ "\t\t\t],\n" +
+ " \"is_graduated\": 0\n" +
+ "\t\t},\n" +
+ "\t\t{\n" +
+ "\t\t\t\"name\": \"一年级一班\",\n" +
+ "\t\t\t\"parentid\": 1,\n" +
+ "\t\t\t\"id\": 3,\n" +
+ "\t\t\t\"type\": 1,\n" +
+ "\t\t\t\"department_admins\": [\n" +
+ "\t\t\t\t{\n" +
+ "\t\t\t\t\t\"userid\": \"zhangsan\",\n" +
+ "\t\t\t\t\t\"type\": 3,\n" +
+ "\t\t\t\t\t\"subject\":\"语文\"\n" +
+ "\t\t\t\t},\n" +
+ "\t\t\t\t{\n" +
+ "\t\t\t\t\t\"userid\": \"lisi\",\n" +
+ "\t\t\t\t\t\"type\": 4,\n" +
+ "\t\t\t\t\t\"subject\":\"数学\"\n" +
+ "\t\t\t\t}\n" +
+ "\t\t\t],\n" +
+ "\t\t\t\"open_group_chat\": 1,\n" +
+ " \"group_chat_id\": \"group_chat_id\"\n" +
+ "\t\t}\n" +
+ "\t]\n" +
+ "}\n";
+
+ String deptId3Json = "{\n" +
+ " \"errcode\": 0,\n" +
+ " \"errmsg\": \"ok\",\n" +
+ " \"departments\": [\n" +
+ " {\n" +
+ " \"name\": \"一年级一班\",\n" +
+ " \"parentid\": 1,\n" +
+ " \"id\": 3,\n" +
+ " \"type\": 1,\n" +
+ " \"department_admins\": [\n" +
+ " {\n" +
+ " \"userid\": \"zhangsan\",\n" +
+ " \"type\": 3,\n" +
+ " \"subject\":\"语文\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"userid\": \"lisi\",\n" +
+ " \"type\": 4,\n" +
+ " \"subject\":\"数学\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"open_group_chat\": 1,\n" +
+ " \"group_chat_id\": \"group_chat_id\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ String deptId2Json = "{\n" +
+ " \"errcode\": 0,\n" +
+ " \"errmsg\": \"ok\",\n" +
+ " \"departments\": []\n" +
+ "}\n";
+
+
+ @Test
+ public void testListDepartmentWhenIdIsNull() throws WxErrorException {
+
+ WxCpService mockCpService = Mockito.mock(WxCpService.class);
+ WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
+ Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
+ Mockito.when(mockCpService.get(mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), null)).thenReturn(allDeptListJson);
+ WxCpDepartmentList wxCpDepartmentList = wxCpSchoolUserService.listDepartment(null);
+ //WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
+ Gson gson = new Gson();
+ assertEquals(gson.toJson(wxCpDepartmentList), gson.toJson(gson.fromJson(allDeptListJson, WxCpDepartmentList.class)), "should be equal");
+
+ }
+
+ @Test
+ public void testListDepartmentWhenIdIs2() throws WxErrorException {
+
+ WxCpService mockCpService = Mockito.mock(WxCpService.class);
+ WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
+ Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
+ Gson gson = new Gson();
+ int deptId = 2;
+ Mockito.when(mockCpService.get(String.format("%s?id=%s", mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), deptId), null)).thenReturn(deptId2Json);
+ //WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
+ assertEquals(gson.toJson(wxCpSchoolUserService.listDepartment(deptId)), gson.toJson(gson.fromJson(deptId2Json, WxCpDepartmentList.class)), "should be equal");
+
+ }
+
+ @Test
+ public void testListDepartmentWhenIdIs3() throws WxErrorException {
+
+ WxCpService mockCpService = Mockito.mock(WxCpService.class);
+ WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
+ Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
+ Gson gson = new Gson();
+ int deptId = 3;
+ Mockito.when(mockCpService.get(String.format("%s?id=%s", mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), deptId), null)).thenReturn(deptId3Json);
+ //WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
+ assertEquals(gson.toJson(wxCpSchoolUserService.listDepartment(deptId)), gson.toJson(gson.fromJson(deptId3Json, WxCpDepartmentList.class)), "should be equal");
+
+ }
+}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
index d6cd827630..28246cf00b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
@@ -152,7 +152,7 @@ public void enterAppTest() {
assertEquals(wxXmlMessage.getCreateTime(), Long.valueOf(1408091189));
assertEquals(wxXmlMessage.getEvent(), "enter_agent");
assertEquals(wxXmlMessage.getEventKey(), "");
- assertEquals(wxXmlMessage.getAgentID(), Integer.valueOf(1));
+ assertEquals(wxXmlMessage.getAgentID(), 1);
}
/**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java
index a760a17ff6..ae4fbba8f6 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java
@@ -6,6 +6,7 @@
import org.testng.annotations.Test;
import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK;
+import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.UPLOAD_MEDIA_JOB_FINISH;
import static org.assertj.core.api.Assertions.assertThat;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
@@ -71,7 +72,7 @@ public void testFromXml() {
assertEquals(wxMessage.getCreateTime(), Long.valueOf(1348831860));
assertEquals(wxMessage.getMsgType(), WxConsts.XmlMsgType.TEXT);
assertEquals(wxMessage.getContent(), "this is a test");
- assertEquals(wxMessage.getMsgId(), Long.valueOf(1234567890123456L));
+ assertEquals(wxMessage.getMsgId(), "1234567890123456");
assertEquals(wxMessage.getPicUrl(), "this is a url");
assertEquals(wxMessage.getMediaId(), "media_id");
assertEquals(wxMessage.getFormat(), "Format");
@@ -421,4 +422,53 @@ public void testOpenApprovalChange() {
assertThat(wxCpXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getItems().get(0).getItemName()).isNotEmpty();
assertThat(wxCpXmlMessage.getApprovalInfo().getNotifyNodes().get(0).getItemName()).isNotEmpty();
}
+
+ /**
+ * Test open approval change.
+ */
+ public void testUploadMediaJobFinishEvent() {
+ String xml = "\n" +
+ "\t \n" +
+ "\t \n" +
+ "\t1425284517 \n" +
+ "\t \n" +
+ "\t \n" +
+ "\t \n" +
+ " ";
+
+ WxCpXmlMessage wxCpXmlMessage = WxCpXmlMessage.fromXml(xml);
+ assertThat(wxCpXmlMessage).isNotNull();
+ assertThat(wxCpXmlMessage.getJobId()).isNotEmpty();
+ assertThat(wxCpXmlMessage.getJobId()).isEqualTo("jobid_S0MrnndvRG5fadSlLwiBqiDDbM143UqTmKP3152FZk4");
+ assertThat(wxCpXmlMessage.getEvent()).isEqualTo(UPLOAD_MEDIA_JOB_FINISH);
+ }
+
+ /**
+ * Test both numeric and string msgId formats to ensure backward compatibility
+ */
+ public void testMsgIdStringAndNumericFormats() {
+ // Test with numeric msgId (old format)
+ String xmlWithNumeric = ""
+ + " "
+ + " "
+ + "1348831860 "
+ + " "
+ + " "
+ + "1234567890123456 "
+ + " ";
+ WxCpXmlMessage wxMessageNumeric = WxCpXmlMessage.fromXml(xmlWithNumeric);
+ assertEquals(wxMessageNumeric.getMsgId(), "1234567890123456");
+
+ // Test with string msgId (new format - the actual issue case)
+ String xmlWithString = ""
+ + " "
+ + " "
+ + "1348831860 "
+ + " "
+ + " "
+ + "CAIQg/PKxgYY2sC9tpuAgAMg9/zKaw== "
+ + " ";
+ WxCpXmlMessage wxMessageString = WxCpXmlMessage.fromXml(xmlWithString);
+ assertEquals(wxMessageString.getMsgId(), "CAIQg/PKxgYY2sC9tpuAgAMg9/zKaw==");
+ }
}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequestTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequestTest.java
index f2dedb4ddf..e6fc2e8004 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequestTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApplyEventRequestTest.java
@@ -95,4 +95,99 @@ public void testToJson() {
assertThat(request.toJson()).isEqualTo(GsonParser.parse(json).toString());
}
+
+ /**
+ * Test to json with process.
+ */
+ @Test
+ public void testToJsonWithProcess() {
+ String json = "{\n" +
+ " \"creator_userid\": \"WangXiaoMing\",\n" +
+ " \"template_id\": \"3Tka1eD6v6JfzhDMqPd3aMkFdxqtJMc2ZRioeFXkaaa\",\n" +
+ " \"use_template_approver\":0,\n" +
+ " \"process\": {\n" +
+ " \"node_list\": [\n" +
+ " {\n" +
+ " \"type\": 1,\n" +
+ " \"apv_rel\": 2,\n" +
+ " \"userid\": [\"WuJunJie\",\"WangXiaoMing\"]\n" +
+ " },\n" +
+ " {\n" +
+ " \"type\": 1,\n" +
+ " \"apv_rel\": 1,\n" +
+ " \"userid\": [\"LiuXiaoGang\"]\n" +
+ " },\n" +
+ " {\n" +
+ " \"type\": 2,\n" +
+ " \"userid\": [\"ZhangSan\",\"LiSi\"]\n" +
+ " }\n" +
+ " ]\n" +
+ " },\n" +
+ " \"apply_data\": {\n" +
+ " \"contents\": [\n" +
+ " {\n" +
+ " \"control\": \"Text\",\n" +
+ " \"id\": \"Text-15111111111\",\n" +
+ " \"value\": {\n" +
+ " \"text\": \"文本填写的内容\"\n" +
+ " }\n" +
+ " }\n" +
+ " ]\n" +
+ " },\n" +
+ " \"summary_list\": [\n" +
+ " {\n" +
+ " \"summary_info\": [{\n" +
+ " \"text\": \"摘要第1行\",\n" +
+ " \"lang\": \"zh_CN\"\n" +
+ " }]\n" +
+ " },\n" +
+ " {\n" +
+ " \"summary_info\": [{\n" +
+ " \"text\": \"摘要第2行\",\n" +
+ " \"lang\": \"zh_CN\"\n" +
+ " }]\n" +
+ " },\n" +
+ " {\n" +
+ " \"summary_info\": [{\n" +
+ " \"text\": \"摘要第3行\",\n" +
+ " \"lang\": \"zh_CN\"\n" +
+ " }]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ WxCpOaApplyEventRequest request = new WxCpOaApplyEventRequest();
+ request.setCreatorUserId("WangXiaoMing")
+ .setTemplateId("3Tka1eD6v6JfzhDMqPd3aMkFdxqtJMc2ZRioeFXkaaa")
+ .setUseTemplateApprover(0)
+ .setProcess(new WxCpOaApplyEventRequest.Process()
+ .setNodeList(Arrays.asList(
+ new WxCpOaApplyEventRequest.ProcessNode()
+ .setType(1)
+ .setApvRel(2)
+ .setUserIds(new String[]{"WuJunJie", "WangXiaoMing"}),
+ new WxCpOaApplyEventRequest.ProcessNode()
+ .setType(1)
+ .setApvRel(1)
+ .setUserIds(new String[]{"LiuXiaoGang"}),
+ new WxCpOaApplyEventRequest.ProcessNode()
+ .setType(2)
+ .setUserIds(new String[]{"ZhangSan", "LiSi"})
+ )))
+ .setApplyData(new WxCpOaApplyEventRequest.ApplyData()
+ .setContents(Collections.singletonList(new ApplyDataContent()
+ .setControl("Text").setId("Text-15111111111").setValue(new ContentValue().setText("文本填写的内容")))))
+ .setSummaryList(Arrays.asList(new SummaryInfo()
+ .setSummaryInfoData(Collections.singletonList(new SummaryInfo.SummaryInfoData().setLang("zh_CN").setText(
+ "摘要第1行"))),
+ new SummaryInfo()
+ .setSummaryInfoData(Collections.singletonList(new SummaryInfo.SummaryInfoData().setLang("zh_CN").setText(
+ "摘要第2行"))),
+ new SummaryInfo()
+ .setSummaryInfoData(Collections.singletonList(new SummaryInfo.SummaryInfoData().setLang("zh_CN").setText(
+ "摘要第3行")))))
+ ;
+
+ assertThat(request.toJson()).isEqualTo(GsonParser.parse(json).toString());
+ }
}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResultTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResultTest.java
new file mode 100644
index 0000000000..db79a06b32
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResultTest.java
@@ -0,0 +1,390 @@
+package me.chanjar.weixin.cp.bean.oa;
+
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class WxCpOaApprovalTemplateResultTest {
+
+ @Test
+ public void testFromJson() {
+ String json = "{\n"
+ + " \"errcode\": 0,\n"
+ + " \"errmsg\": \"ok\",\n"
+ + " \"template_names\": [\n"
+ + " {\n"
+ + " \"text\": \"智能印章\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " },\n"
+ + " {\n"
+ + " \"text\": \"Company Seal\",\n"
+ + " \"lang\": \"en\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"template_content\": {\n"
+ + " \"controls\": [\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Text\",\n"
+ + " \"id\": \"Text-1747127819114\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"用印事由\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 1,\n"
+ + " \"un_print\": 0,\n"
+ + " \"inner_id\": \"\",\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Selector\",\n"
+ + " \"id\": \"Selector-1747123508806\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"用印类型\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 1,\n"
+ + " \"un_print\": 0,\n"
+ + " \"inner_id\": \"\",\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " },\n"
+ + " \"config\": {\n"
+ + " \"selector\": {\n"
+ + " \"type\": \"single\",\n"
+ + " \"options\": [\n"
+ + " {\n"
+ + " \"key\": \"option-1747123508806\",\n"
+ + " \"value\": [\n"
+ + " {\n"
+ + " \"text\": \"一般事务性用印\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ]\n"
+ + " },\n"
+ + " {\n"
+ + " \"key\": \"option-1747123508807\",\n"
+ + " \"value\": [\n"
+ + " {\n"
+ + " \"text\": \"对外事务性用印\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ]\n"
+ + " },\n"
+ + " {\n"
+ + " \"key\": \"option-1747123530814\",\n"
+ + " \"value\": [\n"
+ + " {\n"
+ + " \"text\": \"重大事务性用印\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ]\n"
+ + " }\n"
+ + " ],\n"
+ + " \"op_relations\": [],\n"
+ + " \"external_option\": {\n"
+ + " \"use_external_option\": false,\n"
+ + " \"external_url\": \"\"\n"
+ + " }\n"
+ + " }\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Tips\",\n"
+ + " \"id\": \"Tips-1747123397470\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"说明\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [],\n"
+ + " \"require\": 0,\n"
+ + " \"un_print\": 0,\n"
+ + " \"inner_id\": \"\",\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " },\n"
+ + " \"config\": {\n"
+ + " \"tips\": {\n"
+ + " \"tips_content\": [\n"
+ + " {\n"
+ + " \"text\": {\n"
+ + " \"sub_text\": [\n"
+ + " {\n"
+ + " \"type\": 1,\n"
+ + " \"content\": {\n"
+ + " \"plain_text\": {\n"
+ + " \"content\": \"用印类型说明:1. 一般事务性用印:内部日常材料流转、常规业务报表报送、非对外承诺性质的证明文件,用印文件内容不得涉及经济、法律责任条款 \"\n"
+ + " }\n"
+ + " }\n"
+ + " }\n"
+ + " ]\n"
+ + " },\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ]\n"
+ + " }\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Table\",\n"
+ + " \"id\": \"Table-1746005041962\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"印章明细\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 0,\n"
+ + " \"un_print\": 0,\n"
+ + " \"inner_id\": \"\",\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " },\n"
+ + " \"config\": {\n"
+ + " \"table\": {\n"
+ + " \"children\": [\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Text\",\n"
+ + " \"id\": \"Text-1747127691499\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"印章名称\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"请输入“公章”\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 1,\n"
+ + " \"un_print\": 0,\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Number\",\n"
+ + " \"id\": \"Number-1746006598992\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"普通用印\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"请填写正文用印次数\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 1,\n"
+ + " \"un_print\": 0,\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Number\",\n"
+ + " \"id\": \"Number-1746006601002\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"骑缝用印\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"请填写骑缝用印次数\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 1,\n"
+ + " \"un_print\": 0,\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Selector\",\n"
+ + " \"id\": \"Selector-1746005136537\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"是否外借\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 0,\n"
+ + " \"un_print\": 0,\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " },\n"
+ + " \"config\": {\n"
+ + " \"selector\": {\n"
+ + " \"type\": \"single\",\n"
+ + " \"exp_type\": 0,\n"
+ + " \"options\": [\n"
+ + " {\n"
+ + " \"key\": \"option-1746005136537\",\n"
+ + " \"value\": [\n"
+ + " {\n"
+ + " \"text\": \"是\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ]\n"
+ + " },\n"
+ + " {\n"
+ + " \"key\": \"option-1746005136538\",\n"
+ + " \"value\": [\n"
+ + " {\n"
+ + " \"text\": \"否\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ]\n"
+ + " }\n"
+ + " ],\n"
+ + " \"op_relations\": [],\n"
+ + " \"external_option\": {\n"
+ + " \"use_external_option\": false,\n"
+ + " \"external_url\": \"\"\n"
+ + " }\n"
+ + " }\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Date\",\n"
+ + " \"id\": \"Date-1746005165574\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"外借开始时间\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 0,\n"
+ + " \"un_print\": 0,\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " },\n"
+ + " \"config\": {\n"
+ + " \"date\": {\n"
+ + " \"type\": \"day\"\n"
+ + " }\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"Date\",\n"
+ + " \"id\": \"Date-1746005173386\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"外借结束时间\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 0,\n"
+ + " \"un_print\": 0,\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " },\n"
+ + " \"config\": {\n"
+ + " \"date\": {\n"
+ + " \"type\": \"day\"\n"
+ + " }\n"
+ + " }\n"
+ + " }\n"
+ + " ],\n"
+ + " \"stat_field\": [],\n"
+ + " \"sum_field\": [],\n"
+ + " \"print_format\": 0\n"
+ + " }\n"
+ + " }\n"
+ + " },\n"
+ + " {\n"
+ + " \"property\": {\n"
+ + " \"control\": \"File\",\n"
+ + " \"id\": \"item-1494250388062\",\n"
+ + " \"title\": [\n"
+ + " {\n"
+ + " \"text\": \"用印文件\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " },\n"
+ + " {\n"
+ + " \"text\": \"Attachment\",\n"
+ + " \"lang\": \"en\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"placeholder\": [\n"
+ + " {\n"
+ + " \"text\": \"\",\n"
+ + " \"lang\": \"zh_CN\"\n"
+ + " }\n"
+ + " ],\n"
+ + " \"require\": 1,\n"
+ + " \"un_print\": 0,\n"
+ + " \"inner_id\": \"\",\n"
+ + " \"un_replace\": 0,\n"
+ + " \"display\": 1\n"
+ + " }\n"
+ + " }\n"
+ + " ]\n"
+ + " }\n"
+ + "}";
+
+ WxCpOaApprovalTemplateResult templateDetail = WxCpGsonBuilder.create().fromJson(json, WxCpOaApprovalTemplateResult.class);
+ System.out.println(templateDetail);
+ }
+}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/DemoToStringFix.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/DemoToStringFix.java
new file mode 100644
index 0000000000..48fe9a6639
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/DemoToStringFix.java
@@ -0,0 +1,66 @@
+package me.chanjar.weixin.cp.config.impl;
+
+import me.chanjar.weixin.common.redis.WxRedisOps;
+
+/**
+ * Demonstration of the fix for toString() StackOverflowError issue
+ */
+public class DemoToStringFix {
+
+ public static void main(String[] args) {
+ System.out.println("=== Demonstrating toString() Fix for WxCp Redis Config ===");
+
+ // Create a simple stub WxRedisOps implementation for testing
+ WxRedisOps stubRedisOps = new WxRedisOps() {
+ @Override
+ public String getValue(String key) { return null; }
+ @Override
+ public void setValue(String key, String value, int expire, java.util.concurrent.TimeUnit timeUnit) {}
+ @Override
+ public Long getExpire(String key) { return null; }
+ @Override
+ public void expire(String key, int expire, java.util.concurrent.TimeUnit timeUnit) {}
+ @Override
+ public java.util.concurrent.locks.Lock getLock(String key) { return null; }
+ };
+
+ // Test AbstractWxCpInRedisConfigImpl directly with our stub
+ AbstractWxCpInRedisConfigImpl config = new AbstractWxCpInRedisConfigImpl(stubRedisOps, "demo:") {
+ // Anonymous class to test the abstract parent
+ };
+
+ config.setCorpId("demoCorpId");
+ config.setAgentId(1001);
+
+ System.out.println("Testing toString() method:");
+ try {
+ String result = config.toString();
+ System.out.println("✓ Success! toString() returned: " + result);
+ System.out.println("✓ No StackOverflowError occurred");
+
+ // Verify the result contains expected information and excludes redisOps
+ boolean containsCorpId = result.contains("demoCorpId");
+ boolean containsAgentId = result.contains("1001");
+ boolean containsKeyPrefix = result.contains("demo:");
+ boolean excludesRedisOps = !result.contains("redisOps") && !result.contains("WxRedisOps");
+
+ System.out.println("✓ Contains corpId: " + containsCorpId);
+ System.out.println("✓ Contains agentId: " + containsAgentId);
+ System.out.println("✓ Contains keyPrefix: " + containsKeyPrefix);
+ System.out.println("✓ Excludes redisOps: " + excludesRedisOps);
+
+ if (containsCorpId && containsAgentId && containsKeyPrefix && excludesRedisOps) {
+ System.out.println("✓ All validations passed!");
+ } else {
+ System.out.println("✗ Some validations failed");
+ }
+
+ } catch (StackOverflowError e) {
+ System.out.println("✗ StackOverflowError still occurred - fix failed");
+ } catch (Exception e) {
+ System.out.println("✗ Unexpected error: " + e.getMessage());
+ }
+
+ System.out.println("\n=== Demo completed ===");
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpApprovalWorkflowDemo.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpApprovalWorkflowDemo.java
new file mode 100644
index 0000000000..07aed001de
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/demo/WxCpApprovalWorkflowDemo.java
@@ -0,0 +1,190 @@
+package me.chanjar.weixin.cp.demo;
+
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.oa.WxCpApprovalDetailResult;
+import me.chanjar.weixin.cp.bean.oa.WxCpApprovalInfo;
+import me.chanjar.weixin.cp.bean.oa.WxCpOaApplyEventRequest;
+import me.chanjar.weixin.cp.bean.oa.WxCpOaApprovalTemplateResult;
+import me.chanjar.weixin.cp.bean.oa.applydata.ApplyDataContent;
+import me.chanjar.weixin.cp.bean.oa.applydata.ContentValue;
+
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * 企业微信流程审批功能演示代码
+ * WeChat Enterprise Workflow Approval Demo
+ *
+ * 演示如何使用WxJava SDK中已实现的完整审批流程功能
+ * Demonstrates how to use the comprehensive approval workflow features already implemented in WxJava SDK
+ *
+ * 文档参考 Documentation Reference: https://work.weixin.qq.com/api/doc/90000/90135/91853
+ */
+public class WxCpApprovalWorkflowDemo {
+
+ private WxCpService wxCpService;
+
+ public WxCpApprovalWorkflowDemo(WxCpService wxCpService) {
+ this.wxCpService = wxCpService;
+ }
+
+ /**
+ * 示例1: 提交审批申请
+ * Example 1: Submit Approval Application
+ * API: /cgi-bin/oa/applyevent (Document 91853)
+ */
+ public String submitApprovalApplication() throws Exception {
+ // 构建审批申请请求
+ WxCpOaApplyEventRequest request = new WxCpOaApplyEventRequest()
+ .setCreatorUserId("creator_user_id") // 申请人userid
+ .setTemplateId("3Tka1eD6v6JfzhDMqPd3aMkFdxqtJMc2ZRioUBGCNS") // 模板id
+ .setUseTemplateApprover(0) // 不使用模板中的审批流
+ .setApprovers(Arrays.asList(
+ new WxCpOaApplyEventRequest.Approver()
+ .setAttr(2) // 审批类型: 或签
+ .setUserIds(new String[]{"approver1", "approver2"})
+ ))
+ .setNotifiers(new String[]{"notifier1", "notifier2"}) // 抄送人
+ .setNotifyType(1) // 抄送方式: 提单时抄送
+ .setApplyData(new WxCpOaApplyEventRequest.ApplyData()
+ .setContents(Arrays.asList(
+ // 文本控件
+ new ApplyDataContent()
+ .setControl("Text")
+ .setId("Text-1234567890")
+ .setValue(new ContentValue().setText("这是一个审批申请的文本内容")),
+
+ // 数字控件
+ new ApplyDataContent()
+ .setControl("Number")
+ .setId("Number-1234567890")
+ .setValue(new ContentValue().setNewNumber("1000")),
+
+ // 金额控件
+ new ApplyDataContent()
+ .setControl("Money")
+ .setId("Money-1234567890")
+ .setValue(new ContentValue().setNewMoney("10000"))
+ ))
+ );
+
+ // 提交审批申请
+ String spNo = wxCpService.getOaService().apply(request);
+ System.out.println("审批申请提交成功,审批单号: " + spNo);
+
+ return spNo;
+ }
+
+ /**
+ * 示例2: 获取审批申请详情
+ * Example 2: Get Approval Application Details
+ * API: /cgi-bin/oa/getapprovaldetail
+ */
+ public void getApprovalDetails(String spNo) throws Exception {
+ WxCpApprovalDetailResult result = wxCpService.getOaService().getApprovalDetail(spNo);
+
+ WxCpApprovalDetailResult.WxCpApprovalDetail detail = result.getInfo();
+
+ System.out.println("审批单号: " + detail.getSpNo());
+ System.out.println("审批名称: " + detail.getSpName());
+ System.out.println("审批状态: " + detail.getSpStatus());
+ System.out.println("申请人: " + detail.getApplier().getUserId());
+ System.out.println("申请时间: " + detail.getApplyTime());
+
+ // 打印审批记录
+ if (detail.getSpRecords() != null) {
+ Arrays.stream(detail.getSpRecords()).forEach(record -> {
+ System.out.println("审批节点状态: " + record.getStatus());
+ System.out.println("审批人: " + record.getDetails());
+ });
+ }
+ }
+
+ /**
+ * 示例3: 批量获取审批单号
+ * Example 3: Batch Get Approval Numbers
+ * API: /cgi-bin/oa/getapprovalinfo
+ */
+ public void batchGetApprovalInfo() throws Exception {
+ // 获取最近7天的审批单
+ Date startTime = new Date(System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000L);
+ Date endTime = new Date();
+
+ WxCpApprovalInfo approvalInfo = wxCpService.getOaService()
+ .getApprovalInfo(startTime, endTime, "0", 100, null);
+
+ System.out.println("获取到的审批单数量: " + (approvalInfo.getSpNoList() != null ? approvalInfo.getSpNoList().size() : 0));
+
+ // 遍历审批单号
+ if (approvalInfo.getSpNoList() != null) {
+ approvalInfo.getSpNoList().forEach(spNo -> {
+ System.out.println("审批单号: " + spNo);
+ // 可以进一步调用 getApprovalDetails 获取详情
+ });
+ }
+ }
+
+ /**
+ * 示例4: 模板管理
+ * Example 4: Template Management
+ */
+ public void templateManagement() throws Exception {
+ // 获取模板详情
+ String templateId = "3Tka1eD6v6JfzhDMqPd3aMkFdxqtJMc2ZRioUBGCNS";
+ WxCpOaApprovalTemplateResult templateResult = wxCpService.getOaService().getTemplateDetail(templateId);
+
+ System.out.println("模板名称: " + templateResult.getTemplateNames());
+ System.out.println("模板内容: " + templateResult.getTemplateContent());
+ }
+
+ /**
+ * 完整的审批流程演示
+ * Complete Approval Workflow Demo
+ */
+ public void completeWorkflowDemo() {
+ try {
+ System.out.println("=== 企业微信流程审批完整演示 ===");
+
+ // 1. 提交审批申请
+ System.out.println("\n1. 提交审批申请...");
+ String spNo = submitApprovalApplication();
+
+ // 2. 获取审批详情
+ System.out.println("\n2. 获取审批详情...");
+ getApprovalDetails(spNo);
+
+ // 3. 批量获取审批信息
+ System.out.println("\n3. 批量获取审批信息...");
+ batchGetApprovalInfo();
+
+ // 4. 模板管理
+ System.out.println("\n4. 模板管理...");
+ templateManagement();
+
+ System.out.println("\n=== 演示完成 ===");
+ System.out.println("WxJava SDK 已经完整支持企业微信流程审批功能!");
+
+ } catch (Exception e) {
+ System.err.println("演示过程中发生错误: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public static void main(String[] args) {
+ // 注意: 这里需要配置真实的企业微信服务
+ // Note: You need to configure real WeChat Enterprise service here
+
+ System.out.println("企业微信流程审批功能演示");
+ System.out.println("该演示代码展示了WxJava SDK中已经完整实现的审批流程功能");
+ System.out.println("包括文档91853中描述的所有核心功能");
+ System.out.println("");
+ System.out.println("主要功能:");
+ System.out.println("- 提交审批申请 (/cgi-bin/oa/applyevent)");
+ System.out.println("- 获取审批详情 (/cgi-bin/oa/getapprovaldetail)");
+ System.out.println("- 批量获取审批单号 (/cgi-bin/oa/getapprovalinfo)");
+ System.out.println("- 模板管理功能");
+ System.out.println("- 审批流程引擎支持");
+ System.out.println("");
+ System.out.println("如需运行演示,请配置正确的企业微信服务参数。");
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java
index 6f2639c890..c0fc2d614b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImplTest.java
@@ -9,6 +9,8 @@
import me.chanjar.weixin.cp.bean.WxTpCustomizedAuthUrl;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
+import me.chanjar.weixin.cp.config.impl.AbstractWxCpTpInRedisConfigImpl;
+import me.chanjar.weixin.cp.config.impl.WxCpTpRedisTemplateConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpRedissonConfigImpl;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import org.mockito.Mockito;
@@ -69,7 +71,10 @@ public void setUp() {
* @return the wx cp tp config storage
*/
public WxCpTpConfigStorage wxCpTpConfigStorage() {
- return WxCpTpRedissonConfigImpl.builder().corpId(PROVIDER_CORP_ID).providerSecret(PROVIDER_SECRET).wxRedisOps(new RedissonWxRedisOps(redissonClient())).build();
+ WxCpTpRedissonConfigImpl wxCpTpRedissonConfig=new WxCpTpRedissonConfigImpl(redissonClient(),"");
+ wxCpTpRedissonConfig.setCorpId(PROVIDER_CORP_ID);
+ wxCpTpRedissonConfig.setProviderSecret(PROVIDER_SECRET);
+ return wxCpTpRedissonConfig;
}
/**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java
index 75927af4d9..b46ddf003b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImplTest.java
@@ -6,6 +6,8 @@
import me.chanjar.weixin.cp.bean.WxCpProviderToken;
import me.chanjar.weixin.cp.bean.WxCpTpCorpId2OpenCorpId;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+import me.chanjar.weixin.cp.config.impl.AbstractWxCpTpInRedisConfigImpl;
+import me.chanjar.weixin.cp.config.impl.WxCpTpRedisTemplateConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpRedissonConfigImpl;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import org.apache.commons.lang3.StringUtils;
@@ -48,14 +50,10 @@ public class WxCpTpServiceApacheHttpClientImplTest {
* The constant PROVIDER_CORP_ID.
*/
public static final String PROVIDER_CORP_ID = "xxxxxx";
- /**
- * The constant CORP_SECRET.
- */
- public static final String CORP_SECRET = "xxxxxx";
/**
* The constant PROVIDER_SECRET.
*/
- public static final String PROVIDER_SECRET = CORP_SECRET;
+ public static final String PROVIDER_SECRET = "xxxxxx";
/**
* The constant REDIS_ADDR.
*/
@@ -85,9 +83,15 @@ public void setUp() {
* @return the wx cp tp config storage
*/
public WxCpTpConfigStorage wxCpTpConfigStorage() {
- return WxCpTpRedissonConfigImpl.builder().baseApiUrl(API_URL).suiteId(SUITE_ID).suiteSecret(SUITE_SECRET)
- .token(TOKEN).aesKey(AES_KEY).corpId(PROVIDER_CORP_ID).corpSecret(CORP_SECRET).providerSecret(PROVIDER_SECRET)
- .wxRedisOps(new RedissonWxRedisOps(redissonClient())).build();
+ WxCpTpRedissonConfigImpl wxCpTpRedissonConfig=new WxCpTpRedissonConfigImpl(redissonClient(),"");
+ wxCpTpRedissonConfig.setBaseApiUrl(API_URL);
+ wxCpTpRedissonConfig.setSuiteId(SUITE_ID);
+ wxCpTpRedissonConfig.setSuiteSecret(SUITE_SECRET);
+ wxCpTpRedissonConfig.setToken(TOKEN);
+ wxCpTpRedissonConfig.setEncodingAESKey(AES_KEY);
+ wxCpTpRedissonConfig.setCorpId(PROVIDER_CORP_ID);
+ wxCpTpRedissonConfig.setProviderSecret(PROVIDER_SECRET);
+ return wxCpTpRedissonConfig;
}
/**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java
index 9b62a8d580..66be5c66a2 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapterTest.java
@@ -180,4 +180,31 @@ public void testSerialize() {
"{\"type\":2,\"name\":\"测试app\"," +
"\"miniprogram\":{\"appid\":\"wx8bd80126147df384\",\"pagepath\":\"/index\",\"title\":\"my miniprogram\"}}]}}");
}
+
+ /**
+ * Test directLeader empty array serialization.
+ * This test verifies that empty directLeader arrays are included in JSON as "direct_leader":[]
+ * instead of being omitted, which is required for WeChat Work API to reset user direct leaders.
+ */
+ @Test
+ public void testDirectLeaderEmptyArraySerialization() {
+ WxCpUser user = new WxCpUser();
+ user.setUserId("testuser");
+ user.setName("Test User");
+
+ // Test with empty array - should be serialized as "direct_leader":[]
+ user.setDirectLeader(new String[]{});
+ String json = user.toJson();
+ assertThat(json).contains("\"direct_leader\":[]");
+
+ // Test with null - should not include direct_leader field
+ user.setDirectLeader(null);
+ json = user.toJson();
+ assertThat(json).doesNotContain("direct_leader");
+
+ // Test with non-empty array - should be serialized normally
+ user.setDirectLeader(new String[]{"leader1", "leader2"});
+ json = user.toJson();
+ assertThat(json).contains("\"direct_leader\":[\"leader1\",\"leader2\"]");
+ }
}
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index a9bb5f37dc..ac308a4164 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
com.github.binarywang
wx-java
- 4.7.0
+ 4.7.9.B
weixin-java-miniapp
@@ -31,6 +31,11 @@
okhttp
provided
+
+ org.apache.httpcomponents.client5
+ httpclient5
+ provided
+
org.testng
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java
index fa6d444406..d6d13431d5 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java
@@ -7,7 +7,7 @@
import java.util.List;
/**
- * 小程序数据分析相关接口
+ * 小程序数据分析相关接口。
* 文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/analysis.html
*
* @author Charming
@@ -16,114 +16,114 @@
public interface WxMaAnalysisService {
/**
- * 查询概况趋势
+ * 查询概况趋势。
* 温馨提示:小程序接口目前只能查询一天的数据,即 beginDate 和 endDate 一样
*
- * @param beginDate 开始日期
- * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
- * @return 概况趋势
+ * @param beginDate 开始日期
+ * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
+ * @return 概况趋势列表
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
List getDailySummaryTrend(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 获取日访问趋势
+ * 获取日访问趋势。
* 温馨提示:小程序接口目前只能查询一天的数据,即 beginDate 和 endDate 一样
*
- * @param beginDate 开始日期
- * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
- * @return 日访问趋势
+ * @param beginDate 开始日期
+ * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
+ * @return 日访问趋势列表
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
List getDailyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 获取周访问趋势
+ * 获取周访问趋势。
* 限定查询一个自然周的数据,时间必须按照自然周的方式输入: 如:20170306(周一), 20170312(周日)
*
- * @param beginDate 开始日期,为周一日期
- * @param endDate 结束日期,为周日日期,限定查询一周数据
- * @return 周访问趋势(每项数据都是一个自然周汇总)
+ * @param beginDate 开始日期,为周一日期
+ * @param endDate 结束日期,为周日日期,限定查询一周数据
+ * @return 周访问趋势列表(每项数据都是一个自然周汇总)
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
List getWeeklyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 获取月访问趋势
+ * 获取月访问趋势。
* 限定查询一个自然月的数据,时间必须按照自然月的方式输入: 如:20170201(月初), 20170228(月末)
*
- * @param beginDate 开始日期,为自然月第一天
- * @param endDate 结束日期,为自然月最后一天,限定查询一个月数据
- * @return 月访问趋势(每项数据都是一个自然月汇总)
+ * @param beginDate 开始日期,为自然月第一天
+ * @param endDate 结束日期,为自然月最后一天,限定查询一个月数据
+ * @return 月访问趋势列表(每项数据都是一个自然月汇总)
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
List getMonthlyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 获取访问分布
+ * 获取访问分布。
* (此接口目前只能查询一天的数据,即 beginDate 和 endDate 一样)
*
- * @param beginDate 开始日期,为周一日期
- * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
- * @return 访问分布
+ * @param beginDate 开始日期
+ * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
+ * @return 访问分布对象
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
WxMaVisitDistribution getVisitDistribution(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 日留存
+ * 获取日留存数据。
* (此接口目前只能查询一天的数据,即 beginDate 和 endDate 一样)
*
- * @param beginDate 开始日期,为周一日期
- * @param endDate 结束日期,限定查询 1 天数据,endDate 允许设置的最大值为昨日
- * @return 日留存
+ * @param beginDate 开始日期
+ * @param endDate 结束日期,限定查询 1 天数据,endDate 允许设置的最大值为昨日
+ * @return 日留存信息对象
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
WxMaRetainInfo getDailyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 周留存
+ * 获取周留存数据。
* 限定查询一个自然周的数据,时间必须按照自然周的方式输入: 如:20170306(周一), 20170312(周日)
*
- * @param beginDate 开始日期,为周一日期
- * @param endDate 结束日期,为周日日期,限定查询一周数据
- * @return 周留存
+ * @param beginDate 开始日期,为周一日期
+ * @param endDate 结束日期,为周日日期,限定查询一周数据
+ * @return 周留存信息对象
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
WxMaRetainInfo getWeeklyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 月留存
+ * 获取月留存数据。
* 限定查询一个自然月的数据,时间必须按照自然月的方式输入: 如:20170201(月初), 20170228(月末)
*
- * @param beginDate 开始日期,为自然月第一天
- * @param endDate 结束日期,为自然月最后一天,限定查询一个月数据
- * @return 月留存
+ * @param beginDate 开始日期,为自然月第一天
+ * @param endDate 结束日期,为自然月最后一天,限定查询一个月数据
+ * @return 月留存信息对象
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
WxMaRetainInfo getMonthlyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 获取访问页面数据
+ * 获取访问页面数据。
* 温馨提示:此接口目前只能查询一天的数据,即 beginDate 和 endDate 一样
*
- * @param beginDate 开始日期
- * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
- * @return 访问页面数据
+ * @param beginDate 开始日期
+ * @param endDate 结束日期,限定查询1天数据,end_date允许设置的最大值为昨日
+ * @return 访问页面数据列表
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
List getVisitPage(Date beginDate, Date endDate) throws WxErrorException;
/**
- * 获取小程序新增或活跃用户的画像分布数据
+ * 获取小程序新增或活跃用户的画像分布数据。
* 时间范围支持昨天、最近7天、最近30天。
* 其中,新增用户数为时间范围内首次访问小程序的去重用户数,
* 活跃用户数为时间范围内访问过小程序的去重用户数。
* 画像属性包括用户年龄、性别、省份、城市、终端类型、机型。
*
- * @param beginDate 开始日期
- * @param endDate 结束日期,开始日期与结束日期相差的天数限定为0/6/29,分别表示查询最近1/7/30天数据,end_date允许设置的最大值为昨日
- * @return 小程序新增或活跃用户的画像分布数据
+ * @param beginDate 开始日期
+ * @param endDate 结束日期,开始日期与结束日期相差的天数限定为0/6/29,分别表示查询最近1/7/30天数据,end_date允许设置的最大值为昨日
+ * @return 小程序新增或活跃用户的画像分布数据对象
* @throws WxErrorException 获取失败时抛出,具体错误码请看文档
*/
WxMaUserPortrait getUserPortrait(Date beginDate, Date endDate) throws WxErrorException;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java
index 4e18fec5c4..ea7e9ab20f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java
@@ -16,539 +16,457 @@
*/
public interface WxMaCloudService {
/**
- * Invoke cloud function string.
+ * 触发云函数。注意:HTTP API 途径触发云函数不包含用户信息。
*
- * @param name the name
- * @param body the body
- * @return the string
- * @throws WxErrorException the wx error exception
+ * @param name 云函数名称
+ * @param body 云函数的传入参数,具体结构由开发者定义
+ * @return 云函数返回的buffer
+ * @throws WxErrorException 调用失败时抛出
*/
String invokeCloudFunction(String name, String body) throws WxErrorException;
/**
- *
* 触发云函数。注意:HTTP API 途径触发云函数不包含用户信息。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/functions/invokeCloudFunction.html
*
- * 请求地址
- * POST https://api.weixin.qq.com/tcb/invokecloudfunction?access_token=ACCESS_TOKEN&env=ENV&name=FUNCTION_NAME
- *
- *
- *
- * @param env string 是 云开发环境ID
- * @param name string 是 云函数名称
- * @param body string 是 云函数的传入参数,具体结构由开发者定义。
- * @return resp_data string 云函数返回的buffer
- * @throws WxErrorException .
+ * @param env 云开发环境ID
+ * @param name 云函数名称
+ * @param body 云函数的传入参数,具体结构由开发者定义
+ * @return 云函数返回的buffer
+ * @throws WxErrorException 调用失败时抛出
*/
String invokeCloudFunction(String env, String name, String body) throws WxErrorException;
/**
- * Add list.
+ * 批量添加记录到集合。
*
- * @param collection the collection
- * @param list the list
- * @return the list
- * @throws WxErrorException the wx error exception
+ * @param collection 集合名称
+ * @param list 要添加的记录列表
+ * @return 插入成功的记录ID列表
+ * @throws WxErrorException 添加失败时抛出
*/
- List add(String collection, List list) throws WxErrorException;
+ List add(String collection, List> list) throws WxErrorException;
/**
- * Add string.
+ * 添加单条记录到集合。
*
- * @param collection the collection
- * @param obj the obj
- * @return the string
- * @throws WxErrorException the wx error exception
+ * @param collection 集合名称
+ * @param obj 要添加的记录对象
+ * @return 插入成功的记录ID
+ * @throws WxErrorException 添加失败时抛出
*/
String add(String collection, Object obj) throws WxErrorException;
/**
- * Database add json array.
+ * 数据库插入记录。
*
- * @param query the query
- * @return the json array
- * @throws WxErrorException the wx error exception
+ * @param query 数据库操作语句
+ * @return 插入成功的数据集合主键_id列表
+ * @throws WxErrorException 插入失败时抛出
*/
JsonArray databaseAdd(String query) throws WxErrorException;
/**
- *
- * 数据库插入记录
- *
+ * 数据库插入记录。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAdd.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databaseadd?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param query 数据库操作语句
- * @return 插入成功的数据集合主键_id json array
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param query 数据库操作语句
+ * @return 插入成功的数据集合主键_id列表
+ * @throws WxErrorException 插入失败时抛出
*/
JsonArray databaseAdd(String env, String query) throws WxErrorException;
/**
- * Delete integer.
+ * 删除集合中符合条件的记录。
*
- * @param collection the collection
- * @param whereJson the where json
- * @return the integer
- * @throws WxErrorException the wx error exception
+ * @param collection 集合名称
+ * @param whereJson 查询条件JSON字符串
+ * @return 删除的记录数量
+ * @throws WxErrorException 删除失败时抛出
*/
Integer delete(String collection, String whereJson) throws WxErrorException;
/**
- * Database delete int.
+ * 数据库删除记录。
*
- * @param query the query
- * @return the int
- * @throws WxErrorException the wx error exception
+ * @param query 数据库操作语句
+ * @return 删除记录数量
+ * @throws WxErrorException 删除失败时抛出
*/
int databaseDelete(String query) throws WxErrorException;
/**
- *
- * 数据库删除记录
- *
+ * 数据库删除记录。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseDelete.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasedelete?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param query 数据库操作语句
- * @return 删除记录数量 int
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param query 数据库操作语句
+ * @return 删除记录数量
+ * @throws WxErrorException 删除失败时抛出
*/
int databaseDelete(String env, String query) throws WxErrorException;
/**
- * Update wx cloud database update result.
+ * 更新集合中符合条件的记录。
*
- * @param collection the collection
- * @param whereJson the where json
- * @param updateJson the update json
- * @return the wx cloud database update result
- * @throws WxErrorException the wx error exception
+ * @param collection 集合名称
+ * @param whereJson 查询条件JSON字符串
+ * @param updateJson 更新内容JSON字符串
+ * @return 更新结果对象
+ * @throws WxErrorException 更新失败时抛出
*/
WxCloudDatabaseUpdateResult update(String collection, String whereJson, String updateJson) throws WxErrorException;
/**
- * Database update wx cloud database update result.
+ * 数据库更新记录。
*
- * @param query the query
- * @return the wx cloud database update result
- * @throws WxErrorException the wx error exception
+ * @param query 数据库操作语句
+ * @return 更新结果对象
+ * @throws WxErrorException 更新失败时抛出
*/
WxCloudDatabaseUpdateResult databaseUpdate(String query) throws WxErrorException;
/**
- *
- * 数据库更新记录
- *
+ * 数据库更新记录。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseUpdate.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databaseupdate?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param query 数据库操作语句
- * @return . wx cloud database update result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param query 数据库操作语句
+ * @return 更新结果对象
+ * @throws WxErrorException 更新失败时抛出
*/
WxCloudDatabaseUpdateResult databaseUpdate(String env, String query) throws WxErrorException;
/**
+ * 查询集合中的记录。
+ * 示例:
* db.collection('geo')
- * .where({
- * price: _.gt(10)
- * })
- * .orderBy('_id', 'asc')
- * .orderBy('price', 'desc')
- * .skip(1)
- * .limit(10)
- * .get()
- *
- * @param collection the collection
- * @param whereJson the where json
- * @param orderBy the order by
- * @param skip the skip
- * @param limit the limit
- * @return wx cloud database query result
- * @throws WxErrorException the wx error exception
+ * .where({price: _.gt(10)})
+ * .orderBy('_id', 'asc')
+ * .orderBy('price', 'desc')
+ * .skip(1)
+ * .limit(10)
+ * .get()
+ *
+ * @param collection 集合名称
+ * @param whereJson 查询条件JSON字符串
+ * @param orderBy 排序条件Map
+ * @param skip 跳过记录数
+ * @param limit 限制返回记录数
+ * @return 查询结果对象
+ * @throws WxErrorException 查询失败时抛出
*/
WxCloudDatabaseQueryResult query(String collection, String whereJson, Map orderBy,
Integer skip, Integer limit) throws WxErrorException;
/**
- * Database query wx cloud database query result.
+ * 数据库查询记录。
*
- * @param query the query
- * @return the wx cloud database query result
- * @throws WxErrorException the wx error exception
+ * @param query 数据库操作语句
+ * @return 查询结果对象
+ * @throws WxErrorException 查询失败时抛出
*/
WxCloudDatabaseQueryResult databaseQuery(String query) throws WxErrorException;
/**
- *
- * 数据库查询记录
- *
+ * 数据库查询记录。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseQuery.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasequery?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param query 数据库操作语句
- * @return . wx cloud database query result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param query 数据库操作语句
+ * @return 查询结果对象
+ * @throws WxErrorException 查询失败时抛出
*/
WxCloudDatabaseQueryResult databaseQuery(String env, String query) throws WxErrorException;
/**
- * Database aggregate json array.
+ * 数据库聚合记录。
*
- * @param query the query
- * @return the json array
- * @throws WxErrorException the wx error exception
+ * @param query 数据库操作语句
+ * @return 聚合结果JSON数组
+ * @throws WxErrorException 聚合失败时抛出
*/
JsonArray databaseAggregate(String query) throws WxErrorException;
/**
- *
- * 数据库聚合记录
- *
+ * 数据库聚合记录。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAggregate.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databaseaggregate?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param query 数据库操作语句
- * @return . json array
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param query 数据库操作语句
+ * @return 聚合结果JSON数组
+ * @throws WxErrorException 聚合失败时抛出
*/
JsonArray databaseAggregate(String env, String query) throws WxErrorException;
/**
- * Count long.
+ * 统计集合中符合条件的记录数。
*
- * @param collection the collection
- * @param whereJson the where json
- * @return the long
- * @throws WxErrorException the wx error exception
+ * @param collection 集合名称
+ * @param whereJson 查询条件JSON字符串
+ * @return 记录数量
+ * @throws WxErrorException 统计失败时抛出
*/
Long count(String collection, String whereJson) throws WxErrorException;
/**
- * Database count long.
+ * 统计集合记录数或统计查询语句对应的结果记录数。
*
- * @param query the query
- * @return the long
- * @throws WxErrorException the wx error exception
+ * @param query 数据库操作语句
+ * @return 记录数量
+ * @throws WxErrorException 统计失败时抛出
*/
Long databaseCount(String query) throws WxErrorException;
/**
- *
- * 统计集合记录数或统计查询语句对应的结果记录数
- *
+ * 统计集合记录数或统计查询语句对应的结果记录数。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCount.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasecount?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param query 数据库操作语句
- * @return 记录数量 long
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param query 数据库操作语句
+ * @return 记录数量
+ * @throws WxErrorException 统计失败时抛出
*/
Long databaseCount(String env, String query) throws WxErrorException;
/**
- * Update index.
+ * 变更数据库索引。
*
- * @param collectionName the collection name
- * @param createIndexes the create indexes
- * @param dropIndexNames the drop index names
- * @throws WxErrorException the wx error exception
+ * @param collectionName 集合名称
+ * @param createIndexes 新增索引对象列表
+ * @param dropIndexNames 要删除的索引名称列表
+ * @throws WxErrorException 更新失败时抛出
*/
void updateIndex(String collectionName, List createIndexes,
List dropIndexNames) throws WxErrorException;
/**
- *
- * 变更数据库索引
- *
+ * 变更数据库索引。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/updateIndex.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/updateindex?access_token=ACCESS_TOKEN
- *
*
- * @param env 云环境ID
- * @param collectionName 集合名称
- * @param createIndexes 新增索引对象
- * @param dropIndexNames 要删除的索引的名字
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param collectionName 集合名称
+ * @param createIndexes 新增索引对象列表
+ * @param dropIndexNames 要删除的索引名称列表
+ * @throws WxErrorException 更新失败时抛出
*/
void updateIndex(String env, String collectionName, List createIndexes,
List dropIndexNames) throws WxErrorException;
/**
- * Database migrate import long.
+ * 数据库导入。
*
- * @param collectionName the collection name
- * @param filePath the file path
- * @param fileType the file type
- * @param stopOnError the stop on error
- * @param conflictMode the conflict mode
- * @return the long
- * @throws WxErrorException the wx error exception
+ * @param collectionName 导入collection名
+ * @param filePath 导入文件路径
+ * @param fileType 导入文件类型,1:JSON,2:CSV
+ * @param stopOnError 是否在遇到错误时停止导入
+ * @param conflictMode 冲突处理模式,1:INSERT,2:UPSERT
+ * @return 任务ID
+ * @throws WxErrorException 导入失败时抛出
*/
Long databaseMigrateImport(String collectionName, String filePath, int fileType,
boolean stopOnError, int conflictMode) throws WxErrorException;
/**
- *
- * 数据库导入
+ * 数据库导入。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateImport.html
+ * 注意:导入文件需先上传到同环境的存储中,可使用开发者工具或HTTP API的上传文件API上传
*
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateImport
- * .html
- * 请求地址: POST https://api.weixin.qq.com/tcb/databasemigrateimport?access_token=ACCESS_TOKEN
- *
- *
- * @param env 云环境ID
- * @param collectionName 导入collection名
- * @param filePath 导入文件路径(导入文件需先上传到同环境的存储中,可使用开发者工具或 HTTP API的上传文件 API上传)
- * @param fileType 导入文件类型, 1 JSON, 2 CSV
- * @param stopOnError 是否在遇到错误时停止导入
- * @param conflictMode 冲突处理模式 : 1 INSERT , 2 UPSERT
- * @return jobId long
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param collectionName 导入collection名
+ * @param filePath 导入文件路径
+ * @param fileType 导入文件类型,1:JSON,2:CSV
+ * @param stopOnError 是否在遇到错误时停止导入
+ * @param conflictMode 冲突处理模式,1:INSERT,2:UPSERT
+ * @return 任务ID
+ * @throws WxErrorException 导入失败时抛出
*/
Long databaseMigrateImport(String env, String collectionName, String filePath, int fileType, boolean stopOnError,
int conflictMode) throws WxErrorException;
/**
- * Database migrate export long.
+ * 数据库导出。
*
- * @param filePath the file path
- * @param fileType the file type
- * @param query the query
- * @return the long
- * @throws WxErrorException the wx error exception
+ * @param filePath 导出文件路径
+ * @param fileType 导出文件类型,1:JSON,2:CSV
+ * @param query 导出条件
+ * @return 任务ID
+ * @throws WxErrorException 导出失败时抛出
*/
Long databaseMigrateExport(String filePath, int fileType, String query) throws WxErrorException;
/**
- *
- * 数据库导出
- *
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateExport
- * .html
- * 请求地址: POST https://api.weixin.qq.com/tcb/databasemigrateexport?access_token=ACCESS_TOKEN
- *
+ * 数据库导出。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateExport.html
+ * 注意:文件会导出到同环境的云存储中,可使用获取下载链接API获取下载链接
*
- * @param env 云环境ID
- * @param filePath 导出文件路径(文件会导出到同环境的云存储中,可使用获取下载链接 API 获取下载链接)
- * @param fileType 导出文件类型, 1 JSON, 2 CSV
- * @param query 导出条件
- * @return jobId long
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param filePath 导出文件路径
+ * @param fileType 导出文件类型,1:JSON,2:CSV
+ * @param query 导出条件
+ * @return 任务ID
+ * @throws WxErrorException 导出失败时抛出
*/
Long databaseMigrateExport(String env, String filePath, int fileType, String query) throws WxErrorException;
/**
- * Database migrate query info wx cloud cloud database migrate query info result.
+ * 数据库迁移状态查询。
*
- * @param jobId the job id
- * @return the wx cloud cloud database migrate query info result
- * @throws WxErrorException the wx error exception
+ * @param jobId 迁移任务ID
+ * @return 迁移状态查询结果
+ * @throws WxErrorException 查询失败时抛出
*/
WxCloudCloudDatabaseMigrateQueryInfoResult databaseMigrateQueryInfo(Long jobId) throws WxErrorException;
/**
- *
- * 数据库迁移状态查询
- *
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database
- * /databaseMigrateQueryInfo.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasemigratequeryinfo?access_token=ACCESS_TOKEN
- *
+ * 数据库迁移状态查询。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateQueryInfo.html
*
- * @param env 云环境ID
- * @param jobId 迁移任务ID
- * @return . wx cloud cloud database migrate query info result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param jobId 迁移任务ID
+ * @return 迁移状态查询结果
+ * @throws WxErrorException 查询失败时抛出
*/
WxCloudCloudDatabaseMigrateQueryInfoResult databaseMigrateQueryInfo(String env, Long jobId) throws WxErrorException;
/**
- * Upload file wx cloud upload file result.
+ * 获取文件上传链接。
*
- * @param path the path
- * @return the wx cloud upload file result
- * @throws WxErrorException the wx error exception
+ * @param path 上传路径
+ * @return 上传结果对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudUploadFileResult uploadFile(String path) throws WxErrorException;
/**
- *
- * 获取文件上传链接
- *
+ * 获取文件上传链接。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN
- *
- *
*
- * @param env 云环境ID
- * @param path 上传路径
- * @return 上传结果 wx cloud upload file result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param path 上传路径
+ * @return 上传结果对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudUploadFileResult uploadFile(String env, String path) throws WxErrorException;
/**
- * Batch download file wx cloud batch download file result.
+ * 获取文件下载链接。
*
- * @param fileIds the file ids
- * @param maxAges the max ages
- * @return the wx cloud batch download file result
- * @throws WxErrorException the wx error exception
+ * @param fileIds 文件ID数组
+ * @param maxAges 下载链接有效期数组,对应文件id列表
+ * @return 下载链接信息对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudBatchDownloadFileResult batchDownloadFile(String[] fileIds, long[] maxAges) throws WxErrorException;
/**
- *
- * 获取文件下载链接
- *
+ * 获取文件下载链接。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDownloadFile.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/batchdownloadfile?access_token=ACCESS_TOKEN
- *
- *
*
- * @param env 云环境ID
- * @param fileIds 文件ID列表
- * @param maxAges 下载链接有效期列表,对应文件id列表
- * @return 下载链接信息 wx cloud batch download file result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param fileIds 文件ID数组
+ * @param maxAges 下载链接有效期数组,对应文件id列表
+ * @return 下载链接信息对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudBatchDownloadFileResult batchDownloadFile(String env, String[] fileIds, long[] maxAges) throws WxErrorException;
/**
- * Batch delete file wx cloud batch delete file result.
+ * 删除文件。
*
- * @param fileIds the file ids
- * @return the wx cloud batch delete file result
- * @throws WxErrorException the wx error exception
+ * @param fileIds 文件ID数组
+ * @return 删除结果对象
+ * @throws WxErrorException 删除失败时抛出
*/
WxCloudBatchDeleteFileResult batchDeleteFile(String[] fileIds) throws WxErrorException;
/**
- *
- * 删除文件
- *
+ * 删除文件。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDeleteFile.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/batchdeletefile?access_token=ACCESS_TOKEN
- *
- *
*
- * @param env 云环境ID
- * @param fileIds 文件ID列表
- * @return 下载链接信息 wx cloud batch delete file result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param fileIds 文件ID数组
+ * @return 删除结果对象
+ * @throws WxErrorException 删除失败时抛出
*/
WxCloudBatchDeleteFileResult batchDeleteFile(String env, String[] fileIds) throws WxErrorException;
/**
- *
- * 获取腾讯云API调用凭证
- *
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/utils/getQcloudToken.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/getqcloudtoken?access_token=ACCESS_TOKEN
- *
+ * 获取腾讯云API调用凭证。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/utils/getQcloudToken.html
*
- * @param lifeSpan 有效期(单位为秒,最大7200)
- * @return . qcloud token
- * @throws WxErrorException .
+ * @param lifeSpan 有效期(单位为秒,最大7200)
+ * @return 腾讯云Token结果对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudGetQcloudTokenResult getQcloudToken(long lifeSpan) throws WxErrorException;
/**
- * Database collection add.
+ * 新增集合。
*
- * @param collectionName the collection name
- * @throws WxErrorException the wx error exception
+ * @param collectionName 集合名称
+ * @throws WxErrorException 新增失败时抛出
*/
void databaseCollectionAdd(String collectionName) throws WxErrorException;
/**
- *
- * 新增集合
+ * 新增集合。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionAdd.html
*
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionAdd
- * .html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasecollectionadd?access_token=ACCESS_TOKEN
- *
- *
- * @param env 云环境ID
- * @param collectionName 集合名称
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param collectionName 集合名称
+ * @throws WxErrorException 新增失败时抛出
*/
void databaseCollectionAdd(String env, String collectionName) throws WxErrorException;
/**
- * Database collection delete.
+ * 删除集合。
*
- * @param collectionName the collection name
- * @throws WxErrorException the wx error exception
+ * @param collectionName 集合名称
+ * @throws WxErrorException 删除失败时抛出
*/
void databaseCollectionDelete(String collectionName) throws WxErrorException;
/**
- *
- * 删除集合
- *
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database
- * /databaseCollectionDelete.html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasecollectionadd?access_token=ACCESS_TOKEN
- *
+ * 删除集合。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionDelete.html
*
- * @param env 云环境ID
- * @param collectionName 集合名称
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param collectionName 集合名称
+ * @throws WxErrorException 删除失败时抛出
*/
void databaseCollectionDelete(String env, String collectionName) throws WxErrorException;
/**
- * Database collection get wx cloud database collection get result.
+ * 获取特定云环境下集合信息。
*
- * @param limit the limit
- * @param offset the offset
- * @return the wx cloud database collection get result
- * @throws WxErrorException the wx error exception
+ * @param limit 获取数量限制,默认值:10
+ * @param offset 偏移量,默认值:0
+ * @return 集合信息获取结果对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudDatabaseCollectionGetResult databaseCollectionGet(Long limit, Long offset) throws WxErrorException;
/**
- *
- * 获取特定云环境下集合信息
- *
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionGet
- * .html
- * 请求地址:POST https://api.weixin.qq.com/tcb/databasecollectionget?access_token=ACCESS_TOKEN
- *
+ * 获取特定云环境下集合信息。
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionGet.html
*
- * @param env 云环境ID
- * @param limit 获取数量限制,默认值:10
- * @param offset 偏移量,默认值:0
- * @return . wx cloud database collection get result
- * @throws WxErrorException .
+ * @param env 云环境ID
+ * @param limit 获取数量限制,默认值:10
+ * @param offset 偏移量,默认值:0
+ * @return 集合信息获取结果对象
+ * @throws WxErrorException 获取失败时抛出
*/
WxCloudDatabaseCollectionGetResult databaseCollectionGet(String env, Long limit, Long offset) throws WxErrorException;
/**
- * 发送携带 URL Link 的短信
- *
+ * 发送携带 URL Link 的短信。
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/cloudbase/cloudbase.sendSmsV2.html
- * @param request
- * @return WxCloudSendSmsV2Result
- * @throws WxErrorException
+ *
+ * @param request 短信发送请求对象
+ * @return 短信发送结果对象
+ * @throws WxErrorException 发送失败时抛出
*/
WxCloudSendSmsV2Result sendSmsV2(WxCloudSendSmsV2Request request) throws WxErrorException;
-
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaComplaintService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaComplaintService.java
new file mode 100644
index 0000000000..bd12f60850
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaComplaintService.java
@@ -0,0 +1,159 @@
+package cn.binarywang.wx.miniapp.api;
+
+import cn.binarywang.wx.miniapp.bean.complaint.*;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 小程序交易投诉接口
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+public interface WxMaComplaintService {
+
+ /**
+ *
+ * 查询投诉单列表API
+ * 商户可通过调用此接口,查询指定时间段的所有用户投诉信息,以分页输出查询结果。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaComplaintRequest} 查询投诉单列表请求数据
+ * @return {@link WxMaComplaintResult} 微信返回的投诉单列表
+ * @throws WxErrorException the wx error exception
+ */
+ WxMaComplaintResult queryComplaints(WxMaComplaintRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 查询投诉单详情API
+ * 商户可通过调用此接口,查询指定投诉单的用户投诉详情,包含投诉内容、投诉关联订单、投诉人联系方式等信息,方便商户处理投诉。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaComplaintDetailRequest} 投诉单详情请求数据
+ * @return {@link WxMaComplaintDetailResult} 微信返回的投诉单详情
+ * @throws WxErrorException the wx error exception
+ */
+ WxMaComplaintDetailResult getComplaint(WxMaComplaintDetailRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 查询投诉协商历史API
+ * 商户可通过调用此接口,查询指定投诉的用户商户协商历史,以分页输出查询结果,方便商户根据处理历史来制定后续处理方案。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaNegotiationHistoryRequest} 请求数据
+ * @return {@link WxMaNegotiationHistoryResult} 微信返回结果
+ * @throws WxErrorException the wx error exception
+ */
+ WxMaNegotiationHistoryResult queryNegotiationHistorys(WxMaNegotiationHistoryRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 创建投诉通知回调地址API
+ * 商户通过调用此接口创建投诉通知回调URL,当用户产生新投诉且投诉状态已变更时,微信会通过回调URL通知商户。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaComplaintNotifyUrlRequest} 请求数据
+ * @return {@link WxMaComplaintNotifyUrlResult} 微信返回结果
+ * @throws WxErrorException the wx error exception
+ */
+ WxMaComplaintNotifyUrlResult addComplaintNotifyUrl(WxMaComplaintNotifyUrlRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 查询投诉通知回调地址API
+ * 商户通过调用此接口查询投诉通知的回调URL。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @return {@link WxMaComplaintNotifyUrlResult} 微信返回结果
+ * @throws WxErrorException the wx error exception
+ */
+ WxMaComplaintNotifyUrlResult getComplaintNotifyUrl() throws WxErrorException;
+
+ /**
+ *
+ * 更新投诉通知回调地址API
+ * 商户通过调用此接口更新投诉通知的回调URL。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaComplaintNotifyUrlRequest} 请求数据
+ * @return {@link WxMaComplaintNotifyUrlResult} 微信返回结果
+ * @throws WxErrorException the wx error exception
+ */
+ WxMaComplaintNotifyUrlResult updateComplaintNotifyUrl(WxMaComplaintNotifyUrlRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 删除投诉通知回调地址API
+ * 当商户不再需要推送通知时,可通过调用此接口删除投诉通知的回调URL,取消通知回调。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @throws WxErrorException the wx error exception
+ */
+ void deleteComplaintNotifyUrl() throws WxErrorException;
+
+ /**
+ *
+ * 提交回复API
+ * 商户可通过调用此接口,提交回复内容。其中上传图片凭证需首先调用商户上传反馈图片接口,得到图片id,再将id填入请求。
+ * 回复可配置文字链,传入跳转链接文案和跳转链接字段,用户点击即可跳转对应页面
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaResponseRequest} 请求数据
+ * @throws WxErrorException the wx error exception
+ */
+ void submitResponse(WxMaResponseRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 反馈处理完成API
+ * 商户可通过调用此接口,反馈投诉单已处理完成。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param request {@link WxMaCompleteRequest} 请求数据
+ * @throws WxErrorException the wx error exception
+ */
+ void complete(WxMaCompleteRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 商户上传反馈图片API
+ * 商户可通过调用此接口上传反馈图片凭证,上传成功后可在提交回复时使用。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param imageFile 需要上传的图片文件
+ * @return String 微信返回的媒体文件标识Id
+ * @throws WxErrorException the wx error exception
+ * @throws IOException IO异常
+ */
+ String uploadResponseImage(File imageFile) throws WxErrorException, IOException;
+
+ /**
+ *
+ * 商户上传反馈图片API
+ * 商户可通过调用此接口上传反馈图片凭证,上传成功后可在提交回复时使用。
+ * 文档详见: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ *
+ * @param inputStream 需要上传的图片文件流
+ * @param fileName 需要上传的图片文件名
+ * @return String 微信返回的媒体文件标识Id
+ * @throws WxErrorException the wx error exception
+ * @throws IOException IO异常
+ */
+ String uploadResponseImage(InputStream inputStream, String fileName) throws WxErrorException, IOException;
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCustomserviceWorkService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCustomserviceWorkService.java
new file mode 100644
index 0000000000..bf119bc596
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCustomserviceWorkService.java
@@ -0,0 +1,57 @@
+package cn.binarywang.wx.miniapp.api;
+
+import cn.binarywang.wx.miniapp.bean.customservice.WxMaCustomserviceResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+
+/**
+ *
+ * 小程序 - 微信客服 相关接口
+ * 负责处理 https://api.weixin.qq.com/customservice/work/**
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/kf-work/getKfWorkBound.html
+ * 绑定的企业ID,需和小程序主体一致。
+ * 目前仅支持绑定非个人小程序。
+ * Created by tryking123 on 2025/8/18.
+ *
+ *
+ * @author tryking123
+ */
+public interface WxMaCustomserviceWorkService {
+
+ /**
+ * 查询小程序的微信客服绑定情况
+ */
+ String GET_CUSTOMSERVICE_URL = "https://api.weixin.qq.com/customservice/work/get";
+ /**
+ * 为小程序绑定微信客服 注:此接口绑定的企业ID需完成企业认证
+ */
+ String BIND_CUSTOMSERVICE_URL = "https://api.weixin.qq.com/customservice/work/bind";
+ /**
+ * 为小程序解除绑定微信客服
+ */
+ String UNBIND_CUSTOMSERVICE_URL = "https://api.weixin.qq.com/customservice/work/unbind";
+
+ /**
+ * 查询小程序的微信客服绑定情况
+ *
+ * @return 成功示例json { "errcode": 0,"entityName": "XXXXX有限公司","corpid": "wwee11111xxxxxxx","bindTime": 1694611289 }
+ * @throws WxErrorException
+ */
+ WxMaCustomserviceResult getCustomservice() throws WxErrorException;
+
+ /**
+ * 绑定微信客服
+ * @param corpid 企业ID,获取方式参考:https://developer.work.weixin.qq.com/document/path/90665#corpid
+ * @return 成功示例json { "errcode": 0 }
+ * @throws WxErrorException
+ */
+ WxMaCustomserviceResult bindCustomservice(String corpid) throws WxErrorException;
+
+ /**
+ * 解除绑定微信客服
+ * @param corpid 企业ID,获取方式参考:https://developer.work.weixin.qq.com/document/path/90665#corpid
+ * @return 成功示例json { "errcode": 0 }
+ * @throws WxErrorException
+ */
+ WxMaCustomserviceResult unbindCustomservice(String corpid) throws WxErrorException;
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java
index 4254d18dfe..6d950f6801 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java
@@ -5,18 +5,47 @@
import me.chanjar.weixin.common.error.WxErrorException;
/**
- * 退货组件
+ * 微信小程序物流退货组件接口。
+ * 用于处理退货单相关操作,包括新增、查询和取消退货单。
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/express.html
+ *
*/
public interface WxMaExpressDeliveryReturnService {
- /**
- * 获取支持的快递公司列表
- */
+ /** 新增退货单接口地址 */
String ADD_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/add";
+ /** 获取退货单接口地址 */
String GET_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/get";
+ /** 取消退货单接口地址 */
String UNBIND_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/unbind";
+ /**
+ * 新增退货单。
+ * 用于创建新的退货单,返回退货单信息。
+ *
+ * @param wxMaExpressDeliveryReturnAddRequest 退货单新增请求对象
+ * @return 退货单信息结果
+ * @throws WxErrorException 新增失败时抛出
+ */
WxMaExpressReturnInfoResult addDeliveryReturn(WxMaExpressDeliveryReturnAddRequest wxMaExpressDeliveryReturnAddRequest) throws WxErrorException;
+
+ /**
+ * 获取退货单信息。
+ * 根据退货单ID查询退货单的详细信息。
+ *
+ * @param returnId 退货单ID
+ * @return 退货单信息结果
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaExpressReturnInfoResult getDeliveryReturn(String returnId) throws WxErrorException;
+
+ /**
+ * 取消退货单。
+ * 取消指定的退货单,取消后的退货单将无法继续使用。
+ *
+ * @param returnId 退货单ID
+ * @return 操作结果
+ * @throws WxErrorException 取消失败时抛出
+ */
WxMaExpressReturnInfoResult unbindDeliveryReturn(String returnId) throws WxErrorException;
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaKefuService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaKefuService.java
new file mode 100644
index 0000000000..b8b5a03809
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaKefuService.java
@@ -0,0 +1,128 @@
+package cn.binarywang.wx.miniapp.api;
+
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfInfo;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfList;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSession;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSessionList;
+import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfAccountRequest;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ *
+ * 小程序客服管理接口.
+ * 不同于 WxMaCustomserviceWorkService (企业微信客服绑定) 和 WxMaMsgService.sendKefuMsg (发送客服消息),
+ * 此接口专门处理小程序客服账号管理、会话管理等功能。
+ *
+ * 注意:小程序客服管理接口与公众号客服管理接口在API端点和功能上有所不同。
+ *
+ *
+ * @author Binary Wang
+ */
+public interface WxMaKefuService {
+
+ /**
+ *
+ * 获取客服基本信息
+ * 详情请见:获取客服基本信息
+ * 接口url格式:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
+ *
+ *
+ * @return 客服列表
+ * @throws WxErrorException 异常
+ */
+ WxMaKfList kfList() throws WxErrorException;
+
+ /**
+ *
+ * 添加客服账号
+ * 详情请见:添加客服账号
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
+ *
+ *
+ * @param request 客服账号信息
+ * @return 是否成功
+ * @throws WxErrorException 异常
+ */
+ boolean kfAccountAdd(WxMaKfAccountRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 修改客服账号
+ * 详情请见:修改客服账号
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
+ *
+ *
+ * @param request 客服账号信息
+ * @return 是否成功
+ * @throws WxErrorException 异常
+ */
+ boolean kfAccountUpdate(WxMaKfAccountRequest request) throws WxErrorException;
+
+ /**
+ *
+ * 删除客服账号
+ * 详情请见:删除客服账号
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+ *
+ *
+ * @param kfAccount 客服账号
+ * @return 是否成功
+ * @throws WxErrorException 异常
+ */
+ boolean kfAccountDel(String kfAccount) throws WxErrorException;
+
+ /**
+ *
+ * 创建会话
+ * 详情请见:创建会话
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN
+ *
+ *
+ * @param openid 用户openid
+ * @param kfAccount 客服账号
+ * @return 是否成功
+ * @throws WxErrorException 异常
+ */
+ boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException;
+
+ /**
+ *
+ * 关闭会话
+ * 详情请见:关闭会话
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN
+ *
+ *
+ * @param openid 用户openid
+ * @param kfAccount 客服账号
+ * @return 是否成功
+ * @throws WxErrorException 异常
+ */
+ boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException;
+
+ /**
+ *
+ * 获取客户的会话状态
+ * 详情请见:获取客户的会话状态
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID
+ *
+ *
+ * @param openid 用户openid
+ * @return 会话信息
+ * @throws WxErrorException 异常
+ */
+ WxMaKfSession kfSessionGet(String openid) throws WxErrorException;
+
+ /**
+ *
+ * 获取客服的会话列表
+ * 详情请见:获取客服的会话列表
+ * 接口url格式:https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
+ *
+ *
+ * @param kfAccount 客服账号
+ * @return 会话列表
+ * @throws WxErrorException 异常
+ */
+ WxMaKfSessionList kfSessionList(String kfAccount) throws WxErrorException;
+
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java
new file mode 100644
index 0000000000..91980e9427
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java
@@ -0,0 +1,39 @@
+package cn.binarywang.wx.miniapp.api;
+
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath;
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:20
+ */
+public interface WxMaOrderManagementService {
+
+ /**
+ * 查询订单详情路径
+ * 注意事项
+ * 如果没有配置过订单详情路径,会返回成功,其中path为''。
+ *
+ * @return WxMaOrderManagementGetOrderDetailPath
+ * @throws WxErrorException e
+ */
+ WxMaOrderManagementGetOrderDetailPath getOrderDetailPath()
+ throws WxErrorException;
+
+
+ /**
+ * 配置订单详情路径
+ * 注意事项
+ * 调用接口前需要先完成订单中心授权协议签署。
+ * 请确保配置的path可正常跳转到小程序,并且path必须包含字符串“${商品订单号}”。
+ *
+ * @param path 订单详情路径
+ * @return WxMaOrderManagementResult
+ * @throws WxErrorException e
+ */
+ WxMaOrderManagementResult updateOrderDetailPath(String path)
+ throws WxErrorException;
+
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java
index b629772a27..1c4bbb56c9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java
@@ -5,18 +5,16 @@
import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetBrandResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetCategoryResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetFrightTemplateResponse;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopOrderListResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopResult;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopSku;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopSkuListResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpu;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpuGet;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpuGetResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpuListResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopUpdateGoodsSkuData;
import cn.binarywang.wx.miniapp.bean.shop.request.WxMaShopSpuPageRequest;
import cn.binarywang.wx.miniapp.bean.shop.response.WxMaShopBaseResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaShopGetSpuListResponse;
+
import java.io.File;
import java.util.List;
import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
index 9d55df3797..26ced8bedd 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
@@ -16,7 +16,7 @@
import me.chanjar.weixin.common.util.http.RequestHttp;
/**
- * The interface Wx ma service.
+ * 微信小程序主服务接口,定义了所有小程序相关的核心操作方法。
*
* @author Binary Wang
*/
@@ -37,557 +37,588 @@ public interface WxMaService extends WxService {
String SET_DYNAMIC_DATA_URL = "https://api.weixin.qq.com/wxa/setdynamicdata";
/**
- * 获取登录后的session信息.
+ * 获取登录后的 session 信息。
*
- * @param jsCode 登录时获取的 code
- * @return the wx ma jscode 2 session result
- * @throws WxErrorException the wx error exception
+ * @param jsCode 登录时获取的 code
+ * @return 登录 session 结果对象
+ * @throws WxErrorException 调用微信接口失败时抛出
*/
WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException;
/**
- * 导入抽样数据
- *
- *
+ * 导入抽样数据到微信后台,用于流量分配。
* 第三方通过调用微信API,将数据写入到setdynamicdata这个API。每个Post数据包不超过5K,若数据过多可开多进(线)程并发导入数据(例如:数据量为十万量级可以开50个线程并行导数据)。
* 文档地址:https://wsad.weixin.qq.com/wsad/zh_CN/htmledition/widget-docs-v3/html/custom/quickstart/implement/import/index.html
* http请求方式:POST http(s)://api.weixin.qq.com/wxa/setdynamicdata?access_token=ACCESS_TOKEN
- *
*
- * @param lifespan 数据有效时间,秒为单位,一般为86400,一天一次导入的频率
- * @param type 用于标识数据所属的服务类目
- * @param scene 1代表用于搜索的数据
- * @param data 推送到微信后台的数据列表,该数据被微信用于流量分配,注意该字段为string类型而不是object
- * @throws WxErrorException .
+ * @param lifespan 数据有效时间(秒),如 86400 表示一天
+ * @param type 数据所属服务类目标识
+ * @param scene 场景值,1 代表用于搜索的数据
+ * @param data 推送到微信后台的数据列表(字符串类型)
+ * @throws WxErrorException 调用微信接口失败时抛出
*/
void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException;
/**
- *
- *
- *
- * 验证消息的确来自微信服务器.
+ * 校验消息是否来自微信服务器。
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
- *
*
- * @param timestamp the timestamp
- * @param nonce the nonce
- * @param signature the signature
- * @return the boolean
+ * @param timestamp 时间戳
+ * @param nonce 随机数
+ * @param signature 签名字符串
+ * @return 校验通过返回 true,否则返回 false
*/
boolean checkSignature(String timestamp, String nonce, String signature);
/**
- * 获取access_token, 不强制刷新access_token.
+ * 获取 access_token,不强制刷新。
*
- * @return the access token
- * @throws WxErrorException the wx error exception
- * @see #getAccessToken(boolean) #getAccessToken(boolean)
+ * @return access_token 字符串
+ * @throws WxErrorException 调用微信接口失败时抛出
+ * @see #getAccessToken(boolean)
*/
String getAccessToken() throws WxErrorException;
/**
+ * 获取 access_token,本方法线程安全。多线程同时刷新时只刷新一次,避免超出调用次数上限。
+ * 一般无需主动调用,所有接口会自动处理 token 过期。
+ * 详情见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
*
- *
- *
- * 获取access_token,本方法线程安全.
- * 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
- *
- * 另:本service的所有方法都会在access_token过期是调用此方法
- *
- * 程序员在非必要情况下尽量不要主动调用此方法
- *
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
- *
- *
- * @param forceRefresh 强制刷新
- * @return the access token
- * @throws WxErrorException the wx error exception
+ * @param forceRefresh 是否强制刷新
+ * @return access_token 字符串
+ * @throws WxErrorException 调用微信接口失败时抛出
*/
String getAccessToken(boolean forceRefresh) throws WxErrorException;
/**
- *
- *
- *
* 用户支付完成后,获取该用户的 UnionId,无需用户授权。本接口支持第三方平台代理查询。
- *
* 注意:调用前需要用户完成支付,且在支付后的五分钟内有效。
* 请求地址: GET https://api.weixin.qq.com/wxa/getpaidunionid?access_token=ACCESS_TOKEN&openid=OPENID
- * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
- *
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
*
- * @param openid 必填 支付用户唯一标识
- * @param transactionId 非必填 微信支付订单号
- * @param mchId 非必填 微信支付分配的商户号,和商户订单号配合使用
- * @param outTradeNo 非必填 微信支付商户订单号,和商户号配合使用
- * @return UnionId. paid union id
- * @throws WxErrorException .
+ * @param openid 支付用户唯一标识(必填)
+ * @param transactionId 微信支付订单号(可选)
+ * @param mchId 微信支付分配的商户号,与商户订单号配合使用(可选)
+ * @param outTradeNo 微信支付商户订单号,与商户号配合使用(可选)
+ * @return 用户的 UnionId
+ * @throws WxErrorException 调用微信接口失败时抛出
*/
String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
throws WxErrorException;
/**
+ * 执行自定义的微信API请求。
+ *
+ * Service没有实现某个API的时候,可以用这个方法,比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+ * 可以参考 {@link MediaUploadRequestExecutor} 的实现方法。
*
- *
- *
- * Service没有实现某个API的时候,可以用这个,
- * 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
- * 可以参考,{@link MediaUploadRequestExecutor}的实现方法
- *
- *
- * @param .
- * @param .
- * @param executor 执行器
- * @param uri 接口请求地址
- * @param data 参数或请求数据
- * @return . t
- * @throws WxErrorException the wx error exception
+ * @param 返回的数据类型
+ * @param 请求参数的数据类型
+ * @param executor 执行器对象
+ * @param uri 接口请求地址
+ * @param data 请求参数或数据
+ * @return 微信接口返回的数据对象
+ * @throws WxErrorException 微信接口调用异常
*/
T execute(RequestExecutor executor, String uri, E data) throws WxErrorException;
+ /**
+ * 执行带有签名的微信API请求。
+ *
+ * @param executor 签名请求执行器
+ * @param uri 接口请求地址
+ * @param headers 请求头信息
+ * @param data 请求数据
+ * @return 微信接口响应对象
+ * @throws WxErrorException 微信接口调用异常
+ */
WxMaApiResponse execute(
- ApiSignaturePostRequestExecutor executor,
+ ApiSignaturePostRequestExecutor, ?> executor,
String uri,
Map headers,
String data)
throws WxErrorException;
/**
+ * 设置微信系统繁忙时的重试等待时间(毫秒)。
*
- *
- *
- * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
- * 默认:1000ms
- *
- *
- * @param retrySleepMillis 重试等待毫秒数
+ * @param retrySleepMillis 重试等待的毫秒数,默认1000ms
*/
void setRetrySleepMillis(int retrySleepMillis);
/**
+ * 设置微信系统繁忙时的最大重试次数。
*
- *
- *
- * 设置当微信系统响应系统繁忙时,最大重试次数.
- * 默认:5次
- *
- *
- * @param maxRetryTimes 最大重试次数
+ * @param maxRetryTimes 最大重试次数,默认5次
*/
void setMaxRetryTimes(int maxRetryTimes);
/**
- * 获取WxMaConfig 对象.
+ * 获取当前小程序的配置信息对象。
*
- * @return WxMaConfig wx ma config
+ * @return 当前小程序的WxMaConfig配置对象
*/
WxMaConfig getWxMaConfig();
/**
- * 注入 {@link WxMaConfig} 的实现.
+ * 注入小程序配置信息。
*
- * @param maConfig config
+ * @param maConfig 小程序配置信息对象
*/
void setWxMaConfig(WxMaConfig maConfig);
/**
- * Map里 加入新的 {@link WxMaConfig},适用于动态添加新的微信公众号配置.
+ * 动态添加新的小程序配置信息。
*
- * @param miniappId 小程序标识
- * @param configStorage 新的微信配置
+ * @param miniappId 小程序唯一标识
+ * @param configStorage 新的小程序配置信息
*/
void addConfig(String miniappId, WxMaConfig configStorage);
/**
- * 从 Map中 移除 {@link String miniappId} 所对应的 {@link WxMaConfig},适用于动态移除小程序配置.
+ * 动态移除指定小程序的配置信息。
*
- * @param miniappId 对应小程序的标识
+ * @param miniappId 小程序唯一标识
*/
void removeConfig(String miniappId);
/**
- * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String mpId} 值 随机采用一个{@link
- * String mpId}进行Http初始化操作
+ * 批量注入多个小程序配置信息。
*
- * @param configs WxMaConfig map
+ * @param configs 小程序配置Map,key为小程序标识
*/
void setMultiConfigs(Map configs);
/**
- * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String label} 值
+ * 批量注入多个小程序配置信息,并指定默认小程序。
*
- * @param configs WxMaConfig map
- * @param defaultMiniappId 设置一个{@link WxMaConfig} 所对应的{@link String defaultMiniappId}进行Http初始化
+ * @param configs 小程序配置Map,key为小程序标识
+ * @param defaultMiniappId 默认小程序标识
*/
void setMultiConfigs(Map configs, String defaultMiniappId);
/**
- * 进行相应的公众号切换.
+ * 切换到指定公众号。
*
- * @param mpId 公众号标识
- * @return 切换是否成功 boolean
+ * @param mpId 公众号标识
+ * @return 切换是否成功,true为成功,false为失败
*/
boolean switchover(String mpId);
/**
- * 进行相应的小程序切换.
+ * 切换到指定小程序。
*
- * @param miniAppId 小程序标识
- * @return 切换成功 ,则返回当前对象,方便链式调用,否则抛出异常
+ * @param miniAppId 小程序标识
+ * @return 切换成功则返回当前对象,方便链式调用,否则抛出异常
*/
WxMaService switchoverTo(String miniAppId);
/**
- * 进行相应的小程序切换.
+ * 切换到指定小程序,并在配置不存在时通过函数获取配置。
*
- * @param miniAppId 小程序标识
- * @param func 当对应的小程序配置不存在时,允许通过函数的方式进行调用获取
- * @return 切换成功 ,则返回当前对象,方便链式调用,否则抛出异常
+ * @param miniAppId 小程序标识
+ * @param func 获取配置的函数
+ * @return 切换成功则返回当前对象,方便链式调用,否则抛出异常
*/
WxMaService switchoverTo(String miniAppId, Function func);
/**
- * 返回消息(客服消息和模版消息)发送接口方法实现类,以方便调用其各个接口.
+ * 获取消息(客服消息和模板消息)发送服务对象。
*
- * @return WxMaMsgService msg service
+ * @return 消息服务对象WxMaMsgService
*/
WxMaMsgService getMsgService();
/**
- * 返回素材相关接口方法的实现类对象,以方便调用其各个接口.
+ * 获取素材相关服务对象。
*
- * @return WxMaMediaService media service
+ * @return 素材服务对象WxMaMediaService
*/
WxMaMediaService getMediaService();
/**
- * 返回用户相关接口方法的实现类对象,以方便调用其各个接口.
+ * 获取用户相关服务对象。
*
- * @return WxMaUserService user service
+ * @return 用户服务对象WxMaUserService
*/
WxMaUserService getUserService();
/**
- * 返回二维码相关接口方法的实现类对象,以方便调用其各个接口.
+ * 获取二维码相关服务对象。
*
- * @return WxMaQrcodeService qrcode service
+ * @return 二维码服务对象WxMaQrcodeService
*/
WxMaQrcodeService getQrcodeService();
/**
- * 返回获取小程序scheme码实现对象,以方便调用其各个接口.
+ * 获取小程序scheme码服务对象。
*
- * @return WxMaSchemeService wx ma scheme service
+ * @return scheme码服务对象WxMaSchemeService
*/
WxMaSchemeService getWxMaSchemeService();
/**
- * 返回订阅消息配置相关接口方法的实现类对象, 以方便调用其各个接口.
+ * 获取订阅消息配置相关服务对象。
*
- * @return WxMaSubscribeService subscribe service
+ * @return 订阅消息服务对象WxMaSubscribeService
*/
WxMaSubscribeService getSubscribeService();
/**
- * 数据分析相关查询服务.
+ * 获取数据分析相关服务对象。
*
- * @return WxMaAnalysisService analysis service
+ * @return 数据分析服务对象WxMaAnalysisService
*/
WxMaAnalysisService getAnalysisService();
/**
- * 返回代码操作相关的 API.
+ * 获取代码操作相关服务对象。
*
- * @return WxMaCodeService code service
+ * @return 代码服务对象WxMaCodeService
*/
WxMaCodeService getCodeService();
/**
- * 返回jsapi操作相关的 API服务类对象.
+ * 获取小程序 - 微信客服。
+ *
+ * @return 微信客服服务对象WxMaCustomserviceWorkService
+ */
+ WxMaCustomserviceWorkService getCustomserviceWorkService();
+
+ /**
+ * 获取小程序客服管理服务。
*
- * @return WxMaJsapiService jsapi service
+ * @return 客服管理服务对象WxMaKefuService
+ */
+ WxMaKefuService getKefuService();
+
+ /**
+ * 获取jsapi操作相关服务对象。
+ *
+ * @return jsapi服务对象WxMaJsapiService
*/
WxMaJsapiService getJsapiService();
/**
- * 小程序修改服务器地址、成员管理 API.
+ * 获取小程序服务器地址、成员管理相关服务对象。
*
- * @return WxMaSettingService setting service
+ * @return 设置服务对象WxMaSettingService
*/
WxMaSettingService getSettingService();
/**
- * 返回分享相关查询服务.
+ * 获取分享相关服务对象。
*
- * @return WxMaShareService share service
+ * @return 分享服务对象WxMaShareService
*/
WxMaShareService getShareService();
/**
- * 返回微信运动相关接口服务对象.
+ * 获取微信运动相关服务对象。
*
- * @return WxMaShareService run service
+ * @return 微信运动服务对象WxMaRunService
*/
WxMaRunService getRunService();
/**
- * 返回小程序安全相关接口服务对象.
+ * 获取小程序安全相关服务对象。
*
- * @return WxMaShareService sec check service
+ * @return 安全服务对象WxMaSecurityService
*/
WxMaSecurityService getSecurityService();
/**
- * 返回插件相关接口服务对象.
+ * 获取插件相关服务对象。
*
- * @return WxMaPluginService plugin service
+ * @return 插件服务对象WxMaPluginService
*/
WxMaPluginService getPluginService();
- /** 初始化http请求对象. */
+ /**
+ * 初始化http请求对象。
+ */
void initHttp();
/**
- * 请求http请求相关信息.
+ * 获取http请求相关信息。
*
- * @return . request http
+ * @return http请求对象RequestHttp
*/
- RequestHttp getRequestHttp();
+ RequestHttp, ?> getRequestHttp();
/**
- * 获取物流助手接口服务对象
+ * 获取物流助手接口服务对象。
*
- * @return . express service
+ * @return 物流助手服务对象WxMaExpressService
*/
WxMaExpressService getExpressService();
/**
- * 获取云开发接口服务对象
+ * 获取云开发接口服务对象。
*
- * @return . cloud service
+ * @return 云开发服务对象WxMaCloudService
*/
WxMaCloudService getCloudService();
/**
- * 获取服务端网络接口服务对象
+ * 获取服务端网络接口服务对象。
*
- * @return 。internet service
+ * @return 网络服务对象WxMaInternetService
*/
WxMaInternetService getInternetService();
/**
- * 获取直播接口服务对象
+ * 获取直播接口服务对象。
*
- * @return . live service
+ * @return 直播服务对象WxMaLiveService
*/
WxMaLiveService getLiveService();
/**
- * 获取直播间商品服务对象
+ * 获取直播间商品服务对象。
*
- * @return . live goods service
+ * @return 直播商品服务对象WxMaLiveGoodsService
*/
WxMaLiveGoodsService getLiveGoodsService();
/**
- * 获取直播成员管理接口服务对象
+ * 获取直播成员管理接口服务对象。
*
- * @return . live service
+ * @return 直播成员服务对象WxMaLiveMemberService
*/
WxMaLiveMemberService getLiveMemberService();
/**
- * 获取ocr实现接口服务对象
+ * 获取OCR实现接口服务对象。
*
- * @return 。
+ * @return OCR服务对象WxOcrService
*/
WxOcrService getOcrService();
/**
- * 返回图像处理接口的实现类对象,以方便调用其各个接口.
+ * 获取图像处理接口服务对象。
*
- * @return WxImgProcService img proc service
+ * @return 图像处理服务对象WxImgProcService
*/
WxImgProcService getImgProcService();
/**
- * 返回小程序交易组件-售后服务接口
+ * 获取小程序交易组件-售后服务接口服务对象。
*
- * @return
+ * @return 售后服务对象WxMaShopAfterSaleService
*/
WxMaShopAfterSaleService getShopAfterSaleService();
/**
- * 返回小程序交易组件-物流服务接口
+ * 获取小程序交易组件-物流服务接口服务对象。
*
- * @return
+ * @return 物流服务对象WxMaShopDeliveryService
*/
WxMaShopDeliveryService getShopDeliveryService();
/**
- * 返回小程序交易组件-订单服务接口
+ * 获取小程序交易组件-订单服务接口服务对象。
*
- * @return
+ * @return 订单服务对象WxMaShopOrderService
*/
WxMaShopOrderService getShopOrderService();
/**
- * 返回小程序交易组件-spu商品服务接口
+ * 获取小程序交易组件-spu商品服务接口服务对象。
*
- * @return
+ * @return spu商品服务对象WxMaShopSpuService
*/
WxMaShopSpuService getShopSpuService();
/**
- * 返回小程序交易组件-接入申请接口
+ * 获取小程序交易组件-接入申请接口服务对象。
*
- * @return
+ * @return 接入申请服务对象WxMaShopRegisterService
*/
WxMaShopRegisterService getShopRegisterService();
/**
- * 返回小程序交易组件-商户入驻接口
+ * 获取小程序交易组件-商户入驻接口服务对象。
*
- * @return
+ * @return 商户入驻服务对象WxMaShopAccountService
*/
WxMaShopAccountService getShopAccountService();
/**
- * 小程序交易组件-接入商品前必需接口-类目相关
+ * 获取小程序交易组件-类目相关接口服务对象。
*
- * @return
+ * @return 类目服务对象WxMaShopCatService
*/
WxMaShopCatService getShopCatService();
/**
- * 小程序交易组件-接入商品前必需接口-上传图片
+ * 获取小程序交易组件-上传图片接口服务对象。
*
- * @return
+ * @return 图片服务对象WxMaShopImgService
*/
WxMaShopImgService getShopImgService();
/**
- * 小程序交易组件-接入商品前必需接口-审核相关接口
+ * 获取小程序交易组件-审核相关接口服务对象。
*
- * @return
+ * @return 审核服务对象WxMaShopAuditService
*/
WxMaShopAuditService getShopAuditService();
/**
- * 获取小程序Link服务接口
+ * 获取小程序Link服务接口服务对象。
*
- * @return
+ * @return Link服务对象WxMaLinkService
*/
WxMaLinkService getLinkService();
/**
- * 获取电子发票报销方服务接口
+ * 获取电子发票报销方服务接口服务对象。
*
- * @return
+ * @return 电子发票报销方服务对象WxMaReimburseInvoiceService
*/
WxMaReimburseInvoiceService getReimburseInvoiceService();
/**
- * 返回设备订阅消息相关接口服务对象
+ * 获取设备订阅消息相关接口服务对象。
*
- * @return WxMaDeviceSubscribeService plugin service
+ * @return 设备订阅消息服务对象WxMaDeviceSubscribeService
*/
WxMaDeviceSubscribeService getDeviceSubscribeService();
/**
- * 返回小程序广告接入相关接口服务对象
+ * 获取小程序广告接入相关接口服务对象。
*
- * @return WxMaDeviceSubscribeService plugin service
+ * @return 广告服务对象WxMaMarketingService
*/
WxMaMarketingService getMarketingService();
/**
- * 返回微信小程序即时配送服务接口.
+ * 获取微信小程序即时配送服务接口服务对象。
*
- * @return WxMaImmediateDeliveryService
+ * @return 即时配送服务对象WxMaImmediateDeliveryService
*/
WxMaImmediateDeliveryService getWxMaImmediateDeliveryService();
/**
- * 分享人接口
+ * 获取小程序分享人接口服务对象。
*
- * @return WxMaShopSharerService
+ * @return 分享人服务对象WxMaShopSharerService
*/
WxMaShopSharerService getShopSharerService();
/**
- * 标准交易组件接口
+ * 获取标准交易组件接口服务对象。
*
- * @return WxMaProductService
+ * @return 标准交易组件服务对象WxMaProductService
*/
WxMaProductService getProductService();
/**
- * 小商店-标准交易组件-订单服务
+ * 获取小商店-标准交易组件-订单服务对象。
*
- * @return getProductOrderService
+ * @return 订单服务对象WxMaProductOrderService
*/
WxMaProductOrderService getProductOrderService();
/**
- * 小商店-标准交易组件-优惠券
+ * 获取小商店-标准交易组件-优惠券服务对象。
*
- * @return getWxMaShopCouponService
+ * @return 优惠券服务对象WxMaShopCouponService
*/
WxMaShopCouponService getWxMaShopCouponService();
/**
- * 小程序支付管理-订单支付
+ * 获取小程序支付管理-订单支付服务对象。
*
- * @return getWxMaShopPayService
+ * @return 订单支付服务对象WxMaShopPayService
*/
WxMaShopPayService getWxMaShopPayService();
/**
- * 小程序发货信息管理服务
+ * 获取小程序发货信息管理服务对象。
*
- * @return getWxMaOrderShippingService
+ * @return 发货信息管理服务对象WxMaOrderShippingService
*/
WxMaOrderShippingService getWxMaOrderShippingService();
/**
- * 小程序openApi管理
+ * 获取小程序订单管理服务对象。
*
- * @return getWxMaOpenApiService
+ * @return 订单管理服务对象WxMaOrderManagementService
+ */
+ WxMaOrderManagementService getWxMaOrderManagementService();
+
+ /**
+ * 获取小程序openApi管理服务对象。
+ *
+ * @return openApi管理服务对象WxMaOpenApiService
*/
WxMaOpenApiService getWxMaOpenApiService();
/**
- * 小程序短剧管理
+ * 获取小程序短剧管理服务对象。
*
- * @return getWxMaVodService
+ * @return 短剧管理服务对象WxMaVodService
*/
WxMaVodService getWxMaVodService();
/**
- * 小程序虚拟支付
+ * 获取小程序虚拟支付服务对象。
*
- * @return getWxMaXPayService
+ * @return 虚拟支付服务对象WxMaXPayService
*/
WxMaXPayService getWxMaXPayService();
+ /**
+ * 获取小程序物流退货服务对象。
+ *
+ * @return 物流退货服务对象WxMaExpressDeliveryReturnService
+ */
WxMaExpressDeliveryReturnService getWxMaExpressDeliveryReturnService();
/**
- * 小程序推广员
+ * 获取小程序推广员服务对象。
*
- * @return WxMaPromotionService
+ * @return 推广员服务对象WxMaPromotionService
*/
WxMaPromotionService getWxMaPromotionService();
+ /**
+ * 以签名方式POST数据到指定URL。
+ *
+ * @param url 请求地址
+ * @param obj 请求对象
+ * @return 微信接口响应字符串
+ * @throws WxErrorException 微信接口调用异常
+ */
String postWithSignature(String url, Object obj) throws WxErrorException;
+ /**
+ * 以签名方式POST数据到指定URL。
+ *
+ * @param url 请求地址
+ * @param jsonObject 请求的Json对象
+ * @return 微信接口响应字符串
+ * @throws WxErrorException 微信接口调用异常
+ */
String postWithSignature(String url, JsonObject jsonObject) throws WxErrorException;
/**
- * 微信物流服务 -- 同城配送
- * https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
+ * 获取微信物流服务--同城配送服务对象。
+ *
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
+ *
+ * @return 同城配送服务对象WxMaIntracityService
*/
WxMaIntracityService getIntracityService();
+
+ /**
+ * 获取交易投诉服务对象。
+ *
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html
+ *
+ * @return 交易投诉服务对象WxMaComplaintService
+ */
+ WxMaComplaintService getComplaintService();
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java
index 8c6030e53c..d32aee2c16 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaShareService.java
@@ -1,5 +1,6 @@
package cn.binarywang.wx.miniapp.api;
+import cn.binarywang.wx.miniapp.bean.WxMaGroupEnterInfo;
import cn.binarywang.wx.miniapp.bean.WxMaShareInfo;
/**
@@ -18,4 +19,16 @@ public interface WxMaShareService {
*/
WxMaShareInfo getShareInfo(String sessionKey, String encryptedData, String ivStr);
+ /**
+ * 解密群入口敏感数据.
+ * 对应 wx.getGroupEnterInfo 接口返回的 encryptedData 解密
+ *
+ * @param sessionKey 会话密钥
+ * @param encryptedData 消息密文
+ * @param ivStr 加密算法的初始向量
+ * @return 群入口信息
+ * @see wx.getGroupEnterInfo 官方文档
+ */
+ WxMaGroupEnterInfo getGroupEnterInfo(String sessionKey, String encryptedData, String ivStr);
+
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java
index 8c6a8ef871..21696701d2 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaUserService.java
@@ -1,5 +1,6 @@
package cn.binarywang.wx.miniapp.api;
+import cn.binarywang.wx.miniapp.bean.WxMaCode2VerifyInfoResult;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
@@ -87,4 +88,18 @@ public interface WxMaUserService {
* @return .
*/
boolean checkUserInfo(String sessionKey, String rawData, String signature);
+
+ /**
+ * 多端登录验证接口.
+ *
+ * 通过 code 换取用户登录态信息,用于多端登录场景(如手表端)。
+ *
+ * 文档地址:多端登录
+ *
+ * @param code 登录时获取的 code
+ * @param checkcode 手表授权页面返回的 checkcode
+ * @return 登录验证结果,包含 session_key、openid、unionid 和 is_limit 字段
+ * @throws WxErrorException 调用微信接口失败时抛出
+ */
+ WxMaCode2VerifyInfoResult getCode2VerifyInfo(String code, String checkcode) throws WxErrorException;
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java
index 547d280962..217a699c5a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java
@@ -6,39 +6,181 @@
import java.io.File;
import java.util.List;
+/**
+ * 小程序短剧管理服务接口。
+ * 提供短剧视频上传、管理、审核、播放等相关功能。
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/vod.html
+ *
+ */
public interface WxMaVodService {
+
+ /**
+ * 获取媒体列表。
+ * 分页获取已上传的媒体文件列表。
+ *
+ * @param request 获取媒体列表请求对象
+ * @return 媒体信息列表
+ * @throws WxErrorException 获取失败时抛出
+ */
List listMedia(WxMaVodListMediaRequest request) throws WxErrorException;
+ /**
+ * 获取剧集列表。
+ * 分页获取已创建的剧集列表。
+ *
+ * @param request 获取剧集列表请求对象
+ * @return 剧集信息列表
+ * @throws WxErrorException 获取失败时抛出
+ */
List listDrama(WxMaVodListDramaRequest request) throws WxErrorException;
+ /**
+ * 获取媒体播放链接。
+ * 获取指定媒体文件的播放地址和相关信息。
+ *
+ * @param request 获取媒体播放链接请求对象
+ * @return 媒体播放信息对象
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaVodMediaPlaybackInfo getMediaLink(WxMaVodGetMediaLinkRequest request) throws WxErrorException;
+ /**
+ * 获取媒体详情。
+ * 获取指定媒体文件的详细信息。
+ *
+ * @param request 获取媒体详情请求对象
+ * @return 媒体信息对象
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaVodMediaInfo getMedia(WxMaVodGetMediaRequest request) throws WxErrorException;
+ /**
+ * 删除媒体文件。
+ * 删除指定的媒体文件,删除后无法恢复。
+ *
+ * @param request 删除媒体请求对象
+ * @return 删除是否成功
+ * @throws WxErrorException 删除失败时抛出
+ */
boolean deleteMedia(WxMaVodDeleteMediaRequest request) throws WxErrorException;
+ /**
+ * 获取剧集详情。
+ * 获取指定剧集的详细信息。
+ *
+ * @param request 获取剧集详情请求对象
+ * @return 剧集信息对象
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaVodDramaInfo getDrama(WxMaVodGetDramaRequest request) throws WxErrorException;
+ /**
+ * 审核剧集。
+ * 提交剧集进行内容审核。
+ *
+ * @param request 审核剧集请求对象
+ * @return 审核任务ID
+ * @throws WxErrorException 审核提交失败时抛出
+ */
Integer auditDrama(WxMaVodAuditDramaRequest request) throws WxErrorException;
+ /**
+ * 获取CDN用量数据。
+ * 查询指定时间段内的CDN流量使用情况。
+ *
+ * @param request 获取CDN用量请求对象
+ * @return CDN用量数据响应对象
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaVodGetCdnUsageResponse getCdnUsageData(WxMaVodGetCdnUsageRequest request) throws WxErrorException;
+ /**
+ * 获取CDN日志。
+ * 获取指定时间段内的CDN访问日志。
+ *
+ * @param request 获取CDN日志请求对象
+ * @return CDN日志响应对象
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaVodGetCdnLogResponse getCdnLogs(WxMaVodGetCdnLogRequest request) throws WxErrorException;
-
+ /**
+ * 拉取上传。
+ * 通过URL拉取视频文件到平台进行上传。
+ *
+ * @param request 拉取上传请求对象
+ * @return 拉取上传响应对象
+ * @throws WxErrorException 拉取失败时抛出
+ */
WxMaVodPullUploadResponse pullUpload(WxMaVodPullUploadRequest request) throws WxErrorException;
+ /**
+ * 获取任务状态。
+ * 查询异步任务的执行状态和结果。
+ *
+ * @param request 获取任务状态请求对象
+ * @return 任务状态响应对象
+ * @throws WxErrorException 获取失败时抛出
+ */
WxMaVodGetTaskResponse getTask(WxMaVodGetTaskRequest request) throws WxErrorException;
-
+ /**
+ * 单文件上传(简化版)。
+ * 直接上传单个视频文件到平台。
+ *
+ * @param file 要上传的文件
+ * @param mediaName 媒体文件名称
+ * @param mediaType 媒体文件类型
+ * @return 单文件上传结果
+ * @throws WxErrorException 上传失败时抛出
+ */
WxMaVodSingleFileUploadResult uploadSingleFile(File file, String mediaName, String mediaType) throws WxErrorException;
+ /**
+ * 单文件上传(完整版)。
+ * 上传视频文件和封面图片到平台。
+ *
+ * @param file 要上传的视频文件
+ * @param mediaName 媒体文件名称
+ * @param mediaType 媒体文件类型
+ * @param coverType 封面图片类型
+ * @param coverData 封面图片文件
+ * @param sourceContext 来源上下文信息
+ * @return 单文件上传结果
+ * @throws WxErrorException 上传失败时抛出
+ */
WxMaVodSingleFileUploadResult uploadSingleFile(File file, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) throws WxErrorException;
+ /**
+ * 申请上传。
+ * 申请分片上传的上传凭证和上传地址。
+ *
+ * @param request 申请上传请求对象
+ * @return 申请上传响应对象
+ * @throws WxErrorException 申请失败时抛出
+ */
WxMaVodApplyUploadResponse applyUpload(WxMaVodApplyUploadRequest request) throws WxErrorException;
+ /**
+ * 确认上传。
+ * 确认分片上传完成,合并所有分片文件。
+ *
+ * @param request 确认上传请求对象
+ * @return 确认上传响应对象
+ * @throws WxErrorException 确认失败时抛出
+ */
WxMaVodCommitUploadResponse commitUpload(WxMaVodCommitUploadRequest request) throws WxErrorException;
+ /**
+ * 上传分片。
+ * 上传文件的一个分片。
+ *
+ * @param file 分片文件
+ * @param uploadId 上传ID
+ * @param partNumber 分片编号
+ * @param resourceType 资源类型
+ * @return 分片上传结果
+ * @throws WxErrorException 上传失败时抛出
+ */
WxMaVodUploadPartResult uploadPart(File file, String uploadId, Integer partNumber, Integer resourceType) throws WxErrorException;
-
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java
index a099cd6dd7..a633c93de6 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java
@@ -1,37 +1,305 @@
package cn.binarywang.wx.miniapp.api;
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
import cn.binarywang.wx.miniapp.bean.xpay.*;
import me.chanjar.weixin.common.error.WxErrorException;
+/**
+ * 小程序虚拟支付相关接口。
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/virtual-payment.html
+ *
+ */
public interface WxMaXPayService {
+ /**
+ * 查询用户虚拟币余额。
+ *
+ * @param request 查询用户余额请求对象
+ * @param sigParams 签名参数对象
+ * @return 用户余额查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
WxMaXPayQueryUserBalanceResponse queryUserBalance(WxMaXPayQueryUserBalanceRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 虚拟币充值下单。
+ *
+ * @param request 虚拟币充值请求对象
+ * @param sigParams 签名参数对象
+ * @return 虚拟币充值结果
+ * @throws WxErrorException 充值失败时抛出
+ */
WxMaXPayCurrencyPayResponse currencyPay(WxMaXPayCurrencyPayRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 查询订单信息。
+ *
+ * @param request 查询订单请求对象
+ * @param sigParams 签名参数对象
+ * @return 订单查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
WxMaXPayQueryOrderResponse queryOrder(WxMaXPayQueryOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 取消虚拟币充值订单。
+ *
+ * @param request 取消充值订单请求对象
+ * @param sigParams 签名参数对象
+ * @return 取消充值订单结果
+ * @throws WxErrorException 取消失败时抛出
+ */
WxMaXPayCancelCurrencyPayResponse cancelCurrencyPay(WxMaXPayCancelCurrencyPayRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 通知发货。
+ *
+ * @param request 通知发货请求对象
+ * @param sigParams 签名参数对象
+ * @return 通知发货是否成功
+ * @throws WxErrorException 通知失败时抛出
+ */
boolean notifyProvideGoods(WxMaXPayNotifyProvideGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 赠送虚拟币。
+ *
+ * @param request 赠送虚拟币请求对象
+ * @param sigParams 签名参数对象
+ * @return 赠送虚拟币结果
+ * @throws WxErrorException 赠送失败时抛出
+ */
WxMaXPayPresentCurrencyResponse presentCurrency(WxMaXPayPresentCurrencyRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
-
+ /**
+ * 下载对账单。
+ *
+ * @param request 下载对账单请求对象
+ * @param sigParams 签名参数对象
+ * @return 对账单下载结果
+ * @throws WxErrorException 下载失败时抛出
+ */
WxMaXPayDownloadBillResponse downloadBill(WxMaXPayDownloadBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 退款申请。
+ *
+ * @param request 退款申请请求对象
+ * @param sigParams 签名参数对象
+ * @return 退款申请结果
+ * @throws WxErrorException 退款失败时抛出
+ */
WxMaXPayRefundOrderResponse refundOrder(WxMaXPayRefundOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 创建提现订单。
+ *
+ * @param request 创建提现订单请求对象
+ * @param sigParams 签名参数对象
+ * @return 创建提现订单结果
+ * @throws WxErrorException 创建失败时抛出
+ */
WxMaXPayCreateWithdrawOrderResponse createWithdrawOrder(WxMaXPayCreateWithdrawOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 查询提现订单。
+ *
+ * @param request 查询提现订单请求对象
+ * @param sigParams 签名参数对象
+ * @return 提现订单查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
WxMaXPayQueryWithdrawOrderResponse queryWithdrawOrder(WxMaXPayQueryWithdrawOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 启动道具上传。
+ *
+ * @param request 启动道具上传请求对象
+ * @param sigParams 签名参数对象
+ * @return 启动道具上传是否成功
+ * @throws WxErrorException 启动失败时抛出
+ */
boolean startUploadGoods(WxMaXPayStartUploadGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 查询道具上传状态。
+ *
+ * @param request 查询道具上传状态请求对象
+ * @param sigParams 签名参数对象
+ * @return 道具上传状态查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
WxMaXPayQueryUploadGoodsResponse queryUploadGoods(WxMaXPayQueryUploadGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 启动道具发布。
+ *
+ * @param request 启动道具发布请求对象
+ * @param sigParams 签名参数对象
+ * @return 启动道具发布是否成功
+ * @throws WxErrorException 启动失败时抛出
+ */
boolean startPublishGoods(WxMaXPayStartPublishGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 查询道具发布状态。
+ *
+ * @param request 查询道具发布状态请求对象
+ * @param sigParams 签名参数对象
+ * @return 道具发布状态查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
WxMaXPayQueryPublishGoodsResponse queryPublishGoods(WxMaXPayQueryPublishGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+ /**
+ * 查询商家账户里的可提现余额。
+ *
+ * @param request 查询商家账户里的可提现余额请求对象
+ * @param sigParams 签名参数对象
+ * @return 商家账户里的可提现余额查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayQueryBizBalanceResponse queryBizBalance(WxMaXPayQueryBizBalanceRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 查询广告金充值账户。
+ *
+ * @param request 查询广告金充值账户请求对象
+ * @param sigParams 签名参数对象
+ * @return 广告金充值账户查询结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayQueryTransferAccountResponse queryTransferAccount(WxMaXPayQueryTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 查询广告金发放记录。
+ *
+ * @param request 查询广告金发放记录请求对象
+ * @param sigParams 签名参数对象
+ * @return 查询广告金发放记录结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayQueryAdverFundsResponse queryAdverFunds(WxMaXPayQueryAdverFundsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 充值广告金。
+ *
+ * @param request 充值广告金请求对象
+ * @param sigParams 签名参数对象
+ * @return 充值广告金结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayCreateFundsBillResponse createFundsBill(WxMaXPayCreateFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 绑定广告金充值账户。
+ *
+ * @param request 绑定广告金充值账户请求对象
+ * @param sigParams 签名参数对象
+ * @return 绑定广告金充值账户结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaBaseResponse bindTransferAccount(WxMaXPayBindTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 查询广告金充值记录。
+ *
+ * @param request 查询广告金充值记录请求对象
+ * @param sigParams 签名参数对象
+ * @return 查询广告金充值记录结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayQueryFundsBillResponse queryFundsBill(WxMaXPayQueryFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 查询广告金回收记录。
+ *
+ * @param request 查询广告金回收记录请求对象
+ * @param sigParams 签名参数对象
+ * @return 查询广告金回收记录结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayQueryRecoverBillResponse queryRecoverBill(WxMaXPayQueryRecoverBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+
+ /**
+ * 获取投诉列表。
+ *
+ * @param request 获取投诉列表请求对象
+ * @param sigParams 签名参数对象
+ * @return 获取投诉列表结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayGetComplaintListResponse getComplaintList(WxMaXPayGetComplaintListRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 获取投诉详情。
+ *
+ * @param request 获取投诉详情请求对象
+ * @param sigParams 签名参数对象
+ * @return 获取投诉详情结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayGetComplaintDetailResponse getComplaintDetail(WxMaXPayGetComplaintDetailRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 获取协商历史。
+ *
+ * @param request 获取协商历史请求对象
+ * @param sigParams 签名参数对象
+ * @return 获取协商历史结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayGetNegotiationHistoryResponse getNegotiationHistory(WxMaXPayGetNegotiationHistoryRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 回复用户。
+ *
+ * @param request 回复用户请求对象
+ * @param sigParams 签名参数对象
+ * @return 回复用户结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaBaseResponse responseComplaint(WxMaXPayResponseComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 完成投诉处理。
+ *
+ * @param request 完成投诉处理请求对象
+ * @param sigParams 签名参数对象
+ * @return 完成投诉处理结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaBaseResponse completeComplaint(WxMaXPayCompleteComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 上传媒体文件(如图片,凭证等)。
+ *
+ * @param request 上传媒体文件(如图片,凭证等)请求对象
+ * @param sigParams 签名参数对象
+ * @return 上传媒体文件(如图片,凭证等)结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayUploadVpFileResponse uploadVpFile(WxMaXPayUploadVpFileRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 获取微信支付反馈投诉图片的签名头部。
+ *
+ * @param request 获取微信支付反馈投诉图片的签名头部请求对象
+ * @param sigParams 签名参数对象
+ * @return 获取微信支付反馈投诉图片的签名头部结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayGetUploadFileSignResponse getUploadFileSign(WxMaXPayGetUploadFileSignRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+ * 下载广告金对应的商户订单信息。
+ *
+ * @param request 下载广告金对应的商户订单信息请求对象
+ * @param sigParams 签名参数对象
+ * @return 下载广告金对应的商户订单信息结果
+ * @throws WxErrorException 查询失败时抛出
+ */
+ WxMaXPayDownloadAdverfundsOrderResponse downloadAdverfundsOrder(WxMaXPayDownloadAdverfundsOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
index 8af0626b92..93bb2656e6 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
@@ -38,6 +38,7 @@
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.error.WxMaErrorMsgEnum;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
import me.chanjar.weixin.common.service.WxImgProcService;
@@ -111,6 +112,8 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
private final WxMaSchemeService schemeService = new WxMaSchemeServiceImpl(this);
private final WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this);
private final WxMaCodeService codeService = new WxMaCodeServiceImpl(this);
+ private final WxMaCustomserviceWorkService customserviceWorkService = new WxMaCustomserviceWorkServiceImpl(this);
+ private final WxMaKefuService maKefuService = new WxMaKefuServiceImpl(this);
private final WxMaInternetService internetService = new WxMaInternetServiceImpl(this);
private final WxMaSettingService settingService = new WxMaSettingServiceImpl(this);
private final WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this);
@@ -153,6 +156,9 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
private final WxMaOrderShippingService wxMaOrderShippingService =
new WxMaOrderShippingServiceImpl(this);
+ private final WxMaOrderManagementService wxMaOrderManagementService =
+ new WxMaOrderManagementServiceImpl(this);
+
private final WxMaOpenApiService wxMaOpenApiService = new WxMaOpenApiServiceImpl(this);
private final WxMaVodService wxMaVodService = new WxMaVodServiceImpl(this);
private final WxMaXPayService wxMaXPayService = new WxMaXPayServiceImpl(this);
@@ -160,13 +166,14 @@ public abstract class BaseWxMaServiceImpl implements WxMaService, RequestH
new WxMaExpressDeliveryReturnServiceImpl(this);
private final WxMaPromotionService wxMaPromotionService = new WxMaPromotionServiceImpl(this);
private final WxMaIntracityService intracityService = new WxMaIntracityServiceImpl(this);
+ private final WxMaComplaintService complaintService = new WxMaComplaintServiceImpl(this);
private Map configMap = new HashMap<>();
private int retrySleepMillis = 1000;
private int maxRetryTimes = 5;
@Override
- public RequestHttp getRequestHttp() {
+ public RequestHttp getRequestHttp() {
return this;
}
@@ -229,7 +236,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
try {
return SHA1.gen(this.getWxMaConfig().getToken(), timestamp, nonce).equals(signature);
} catch (Exception e) {
- log.error("Checking signature failed, and the reason is :" + e.getMessage());
+ log.error("Checking signature failed, and the reason is :{}", e.getMessage());
return false;
}
}
@@ -294,7 +301,7 @@ public String get(String url, String queryParam) throws WxErrorException {
private boolean isApiSignatureRequired(String url) {
return this.getWxMaConfig().getApiSignatureAesKey() != null
- && Arrays.stream(urlPathSupportApiSignature).anyMatch(part -> url.contains(part));
+ && Arrays.stream(urlPathSupportApiSignature).anyMatch(url::contains);
}
@Override
@@ -358,7 +365,7 @@ public R execute(RequestExecutor executor, String uri, T data)
@Override
public WxMaApiResponse execute(
- ApiSignaturePostRequestExecutor executor,
+ ApiSignaturePostRequestExecutor, ?> executor,
String uri,
Map headers,
String data)
@@ -420,8 +427,9 @@ private R executeInternal(
}
String accessToken = getAccessToken(false);
- if (StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl())) {
- uri = uri.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl());
+ String effectiveApiHostUrl = this.getWxMaConfig().getEffectiveApiHostUrl();
+ if (!WxMaConfig.DEFAULT_API_HOST_URL.equals(effectiveApiHostUrl)) {
+ uri = uri.replace(WxMaConfig.DEFAULT_API_HOST_URL, effectiveApiHostUrl);
}
String uriWithAccessToken =
@@ -455,7 +463,12 @@ private R executeInternal(
}
if (error.getErrorCode() != 0) {
- log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+ if (error.getErrorCode() == WxMaErrorMsgEnum.CODE_43101.getCode()) {
+ // 43101 日志太多, 打印为debug, 其他情况打印为warn
+ log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+ } else {
+ log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
+ }
throw new WxErrorException(error, e);
}
return null;
@@ -499,7 +512,10 @@ public WxMaConfig getWxMaConfig() {
@Override
public void setWxMaConfig(WxMaConfig maConfig) {
final String appid = maConfig.getAppid();
- this.setMultiConfigs(ImmutableMap.of(appid, maConfig), appid);
+ Map map = new HashMap<>();
+ map.put(appid, maConfig);
+ Map configMap = Collections.unmodifiableMap(map);
+ this.setMultiConfigs(configMap, appid);
}
@Override
@@ -639,6 +655,16 @@ public WxMaCodeService getCodeService() {
return this.codeService;
}
+ @Override
+ public WxMaCustomserviceWorkService getCustomserviceWorkService() {
+ return this.customserviceWorkService;
+ }
+
+ @Override
+ public WxMaKefuService getKefuService() {
+ return this.maKefuService;
+ }
+
@Override
public WxMaJsapiService getJsapiService() {
return this.jsapiService;
@@ -814,6 +840,16 @@ public WxMaOrderShippingService getWxMaOrderShippingService() {
return this.wxMaOrderShippingService;
}
+ /**
+ * 小程序订单管理服务
+ *
+ * @return WxMaOrderManagementService
+ */
+ @Override
+ public WxMaOrderManagementService getWxMaOrderManagementService() {
+ return this.wxMaOrderManagementService;
+ }
+
@Override
public WxMaOpenApiService getWxMaOpenApiService() {
return this.wxMaOpenApiService;
@@ -876,6 +912,10 @@ public String postWithSignature(String url, JsonObject jsonObject) throws WxErro
String rndStr = UUID.randomUUID().toString().replace("-", "").substring(0, 30);
String aesKey = this.getWxMaConfig().getApiSignatureAesKey();
String aesKeySn = this.getWxMaConfig().getApiSignatureAesKeySn();
+ String rsaKeySn = this.getWxMaConfig().getApiSignatureRsaPrivateKeySn();
+ if (rsaKeySn == null || rsaKeySn.isEmpty()) {
+ throw new SecurityException("ApiSignatureRsaPrivateKeySn不能为空,请检查配置");
+ }
jsonObject.addProperty("_n", rndStr);
jsonObject.addProperty("_appid", appId);
@@ -920,7 +960,7 @@ public String postWithSignature(String url, JsonObject jsonObject) throws WxErro
String requestJson = reqData.toString();
// 计算签名 RSA
- String payload = urlPath + "\n" + appId + "\n" + timestamp + "\n" + requestJson;
+ String payload = urlPath + "\n" + appId + "\n" + timestamp + "\n" + rsaKeySn + "\n" + requestJson;
byte[] dataBuffer = payload.getBytes(StandardCharsets.UTF_8);
RSAPrivateKey priKey;
try {
@@ -949,6 +989,7 @@ public String postWithSignature(String url, JsonObject jsonObject) throws WxErro
header.put("Wechatmp-Signature", signatureString);
header.put("Wechatmp-Appid", appId);
header.put("Wechatmp-TimeStamp", String.valueOf(timestamp));
+ header.put("Wechatmp-Serial", rsaKeySn);
log.debug("发送请求uri:{}, headers:{}, postData:{}", url, header, requestJson);
WxMaApiResponse response =
this.execute(ApiSignaturePostRequestExecutor.create(this), url, header, requestJson);
@@ -1002,4 +1043,9 @@ private String aesDecodeResponse(WxMaApiResponse response, String aad, SecretKey
public WxMaIntracityService getIntracityService() {
return this.intracityService;
}
+
+ @Override
+ public WxMaComplaintService getComplaintService() {
+ return this.complaintService;
+ }
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java
index 3e16814479..45c7339bc9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java
@@ -55,7 +55,7 @@ public String invokeCloudFunction(String env, String name, String body) throws W
}
@Override
- public List add(String collection, List list) throws WxErrorException {
+ public List add(String collection, List> list) throws WxErrorException {
String jsonData = WxMaGsonBuilder.create().toJson(list);
String query = blankJoiner.join(
"db.collection('", collection, "')",
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaComplaintServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaComplaintServiceImpl.java
new file mode 100644
index 0000000000..c534bd6938
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaComplaintServiceImpl.java
@@ -0,0 +1,99 @@
+package cn.binarywang.wx.miniapp.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaComplaintService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.complaint.*;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.bean.CommonUploadParam;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.UUID;
+
+import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Complaint.*;
+
+/**
+ * 小程序交易投诉接口实现
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@RequiredArgsConstructor
+public class WxMaComplaintServiceImpl implements WxMaComplaintService {
+ private static final String JSON_CONTENT_TYPE = "application/json";
+ private final WxMaService wxMaService;
+
+ @Override
+ public WxMaComplaintResult queryComplaints(WxMaComplaintRequest request) throws WxErrorException {
+ String responseContent = this.wxMaService.post(QUERY_COMPLAINTS_URL, request.toJson());
+ return WxMaGsonBuilder.create().fromJson(responseContent, WxMaComplaintResult.class);
+ }
+
+ @Override
+ public WxMaComplaintDetailResult getComplaint(WxMaComplaintDetailRequest request) throws WxErrorException {
+ String responseContent = this.wxMaService.post(GET_COMPLAINT_URL, request.toJson());
+ return WxMaGsonBuilder.create().fromJson(responseContent, WxMaComplaintDetailResult.class);
+ }
+
+ @Override
+ public WxMaNegotiationHistoryResult queryNegotiationHistorys(WxMaNegotiationHistoryRequest request) throws WxErrorException {
+ String responseContent = this.wxMaService.post(QUERY_NEGOTIATION_HISTORY_URL, request.toJson());
+ return WxMaGsonBuilder.create().fromJson(responseContent, WxMaNegotiationHistoryResult.class);
+ }
+
+ @Override
+ public WxMaComplaintNotifyUrlResult addComplaintNotifyUrl(WxMaComplaintNotifyUrlRequest request) throws WxErrorException {
+ String responseContent = this.wxMaService.post(ADD_COMPLAINT_NOTIFY_URL, request.toJson());
+ return WxMaGsonBuilder.create().fromJson(responseContent, WxMaComplaintNotifyUrlResult.class);
+ }
+
+ @Override
+ public WxMaComplaintNotifyUrlResult getComplaintNotifyUrl() throws WxErrorException {
+ String responseContent = this.wxMaService.get(GET_COMPLAINT_NOTIFY_URL, null);
+ return WxMaGsonBuilder.create().fromJson(responseContent, WxMaComplaintNotifyUrlResult.class);
+ }
+
+ @Override
+ public WxMaComplaintNotifyUrlResult updateComplaintNotifyUrl(WxMaComplaintNotifyUrlRequest request) throws WxErrorException {
+ String responseContent = this.wxMaService.post(UPDATE_COMPLAINT_NOTIFY_URL, request.toJson());
+ return WxMaGsonBuilder.create().fromJson(responseContent, WxMaComplaintNotifyUrlResult.class);
+ }
+
+ @Override
+ public void deleteComplaintNotifyUrl() throws WxErrorException {
+ this.wxMaService.post(DELETE_COMPLAINT_NOTIFY_URL, "{}");
+ }
+
+ @Override
+ public void submitResponse(WxMaResponseRequest request) throws WxErrorException {
+ this.wxMaService.post(SUBMIT_RESPONSE_URL, request.toJson());
+ }
+
+ @Override
+ public void complete(WxMaCompleteRequest request) throws WxErrorException {
+ this.wxMaService.post(COMPLETE_COMPLAINT_URL, request.toJson());
+ }
+
+ @Override
+ public String uploadResponseImage(File imageFile) throws WxErrorException, IOException {
+ String result = this.wxMaService.upload(UPLOAD_RESPONSE_IMAGE_URL,
+ CommonUploadParam.fromFile("image", imageFile));
+ JsonObject jsonResult = WxMaGsonBuilder.create().fromJson(result, JsonObject.class);
+ return jsonResult.get("media_id").getAsString();
+ }
+
+ @Override
+ public String uploadResponseImage(InputStream inputStream, String fileName) throws WxErrorException, IOException {
+ try {
+ return this.uploadResponseImage(FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileName));
+ } catch (IOException e) {
+ throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCustomserviceWorkServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCustomserviceWorkServiceImpl.java
new file mode 100644
index 0000000000..0a30f86df3
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCustomserviceWorkServiceImpl.java
@@ -0,0 +1,51 @@
+package cn.binarywang.wx.miniapp.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaCustomserviceWorkService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.customservice.WxMaCustomserviceResult;
+import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+
+
+/**
+ *
+ * 小程序 - 微信客服 相关接口
+ * 负责处理 https://api.weixin.qq.com/customservice/work/**
+ * 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/kf-work/getKfWorkBound.html
+ * 绑定的企业ID,需和小程序主体一致。
+ * 目前仅支持绑定非个人小程序。
+ * Created by tryking123 on 2025/8/18.
+ *
+ *
+ * @author tryking123
+ */
+@RequiredArgsConstructor
+public class WxMaCustomserviceWorkServiceImpl implements WxMaCustomserviceWorkService {
+ private static final String CORPID = "corpid";
+
+ private final WxMaService service;
+
+ @Override
+ public WxMaCustomserviceResult getCustomservice() throws WxErrorException {
+ String responseContent = this.service.get(GET_CUSTOMSERVICE_URL, null);
+ return WxMaCustomserviceResult.fromJson(responseContent);
+ }
+
+ @Override
+ public WxMaCustomserviceResult bindCustomservice(String corpid) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty(CORPID, corpid);
+ String response = this.service.post(BIND_CUSTOMSERVICE_URL, paramJson);
+ return WxMaCustomserviceResult.fromJson(response);
+ }
+
+ @Override
+ public WxMaCustomserviceResult unbindCustomservice(String corpid) throws WxErrorException {
+ JsonObject paramJson = new JsonObject();
+ paramJson.addProperty(CORPID, corpid);
+ String response = this.service.post(UNBIND_CUSTOMSERVICE_URL, paramJson);
+ return WxMaCustomserviceResult.fromJson(response);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java
index 0943a1feeb..7f8dce1df8 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java
@@ -4,7 +4,6 @@
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.device.WxMaDeviceSubscribeMessageRequest;
import cn.binarywang.wx.miniapp.bean.device.WxMaDeviceTicketRequest;
-import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.api.WxConsts;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaExpressDeliveryReturnServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaExpressDeliveryReturnServiceImpl.java
index aef8a2cad2..df4d9780c9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaExpressDeliveryReturnServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaExpressDeliveryReturnServiceImpl.java
@@ -14,23 +14,23 @@ public class WxMaExpressDeliveryReturnServiceImpl implements WxMaExpressDelivery
@Override
public WxMaExpressReturnInfoResult addDeliveryReturn(WxMaExpressDeliveryReturnAddRequest wxMaExpressDeliveryReturnAddRequest) throws WxErrorException {
- String result= this.service.get(ADD_DELIVERY_RETURN_URL,wxMaExpressDeliveryReturnAddRequest.toJson());
+ String result = this.service.post(ADD_DELIVERY_RETURN_URL, wxMaExpressDeliveryReturnAddRequest.toJson());
return WxMaExpressReturnInfoResult.fromJson(result);
}
@Override
public WxMaExpressReturnInfoResult getDeliveryReturn(String returnId) throws WxErrorException {
JsonObject param = new JsonObject();
- param.addProperty("return_id",returnId);
- String result= this.service.get(GET_DELIVERY_RETURN_URL,param.toString());
+ param.addProperty("return_id", returnId);
+ String result = this.service.post(GET_DELIVERY_RETURN_URL, param);
return WxMaExpressReturnInfoResult.fromJson(result);
}
@Override
public WxMaExpressReturnInfoResult unbindDeliveryReturn(String returnId) throws WxErrorException {
JsonObject param = new JsonObject();
- param.addProperty("return_id",returnId);
- String result= this.service.get(UNBIND_DELIVERY_RETURN_URL,param.toString());
+ param.addProperty("return_id", returnId);
+ String result = this.service.post(UNBIND_DELIVERY_RETURN_URL, param);
return WxMaExpressReturnInfoResult.fromJson(result);
}
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImgProcServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImgProcServiceImpl.java
index 03f46fb31e..bfa03bd501 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImgProcServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImgProcServiceImpl.java
@@ -82,7 +82,7 @@ public WxImgProcAiCropResult aiCrop(String imgUrl, String ratios) throws WxError
ratios = "";
}
- final String result = this.service.get(String.format(AI_CROP, imgUrl, ratios), null);
+ final String result = this.service.post(String.format(AI_CROP, imgUrl, ratios), "");
return WxImgProcAiCropResult.fromJson(result);
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java
index 05e8f2e0a7..910eb19d22 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java
@@ -5,7 +5,6 @@
import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
import cn.binarywang.wx.miniapp.bean.delivery.*;
import cn.binarywang.wx.miniapp.bean.delivery.base.WxMaDeliveryBaseResponse;
-import cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants;
import cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.InstantDelivery;
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
import com.google.gson.JsonElement;
@@ -207,7 +206,7 @@ public GetDeliveryListResponse getDeliveryList() throws WxErrorException {
@Override
public WxMaBaseResponse updateWaybillGoods(UpdateWaybillGoodsRequest request) throws WxErrorException {
- String responseContent = this.wxMaService.post(InstantDelivery.GET_DELIVERY_LIST_URL,request);
+ String responseContent = this.wxMaService.post(InstantDelivery.UPDATE_WAYBILL_GOODS_URL,request);
WxMaBaseResponse response = WxMaGsonBuilder.create().fromJson(responseContent, WxMaBaseResponse.class);
if (response.getErrcode() == -1) {
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java
index f42564279a..7da44ddaba 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java
@@ -12,6 +12,7 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
/**
* 服务端网络相关接口
@@ -25,9 +26,9 @@ public class WxMaInternetServiceImpl implements WxMaInternetService {
private String sha256(String data, String sessionKey) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
- SecretKeySpec secret_key = new SecretKeySpec(sessionKey.getBytes("UTF-8"), "HmacSHA256");
+ SecretKeySpec secret_key = new SecretKeySpec(sessionKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
- byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
+ byte[] array = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
index 3e21dab79f..e2681f7cc7 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
@@ -170,7 +170,7 @@ public WxMaStoreFlowResponse extends WxMaStoreFlowResponse.BasicFlowRecord> qu
@Override
public WxMaStoreBalance balanceQuery(String wxStoreId, String serviceTransId, PayMode payMode)
throws WxErrorException {
- if (wxStoreId == null && (payMode != null && payMode != PayMode.STORE)) {
+ if (wxStoreId == null && (payMode == null || payMode == PayMode.STORE)) {
throw new IllegalArgumentException("payMode是PAY_MODE_STORE或null时,必须传递wxStoreId");
}
Map request = new HashMap<>();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImpl.java
new file mode 100644
index 0000000000..2fa39603a0
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaKefuServiceImpl.java
@@ -0,0 +1,92 @@
+package cn.binarywang.wx.miniapp.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaKefuService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfInfo;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfList;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSession;
+import cn.binarywang.wx.miniapp.bean.kefu.WxMaKfSessionList;
+import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfAccountRequest;
+import cn.binarywang.wx.miniapp.bean.kefu.request.WxMaKfSessionRequest;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 小程序客服管理服务实现.
+ *
+ * @author Binary Wang
+ */
+@RequiredArgsConstructor
+public class WxMaKefuServiceImpl implements WxMaKefuService {
+
+ // 小程序客服管理接口URL
+ private static final String KFLIST_GET_URL = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist";
+ private static final String KFACCOUNT_ADD_URL = "https://api.weixin.qq.com/customservice/kfaccount/add";
+ private static final String KFACCOUNT_UPDATE_URL = "https://api.weixin.qq.com/customservice/kfaccount/update";
+ private static final String KFACCOUNT_DEL_URL = "https://api.weixin.qq.com/customservice/kfaccount/del?kf_account=%s";
+ private static final String KFSESSION_CREATE_URL = "https://api.weixin.qq.com/customservice/kfsession/create";
+ private static final String KFSESSION_CLOSE_URL = "https://api.weixin.qq.com/customservice/kfsession/close";
+ private static final String KFSESSION_GET_URL = "https://api.weixin.qq.com/customservice/kfsession/getsession?openid=%s";
+ private static final String KFSESSION_LIST_URL = "https://api.weixin.qq.com/customservice/kfsession/getsessionlist?kf_account=%s";
+
+ private final WxMaService service;
+
+ @Override
+ public WxMaKfList kfList() throws WxErrorException {
+ String responseContent = this.service.get(KFLIST_GET_URL, null);
+ return WxMaKfList.fromJson(responseContent);
+ }
+
+ @Override
+ public boolean kfAccountAdd(WxMaKfAccountRequest request) throws WxErrorException {
+ String responseContent = this.service.post(KFACCOUNT_ADD_URL, request.toJson());
+ return responseContent != null;
+ }
+
+ @Override
+ public boolean kfAccountUpdate(WxMaKfAccountRequest request) throws WxErrorException {
+ String responseContent = this.service.post(KFACCOUNT_UPDATE_URL, request.toJson());
+ return responseContent != null;
+ }
+
+ @Override
+ public boolean kfAccountDel(String kfAccount) throws WxErrorException {
+ String url = String.format(KFACCOUNT_DEL_URL, kfAccount);
+ String responseContent = this.service.get(url, null);
+ return responseContent != null;
+ }
+
+ @Override
+ public boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException {
+ WxMaKfSessionRequest request = WxMaKfSessionRequest.builder()
+ .kfAccount(kfAccount)
+ .openid(openid)
+ .build();
+ String responseContent = this.service.post(KFSESSION_CREATE_URL, request.toJson());
+ return responseContent != null;
+ }
+
+ @Override
+ public boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException {
+ WxMaKfSessionRequest request = WxMaKfSessionRequest.builder()
+ .kfAccount(kfAccount)
+ .openid(openid)
+ .build();
+ String responseContent = this.service.post(KFSESSION_CLOSE_URL, request.toJson());
+ return responseContent != null;
+ }
+
+ @Override
+ public WxMaKfSession kfSessionGet(String openid) throws WxErrorException {
+ String url = String.format(KFSESSION_GET_URL, openid);
+ String responseContent = this.service.get(url, null);
+ return WxMaKfSession.fromJson(responseContent);
+ }
+
+ @Override
+ public WxMaKfSessionList kfSessionList(String kfAccount) throws WxErrorException {
+ String url = String.format(KFSESSION_LIST_URL, kfAccount);
+ String responseContent = this.service.get(url, null);
+ return WxMaKfSessionList.fromJson(responseContent);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java
index cfd8428673..4f9d3be175 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java
@@ -21,7 +21,6 @@
import java.util.Map;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Broadcast.Goods.*;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Code.GET_PAGE_URL;
/**
*
@@ -82,7 +81,7 @@ public WxMaLiveResult getApprovedGoods(Integer offset, Integer limit, Integer st
String responseContent = wxMaService.get(GET_APPROVED_GOODS, Joiner.on("&").withKeyValueSeparator("=").join(params));
JsonObject jsonObject = GsonParser.parse(responseContent);
JsonArray goodsArr = jsonObject.getAsJsonArray("goods");
- if (goodsArr.size() > 0) {
+ if (!goodsArr.isEmpty()) {
for (int i = 0; i < goodsArr.size(); i++) {
// 接口返回key是驼峰
JsonObject goods = (JsonObject) goodsArr.get(i);
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java
index eaf23f11e9..d84603a53b 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java
@@ -6,7 +6,6 @@
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage;
import cn.binarywang.wx.miniapp.bean.WxMaUpdatableMsg;
-import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
import com.google.gson.JsonObject;
import lombok.RequiredArgsConstructor;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderManagementServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderManagementServiceImpl.java
new file mode 100644
index 0000000000..27d7c01487
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderManagementServiceImpl.java
@@ -0,0 +1,71 @@
+package cn.binarywang.wx.miniapp.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaOrderManagementService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath;
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.api.WxConsts;
+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.json.GsonHelper;
+import me.chanjar.weixin.common.util.json.GsonParser;
+
+import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.OrderManagement.*;
+
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:31
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class WxMaOrderManagementServiceImpl implements WxMaOrderManagementService {
+
+ private final WxMaService wxMaService;
+
+ /**
+ * 查询订单详情路径
+ * 注意事项
+ * 如果没有配置过订单详情路径,会返回成功,其中path为''。
+ *
+ * @return WxMaOrderManagementGetOrderDetailPath
+ * @throws WxErrorException e
+ */
+ @Override
+ public WxMaOrderManagementGetOrderDetailPath getOrderDetailPath() throws WxErrorException {
+ return request(GET_ORDER_DETAIL_PATH, new Object(), WxMaOrderManagementGetOrderDetailPath.class);
+
+ }
+
+ /**
+ * 配置订单详情路径
+ * 注意事项
+ * 调用接口前需要先完成订单中心授权协议签署。
+ * 请确保配置的path可正常跳转到小程序,并且path必须包含字符串“${商品订单号}”。
+ *
+ * @param path 订单详情路径
+ * @return WxMaOrderManagementResult
+ * @throws WxErrorException e
+ */
+ @Override
+ public WxMaOrderManagementResult updateOrderDetailPath(String path) throws WxErrorException {
+ JsonObject jsonObject = GsonHelper.buildJsonObject("path", path);
+ return request(UPDATE_ORDER_DETAIL_PATH, jsonObject, WxMaOrderManagementResult.class);
+
+ }
+
+ private T request(String url, Object request, Class resultT) throws WxErrorException {
+ String responseContent = this.wxMaService.post(url, request);
+ JsonObject jsonObject = GsonParser.parse(responseContent);
+ if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) {
+ throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+ }
+ return WxMaGsonBuilder.create().fromJson(responseContent, resultT);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java
index 98135cb466..1627a27cd0 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java
@@ -17,7 +17,6 @@
import me.chanjar.weixin.common.util.json.GsonParser;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.OrderShipping.*;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.GET_CATEGORY;
/**
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java
index 6e6ee05e38..d3c1eb2c3f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java
@@ -4,11 +4,7 @@
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.GET_CATEGORY;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.GET_FREIGHT_TEMPLATE;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.IMG_UPLOAD;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_ADD_SKU_URL;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_BATCH_ADD_SKU_URL;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_DEL_SKU_URL;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_SKU_LIST;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Order.PRODUCT_ORDER_GET_LIST;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_ADD_SKU_URL;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_BATCH_ADD_SKU_URL;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_DEL_SKU_URL;
@@ -28,9 +24,6 @@
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopAddGoodsSkuData;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopAddGoodsSpuData;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopOrderListResponse;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopResult;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopSku;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetBrandResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetCategoryResponse;
import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetFrightTemplateResponse;
@@ -52,11 +45,7 @@
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.api.WxConsts;
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.enums.WxType;
import me.chanjar.weixin.common.error.WxError;
@@ -142,7 +131,7 @@ public WxMinishopResult addSpu(WxMinishopSpu spu) thr
if (respObj.get(ERR_CODE).getAsInt() != 0) {
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult result = new WxMinishopResult<>();
result.setErrcode(respObj.get(ERR_CODE).getAsInt());
JsonObject dataObj = respObj.get("data").getAsJsonObject();
WxMinishopAddGoodsSpuData resultData = new WxMinishopAddGoodsSpuData();
@@ -200,7 +189,7 @@ public WxMinishopResult updateSpu(WxMinishopSpu spu)
if (respObj.get(ERR_CODE).getAsInt() != 0) {
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult result = new WxMinishopResult<>();
result.setErrcode(respObj.get(ERR_CODE).getAsInt());
JsonObject dataObj = respObj.get("data").getAsJsonObject();
WxMinishopAddGoodsSpuData resultData = new WxMinishopAddGoodsSpuData();
@@ -259,7 +248,7 @@ public WxMinishopResult minishiopGoodsAddSku(
if (jsonObject.get(ERR_CODE).getAsInt() != 0) {
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult result = new WxMinishopResult<>();
result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
WxMinishopAddGoodsSkuData resultData = new WxMinishopAddGoodsSkuData();
@@ -279,7 +268,7 @@ public WxMinishopResult> minishopGoodsBatchAddSk
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult> result = new WxMinishopResult<>();
result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
JsonArray jsonArray = jsonObject.get("data").getAsJsonArray();
List skuData = new ArrayList<>();
@@ -317,7 +306,7 @@ public WxMinishopResult minishopGoodsUpdateSku(
if (jsonObject.get(ERR_CODE).getAsInt() != 0) {
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult result = new WxMinishopResult<>();
result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
WxMinishopUpdateGoodsSkuData resultData = new WxMinishopUpdateGoodsSkuData();
@@ -339,7 +328,7 @@ public WxMinishopResult minishopGoodsUpdateSkuPric
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult result = new WxMinishopResult<>();
result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
WxMinishopUpdateGoodsSkuData resultData = new WxMinishopUpdateGoodsSkuData();
@@ -361,7 +350,7 @@ public WxMinishopResult minishopGoodsUpdateSkuStoc
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
}
- WxMinishopResult result = new WxMinishopResult();
+ WxMinishopResult result = new WxMinishopResult<>();
result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
WxMinishopUpdateGoodsSkuData resultData = new WxMinishopUpdateGoodsSkuData();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java
index 7b1ea3e96b..73b4994347 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java
@@ -4,18 +4,17 @@
import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import org.apache.commons.lang3.StringUtils;
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.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
@@ -59,78 +58,46 @@ public HttpHost getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.APACHE_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.APACHE_HTTP;
}
@Override
protected String doGetAccessTokenRequest() throws IOException {
-
String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ?
- this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ?
- WxMaService.GET_ACCESS_TOKEN_URL.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
- WxMaService.GET_ACCESS_TOKEN_URL;
-
+ this.getWxMaConfig().getAccessTokenUrl() :
+ WxMaService.GET_ACCESS_TOKEN_URL.replace(
+ WxMaConfig.DEFAULT_API_HOST_URL, this.getWxMaConfig().getEffectiveApiHostUrl());
url = String.format(url, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
- HttpGet httpGet = null;
- CloseableHttpResponse response = null;
- try {
- httpGet = new HttpGet(url);
- if (this.getRequestHttpProxy() != null) {
- RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
- httpGet.setConfig(config);
- }
- response = getRequestHttpClient().execute(httpGet);
- return new BasicResponseHandler().handleResponse(response);
- } finally {
- if (httpGet != null) {
- httpGet.releaseConnection();
- }
- if (response != null) {
- try {
- response.close();
- } catch (IOException e) {
- }
- }
+ HttpGet httpGet = new HttpGet(url);
+ if (this.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+ httpGet.setConfig(config);
}
+ return getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
}
@Override
protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ?
- this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ?
- GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
- GET_STABLE_ACCESS_TOKEN;
-
- HttpPost httpPost = null;
- CloseableHttpResponse response = null;
- try {
- httpPost = new HttpPost(url);
- if (this.getRequestHttpProxy() != null) {
- RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
- httpPost.setConfig(config);
- }
- WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest();
- wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid());
- wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret());
- wxMaAccessTokenRequest.setGrantType("client_credential");
- wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
- httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
- response = getRequestHttpClient().execute(httpPost);
- return new BasicResponseHandler().handleResponse(response);
- } finally {
- if (httpPost != null) {
- httpPost.releaseConnection();
- }
- if (response != null) {
- try {
- response.close();
- } catch (IOException e) {
- }
- }
+ this.getWxMaConfig().getAccessTokenUrl() :
+ GET_STABLE_ACCESS_TOKEN.replace(
+ WxMaConfig.DEFAULT_API_HOST_URL, this.getWxMaConfig().getEffectiveApiHostUrl());
+
+ HttpPost httpPost = new HttpPost(url);
+ if (this.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
}
+ WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest();
+ wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid());
+ wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret());
+ wxMaAccessTokenRequest.setGrantType("client_credential");
+ wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
+ httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
+ return getRequestHttpClient().execute(httpPost, ApacheBasicResponseHandler.INSTANCE);
}
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java
index d2037a0732..94806121ab 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java
@@ -8,7 +8,7 @@
import jodd.http.ProxyInfo;
import jodd.http.net.SocketHttpConnectionProvider;
import jodd.net.MimeTypes;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
@@ -43,16 +43,16 @@ public ProxyInfo getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.JODD_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.JODD_HTTP;
}
@Override
protected String doGetAccessTokenRequest() throws IOException {
String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ?
- this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ?
- WxMaService.GET_ACCESS_TOKEN_URL.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
- WxMaService.GET_ACCESS_TOKEN_URL;
+ this.getWxMaConfig().getAccessTokenUrl() :
+ WxMaService.GET_ACCESS_TOKEN_URL.replace(
+ WxMaConfig.DEFAULT_API_HOST_URL, this.getWxMaConfig().getEffectiveApiHostUrl());
url = String.format(url, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
HttpRequest request = HttpRequest.get(url);
@@ -67,11 +67,10 @@ protected String doGetAccessTokenRequest() throws IOException {
@Override
protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
-
String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ?
- this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ?
- GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
- GET_STABLE_ACCESS_TOKEN;
+ this.getWxMaConfig().getAccessTokenUrl() :
+ GET_STABLE_ACCESS_TOKEN.replace(
+ WxMaConfig.DEFAULT_API_HOST_URL, this.getWxMaConfig().getEffectiveApiHostUrl());
WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest();
wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid());
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java
index ff78a6984a..096af76caa 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java
@@ -3,7 +3,7 @@
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import okhttp3.*;
@@ -32,12 +32,12 @@ public void initHttp() {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.proxy(getRequestHttpProxy().getProxy());
//设置授权
- clientBuilder.authenticator(new Authenticator() {
+ clientBuilder.proxyAuthenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
return response.request().newBuilder()
- .header("Authorization", credential)
+ .header("Proxy-Authorization", credential)
.build();
}
});
@@ -58,16 +58,16 @@ public OkHttpProxyInfo getRequestHttpProxy() {
}
@Override
- public HttpType getRequestType() {
- return HttpType.OK_HTTP;
+ public HttpClientType getRequestType() {
+ return HttpClientType.OK_HTTP;
}
@Override
protected String doGetAccessTokenRequest() throws IOException {
String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ?
- this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ?
- WxMaService.GET_ACCESS_TOKEN_URL.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
- WxMaService.GET_ACCESS_TOKEN_URL;
+ this.getWxMaConfig().getAccessTokenUrl() :
+ WxMaService.GET_ACCESS_TOKEN_URL.replace(
+ WxMaConfig.DEFAULT_API_HOST_URL, this.getWxMaConfig().getEffectiveApiHostUrl());
url = String.format(url, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
Request request = new Request.Builder().url(url).get().build();
@@ -79,9 +79,10 @@ protected String doGetAccessTokenRequest() throws IOException {
@Override
protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
String url = StringUtils.isNotEmpty(this.getWxMaConfig().getAccessTokenUrl()) ?
- this.getWxMaConfig().getAccessTokenUrl() : StringUtils.isNotEmpty(this.getWxMaConfig().getApiHostUrl()) ?
- GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
- GET_STABLE_ACCESS_TOKEN;
+ this.getWxMaConfig().getAccessTokenUrl() :
+ GET_STABLE_ACCESS_TOKEN.replace(
+ WxMaConfig.DEFAULT_API_HOST_URL, this.getWxMaConfig().getEffectiveApiHostUrl());
+
WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest();
wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid());
wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret());
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImpl.java
index fd1981aa03..a3a8e6176f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaShareServiceImpl.java
@@ -2,6 +2,7 @@
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaShareService;
+import cn.binarywang.wx.miniapp.bean.WxMaGroupEnterInfo;
import cn.binarywang.wx.miniapp.bean.WxMaShareInfo;
import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils;
import lombok.RequiredArgsConstructor;
@@ -18,4 +19,9 @@ public WxMaShareInfo getShareInfo(String sessionKey, String encryptedData, Strin
return WxMaShareInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr));
}
+
+ @Override
+ public WxMaGroupEnterInfo getGroupEnterInfo(String sessionKey, String encryptedData, String ivStr) {
+ return WxMaGroupEnterInfo.fromJson(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr));
+ }
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java
index 2167ba062b..a7db154a68 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java
@@ -8,7 +8,6 @@
import me.chanjar.weixin.common.bean.subscribemsg.PubTemplateKeyword;
import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo;
import me.chanjar.weixin.common.bean.subscribemsg.PubTemplateTitleListResult;
-import cn.binarywang.wx.miniapp.constant.WxMaConstants;
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java
index c9f5c2e335..5c850ee8a2 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaUserServiceImpl.java
@@ -2,6 +2,7 @@
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaUserService;
+import cn.binarywang.wx.miniapp.bean.WxMaCode2VerifyInfoResult;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
@@ -18,6 +19,7 @@
import java.util.Map;
+import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.User.CODE_2_VERIFY_INFO_URL;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.User.GET_PHONE_NUMBER_URL;
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.User.SET_USER_STORAGE;
@@ -86,4 +88,13 @@ public boolean checkUserInfo(String sessionKey, String rawData, String signature
return generatedSignature.equals(signature);
}
+ @Override
+ public WxMaCode2VerifyInfoResult getCode2VerifyInfo(String code, String checkcode) throws WxErrorException {
+ JsonObject param = new JsonObject();
+ param.addProperty("code", code);
+ param.addProperty("checkcode", checkcode);
+ String responseContent = this.service.post(CODE_2_VERIFY_INFO_URL, param.toString());
+ return WxMaCode2VerifyInfoResult.fromJson(responseContent);
+ }
+
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java
index 5e33d1059f..29a7c51a2c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java
@@ -1,10 +1,10 @@
package cn.binarywang.wx.miniapp.api.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
-import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
-import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
import cn.binarywang.wx.miniapp.api.WxMaXPayService;
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
import cn.binarywang.wx.miniapp.bean.xpay.*;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.enums.WxType;
@@ -235,4 +235,217 @@ public WxMaXPayQueryPublishGoodsResponse queryPublishGoods(WxMaXPayQueryPublishG
return getDetailResponse;
}
+
+ @Override
+ public WxMaXPayQueryBizBalanceResponse queryBizBalance(WxMaXPayQueryBizBalanceRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(QUERY_BIZ_BALANCE_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayQueryBizBalanceResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayQueryBizBalanceResponse.class);
+
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayQueryTransferAccountResponse queryTransferAccount(WxMaXPayQueryTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(QUERY_TRANSFER_ACCOUNT_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayQueryTransferAccountResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayQueryTransferAccountResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayQueryAdverFundsResponse queryAdverFunds(WxMaXPayQueryAdverFundsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(QUERY_ADVER_FUNDS_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayQueryAdverFundsResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayQueryAdverFundsResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayCreateFundsBillResponse createFundsBill(WxMaXPayCreateFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(CREATE_FUNDS_BILL_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayCreateFundsBillResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayCreateFundsBillResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaBaseResponse bindTransferAccount(WxMaXPayBindTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(BIND_TRANSFER_ACCOUNT_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaBaseResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaBaseResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayQueryFundsBillResponse queryFundsBill(WxMaXPayQueryFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(QUERY_FUNDS_BILL_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayQueryFundsBillResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayQueryFundsBillResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayQueryRecoverBillResponse queryRecoverBill(WxMaXPayQueryRecoverBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(QUERY_RECOVER_BILL_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayQueryRecoverBillResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayQueryRecoverBillResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+
+ @Override
+ public WxMaXPayGetComplaintListResponse getComplaintList(WxMaXPayGetComplaintListRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(GET_COMPLAINT_LIST_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayGetComplaintListResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayGetComplaintListResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayGetComplaintDetailResponse getComplaintDetail(WxMaXPayGetComplaintDetailRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(GET_COMPLAINT_DETAIL_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayGetComplaintDetailResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayGetComplaintDetailResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayGetNegotiationHistoryResponse getNegotiationHistory(WxMaXPayGetNegotiationHistoryRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(GET_NEGOTIATION_HISTORY_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayGetNegotiationHistoryResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayGetNegotiationHistoryResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaBaseResponse responseComplaint(WxMaXPayResponseComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(RESPONSE_COMPLAINT_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaBaseResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaBaseResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaBaseResponse completeComplaint(WxMaXPayCompleteComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(COMPLETE_COMPLAINT_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaBaseResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaBaseResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayUploadVpFileResponse uploadVpFile(WxMaXPayUploadVpFileRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(UPLOAD_VP_FILE_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayUploadVpFileResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayUploadVpFileResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayGetUploadFileSignResponse getUploadFileSign(WxMaXPayGetUploadFileSignRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(GET_UPLOAD_FILE_SIGN_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayGetUploadFileSignResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayGetUploadFileSignResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
+
+ @Override
+ public WxMaXPayDownloadAdverfundsOrderResponse downloadAdverfundsOrder(WxMaXPayDownloadAdverfundsOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+ final String postBody = request.toJson();
+ final String uri = sigParams.signUriWithPay(DOWNLOAD_ADVERFUNDS_ORDER_URL, postBody);
+ String responseContent = this.service.post(uri, postBody);
+ WxMaXPayDownloadAdverfundsOrderResponse getDetailResponse = WxMaGsonBuilder.create()
+ .fromJson(responseContent, WxMaXPayDownloadAdverfundsOrderResponse.class);
+ if (getDetailResponse.getErrcode() != 0) {
+ throw new WxErrorException(
+ new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+ }
+ return getDetailResponse;
+ }
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaCode2VerifyInfoResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaCode2VerifyInfoResult.java
new file mode 100644
index 0000000000..b36a3a9d86
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaCode2VerifyInfoResult.java
@@ -0,0 +1,44 @@
+package cn.binarywang.wx.miniapp.bean;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ *
+ * 多端登录验证接口的响应
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/miniapp/openapi/code2Verifyinfo.html
+ *
+ * 微信返回报文:{"errcode": 0, "errmsg": "ok", "session_key":"xxx", "openid":"xxx", "unionid":"xxx", "is_limit": false}
+ *
+ *
+ * @author Binary Wang
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class WxMaCode2VerifyInfoResult implements Serializable {
+ private static final long serialVersionUID = -2468325025088437364L;
+
+ @SerializedName("session_key")
+ private String sessionKey;
+
+ @SerializedName("openid")
+ private String openid;
+
+ @SerializedName("unionid")
+ private String unionid;
+
+ /**
+ * 是否为受限用户
+ */
+ @SerializedName("is_limit")
+ private Boolean isLimit;
+
+ public static WxMaCode2VerifyInfoResult fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaCode2VerifyInfoResult.class);
+ }
+
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGroupEnterInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGroupEnterInfo.java
new file mode 100644
index 0000000000..e65ec602da
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGroupEnterInfo.java
@@ -0,0 +1,46 @@
+package cn.binarywang.wx.miniapp.bean;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 微信小程序群入口信息.
+ * 对应 wx.getGroupEnterInfo 接口返回的解密数据
+ *
+ * @see wx.getGroupEnterInfo 官方文档
+ */
+@Data
+public class WxMaGroupEnterInfo implements Serializable {
+ private static final long serialVersionUID = -8053613683499632227L;
+
+ /**
+ * 多聊群下返回的群唯一标识.
+ */
+ @SerializedName("opengid")
+ private String openGId;
+
+ /**
+ * 单聊群下返回的群唯一标识.
+ */
+ @SerializedName("open_single_roomid")
+ private String openSingleRoomid;
+
+ /**
+ * 用户在当前群的唯一标识.
+ */
+ @SerializedName("group_openid")
+ private String groupOpenid;
+
+ /**
+ * 聊天室类型.
+ */
+ @SerializedName("chat_type")
+ private Integer chatType;
+
+ public static WxMaGroupEnterInfo fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaGroupEnterInfo.class);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java
index 0cd77c7937..cdce681175 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaKefuMessage.java
@@ -40,6 +40,9 @@ public class WxMaKefuMessage implements Serializable {
@SerializedName("miniprogrampage")
private KfMaPage maPage;
+ @SerializedName("aimsgcontext")
+ private AiMsgContext aiMsgContext;
+
@Data
@AllArgsConstructor
@NoArgsConstructor
@@ -90,6 +93,16 @@ public static class KfMaPage implements Serializable {
private String thumbMediaId;
}
+ @Data
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class AiMsgContext implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @SerializedName("msgid")
+ private String msgId;
+ }
+
/**
* 获得文本消息builder.
*/
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
index 7a004b845c..88450403e3 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
@@ -31,7 +31,7 @@ public class WxMaMessage implements Serializable {
private static final long serialVersionUID = -3586245291677274914L;
/**
- * 使用dom4j解析的存放所有xml属性和值的map.
+ * 使用dom4j解析的存放所有xml或json属性和值的map.
*/
private Map allFieldsMap;
@@ -212,6 +212,107 @@ public class WxMaMessage implements Serializable {
@XStreamAlias("SubscribeMsgSentEvent")
private WxMaSubscribeMsgEvent.SubscribeMsgSentEvent subscribeMsgSentEvent;
+ // 小程序基本信息
+
+ //region 小程序基本信息 infoType=notify_3rd_wxa_auth_and_icp
+
+ /**
+ * 返回值
+ */
+ @XStreamAlias("ret")
+ private String ret;
+
+ /**
+ * 一级类目id
+ */
+ @XStreamAlias("first")
+ private String first;
+
+ /**
+ * 二级类目id
+ */
+ @XStreamAlias("second")
+ private String second;
+
+ /**
+ * 驳回原因
+ */
+ @XStreamAlias("reason")
+ private String reason;
+
+ /**
+ * 小程序代码审核驳回原因
+ */
+ @XStreamAlias("Reason")
+ private String weAppReason;
+
+ /**
+ * 昵称
+ */
+ @XStreamAlias("nickname")
+ private String nickname;
+
+ /**
+ * 原始通知内容
+ */
+ private String context;
+
+ /**
+ * 微信支付订单号
+ */
+ @XStreamAlias("transaction_id")
+ private String transactionId;
+ /**
+ * 商户号
+ */
+ @XStreamAlias("merchant_id")
+ private String merchantId;
+ /**
+ * 子商户号
+ */
+ @XStreamAlias("sub_merchant_id")
+ private String subMerchantId;
+ /**
+ * 商户订单号
+ */
+ @XStreamAlias("merchant_trade_no")
+ private String merchantTradeNo;
+ /**
+ * 支付成功时间,秒级时间戳
+ */
+ @XStreamAlias("pay_time")
+ private Long payTime;
+ /**
+ * 消息文本内容
+ */
+ @XStreamAlias("msg")
+ private String msg;
+ /**
+ * 发货时间,秒级时间戳
+ */
+ @XStreamAlias("shipped_time")
+ private Long shippedTime;
+ /**
+ * 预计结算时间,秒级时间戳。发货时推送才有该字段
+ */
+ @XStreamAlias("estimated_settlement_time")
+ private Long estimatedSettlementTime;
+ /**
+ * 确认收货方式:1. 手动确认收货;2. 自动确认收货。结算时推送才有该字段
+ */
+ @XStreamAlias("confirm_receive_method")
+ private Integer confirmReceiveMethod;
+ /**
+ * 确认收货时间,秒级时间戳。结算时推送才有该字段
+ */
+ @XStreamAlias("confirm_receive_time")
+ private Long confirmReceiveTime;
+ /**
+ * 订单结算时间,秒级时间戳。结算时推送才有该字段
+ */
+ @XStreamAlias("settlement_time")
+ private Long settlementTime;
+
/**
* 不要直接使用这个字段,
* 这个字段只是为了适配 SubscribeMsgPopupEvent SubscribeMsgChangeEvent SubscribeMsgSentEvent
@@ -261,7 +362,9 @@ public static WxMaMessage fromEncryptedXml(String encryptedXml,
WxMaConfig wxMaConfig, String timestamp, String nonce,
String msgSignature) {
String plainText = new WxMaCryptUtils(wxMaConfig).decryptXml(msgSignature, timestamp, nonce, encryptedXml);
- return fromXml(plainText);
+ WxMaMessage wxMaMessage = fromXml(plainText);
+ wxMaMessage.setContext(plainText);
+ return wxMaMessage;
}
public static WxMaMessage fromEncryptedXml(InputStream is, WxMaConfig wxMaConfig, String timestamp,
@@ -287,6 +390,7 @@ public static WxMaMessage fromJson(String json) {
}
message.setUselessMsg(null);
}
+ message.setAllFieldsMap(WxMaGsonBuilder.create().fromJson(json, Map.class));
return message;
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintDetailRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintDetailRequest.java
new file mode 100644
index 0000000000..759f7392bf
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintDetailRequest.java
@@ -0,0 +1,38 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序投诉单详情请求实体
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaComplaintDetailRequest implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:投诉单号
+ * 是否必填:是
+ * 描述:投诉单对应的投诉单号
+ *
+ */
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintDetailResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintDetailResult.java
new file mode 100644
index 0000000000..52a0be1704
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintDetailResult.java
@@ -0,0 +1,166 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 小程序投诉单详情结果
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxMaComplaintDetailResult extends WxMaBaseResponse {
+
+ /**
+ *
+ * 字段名:投诉单号
+ * 是否必填:是
+ * 描述:投诉单对应的投诉单号
+ *
+ */
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+ /**
+ *
+ * 字段名:投诉时间
+ * 是否必填:是
+ * 描述:用户提交投诉的时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE
+ *
+ */
+ @SerializedName("complaint_time")
+ private String complaintTime;
+
+ /**
+ *
+ * 字段名:投诉详情
+ * 是否必填:是
+ * 描述:用户提交的投诉详情
+ *
+ */
+ @SerializedName("complaint_detail")
+ private String complaintDetail;
+
+ /**
+ *
+ * 字段名:投诉状态
+ * 是否必填:是
+ * 描述:投诉单状态:WAITING_MERCHANT_RESPONSE-等待商户回复 MERCHANT_RESPONSED-商户已回复 WAITING_USER_RESPONSE-等待用户回复 USER_RESPONSED-用户已回复 COMPLAINT_COMPLETED-投诉已完成
+ *
+ */
+ @SerializedName("complaint_state")
+ private String complaintState;
+
+ /**
+ *
+ * 字段名:投诉人openid
+ * 是否必填:是
+ * 描述:投诉人在小程序的openid
+ *
+ */
+ @SerializedName("openid")
+ private String openid;
+
+ /**
+ *
+ * 字段名:投诉人联系方式
+ * 是否必填:否
+ * 描述:投诉人联系方式,可能为空
+ *
+ */
+ @SerializedName("phone_number")
+ private String phoneNumber;
+
+ /**
+ *
+ * 字段名:被投诉订单信息
+ * 是否必填:是
+ * 描述:被投诉的订单信息
+ *
+ */
+ @SerializedName("complaint_order_info")
+ private ComplaintOrderInfo complaintOrderInfo;
+
+ /**
+ *
+ * 字段名:投诉材料
+ * 是否必填:否
+ * 描述:用户上传的投诉相关的图片凭证
+ *
+ */
+ @SerializedName("complaint_media_list")
+ private List complaintMediaList;
+
+ /**
+ * 被投诉订单信息
+ */
+ @Data
+ public static class ComplaintOrderInfo implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:商户订单号
+ * 是否必填:是
+ * 描述:商户系统内部订单号
+ *
+ */
+ @SerializedName("transaction_id")
+ private String transactionId;
+
+ /**
+ *
+ * 字段名:微信订单号
+ * 是否必填:是
+ * 描述:微信支付系统生成的订单号
+ *
+ */
+ @SerializedName("out_trade_no")
+ private String outTradeNo;
+
+ /**
+ *
+ * 字段名:订单金额
+ * 是否必填:是
+ * 描述:订单金额,单位为分
+ *
+ */
+ @SerializedName("amount")
+ private Integer amount;
+ }
+
+ /**
+ * 投诉材料
+ */
+ @Data
+ public static class ComplaintMedia implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:媒体文件业务类型
+ * 是否必填:是
+ * 描述:媒体文件对应的业务类型:USER_COMPLAINT_IMAGE-用户投诉图片
+ *
+ */
+ @SerializedName("media_type")
+ private String mediaType;
+
+ /**
+ *
+ * 字段名:媒体文件请求URL
+ * 是否必填:是
+ * 描述:微信返回的媒体文件请求URL,通过该URL可以获取到对应的媒体文件(图片、视频等)
+ *
+ */
+ @SerializedName("media_url")
+ private String mediaUrl;
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintNotifyUrlRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintNotifyUrlRequest.java
new file mode 100644
index 0000000000..6af338c974
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintNotifyUrlRequest.java
@@ -0,0 +1,38 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序投诉通知回调URL请求实体
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaComplaintNotifyUrlRequest implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:通知地址
+ * 是否必填:是
+ * 描述:通知地址,仅支持https
+ *
+ */
+ @SerializedName("url")
+ private String url;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintNotifyUrlResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintNotifyUrlResult.java
new file mode 100644
index 0000000000..7771998b80
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintNotifyUrlResult.java
@@ -0,0 +1,37 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 小程序投诉通知回调URL结果
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxMaComplaintNotifyUrlResult extends WxMaBaseResponse {
+
+ /**
+ *
+ * 字段名:通知地址
+ * 是否必填:是
+ * 描述:通知地址,仅支持https
+ *
+ */
+ @SerializedName("url")
+ private String url;
+
+ /**
+ *
+ * 字段名:签名串
+ * 是否必填:是
+ * 描述:用于验证通知消息的签名串
+ *
+ */
+ @SerializedName("signature")
+ private String signature;
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintRequest.java
new file mode 100644
index 0000000000..9ac45e0c12
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintRequest.java
@@ -0,0 +1,70 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序交易投诉查询请求实体
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaComplaintRequest implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:开始日期
+ * 是否必填:是
+ * 描述:查询的起始时间,格式为YYYY-MM-DD,例如2021-01-01
+ *
+ */
+ @SerializedName("begin_date")
+ private String beginDate;
+
+ /**
+ *
+ * 字段名:结束日期
+ * 是否必填:是
+ * 描述:查询的结束时间,格式为YYYY-MM-DD,例如2021-01-31
+ *
+ */
+ @SerializedName("end_date")
+ private String endDate;
+
+ /**
+ *
+ * 字段名:分页大小
+ * 是否必填:否
+ * 描述:单次拉取条目,最大为50,不传默认为10
+ *
+ */
+ @SerializedName("limit")
+ @Builder.Default
+ private Integer limit = 10;
+
+ /**
+ *
+ * 字段名:分页开始位置
+ * 是否必填:否
+ * 描述:该次请求的分页开始位置,从0开始计数,例如offset=10,表示从第11条记录开始返回,不传默认为0
+ *
+ */
+ @SerializedName("offset")
+ @Builder.Default
+ private Integer offset = 0;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintResult.java
new file mode 100644
index 0000000000..0e4208fdc1
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaComplaintResult.java
@@ -0,0 +1,156 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 小程序交易投诉查询结果
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxMaComplaintResult extends WxMaBaseResponse {
+
+ /**
+ *
+ * 字段名:投诉单信息
+ * 是否必填:是
+ * 描述:查询返回的投诉单信息
+ *
+ */
+ @SerializedName("data")
+ private List data;
+
+ /**
+ *
+ * 字段名:总数
+ * 是否必填:是
+ * 描述:总投诉单条数,用于分页展示
+ *
+ */
+ @SerializedName("total_count")
+ private Integer totalCount;
+
+ /**
+ * 投诉单信息
+ */
+ @Data
+ public static class Complaint implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:投诉单号
+ * 是否必填:是
+ * 描述:投诉单对应的投诉单号
+ *
+ */
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+ /**
+ *
+ * 字段名:投诉时间
+ * 是否必填:是
+ * 描述:用户提交投诉的时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE
+ *
+ */
+ @SerializedName("complaint_time")
+ private String complaintTime;
+
+ /**
+ *
+ * 字段名:投诉详情
+ * 是否必填:是
+ * 描述:用户提交的投诉详情
+ *
+ */
+ @SerializedName("complaint_detail")
+ private String complaintDetail;
+
+ /**
+ *
+ * 字段名:投诉状态
+ * 是否必填:是
+ * 描述:投诉单状态:WAITING_MERCHANT_RESPONSE-等待商户回复 MERCHANT_RESPONSED-商户已回复 WAITING_USER_RESPONSE-等待用户回复 USER_RESPONSED-用户已回复 COMPLAINT_COMPLETED-投诉已完成
+ *
+ */
+ @SerializedName("complaint_state")
+ private String complaintState;
+
+ /**
+ *
+ * 字段名:投诉人openid
+ * 是否必填:是
+ * 描述:投诉人在小程序的openid
+ *
+ */
+ @SerializedName("openid")
+ private String openid;
+
+ /**
+ *
+ * 字段名:投诉人联系方式
+ * 是否必填:否
+ * 描述:投诉人联系方式,可能为空
+ *
+ */
+ @SerializedName("phone_number")
+ private String phoneNumber;
+
+ /**
+ *
+ * 字段名:被投诉订单信息
+ * 是否必填:是
+ * 描述:被投诉的订单信息
+ *
+ */
+ @SerializedName("complaint_order_info")
+ private ComplaintOrderInfo complaintOrderInfo;
+ }
+
+ /**
+ * 被投诉订单信息
+ */
+ @Data
+ public static class ComplaintOrderInfo implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:商户订单号
+ * 是否必填:是
+ * 描述:商户系统内部订单号
+ *
+ */
+ @SerializedName("transaction_id")
+ private String transactionId;
+
+ /**
+ *
+ * 字段名:微信订单号
+ * 是否必填:是
+ * 描述:微信支付系统生成的订单号
+ *
+ */
+ @SerializedName("out_trade_no")
+ private String outTradeNo;
+
+ /**
+ *
+ * 字段名:订单金额
+ * 是否必填:是
+ * 描述:订单金额,单位为分
+ *
+ */
+ @SerializedName("amount")
+ private Integer amount;
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaCompleteRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaCompleteRequest.java
new file mode 100644
index 0000000000..71d1066024
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaCompleteRequest.java
@@ -0,0 +1,38 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序反馈处理完成请求实体
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaCompleteRequest implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:投诉单号
+ * 是否必填:是
+ * 描述:投诉单对应的投诉单号
+ *
+ */
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaNegotiationHistoryRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaNegotiationHistoryRequest.java
new file mode 100644
index 0000000000..a03742b6af
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaNegotiationHistoryRequest.java
@@ -0,0 +1,60 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序查询投诉协商历史请求实体
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaNegotiationHistoryRequest implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:投诉单号
+ * 是否必填:是
+ * 描述:投诉单对应的投诉单号
+ *
+ */
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+ /**
+ *
+ * 字段名:分页大小
+ * 是否必填:否
+ * 描述:单次拉取条目,最大为50,不传默认为10
+ *
+ */
+ @SerializedName("limit")
+ @Builder.Default
+ private Integer limit = 10;
+
+ /**
+ *
+ * 字段名:分页开始位置
+ * 是否必填:否
+ * 描述:该次请求的分页开始位置,从0开始计数,例如offset=10,表示从第11条记录开始返回,不传默认为0
+ *
+ */
+ @SerializedName("offset")
+ @Builder.Default
+ private Integer offset = 0;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaNegotiationHistoryResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaNegotiationHistoryResult.java
new file mode 100644
index 0000000000..194daca9ff
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaNegotiationHistoryResult.java
@@ -0,0 +1,88 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 小程序查询投诉协商历史结果
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxMaNegotiationHistoryResult extends WxMaBaseResponse {
+
+ /**
+ *
+ * 字段名:协商历史
+ * 是否必填:是
+ * 描述:协商历史记录
+ *
+ */
+ @SerializedName("data")
+ private List data;
+
+ /**
+ *
+ * 字段名:总数
+ * 是否必填:是
+ * 描述:总协商历史条数,用于分页展示
+ *
+ */
+ @SerializedName("total_count")
+ private Integer totalCount;
+
+ /**
+ * 协商历史
+ */
+ @Data
+ public static class NegotiationHistory implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:操作时间
+ * 是否必填:是
+ * 描述:操作时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE
+ *
+ */
+ @SerializedName("operate_time")
+ private String operateTime;
+
+ /**
+ *
+ * 字段名:操作类型
+ * 是否必填:是
+ * 描述:操作类型:USER_CREATE_COMPLAINT-用户提交投诉 USER_CONTINUE_COMPLAINT-用户继续投诉 MERCHANT_RESPONSE-商户回复 MERCHANT_CONFIRM_COMPLETE-商户确认完成处理
+ *
+ */
+ @SerializedName("operate_type")
+ private String operateType;
+
+ /**
+ *
+ * 字段名:操作内容
+ * 是否必填:是
+ * 描述:具体的操作内容
+ *
+ */
+ @SerializedName("operate_details")
+ private String operateDetails;
+
+ /**
+ *
+ * 字段名:图片凭证
+ * 是否必填:否
+ * 描述:操作过程中上传的图片凭证
+ *
+ */
+ @SerializedName("image_list")
+ private List imageList;
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaResponseRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaResponseRequest.java
new file mode 100644
index 0000000000..b4033c4f31
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/complaint/WxMaResponseRequest.java
@@ -0,0 +1,79 @@
+package cn.binarywang.wx.miniapp.bean.complaint;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 小程序提交回复请求实体
+ *
+ * @author Binary Wang
+ * created on 2025-01-01
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaResponseRequest implements Serializable {
+ private static final long serialVersionUID = 3244929701614280806L;
+
+ /**
+ *
+ * 字段名:投诉单号
+ * 是否必填:是
+ * 描述:投诉单对应的投诉单号
+ *
+ */
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+ /**
+ *
+ * 字段名:回复内容
+ * 是否必填:是
+ * 描述:具体的回复内容,长度不超过200字符
+ *
+ */
+ @SerializedName("response_content")
+ private String responseContent;
+
+ /**
+ *
+ * 字段名:回复图片
+ * 是否必填:否
+ * 描述:回复的图片凭证,最多可传5张图片,由图片上传接口返回
+ *
+ */
+ @SerializedName("response_images")
+ private List responseImages;
+
+ /**
+ *
+ * 字段名:跳转链接
+ * 是否必填:否
+ * 描述:点击跳转链接
+ *
+ */
+ @SerializedName("jump_url")
+ private String jumpUrl;
+
+ /**
+ *
+ * 字段名:跳转链接文案
+ * 是否必填:否
+ * 描述:跳转链接文案,在response_content中展示的跳转链接文案,长度不超过10个字符
+ *
+ */
+ @SerializedName("jump_url_text")
+ private String jumpUrlText;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/customservice/WxMaCustomserviceResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/customservice/WxMaCustomserviceResult.java
new file mode 100644
index 0000000000..e7a9a46de3
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/customservice/WxMaCustomserviceResult.java
@@ -0,0 +1,56 @@
+package cn.binarywang.wx.miniapp.bean.customservice;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 客服绑定结果信息,包括错误码、主体名称、企业ID和绑定时间戳。
+ *
+ * 字段说明:
+ *
+ * - errCode: 错误码
+ * - entityName: 小程序主体名称,未绑定时不返回
+ * - corpid: 企业ID,未绑定时不返回
+ * - bindTime: 接受绑定时间戳(毫秒)
+ *
+ * @author tryking123
+ * @since 2025/8/18 17:40
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaCustomserviceResult implements Serializable {
+ private static final long serialVersionUID = 8854979405505241314L;
+
+ @SerializedName("errcode")
+ private Integer errCode;
+
+ /**
+ * 该小程序的主体名称,未绑定时不返回
+ */
+ @SerializedName("entityName")
+ private String entityName;
+
+ /**
+ * 企业ID,未绑定时不返回
+ */
+ @SerializedName("corpid")
+ private String corpid;
+
+ /** 接受绑定时间戳,ms */
+ @JsonProperty("bindTime")
+ private Long bindTime;
+
+ public static WxMaCustomserviceResult fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaCustomserviceResult.class);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/request/WxMaExpressOrderCargo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/request/WxMaExpressOrderCargo.java
index 96817a2256..b6de21b9e6 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/request/WxMaExpressOrderCargo.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/request/WxMaExpressOrderCargo.java
@@ -34,7 +34,7 @@ public class WxMaExpressOrderCargo implements Serializable {
* 描述: 单位是千克(kg)
*
*/
- private Integer weight;
+ private Double weight;
/**
* 包裹长度
@@ -44,7 +44,7 @@ public class WxMaExpressOrderCargo implements Serializable {
*
*/
@SerializedName("space_x")
- private Integer spaceLength;
+ private Double spaceLength;
/**
* 包裹宽度
@@ -54,7 +54,7 @@ public class WxMaExpressOrderCargo implements Serializable {
*
*/
@SerializedName("space_y")
- private Integer spaceWidth;
+ private Double spaceWidth;
/**
* 包裹高度
@@ -64,7 +64,7 @@ public class WxMaExpressOrderCargo implements Serializable {
*
*/
@SerializedName("space_z")
- private Integer spaceHeight;
+ private Double spaceHeight;
/**
* 包裹中商品详情列表
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfInfo.java
new file mode 100644
index 0000000000..476056d518
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfInfo.java
@@ -0,0 +1,79 @@
+package cn.binarywang.wx.miniapp.bean.kefu;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序客服信息.
+ *
+ * @author Binary Wang
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaKfInfo implements Serializable {
+ private static final long serialVersionUID = -7916302137791763175L;
+
+ /**
+ * 客服账号.
+ */
+ @SerializedName("kf_account")
+ private String kfAccount;
+
+ /**
+ * 客服昵称.
+ */
+ @SerializedName("kf_nick")
+ private String kfNick;
+
+ /**
+ * 客服密码.
+ */
+ @SerializedName("kf_id")
+ private String kfId;
+
+ /**
+ * 客服头像.
+ */
+ @SerializedName("kf_headimgurl")
+ private String kfHeadImgUrl;
+
+ /**
+ * 如果客服帐号已绑定了客服人员微信号,则此处显示微信号.
+ */
+ @SerializedName("kf_wx")
+ private String kfWx;
+
+ /**
+ * 如果客服帐号尚未绑定微信号,但是已经发起了一个绑定邀请,则此处显示绑定邀请的微信号.
+ */
+ @SerializedName("invite_wx")
+ private String inviteWx;
+
+ /**
+ * 邀请的状态,有等待确认"waiting",被拒绝"rejected",过期"expired".
+ */
+ @SerializedName("invite_expire_time")
+ private Long inviteExpireTime;
+
+ /**
+ * 邀请的过期时间,为unix时间戳.
+ */
+ @SerializedName("invite_status")
+ private String inviteStatus;
+
+ public static WxMaKfInfo fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaKfInfo.class);
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfList.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfList.java
new file mode 100644
index 0000000000..8dd87a1728
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfList.java
@@ -0,0 +1,35 @@
+package cn.binarywang.wx.miniapp.bean.kefu;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 小程序客服列表.
+ *
+ * @author Binary Wang
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaKfList implements Serializable {
+ private static final long serialVersionUID = 6416633293297389972L;
+
+ @SerializedName("kf_list")
+ private List kfList;
+
+ public static WxMaKfList fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaKfList.class);
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSession.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSession.java
new file mode 100644
index 0000000000..60c010499c
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSession.java
@@ -0,0 +1,43 @@
+package cn.binarywang.wx.miniapp.bean.kefu;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序客服会话.
+ *
+ * @author Binary Wang
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaKfSession implements Serializable {
+ private static final long serialVersionUID = -6987567952389036965L;
+
+ /**
+ * 正在接待的客服,为空表示没有人在接待.
+ */
+ @SerializedName("kf_account")
+ private String kfAccount;
+
+ /**
+ * 会话接入的时间.
+ */
+ @SerializedName("createtime")
+ private Long createTime;
+
+ public static WxMaKfSession fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaKfSession.class);
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSessionList.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSessionList.java
new file mode 100644
index 0000000000..e172e2e4e5
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/WxMaKfSessionList.java
@@ -0,0 +1,61 @@
+package cn.binarywang.wx.miniapp.bean.kefu;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 小程序客服会话列表.
+ *
+ * @author Binary Wang
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaKfSessionList implements Serializable {
+ private static final long serialVersionUID = -1538600729426188776L;
+
+ @SerializedName("sessionlist")
+ private List sessionList;
+
+ @Data
+ @Builder
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class SessionInfo implements Serializable {
+ private static final long serialVersionUID = -2077261313274513580L;
+
+ /**
+ * 粉丝的openid.
+ */
+ @SerializedName("openid")
+ private String openid;
+
+ /**
+ * 会话创建时间,UNIX时间戳.
+ */
+ @SerializedName("createtime")
+ private Long createTime;
+
+ /**
+ * 粉丝的最后一条消息的时间,UNIX时间戳.
+ */
+ @SerializedName("latest_time")
+ private Long latestTime;
+ }
+
+ public static WxMaKfSessionList fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaKfSessionList.class);
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfAccountRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfAccountRequest.java
new file mode 100644
index 0000000000..0ad8913639
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfAccountRequest.java
@@ -0,0 +1,49 @@
+package cn.binarywang.wx.miniapp.bean.kefu.request;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序客服账号操作请求.
+ *
+ * @author Binary Wang
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaKfAccountRequest implements Serializable {
+ private static final long serialVersionUID = -4953504451749066635L;
+
+ /**
+ * 客服账号.
+ */
+ @SerializedName("kf_account")
+ private String kfAccount;
+
+ /**
+ * 客服昵称.
+ */
+ @SerializedName("kf_nick")
+ private String kfNick;
+
+ /**
+ * 客服密码.
+ */
+ @SerializedName("kf_pwd")
+ private String kfPwd;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+
+ public static WxMaKfAccountRequest fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaKfAccountRequest.class);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfSessionRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfSessionRequest.java
new file mode 100644
index 0000000000..f8180f926a
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/kefu/request/WxMaKfSessionRequest.java
@@ -0,0 +1,43 @@
+package cn.binarywang.wx.miniapp.bean.kefu.request;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 小程序客服会话操作请求.
+ *
+ * @author Binary Wang
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaKfSessionRequest implements Serializable {
+ private static final long serialVersionUID = -3278295399203344398L;
+
+ /**
+ * 客服账号.
+ */
+ @SerializedName("kf_account")
+ private String kfAccount;
+
+ /**
+ * 用户openid.
+ */
+ @SerializedName("openid")
+ private String openid;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+
+ public static WxMaKfSessionRequest fromJson(String json) {
+ return WxMaGsonBuilder.create().fromJson(json, WxMaKfSessionRequest.class);
+ }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java
new file mode 100644
index 0000000000..b301e356e8
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java
@@ -0,0 +1,22 @@
+package cn.binarywang.wx.miniapp.bean.order;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:27
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class WxMaOrderManagementGetOrderDetailPath extends WxMaOrderManagementResult {
+ private static final long serialVersionUID = -5288666524298706169L;
+
+ /**
+ * 订单详情路径
+ */
+ @SerializedName("path")
+ private String path;
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementResult.java
new file mode 100644
index 0000000000..5a903b8980
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementResult.java
@@ -0,0 +1,27 @@
+package cn.binarywang.wx.miniapp.bean.order;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:27
+ */
+@Data
+public class WxMaOrderManagementResult implements Serializable {
+ private static final long serialVersionUID = 1468925151935770503L;
+ /**
+ * 错误码
+ */
+ @SerializedName("errcode")
+ private Integer errCode;
+
+ /**
+ * 错误原因
+ */
+ @SerializedName("errmsg")
+ private String errMsg;
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java
index d70e04327a..72d1381cf2 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java
@@ -7,7 +7,6 @@
import lombok.NoArgsConstructor;
import java.io.Serializable;
-import java.util.List;
/**
* @author xzh
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java
index ca3c451601..a8bd30e19a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java
@@ -7,7 +7,6 @@
import lombok.NoArgsConstructor;
import java.io.Serializable;
-import java.util.List;
/**
* @author liming1019
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java
index 19db2d2a1b..59aa5c3369 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java
@@ -2,7 +2,7 @@
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
-import java.util.List;
+
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java
index ac586fa7b7..a86804bb56 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java
@@ -1,6 +1,5 @@
package cn.binarywang.wx.miniapp.bean.shop.request;
-import cn.binarywang.wx.miniapp.bean.shop.request.WxMaShopAfterSaleAddRequest.UploadMediaList;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java
index 74c4a76780..4d8caf010c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java
@@ -1,6 +1,5 @@
package cn.binarywang.wx.miniapp.bean.shop.request.shipping;
-import cn.binarywang.wx.miniapp.bean.shop.request.shipping.ContactBean;
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.OrderKeyBean;
import cn.binarywang.wx.miniapp.bean.shop.request.shipping.PayerBean;
import com.google.gson.annotations.SerializedName;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java
index e4a015e9ab..d83c657732 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java
@@ -2,7 +2,6 @@
import com.google.gson.annotations.SerializedName;
import lombok.Data;
-import lombok.EqualsAndHashCode;
import java.io.Serializable;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java
index ace2c3b749..bb498d4add 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java
@@ -16,18 +16,66 @@
public class WxMaVodListMediaRequest implements Serializable {
private static final long serialVersionUID = 7495157056049312108L;
+ /**
+ *
+ * 必填:否
+ * 说明:根据剧目id获取剧集信息
+ *
+ */
@SerializedName("drama_id")
private Integer dramaId;
+
+ /**
+ *
+ * 必填:否
+ * 说明:媒资文件名,支持精确匹配、模糊匹配。文件太多时使用该参数进行模糊匹配可能无法得到结果,推荐使用 media_name_fuzzy 参数。
+ *
+ */
@SerializedName("media_name")
private String mediaName;
+ /**
+ *
+ * 必填:否
+ * 说明:媒资文件名,模糊匹配。
+ *
+ */
+ @SerializedName("media_name_fuzzy")
+ private String mediaNameFuzzy;
+
+ /**
+ *
+ * 必填:否
+ * 说明:媒资上传时间 >= start_time。
+ *
+ */
@SerializedName("start_time")
private Long startTime;
+
+ /**
+ *
+ * 必填:否
+ * 说明:媒资上传时间 < end_time。
+ *
+ */
@SerializedName("end_time")
private Long endTime;
+ /**
+ *
+ * 必填:否
+ * 说明:分页拉取的起始偏移量。默认值:0。
+ *
+ */
@SerializedName("offset")
private Integer offset;
+
+ /**
+ *
+ * 必填:否
+ * 说明:分页拉取的最大返回结果数。默认值:100;最大值:100。
+ *
+ */
@SerializedName("limit")
private Integer limit;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayBindTransferAccountRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayBindTransferAccountRequest.java
new file mode 100644
index 0000000000..dcabbe8e94
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayBindTransferAccountRequest.java
@@ -0,0 +1,32 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayBindTransferAccountRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("transfer_account_uid")
+ private Long transferAccountUid;
+ @SerializedName("transfer_account_org_name")
+ private String transferAccountOrgName;
+ @SerializedName("env")
+ private Integer env;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCompleteComplaintRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCompleteComplaintRequest.java
new file mode 100644
index 0000000000..2753a9eea9
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCompleteComplaintRequest.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayCompleteComplaintRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillRequest.java
new file mode 100644
index 0000000000..1e6fb4fc71
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillRequest.java
@@ -0,0 +1,48 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayCreateFundsBillRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("transfer_amount")
+ private Integer transferAmount;
+ @SerializedName("transfer_account_uid")
+ private Long transferAccountUid;
+ @SerializedName("transfer_account_name")
+ private String transferAccountName;
+ @SerializedName("transfer_account_agency_id")
+ private Integer transferAccountAgencyId;
+ @SerializedName("request_id")
+ private String requestId;
+ @SerializedName("settle_begin")
+ private Long settleBegin;
+ @SerializedName("settle_end")
+ private Long settleEnd;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("authorize_advertise")
+ private Integer authorizeAdvertise;
+ @SerializedName("fund_type")
+ private Integer fundType;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
+
+
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillResponse.java
new file mode 100644
index 0000000000..745976d017
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillResponse.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayCreateFundsBillResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+
+ @SerializedName("bill_id")
+ private String billId;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
+
+
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderRequest.java
new file mode 100644
index 0000000000..8ae6135860
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderRequest.java
@@ -0,0 +1,31 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @auther fancg
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayDownloadAdverfundsOrderRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("fund_id")
+ private String fundId;
+ @SerializedName("env")
+ private Integer env;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderResponse.java
new file mode 100644
index 0000000000..0a64784564
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderResponse.java
@@ -0,0 +1,27 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayDownloadAdverfundsOrderResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+ @SerializedName("url")
+ private String url;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailRequest.java
new file mode 100644
index 0000000000..24a2517435
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailRequest.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintDetailRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailResponse.java
new file mode 100644
index 0000000000..497dcee0e0
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailResponse.java
@@ -0,0 +1,101 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintDetailResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+
+ @SerializedName("complaint")
+ private Complaint complaint;
+
+ @Data
+ public static class Complaint {
+ @SerializedName("complaint_id")
+ private String complaintId;
+ @SerializedName("complaint_time")
+ private String complaintTime;
+ @SerializedName("complaint_detail")
+ private String complaintDetail;
+ @SerializedName("complaint_state")
+ private String complaintState;
+ @SerializedName("payer_phone")
+ private String payerPhone;
+ @SerializedName("payer_openid")
+ private String payerOpenid;
+ @SerializedName("complaint_order_info")
+ private List complaintOrderInfo;
+ @SerializedName("complaint_full_refunded")
+ private Boolean complaintFullRefunded;
+ @SerializedName("incoming_user_response")
+ private Boolean incomingUserResponse;
+ @SerializedName("user_complaint_times")
+ private Integer userComplaintTimes;
+ @SerializedName("complaint_media_list")
+ private List complaintMediaList;
+ @SerializedName("problem_description")
+ private String problemDescription;
+ @SerializedName("problem_type")
+ private String problemType;
+ @SerializedName("apply_refund_amount")
+ private Integer applyRefundAmount;
+ @SerializedName("user_tag_list")
+ private List userTagList;
+ @SerializedName("service_order_info")
+ private List serviceOrderInfo;
+
+
+ }
+
+ @Data
+ public static class ComplaintOrderInfo {
+ @SerializedName("transaction_id")
+ private String transactionId;
+ @SerializedName("out_trade_no")
+ private String outTradeNo;
+ @SerializedName("amount")
+ private Integer amount;
+ @SerializedName("wxa_out_trade_no")
+ private String wxaOutTradeNo;
+ @SerializedName("wx_order_id")
+ private String wxOrderId;
+ }
+
+ @Data
+ public static class ComplaintMedia {
+
+ @SerializedName("media_type")
+ private String mediaType;
+ @SerializedName("media_url")
+ private List mediaUrl;
+ }
+
+ @Data
+ public static class ServiceOrderInfo {
+ @SerializedName("order_id")
+ private String orderId;
+ @SerializedName("out_order_no")
+ private String outOrderNo;
+ @SerializedName("state")
+ private String state;
+ }
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListRequest.java
new file mode 100644
index 0000000000..69c9d0aaf5
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListRequest.java
@@ -0,0 +1,36 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintListRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("begin_date")
+ private String beginDate;
+ @SerializedName("end_date")
+ private String endDate;
+ @SerializedName("offset")
+ private Integer offset;
+ @SerializedName("limit")
+ private Integer limit;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListResponse.java
new file mode 100644
index 0000000000..a1d926cf8f
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListResponse.java
@@ -0,0 +1,102 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintListResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+
+ @SerializedName("total")
+ private Integer total;
+ @SerializedName("complaints")
+ private List complaints;
+
+ @Data
+ public static class Complaint {
+ @SerializedName("complaint_id")
+ private String complaintId;
+ @SerializedName("complaint_time")
+ private String complaintTime;
+ @SerializedName("complaint_detail")
+ private String complaintDetail;
+ @SerializedName("complaint_state")
+ private String complaintState;
+ @SerializedName("payer_phone")
+ private String payerPhone;
+ @SerializedName("payer_openid")
+ private String payerOpenid;
+ @SerializedName("complaint_order_info")
+ private List complaintOrderInfo;
+ @SerializedName("complaint_full_refunded")
+ private Boolean complaintFullRefunded;
+ @SerializedName("incoming_user_response")
+ private Boolean incomingUserResponse;
+ @SerializedName("user_complaint_times")
+ private Integer userComplaintTimes;
+ @SerializedName("complaint_media_list")
+ private List complaintMediaList;
+ @SerializedName("problem_description")
+ private String problemDescription;
+ @SerializedName("problem_type")
+ private String problemType;
+ @SerializedName("apply_refund_amount")
+ private Integer applyRefundAmount;
+ @SerializedName("user_tag_list")
+ private List userTagList;
+ @SerializedName("service_order_info")
+ private List serviceOrderInfo;
+
+
+ }
+
+ @Data
+ public static class ComplaintOrderInfo {
+ @SerializedName("transaction_id")
+ private String transactionId;
+ @SerializedName("out_trade_no")
+ private String outTradeNo;
+ @SerializedName("amount")
+ private Integer amount;
+ @SerializedName("wxa_out_trade_no")
+ private String wxaOutTradeNo;
+ @SerializedName("wx_order_id")
+ private String wxOrderId;
+ }
+
+ @Data
+ public static class ComplaintMedia {
+
+ @SerializedName("media_type")
+ private String mediaType;
+ @SerializedName("media_url")
+ private List mediaUrl;
+ }
+
+ @Data
+ public static class ServiceOrderInfo {
+ @SerializedName("order_id")
+ private String orderId;
+ @SerializedName("out_order_no")
+ private String outOrderNo;
+ @SerializedName("state")
+ private String state;
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryRequest.java
new file mode 100644
index 0000000000..26dee2c9b9
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryRequest.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetNegotiationHistoryRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("complaint_id")
+ private String complaintId;
+ @SerializedName("offset")
+ private Integer offset;
+ @SerializedName("limit")
+ private Integer limit;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryResponse.java
new file mode 100644
index 0000000000..73d8220b7a
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryResponse.java
@@ -0,0 +1,56 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetNegotiationHistoryResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+
+ @SerializedName("total")
+ private Integer total;
+ @SerializedName("history")
+ private List history;
+
+ @Data
+ public static class History {
+ @SerializedName("log_id")
+ private String logId;
+ @SerializedName("operator")
+ private String operator;
+ @SerializedName("operate_time")
+ private String operateTime;
+ @SerializedName("operate_type")
+ private String operateType;
+ @SerializedName("operate_details")
+ private String operateDetails;
+ @SerializedName("complaint_media_list")
+ private List complaintMediaList;
+
+ @Data
+ public static class ComplaintMedia {
+
+ @SerializedName("media_type")
+ private String mediaType;
+ @SerializedName("media_url")
+ private List mediaUrl;
+ }
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignRequest.java
new file mode 100644
index 0000000000..2613988842
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignRequest.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetUploadFileSignRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("wxpay_url")
+ private String wxpayUrl;
+ @SerializedName("convert_cos")
+ private Boolean convertCos;
+ @SerializedName("complaint_id")
+ private String complaintId;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignResponse.java
new file mode 100644
index 0000000000..ec0cd7e3a2
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignResponse.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetUploadFileSignResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+
+ @SerializedName("sign")
+ private String sign;
+ @SerializedName("cos_url")
+ private String cosUrl;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsRequest.java
new file mode 100644
index 0000000000..d22d0cf40c
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsRequest.java
@@ -0,0 +1,44 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryAdverFundsRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("page")
+ private Integer page;
+ @SerializedName("page_size")
+ private Integer pageSize;
+ @SerializedName("filter")
+ private Filter filter;
+ @SerializedName("env")
+ private Integer env;
+
+ @Data
+ public static class Filter {
+ @SerializedName("settle_begin")
+ private Long settleBegin;
+ @SerializedName("settle_end")
+ private Long settleEnd;
+ @SerializedName("fund_type")
+ private Integer fundType;
+
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsResponse.java
new file mode 100644
index 0000000000..2095fc3a97
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsResponse.java
@@ -0,0 +1,49 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryAdverFundsResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+ @SerializedName("adver_funds_list")
+ private List adverFundsList;
+ @SerializedName("total_page")
+ private Integer totalPage;
+
+
+ @Data
+ public static class AdverFunds {
+ @SerializedName("settle_begin")
+ private Long settleBegin;
+ @SerializedName("settle_end")
+ private Long settleEnd;
+ @SerializedName("total_amount")
+ private Integer totalAmount;
+ @SerializedName("remain_amount")
+ private Integer remainAmount;
+ @SerializedName("expire_time")
+ private Long expireTime;
+ @SerializedName("fund_type")
+ private Integer fundType;
+ @SerializedName("fund_id")
+ private String fundId;
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceRequest.java
new file mode 100644
index 0000000000..767390915d
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceRequest.java
@@ -0,0 +1,24 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryBizBalanceRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceResponse.java
new file mode 100644
index 0000000000..c2f9a59db7
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceResponse.java
@@ -0,0 +1,36 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryBizBalanceResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+
+ @SerializedName("balance_available")
+ private BalanceAvailable balanceAvailable;
+
+ @Data
+ public static class BalanceAvailable {
+ @SerializedName("amount")
+ private String amount;
+ @SerializedName("currency_code")
+ private String currencyCode;
+
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillRequest.java
new file mode 100644
index 0000000000..23a4f408b6
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillRequest.java
@@ -0,0 +1,45 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryFundsBillRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("page")
+ private Integer page;
+ @SerializedName("page_size")
+ private Integer pageSize;
+ @SerializedName("filter")
+ private Filter filter;
+ @SerializedName("env")
+ private Integer env;
+
+ @Data
+ public static class Filter {
+ @SerializedName("oper_time_begin")
+ private Long operTimeBegin;
+ @SerializedName("oper_time_end")
+ private Long operTimeEnd;
+ @SerializedName("bill_id")
+ private String billId;
+ @SerializedName("request_id")
+ private String requestId;
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillResponse.java
new file mode 100644
index 0000000000..e99c47171f
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillResponse.java
@@ -0,0 +1,55 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryFundsBillResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+ @SerializedName("bill_list")
+ private List billList;
+ @SerializedName("total_page")
+ private Integer totalPage;
+
+
+ @Data
+ public static class Bill {
+ @SerializedName("bill_id")
+ private String billId;
+ @SerializedName("oper_time")
+ private Long operTime;
+ @SerializedName("settle_begin")
+ private Long settleBegin;
+ @SerializedName("settle_end")
+ private Long settleEnd;
+ @SerializedName("fund_id")
+ private String fundId;
+ @SerializedName("transfer_account_name")
+ private String transferAccountName;
+ @SerializedName("transfer_account_uid")
+ private Integer transferAccountUid;
+ @SerializedName("transfer_amount")
+ private Integer transferAmount;
+ @SerializedName("status")
+ private Integer status;
+ @SerializedName("request_id")
+ private String requestId;
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillRequest.java
new file mode 100644
index 0000000000..cf76960844
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillRequest.java
@@ -0,0 +1,43 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryRecoverBillRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("page")
+ private Integer page;
+ @SerializedName("page_size")
+ private Integer pageSize;
+ @SerializedName("filter")
+ private Filter filter;
+ @SerializedName("env")
+ private Integer env;
+
+ @Data
+ public static class Filter {
+ @SerializedName("recover_time_begin")
+ private Long recoverTimeBegin;
+ @SerializedName("recover_time_end")
+ private Long recoverTimeEnd;
+ @SerializedName("bill_id")
+ private String billId;
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillResponse.java
new file mode 100644
index 0000000000..26c04129a3
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillResponse.java
@@ -0,0 +1,50 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryRecoverBillResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+ @SerializedName("bill_list")
+ private List billList;
+ @SerializedName("total_page")
+ private Integer totalPage;
+
+ @Data
+ public static class Bill {
+ @SerializedName("bill_id")
+ private String billId;
+ @SerializedName("recover_time")
+ private Long recoverTime;
+ @SerializedName("settle_begin")
+ private Long settleBegin;
+ @SerializedName("settle_end")
+ private Long settleEnd;
+ @SerializedName("fund_id")
+ private String fundId;
+ @SerializedName("recover_account_name")
+ private String recoverAccountName;
+ @SerializedName("recover_amount")
+ private Integer recoverAmount;
+ @SerializedName("refund_order_list")
+ private List refundOrderList;
+ }
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountRequest.java
new file mode 100644
index 0000000000..9b90dd250c
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountRequest.java
@@ -0,0 +1,28 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author 秋日
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryTransferAccountRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountResponse.java
new file mode 100644
index 0000000000..079f088b2e
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountResponse.java
@@ -0,0 +1,46 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryTransferAccountResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+ @SerializedName("acct_list")
+ private List acctList;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+
+ @Data
+ public static class AcctList {
+ @SerializedName("transfer_account_name")
+ private String transferAccountName;
+ @SerializedName("transfer_account_uid")
+ private Long transferAccountUid;
+ @SerializedName("transfer_account_agency_id")
+ private Long transferAccountAgencyId;
+ @SerializedName("transfer_account_agency_name")
+ private String transferAccountAgencyName;
+ @SerializedName("state")
+ private Integer state;
+ @SerializedName("bind_result")
+ private Integer bindResult;
+ @SerializedName("error_msg")
+ private String errorMsg;
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayResponseComplaintRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayResponseComplaintRequest.java
new file mode 100644
index 0000000000..1fac9fc9b2
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayResponseComplaintRequest.java
@@ -0,0 +1,35 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayResponseComplaintRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("complaint_id")
+ private String complaintId;
+ @SerializedName("response_content")
+ private String responseContent;
+ @SerializedName("response_images")
+ private List responseImages;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileRequest.java
new file mode 100644
index 0000000000..2a8ac44b5b
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileRequest.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayUploadVpFileRequest implements Serializable {
+ private static final long serialVersionUID = 7495157056049312108L;
+ @SerializedName("env")
+ private Integer env;
+ @SerializedName("base64_img")
+ private String base64Img;
+ @SerializedName("img_url")
+ private String imgUrl;
+ @SerializedName("file_name")
+ private String fileName;
+
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileResponse.java
new file mode 100644
index 0000000000..68ca557dca
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileResponse.java
@@ -0,0 +1,28 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayUploadVpFileResponse extends WxMaBaseResponse implements Serializable {
+ private static final long serialVersionUID = 7495157056049312109L;
+
+
+ @SerializedName("file_id")
+ private String fileId;
+
+ public String toJson() {
+ return WxMaGsonBuilder.create().toJson(this);
+ }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java
index c353534c3f..71f49ee2d3 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/builder/BaseBuilder.java
@@ -8,6 +8,7 @@
public class BaseBuilder {
protected String msgType;
protected String toUser;
+ protected String aiMsgContextMsgId;
@SuppressWarnings("unchecked")
public T toUser(String toUser) {
@@ -15,6 +16,12 @@ public T toUser(String toUser) {
return (T) this;
}
+ @SuppressWarnings("unchecked")
+ public T aiMsgContextMsgId(String msgId) {
+ this.aiMsgContextMsgId = msgId;
+ return (T) this;
+ }
+
/**
* 构造器方法.
*/
@@ -22,6 +29,9 @@ public WxMaKefuMessage build() {
WxMaKefuMessage m = new WxMaKefuMessage();
m.setMsgType(this.msgType);
m.setToUser(this.toUser);
+ if (this.aiMsgContextMsgId != null) {
+ m.setAiMsgContext(new WxMaKefuMessage.AiMsgContext(this.aiMsgContextMsgId));
+ }
return m;
}
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java
index ba71b931cc..8164d48346 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java
@@ -16,9 +16,9 @@ public interface WxMaConfig {
default void setUpdateAccessTokenBefore(Consumer updateAccessTokenBefore) {}
/**
- * Gets access token.
+ * 获取当前的 access_token
*
- * @return the access token
+ * @return 当前的 access_token 字符串
*/
String getAccessToken();
@@ -30,26 +30,28 @@ default void setUpdateAccessTokenBefore(Consumer updateAcce
// endregion
/**
- * Gets access token lock.
+ * 获取用于保护 access_token 更新的锁(线程安全用)
*
- * @return the access token lock
+ * @return access_token 的锁对象
*/
Lock getAccessTokenLock();
/**
- * Is access token expired boolean.
+ * 判断 access_token 是否已过期
*
- * @return the boolean
+ * @return 如果已过期则返回 true,否则返回 false
*/
boolean isAccessTokenExpired();
- /** 强制将access token过期掉 */
+ /**
+ * 强制将 access_token 标记为已过期
+ */
void expireAccessToken();
/**
* 应该是线程安全的
*
- * @param accessToken 要更新的WxAccessToken对象
+ * @param accessToken 要更新的 WxAccessToken 对象
*/
default void updateAccessToken(WxAccessToken accessToken) {
updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
@@ -58,8 +60,8 @@ default void updateAccessToken(WxAccessToken accessToken) {
/**
* 应该是线程安全的
*
- * @param accessToken 新的accessToken值
- * @param expiresInSeconds 过期时间,以秒为单位
+ * @param accessToken 新的 access_token 值
+ * @param expiresInSeconds 过期时间,单位:秒
*/
void updateAccessToken(String accessToken, int expiresInSeconds);
@@ -75,229 +77,237 @@ default void updateAccessTokenProcessor(String accessToken, int expiresInSeconds
default void updateAccessTokenBefore(WxAccessTokenEntity wxAccessTokenEntity) {}
/**
- * Gets jsapi ticket.
+ * 获取当前的 JSAPI ticket
*
- * @return the jsapi ticket
+ * @return 当前的 jsapi_ticket 字符串
*/
String getJsapiTicket();
/**
- * Gets jsapi ticket lock.
+ * 获取用于保护 jsapi_ticket 更新的锁(线程安全用)
*
- * @return the jsapi ticket lock
+ * @return jsapi_ticket 的锁对象
*/
Lock getJsapiTicketLock();
/**
- * Is jsapi ticket expired boolean.
+ * 判断 jsapi_ticket 是否已过期
*
- * @return the boolean
+ * @return 如果已过期则返回 true,否则返回 false
*/
boolean isJsapiTicketExpired();
- /** 强制将jsapi ticket过期掉 */
+ /**
+ * 强制将 jsapi_ticket 标记为已过期
+ */
void expireJsapiTicket();
/**
* 应该是线程安全的
*
- * @param jsapiTicket 新的jsapi ticket值
- * @param expiresInSeconds 过期时间,以秒为单位
+ * @param jsapiTicket 新的 jsapi_ticket 值
+ * @param expiresInSeconds 过期时间,单位:秒
*/
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
/**
- * 卡券api_ticket.
+ * 获取卡券相关的 api_ticket
*
- * @return the card api ticket
+ * @return 卡券 api_ticket 字符串
*/
String getCardApiTicket();
/**
- * Gets card api ticket lock.
+ * 获取用于保护卡券 api_ticket 更新的锁(线程安全用)
*
- * @return the card api ticket lock
+ * @return 卡券 api_ticket 的锁对象
*/
Lock getCardApiTicketLock();
/**
- * Is card api ticket expired boolean.
+ * 判断卡券 api_ticket 是否已过期
*
- * @return the boolean
+ * @return 如果已过期则返回 true,否则返回 false
*/
boolean isCardApiTicketExpired();
- /** 强制将卡券api ticket过期掉. */
+ /**
+ * 强制将卡券 api_ticket 标记为已过期
+ */
void expireCardApiTicket();
/**
- * 应该是线程安全的.
+ * 应该是线程安全的
*
- * @param apiTicket 新的卡券api ticket值
- * @param expiresInSeconds 过期时间,以秒为单位
+ * @param apiTicket 新的卡券 api_ticket 值
+ * @param expiresInSeconds 过期时间,单位:秒
*/
void updateCardApiTicket(String apiTicket, int expiresInSeconds);
/**
- * Gets appid.
+ * 获取小程序的 appId
*
- * @return the appid
+ * @return 小程序的 appId
*/
String getAppid();
/**
- * Gets secret.
+ * 获取小程序的 secret
*
- * @return the secret
+ * @return 小程序的 secret
*/
String getSecret();
/**
- * Gets token.
+ * 获取消息校验用的 token
*
- * @return the token
+ * @return token 字符串
*/
String getToken();
/**
- * Gets aes key.
+ * 获取消息加解密使用的 AES 密钥(用于消息加密/解密)
*
- * @return the aes key
+ * @return AES 密钥字符串
*/
String getAesKey();
/**
- * Gets original id.
+ * 获取原始 ID(原始公众号/小程序 ID)
*
- * @return the original id
+ * @return 原始 ID 字符串
*/
String getOriginalId();
/**
- * Gets cloud env.
+ * 获取云开发(Cloud)环境标识
*
- * @return the cloud env
+ * @return 云环境 ID
*/
String getCloudEnv();
/**
- * Gets msg data format.
+ * 获取消息数据的格式(例如 json)
*
- * @return the msg data format
+ * @return 消息数据格式字符串
*/
String getMsgDataFormat();
/**
- * Gets expires time.
+ * 获取 access_token 或 ticket 的过期时间(时间戳)
*
- * @return the expires time
+ * @return 过期时间的毫秒时间戳
*/
long getExpiresTime();
/**
- * Gets http proxy host.
+ * 获取 HTTP 代理主机
*
- * @return the http proxy host
+ * @return 代理主机名或 IP
*/
String getHttpProxyHost();
/**
- * Gets http proxy port.
+ * 获取 HTTP 代理端口
*
- * @return the http proxy port
+ * @return 代理端口号
*/
int getHttpProxyPort();
/**
- * Gets http proxy username.
+ * 获取 HTTP 代理用户名
*
- * @return the http proxy username
+ * @return 代理用户名
*/
String getHttpProxyUsername();
/**
- * Gets http proxy password.
+ * 获取 HTTP 代理密码
*
- * @return the http proxy password
+ * @return 代理密码
*/
String getHttpProxyPassword();
/**
- * http 请求重试间隔
+ * HTTP 请求重试间隔(毫秒)
*
*
* {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setRetrySleepMillis(int)}
*
+ *
+ * @return 重试间隔,单位:毫秒
*/
int getRetrySleepMillis();
/**
- * http 请求最大重试次数
+ * HTTP 请求最大重试次数
*
*
* {@link cn.binarywang.wx.miniapp.api.impl.BaseWxMaServiceImpl#setMaxRetryTimes(int)}
*
+ *
+ * @return 最大重试次数
*/
int getMaxRetryTimes();
/**
- * http client builder
+ * 获取用于创建 HTTP 客户端的 ApacheHttpClientBuilder
*
- * @return ApacheHttpClientBuilder apache http client builder
+ * @return ApacheHttpClientBuilder 实例
*/
ApacheHttpClientBuilder getApacheHttpClientBuilder();
/**
- * 是否自动刷新token
+ * 是否在 token 失效时自动刷新
*
- * @return the boolean
+ * @return 如果自动刷新则返回 true,否则返回 false
*/
boolean autoRefreshToken();
/**
- * 设置自定义的apiHost地址
- * 具体取值,可以参考https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Interface_field_description.html
+ * 设置自定义的 apiHost 地址
+ * 具体取值,可以参考 API 域名文档
*
- * @param apiHostUrl api域名地址
+ * @param apiHostUrl api 域名地址
*/
void setApiHostUrl(String apiHostUrl);
/**
- * 获取自定义的apiHost地址,用于替换原请求中的https://api.weixin.qq.com
- * 具体取值,可以参考https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Interface_field_description.html
+ * 获取自定义的 apiHost 地址,用于替换原请求中的 https://api.weixin.qq.com
+ * 具体取值,可以参考 API 域名文档
*
- * @return 自定义的api域名地址
+ * @return 自定义的 api 域名地址
*/
String getApiHostUrl();
/**
- * 获取自定义的获取accessToken地址,用于向自定义统一服务获取accessToken
+ * 获取自定义的获取 accessToken 地址,用于向自定义统一服务获取 accessToken
*
- * @return 自定义的获取accessToken地址
+ * @return 自定义的获取 accessToken 地址
*/
String getAccessTokenUrl();
/**
- * 设置自定义的获取accessToken地址 可用于设置获取accessToken的自定义服务
+ * 设置自定义的获取 accessToken 地址,可用于设置获取 accessToken 的自定义服务
*
- * @param accessTokenUrl 自定义的获取accessToken地址
+ * @param accessTokenUrl 自定义的获取 accessToken 地址
*/
void setAccessTokenUrl(String accessTokenUrl);
/**
- * 服务端API签名用到的RSA私钥【pkcs8格式,会以 -----BEGIN PRIVATE KEY-----开头, 'BEGIN RSA PRIVATE
- * KEY'的是pkcs1格式,需要转换(可用openssl转换)。 设置参考:
- * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html
+ * 服务端 API 签名用到的 RSA 私钥(pkcs8 格式,会以 -----BEGIN PRIVATE KEY----- 开头,
+ * 'BEGIN RSA PRIVATE KEY' 的是 pkcs1 格式,需要转换(可用 openssl 转换)。设置参考:
+ * API 签名文档
*
- * @return rsa private key string
+ * @return RSA 私钥字符串(pkcs8 格式)
*/
String getApiSignatureRsaPrivateKey();
/**
- * 服务端API签名用到的AES密钥
- * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html
+ * 服务端 API 签名用到的 AES 密钥
+ * API 签名文档
*
- * @return aes key string
+ * @return AES 密钥字符串
*/
String getApiSignatureAesKey();
@@ -307,6 +317,52 @@ default void updateAccessTokenBefore(WxAccessTokenEntity wxAccessTokenEntity) {}
/** 密钥对应的序号 */
String getApiSignatureRsaPrivateKeySn();
- /** 密钥对应的小程序ID (普通小程序同 appId, 托管第三方平台的是 componentAppId) */
+ /** 密钥对应的小程序 ID(普通小程序为 appId,托管第三方平台为 componentAppId) */
String getWechatMpAppid();
+
+ /** 微信 API 默认主机地址 */
+ String DEFAULT_API_HOST_URL = "https://api.weixin.qq.com";
+ /** 微信云托管使用的 HTTP 协议主机地址 */
+ String CLOUD_RUN_API_HOST_URL = "http://api.weixin.qq.com";
+
+ /**
+ * 是否使用微信云托管内网模式
+ * 当部署在微信云托管环境时,api.weixin.qq.com 会被解析为内网地址,此时需要使用 HTTP 协议访问
+ * 开启此配置后,SDK 会自动将 https://api.weixin.qq.com 替换为 http://api.weixin.qq.com
+ *
+ * @see 微信云托管内网调用微信接口
+ * @return 是否使用微信云托管模式
+ */
+ default boolean isUseWxCloudRun() {
+ return false;
+ }
+
+ /**
+ * 设置是否使用微信云托管内网模式
+ * 当部署在微信云托管环境时,api.weixin.qq.com 会被解析为内网地址,此时需要使用 HTTP 协议访问
+ * 开启此配置后,SDK 会自动将 https://api.weixin.qq.com 替换为 http://api.weixin.qq.com
+ *
+ * @see 微信云托管内网调用微信接口
+ * @param useWxCloudRun 是否使用微信云托管模式
+ */
+ default void setUseWxCloudRun(boolean useWxCloudRun) {
+ // 默认空实现
+ }
+
+ /**
+ * 根据配置获取实际应使用的 API 主机地址
+ * 优先级:自定义 apiHostUrl > 微信云托管模式 > 默认 HTTPS 地址
+ *
+ * @return 实际应使用的 API 主机地址
+ */
+ default String getEffectiveApiHostUrl() {
+ String apiHostUrl = getApiHostUrl();
+ if (apiHostUrl != null && !apiHostUrl.isEmpty()) {
+ return apiHostUrl;
+ }
+ if (isUseWxCloudRun()) {
+ return CLOUD_RUN_API_HOST_URL;
+ }
+ return DEFAULT_API_HOST_URL;
+ }
}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java
index ab82d6209e..07dfaefcc9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/impl/WxMaDefaultConfigImpl.java
@@ -69,6 +69,10 @@ public class WxMaDefaultConfigImpl implements WxMaConfig {
private String apiHostUrl;
private String accessTokenUrl;
+ /** 是否使用微信云托管模式(使用 HTTP 协议访问内网地址) */
+ @Getter(AccessLevel.NONE)
+ private boolean useWxCloudRun = false;
+
/** 自定义配置token的消费者 */
@Setter private Consumer updateAccessTokenBefore;
@@ -388,6 +392,16 @@ public void setAccessTokenUrl(String accessTokenUrl) {
this.accessTokenUrl = accessTokenUrl;
}
+ @Override
+ public boolean isUseWxCloudRun() {
+ return this.useWxCloudRun;
+ }
+
+ @Override
+ public void setUseWxCloudRun(boolean useWxCloudRun) {
+ this.useWxCloudRun = useWxCloudRun;
+ }
+
@Override
public String getAppid() {
return appid;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java
index 5908385790..45e1219659 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java
@@ -364,6 +364,8 @@ public interface User {
String SET_USER_STORAGE =
"https://api.weixin.qq.com/wxa/set_user_storage?appid=%s&signature=%s&openid=%s&sig_method=%s";
String GET_PHONE_NUMBER_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
+ /** 多端登录验证接口 */
+ String CODE_2_VERIFY_INFO_URL = "https://api.weixin.qq.com/wxa/sec/checkcode2verifyinfo";
}
public interface Ocr {
@@ -626,7 +628,7 @@ public interface InstantDelivery {
String GET_DELIVERY_LIST_URL =
"https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list";
- /** 获取运力id列表get_delivery_list 商户使用此接口获取所有运力id的列表 */
+ /** 物流服务-查询组件-更新物品信息接口 update_waybill_goods 更新物品信息 */
String UPDATE_WAYBILL_GOODS_URL =
"https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/update_waybill_goods";
@@ -751,7 +753,7 @@ public interface OrderShipping {
*
*/
String UPLOAD_COMBINED_SHIPPING_INFO =
- "https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info";
+ "https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info";
/**
* 查询订单发货状态.
@@ -779,7 +781,7 @@ public interface OrderShipping {
*
*/
String NOTIFY_CONFIRM_RECEIVE =
- "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive";
+ "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive";
/**
* 消息跳转路径设置接口.
@@ -809,6 +811,35 @@ public interface OrderShipping {
}
+ /**
+ * 小程序订单管理
+ *
+ * + * 文档地址: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html + *+ */ + public interface OrderManagement { + + /** + * 配置订单详情路径. + * + *
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html + *+ */ + String UPDATE_ORDER_DETAIL_PATH = "https://api.weixin.qq.com/wxa/sec/order/update_order_detail_path"; + + /** + * 查询订单详情路径. + * + *
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html + *+ */ + String GET_ORDER_DETAIL_PATH = "https://api.weixin.qq.com/wxa/sec/order/get_order_detail_path"; + + } + public interface Vod { String LIST_MEDIA_URL = "https://api.weixin.qq.com/wxa/sec/vod/listmedia"; String GET_MEDIA_URL = "https://api.weixin.qq.com/wxa/sec/vod/getmedia"; @@ -856,6 +887,22 @@ public interface XPay { "https://api.weixin.qq.com/xpay/start_publish_goods?pay_sig=%s"; String QUERY_PUBLISH_GOODS_URL = "https://api.weixin.qq.com/xpay/query_publish_goods?pay_sig=%s"; + String QUERY_BIZ_BALANCE_URL = + "https://api.weixin.qq.com/xpay/query_biz_balance?pay_sig=%s"; + String QUERY_TRANSFER_ACCOUNT_URL = "https://api.weixin.qq.com/xpay/query_transfer_account?pay_sig=%s"; + String QUERY_ADVER_FUNDS_URL = "https://api.weixin.qq.com/xpay/query_adver_funds?pay_sig=%s"; + String CREATE_FUNDS_BILL_URL = "https://api.weixin.qq.com/xpay/create_funds_bill?pay_sig=%s"; + String BIND_TRANSFER_ACCOUNT_URL = "https://api.weixin.qq.com/xpay/bind_transfer_accout?pay_sig=%s"; + String QUERY_FUNDS_BILL_URL = "https://api.weixin.qq.com/xpay/query_funds_bill?pay_sig=%s"; + String QUERY_RECOVER_BILL_URL = "https://api.weixin.qq.com/xpay/query_recover_bill?pay_sig=%s"; + String GET_COMPLAINT_LIST_URL = "https://api.weixin.qq.com/xpay/get_complaint_list?pay_sig=%s"; + String GET_COMPLAINT_DETAIL_URL = "https://api.weixin.qq.com/xpay/get_complaint_detail?pay_sig=%s"; + String GET_NEGOTIATION_HISTORY_URL = "https://api.weixin.qq.com/xpay/get_negotiation_history?pay_sig=%s"; + String RESPONSE_COMPLAINT_URL = "https://api.weixin.qq.com/xpay/response_complaint?pay_sig=%s"; + String COMPLETE_COMPLAINT_URL = "https://api.weixin.qq.com/xpay/complete_complaint?pay_sig=%s"; + String UPLOAD_VP_FILE_URL = "https://api.weixin.qq.com/xpay/upload_vp_file?pay_sig=%s"; + String GET_UPLOAD_FILE_SIGN_URL = "https://api.weixin.qq.com/xpay/get_upload_file_sign?pay_sig=%s"; + String DOWNLOAD_ADVERFUNDS_ORDER_URL = "https://api.weixin.qq.com/xpay/download_adverfunds_order?pay_sig=%s"; } /** @@ -919,4 +966,34 @@ public interface Intracity { String GET_CITY = "https://api.weixin.qq.com/cgi-bin/express/intracity/getcity"; } + + /** + * 小程序交易投诉接口 + * + *
+ * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/guarantee/complaint.html + *+ */ + public interface Complaint { + /** 查询投诉单列表 */ + String QUERY_COMPLAINTS_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/list"; + /** 查询投诉单详情 */ + String GET_COMPLAINT_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/detail"; + /** 查询投诉协商历史 */ + String QUERY_NEGOTIATION_HISTORY_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/negotiation/history"; + /** 创建投诉通知回调地址 */ + String ADD_COMPLAINT_NOTIFY_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/notify/add"; + /** 查询投诉通知回调地址 */ + String GET_COMPLAINT_NOTIFY_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/notify/get"; + /** 更新投诉通知回调地址 */ + String UPDATE_COMPLAINT_NOTIFY_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/notify/update"; + /** 删除投诉通知回调地址 */ + String DELETE_COMPLAINT_NOTIFY_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/notify/delete"; + /** 提交回复 */ + String SUBMIT_RESPONSE_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/response"; + /** 反馈处理完成 */ + String COMPLETE_COMPLAINT_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/complete"; + /** 上传反馈图片 */ + String UPLOAD_RESPONSE_IMAGE_URL = "https://api.weixin.qq.com/cgi-bin/miniapp/complaint/upload"; + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java index 3dcf22b10f..0a858256a8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java @@ -1,30 +1,27 @@ package cn.binarywang.wx.miniapp.executor; import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; 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.apache.Utf8ResponseHandler; -import org.apache.http.Consts; import org.apache.http.Header; 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 org.slf4j.Logger; -import org.slf4j.LoggerFactory; -public class ApacheApiSignaturePostRequestExecutor - extends ApiSignaturePostRequestExecutor
- * 微信AI开放接口(语音识别,微信翻译). - * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21516712282KzWVE - * Created by BinaryWang on 2018/6/9. - *+ * 微信AI开放接口(语音识别,微信翻译) + *
+ * 提供微信AI相关的功能,包括语音识别、微信翻译等。 + * 支持上传语音文件进行语音识别,以及文本翻译功能。 + *
+ *+ * 详情请见:微信AI开放接口 + *
+ * Created by BinaryWang on 2018/6/9. * * @author Binary Wang */ public interface WxMpAiOpenService { - /** - *- * 提交语音. - * http请求方式: POST - * http://api.weixin.qq.com/cgi-bin/media/voice/addvoicetorecofortext?access_token=ACCESS_TOKEN&format=&voice_id=xxxxxx&lang=zh_CN - *- * - * @param voiceId 语音唯一标识 - * @param lang 语言,zh_CN 或 en_US,默认中文 - * @param voiceFile 语音文件 - * @throws WxErrorException the wx error exception - */ - void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException; + /** + *
+ * 提交语音 + *+ * + * @param voiceId 语音唯一标识 + * @param lang 语言,zh_CN 或 en_US,默认中文 + * @param voiceFile 语音文件 + * @throws WxErrorException 微信API调用异常,可能包括: + *
- * 获取语音识别结果. - * 接口调用请求说明 - * - * http://api.weixin.qq.com/cgi-bin/media/voice/queryrecoresultfortext?access_token=ACCESS_TOKEN&voice_id=xxxxxx&lang=zh_CN - * 请注意,添加完文件之后10s内调用这个接口 - * - *- * - * @param voiceId 语音唯一标识 - * @param lang 语言,zh_CN 或 en_US,默认中文 - * @return the string - * @throws WxErrorException the wx error exception - */ - String queryRecognitionResult(String voiceId, AiLangType lang) throws WxErrorException; + /** + *
+ * 获取语音识别结果 + * 请注意,添加完文件之后10s内调用这个接口 + *+ * + * @param voiceId 语音唯一标识 + * @param lang 语言,zh_CN 或 en_US,默认中文 + * @return 语音识别结果文本 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 识别指定语音文件内容 + * 此方法揉合了前两两个方法:uploadVoice 和 queryRecognitionResult + *+ * + * @param voiceId 语音唯一标识 + * @param lang 语言,zh_CN 或 en_US,默认中文 + * @param voiceFile 语音文件 + * @return 语音识别结果文本 + * @throws WxErrorException 微信API调用异常,可能包括: + *
- * 微信翻译. - * 接口调用请求说明 - * - * http请求方式: POST - * http://api.weixin.qq.com/cgi-bin/media/voice/translatecontent?access_token=ACCESS_TOKEN&lfrom=xxx<o=xxx - * - *- * - * @param langFrom 源语言,zh_CN 或 en_US - * @param langTo 目标语言,zh_CN 或 en_US - * @param content 要翻译的文本内容 - * @return the string - * @throws WxErrorException the wx error exception - */ - String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException; + /** + *
+ * 微信翻译 + *+ * + * @param langFrom 源语言,zh_CN 或 en_US + * @param langTo 目标语言,zh_CN 或 en_US + * @param content 要翻译的文本内容 + * @return 翻译结果文本 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 提供微信卡券的创建、查询、核销、管理等功能。 + * 支持卡券API签名生成、卡券Code解码、卡券核销、库存管理等功能。 + *
+ *+ * 详情请见:卡券开发文档 + *
* * @author YuJian(mgcnrx11 @ hotmail.com) on 01/11/2016 * @author yuanqixun 2018-08-29 */ public interface WxMpCardService { /** - * 得到WxMpService. + *+ * 获取WxMpService实例 + ** - * @return WxMpService wx mp service + * @return WxMpService实例 */ WxMpService getWxMpService(); /** - * 获得卡券api_ticket,不强制刷新卡券api_ticket. + *
+ * 获得卡券api_ticket,不强制刷新卡券api_ticket + ** - * @return 卡券api_ticket card api ticket - * @throws WxErrorException 异常 - * @see #getCardApiTicket(boolean) #getCardApiTicket(boolean)#getCardApiTicket(boolean) + * @return 卡券api_ticket + * @throws WxErrorException 微信API调用异常,可能包括: + *
- * 获得卡券api_ticket.
+ * 获得卡券api_ticket
* 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
- *
- * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94.9F.E6.88.90.E7.AE.97.E6.B3.95
*
*
- * @param forceRefresh 强制刷新
- * @return 卡券api_ticket card api ticket
- * @throws WxErrorException 异常
+ * @param forceRefresh 强制刷新,如果为true则强制刷新api_ticket
+ * @return 卡券api_ticket
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 创建调用卡券api时所需要的签名.
- *
- * 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
- * .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
- * .9F.E6.88.90.E7.AE.97.E6.B3.95
+ * 创建调用卡券api时所需要的签名
*
*
- * @param optionalSignParam 参与签名的参数数组。可以为下列字段:app_id, card_id, card_type, code, openid, location_id 注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空
- * @return 卡券Api签名对象 wx card api signature
- * @throws WxErrorException 异常
+ * @param optionalSignParam 参与签名的参数数组。可以为下列字段:app_id, card_id, card_type, code, openid, location_id
+ * 注意:当做wx.chooseCard调用时,必须传入app_id参与签名,否则会造成签名失败导致拉取卡券列表为空
+ * @return 卡券Api签名对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ * + * 卡券Code解码 + ** * @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得 - * @return 解密后的Code string - * @throws WxErrorException 异常 + * @return 解密后的Code + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 卡券Code查询 + ** * @param cardId 卡券ID代表一类卡券 * @param code 单张卡券的唯一标准 * @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同 - * @return WxMpCardResult对象 wx mp card result - * @throws WxErrorException 异常 + * @return WxMpCardResult对象,包含卡券查询结果信息 + * @throws WxErrorException 微信API调用异常,可能包括: + *
* 卡券Code核销。核销失败会抛出异常
+ *
*
* @param code 单张卡券的唯一标准
- * @return 调用返回的JSON字符串 。可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。
- * @throws WxErrorException 异常
+ * @return 调用返回的JSON字符串,可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ * + * 卡券Code核销。核销失败会抛出异常 + ** * @param code 单张卡券的唯一标准 * @param cardId 当自定义Code卡券时需要传入card_id - * @return 调用返回的JSON字符串 。可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息。 - * @throws WxErrorException 异常 + * @return 调用返回的JSON字符串,可用 com.google.gson.JsonParser#parse 等方法直接取JSON串中的errcode等信息 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 卡券Mark接口
* 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住),
* 才能进一步调用核销接口,否则报错。
+ *
*
* @param code 卡券的code码
* @param cardId 卡券的ID
* @param openId 用券用户的openid
* @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用
- * @throws WxErrorException 异常
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ * + * 查看卡券详情接口 + ** * @param cardId 卡券的ID - * @return 返回的卡券详情JSON字符串
+ * 添加测试白名单 + ** * @param openid 用户的openid - * @return string string - * @throws WxErrorException 异常 + * @return 操作结果字符串 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 创建卡券 + ** - * @param cardCreateMessage 请求 - * @return result wx mp card create result - * @throws WxErrorException 异常 + * @param cardCreateRequest 卡券创建请求对象 + * @return 卡券创建结果对象 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 创建卡券二维码 + ** * @param cardId 卡券编号 * @param outerStr 二维码标识 - * @return WxMpCardQrcodeCreateResult wx mp card qrcode create result - * @throws WxErrorException 异常 + * @return 卡券二维码创建结果对象 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 创建卡券二维码 + ** * @param cardId 卡券编号 - * @param outerStr 二维码标识 + * @param outerStr 用户首次领卡时,会通过 领取事件推送 给商户; 对于会员卡的二维码,用户每次扫码打开会员卡后点击任何url,会将该值拼入url中,方便开发者定位扫码来源 * @param expiresIn 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 - * @return WxMpCardQrcodeCreateResult wx mp card qrcode create result - * @throws WxErrorException 异常 + * @return 卡券二维码创建结果对象 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 创建卡券二维码 + ** * @param cardId 卡券编号 * @param outerStr 用户首次领卡时,会通过 领取事件推送 给商户; 对于会员卡的二维码,用户每次扫码打开会员卡后点击任何url,会将该值拼入url中,方便开发者定位扫码来源 * @param expiresIn 指定二维码的有效时间,范围是60 ~ 1800秒。不填默认为365天有效 - * @param openid 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写。 - * @param code 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写。 - * @param isUniqueCode 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时,卡券须通过审核且库存不为0。 - * @return WxMpCardQrcodeCreateResult wx mp card qrcode create result - * @throws WxErrorException 异常 + * @param openid 指定领取者的openid,只有该用户能领取。bind_openid字段为true的卡券必须填写,非指定openid不必填写 + * @param code 卡券Code码,use_custom_code字段为true的卡券必须填写,非自定义code和导入code模式的卡券不必填写 + * @param isUniqueCode 指定下发二维码,生成的二维码随机分配一个code,领取后不可再次扫描。填写true或false。默认false,注意填写该字段时,卡券须通过审核且库存不为0 + * @return 卡券二维码创建结果对象 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 创建卡券货架 + ** * @param createRequest 货架创建参数 - * @return WxMpCardLandingPageCreateResult wx mp card landing page create result - * @throws WxErrorException 异常 + * @return 货架创建结果对象 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 将用户的卡券设置为失效状态 + ** * @param cardId 卡券编号 * @param code 用户会员卡号 * @param reason 设置为失效的原因 - * @return result string - * @throws WxErrorException 异常 + * @return 操作结果字符串 + * @throws WxErrorException 微信API调用异常,可能包括: + *
+ * 删除卡券接口 + ** * @param cardId 卡券id - * @return 删除结果 wx mp card delete result - * @throws WxErrorException 异常 + * @return 删除结果对象 + * @throws WxErrorException 微信API调用异常,可能包括: + *
* 导入自定义code(仅对自定义code商户)
+ *
*
* @param cardId 卡券id
- * @param codeList 需导入微信卡券后台的自定义code,上限为100个。
- * @return the wx mp card code deposit result
- * @throws WxErrorException the wx error exception
+ * @param codeList 需导入微信卡券后台的自定义code,上限为100个
+ * @return 导入结果对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 查询导入code数目接口
+ *
*
* @param cardId 卡券id
- * @return the wx mp card code deposit count result
- * @throws WxErrorException the wx error exception
+ * @return 查询结果对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 核查code接口
+ *
*
* @param cardId 卡券id
* @param codeList 已经微信卡券后台的自定义code,上限为100个
- * @return the wx mp card code checkcode result
- * @throws WxErrorException the wx error exception
+ * @return 核查结果对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 图文消息群发卡券获取内嵌html
+ *
*
* @param cardId 卡券id
- * @return the wx mp card mpnews gethtml result
- * @throws WxErrorException the wx error exception
+ * @return HTML获取结果对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 修改库存接口
- * https://developers.weixin.qq.com/doc/offiaccount/Cards_and_Offer/Managing_Coupons_Vouchers_and_Cards.html#5
+ *
*
* @param cardId 卡券ID
* @param changeValue 库存变更值,负值为减少库存
- * @throws WxErrorException the wx error exception
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 更改Code接口
- * https://developers.weixin.qq.com/doc/offiaccount/Cards_and_Offer/Managing_Coupons_Vouchers_and_Cards.html#6
+ *
*
* @param cardId 卡券ID
* @param oldCode 需变更的Code码
* @param newCode 变更后的有效Code码
- * @throws WxErrorException the wx error exception
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 设置买单接口
- * https://developers.weixin.qq.com/doc/offiaccount/Cards_and_Offer/Create_a_Coupon_Voucher_or_Card.html#12
+ *
*
* @param cardId 卡券ID
* @param isOpen 是否开启买单功能,填true/false
- * @throws WxErrorException the wx error exception
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 设置自助核销
- * https://developers.weixin.qq.com/doc/offiaccount/Cards_and_Offer/Create_a_Coupon_Voucher_or_Card.html#14
+ *
*
* @param cardId 卡券ID
* @param isOpen 是否开启自助核销功能
* @param needVerifyCod 用户核销时是否需要输入验证码, 填true/false, 默认为false
* @param needRemarkAmount 用户核销时是否需要备注核销金额, 填true/false, 默认为false
- * @throws WxErrorException the wx error exception
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 获取用户已领取卡券接口
- * https://developers.weixin.qq.com/doc/offiaccount/Cards_and_Offer/Managing_Coupons_Vouchers_and_Cards.html#1
+ *
*
* @param openId 需要查询的用户openid
* @param cardId 卡券ID。不填写时默认查询当前appid下的卡券
- * @return user card list
- * @throws WxErrorException the wx error exception
+ * @return 用户卡券列表结果对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 设置客服信息(即更新客服信息)
+ * 邀请绑定客服账号
* 详情请见:客服管理
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN
*
*
- * @param request the request
- * @return the boolean
- * @throws WxErrorException 异常
+ * @param request 客服账号请求对象,包含客服账号、邀请者微信号等信息
+ * @return 邀请是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean kfAccountInviteWorker(WxMpKfAccountRequest request) throws WxErrorException;
@@ -120,10 +120,10 @@ public interface WxMpKefuService {
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
*
*
- * @param kfAccount the kf account
- * @param imgFile the img file
- * @return the boolean
- * @throws WxErrorException 异常
+ * @param kfAccount 客服账号,格式为:账号前缀@微信号
+ * @param imgFile 头像图片文件,支持JPG、PNG格式,大小不超过2MB
+ * @return 上传是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean kfAccountUploadHeadImg(String kfAccount, File imgFile) throws WxErrorException;
@@ -134,9 +134,9 @@ public interface WxMpKefuService {
* 接口url格式:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
*
*
- * @param kfAccount the kf account
- * @return the boolean
- * @throws WxErrorException 异常
+ * @param kfAccount 客服账号,格式为:账号前缀@微信号
+ * @return 删除是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean kfAccountDel(String kfAccount) throws WxErrorException;
@@ -150,10 +150,10 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/create?access_token=ACCESS_TOKEN
*
*
- * @param openid the openid
- * @param kfAccount the kf account
- * @return the boolean
- * @throws WxErrorException 异常
+ * @param openid 用户的openid,标识具体的用户
+ * @param kfAccount 客服账号,格式为:账号前缀@微信号
+ * @return 创建是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean kfSessionCreate(String openid, String kfAccount) throws WxErrorException;
@@ -165,10 +165,10 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/close?access_token=ACCESS_TOKEN
*
*
- * @param openid the openid
- * @param kfAccount the kf account
- * @return the boolean
- * @throws WxErrorException 异常
+ * @param openid 用户的openid,标识具体的用户
+ * @param kfAccount 客服账号,格式为:账号前缀@微信号
+ * @return 关闭是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean kfSessionClose(String openid, String kfAccount) throws WxErrorException;
@@ -180,9 +180,9 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsession?access_token=ACCESS_TOKEN&openid=OPENID
*
*
- * @param openid the openid
- * @return the wx mp kf session get result
- * @throws WxErrorException 异常
+ * @param openid 用户的openid,标识具体的用户
+ * @return 客户会话状态信息,包含客服账号、会话状态等
+ * @throws WxErrorException 微信API调用异常
*/
WxMpKfSessionGetResult kfSessionGet(String openid) throws WxErrorException;
@@ -194,9 +194,9 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getsessionlist?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
*
*
- * @param kfAccount the kf account
- * @return the wx mp kf session list
- * @throws WxErrorException 异常
+ * @param kfAccount 客服账号,格式为:账号前缀@微信号
+ * @return 客服会话列表,包含正在接待的会话信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpKfSessionList kfSessionList(String kfAccount) throws WxErrorException;
@@ -208,8 +208,8 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/kfsession/getwaitcase?access_token=ACCESS_TOKEN
*
*
- * @return the wx mp kf session wait case list
- * @throws WxErrorException 异常
+ * @return 未接入会话列表,包含等待接入的会话信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpKfSessionWaitCaseList kfSessionGetWaitCase() throws WxErrorException;
@@ -223,12 +223,12 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=ACCESS_TOKEN
*
*
- * @param startTime 起始时间
- * @param endTime 结束时间
- * @param msgId 消息id顺序从小到大,从1开始
- * @param number 每次获取条数,最多10000条
- * @return 聊天记录对象 wx mp kf msg list
- * @throws WxErrorException 异常
+ * @param startTime 起始时间,用于筛选聊天记录的时间范围
+ * @param endTime 结束时间,用于筛选聊天记录的时间范围
+ * @param msgId 消息id顺序从小到大,从1开始,用于分页获取
+ * @param number 每次获取条数,最多10000条,用于分页控制
+ * @return 聊天记录对象,包含客服和用户的聊天消息列表
+ * @throws WxErrorException 微信API调用异常
*/
WxMpKfMsgList kfMsgList(Date startTime, Date endTime, Long msgId, Integer number) throws WxErrorException;
@@ -240,17 +240,17 @@ public interface WxMpKefuService {
* 接口url格式: https://api.weixin.qq.com/customservice/msgrecord/getmsglist?access_token=ACCESS_TOKEN
*
*
- * @param startTime 起始时间
- * @param endTime 结束时间
- * @return 聊天记录对象 wx mp kf msg list
- * @throws WxErrorException 异常
+ * @param startTime 起始时间,用于筛选聊天记录的时间范围
+ * @param endTime 结束时间,用于筛选聊天记录的时间范围
+ * @return 聊天记录对象,包含客服和用户的聊天消息列表
+ * @throws WxErrorException 微信API调用异常
*/
WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorException;
/**
*
* 客服输入状态
- * 开发者可通过调用“客服输入状态”接口,返回客服当前输入状态给用户。
+ * 开发者可通过调用"客服输入状态"接口,返回客服当前输入状态给用户。
* 此接口需要客服消息接口权限。
* 如果不满足发送客服消息的触发条件,则无法下发输入状态。
* 下发输入状态,需要客服之前30秒内跟用户有过消息交互。
@@ -261,10 +261,10 @@ public interface WxMpKefuService {
* 接口url格式:https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN
*
*
- * @param openid 用户id
- * @param command "Typing":对用户下发“正在输入"状态 "CancelTyping":取消对用户的”正在输入"状态
- * @return the boolean
- * @throws WxErrorException 异常
+ * @param openid 用户的openid,标识具体的用户
+ * @param command 输入状态命令,可选值:"Typing":对用户下发"正在输入"状态;"CancelTyping":取消对用户的"正在输入"状态
+ * @return 发送是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean sendKfTypingState(String openid, String command) throws WxErrorException;
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java
index 823c2c6343..5ad3098c2a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMassMessageService.java
@@ -8,138 +8,234 @@
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
/**
- * - * 群发消息服务类. + * 群发消息服务类 + ** * @author Binary Wang */ public interface WxMpMassMessageService { /** *+ * 提供微信公众号群发消息的功能,包括图文消息、视频消息的群发, + * 支持按分组群发、按openid列表群发、消息预览、群发状态查询等功能。 + *
+ *+ * 详情请见:群发消息开发文档 + *
* Created by Binary Wang on 2017-8-16. - *
- * 上传群发用的图文消息,上传后才能群发图文消息.
- *
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
+ * 上传群发用的图文消息,上传后才能群发图文消息
*
*
- * @param news the news
- * @return the wx mp mass upload result
- * @throws WxErrorException the wx error exception
- * @see #massGroupMessageSend(WxMpMassTagMessage) #massGroupMessageSend(WxMpMassTagMessage)
- * @see #massOpenIdsMessageSend(WxMpMassOpenIdsMessage) #massOpenIdsMessageSend(WxMpMassOpenIdsMessage)
+ * @param news 图文消息对象
+ * @return 上传结果对象,包含media_id等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 上传群发用的视频,上传后才能群发视频消息.
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
+ * 上传群发用的视频,上传后才能群发视频消息
*
*
- * @param video the video
- * @return the wx mp mass upload result
- * @throws WxErrorException the wx error exception
- * @see #massGroupMessageSend(WxMpMassTagMessage) #massGroupMessageSend(WxMpMassTagMessage)
- * @see #massOpenIdsMessageSend(WxMpMassOpenIdsMessage) #massOpenIdsMessageSend(WxMpMassOpenIdsMessage)
+ * @param video 视频消息对象
+ * @return 上传结果对象,包含media_id等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 分组群发消息.
+ * 分组群发消息
* 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送
* 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
*
*
- * @param message the message
- * @return the wx mp mass send result
- * @throws WxErrorException the wx error exception
+ * @param message 分组群发消息对象
+ * @return 群发结果对象,包含msg_id等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 按openId列表群发消息.
+ * 按openId列表群发消息
* 如果发送图文消息,必须先使用 {@link #massNewsUpload(WxMpMassNews)} 获得media_id,然后再发送
* 如果发送视频消息,必须先使用 {@link #massVideoUpload(WxMpMassVideo)} 获得media_id,然后再发送
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
*
*
- * @param message the message
- * @return the wx mp mass send result
- * @throws WxErrorException the wx error exception
+ * @param message 按openid列表群发消息对象
+ * @return 群发结果对象,包含msg_id等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 群发消息预览接口.
+ * 群发消息预览接口
* 开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版。为了满足第三方平台开发者的需求,
* 在保留对openID预览能力的同时,增加了对指定微信号发送预览的能力,但该能力每日调用次数有限制(100次),请勿滥用。
- * 接口调用请求说明
- * http请求方式: POST
- * https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN
- * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140549&token=&lang=zh_CN
*
*
- * @param wxMpMassPreviewMessage the wx mp mass preview message
- * @return wxMpMassSendResult wx mp mass send result
- * @throws WxErrorException the wx error exception
+ * @param wxMpMassPreviewMessage 预览消息对象
+ * @return 群发结果对象,包含msg_id等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * 删除群发.
+ * 删除群发
* 群发之后,随时可以通过该接口删除群发。
* 请注意:
* 1、只有已经发送成功的消息才能删除
* 2、删除消息是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片。
* 3、删除群发消息只能删除图文消息和视频消息,其他类型的消息一经发送,无法删除。
* 4、如果多次群发发送的是一个图文消息,那么删除其中一次群发,就会删除掉这个图文消息也,导致所有群发都失效
- * 接口调用请求说明:
- * http请求方式: POST
- * https://api.weixin.qq.com/cgi-bin/message/mass/delete?access_token=ACCESS_TOKEN
- * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1481187827_i0l21
*
*
* @param msgId 发送出去的消息ID
* @param articleIndex 要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章
- * @throws WxErrorException the wx error exception
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 获取群发速度
- * https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Batch_Sends_and_Originality_Checks.html#9
+ *
*
- * @return the wx mp mass speed get result
- * @throws WxErrorException the wx error exception
+ * @return 群发速度获取结果对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 设置群发速度
- * https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Batch_Sends_and_Originality_Checks.html#9
+ *
*
- * @param speed 群发速度的级别,是一个0到4的整数,数字越大表示群发速度越慢。 speed realspeed 0 80w/分钟 1 60w/分钟 2 45w/分钟 3 30w/分钟 4 10w/分钟
- * @throws WxErrorException the wx error exception
+ * @param speed 群发速度的级别,是一个0到4的整数,数字越大表示群发速度越慢。
+ * speed realspeed
+ * 0 80w/分钟
+ * 1 60w/分钟
+ * 2 45w/分钟
+ * 3 30w/分钟
+ * 4 10w/分钟
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
* 查询群发消息发送状态【订阅号与服务号认证后均可用】
- * https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Batch_Sends_and_Originality_Checks.html#%E6%9F%A5%E8%AF%A2%E7%BE%A4%E5%8F%91%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E7%8A%B6%E6%80%81%E3%80%90%E8%AE%A2%E9%98%85%E5%8F%B7%E4%B8%8E%E6%9C%8D%E5%8A%A1%E5%8F%B7%E8%AE%A4%E8%AF%81%E5%90%8E%E5%9D%87%E5%8F%AF%E7%94%A8%E3%80%91
+ *
*
* @param msgId 群发消息后返回的消息id
- * @return 消息发送后的状态 ,SEND_SUCCESS表示发送成功,SENDING表示发送中,SEND_FAIL表示发送失败,DELETE表示已删除
- * @throws WxErrorException the wx error exception
+ * @return 消息发送后的状态,SEND_SUCCESS表示发送成功,SENDING表示发送中,SEND_FAIL表示发送失败,DELETE表示已删除
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
- * Created by Binary Wang on 2016/7/21.
* 素材管理的相关接口,包括媒体管理的接口,
* 即以https://api.weixin.qq.com/cgi-bin/material
* 和 https://api.weixin.qq.com/cgi-bin/media开头的接口
@@ -36,7 +35,7 @@ public interface WxMpMaterialService {
* 2、media_id是可复用的。
* 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/amr格式
* 4、需使用https调用本接口。
- * 本接口即为原“上传多媒体文件”接口。
+ * 本接口即为原"上传多媒体文件"接口。
* 注意事项:
* 上传的临时多媒体文件有格式和大小限制,如下:
* 图片(image): 2M,支持PNG\JPEG\JPG\GIF格式
@@ -49,17 +48,17 @@ public interface WxMpMaterialService {
*
*
* @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
- * @param file 文件对象
- * @return the wx media upload result
- * @throws WxErrorException the wx error exception
- * @see #mediaUpload(String, String, InputStream) #mediaUpload(String, String, InputStream)#mediaUpload(String, String, InputStream)
+ * @param file 文件对象,需要上传的临时素材文件
+ * @return 上传结果,包含media_id等信息
+ * @throws WxErrorException 微信API调用异常
+ * @see #mediaUpload(String, String, InputStream) 使用输入流上传临时素材
*/
WxMediaUploadResult mediaUpload(String mediaType, File file) throws WxErrorException;
/**
*
* 新增临时素材
- * 本接口即为原“上传多媒体文件”接口。
+ * 本接口即为原"上传多媒体文件"接口。
*
* 详情请见: 新增临时素材
* 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
@@ -67,10 +66,10 @@ public interface WxMpMaterialService {
*
* @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
* @param fileType 文件类型,请看{@link me.chanjar.weixin.common.api.WxConsts}
- * @param inputStream 输入流
- * @return the wx media upload result
- * @throws WxErrorException the wx error exception
- * @see #mediaUpload(java.lang.String, java.io.File) #mediaUpload(java.lang.String, java.io.File)#mediaUpload(java.lang.String, java.io.File)
+ * @param inputStream 输入流,包含要上传的临时素材内容
+ * @return 上传结果,包含media_id等信息
+ * @throws WxErrorException 微信API调用异常
+ * @see #mediaUpload(String, File) 使用文件对象上传临时素材
*/
WxMediaUploadResult mediaUpload(String mediaType, String fileType, InputStream inputStream) throws WxErrorException;
@@ -78,15 +77,15 @@ public interface WxMpMaterialService {
*
* 获取临时素材
* 公众号可以使用本接口获取临时素材(即下载临时的多媒体文件)。请注意,视频文件不支持https下载,调用该接口需http协议。
- * 本接口即为原“下载多媒体文件”接口。
+ * 本接口即为原"下载多媒体文件"接口。
* 根据微信文档,视频文件下载不了,会返回null
* 详情请见: 获取临时素材
* 接口url格式:https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
*
*
- * @param mediaId 媒体文件Id
- * @return 保存到本地的临时文件 file
- * @throws WxErrorException the wx error exception
+ * @param mediaId 媒体文件Id,通过上传临时素材接口获取
+ * @return 保存到本地的临时文件,如果下载失败则返回null
+ * @throws WxErrorException 微信API调用异常
*/
File mediaDownload(String mediaId) throws WxErrorException;
@@ -100,9 +99,9 @@ public interface WxMpMaterialService {
* 接口url格式:https://api.weixin.qq.com/cgi-bin/media/get/jssdk?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
*
*
- * @param mediaId 媒体文件Id
- * @return 保存到本地的临时文件 file
- * @throws WxErrorException the wx error exception
+ * @param mediaId 媒体文件Id,通过JSSDK上传语音素材获取
+ * @return 保存到本地的临时文件,高清语音素材
+ * @throws WxErrorException 微信API调用异常
*/
File jssdkMediaDownload(String mediaId) throws WxErrorException;
@@ -114,9 +113,9 @@ public interface WxMpMaterialService {
* 接口url格式:https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
*
*
- * @param file 上传的文件对象
- * @return WxMediaImgUploadResult 返回图片url
- * @throws WxErrorException the wx error exception
+ * @param file 上传的文件对象,图片素材,支持jpg/png格式,大小不超过1MB
+ * @return 图片上传结果,包含图片URL,可用于图文消息中
+ * @throws WxErrorException 微信API调用异常
*/
WxMediaImgUploadResult mediaImgUpload(File file) throws WxErrorException;
@@ -141,35 +140,11 @@ public interface WxMpMaterialService {
*
* @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
* @param material 上传的素材, 请看{@link WxMpMaterial}
- * @return the wx mp material upload result
- * @throws WxErrorException the wx error exception
+ * @return 上传结果,包含media_id等信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException;
- /**
- * - * 新增永久图文素材 - * - * 详情请见: 新增永久素材 - * 接口url格式:https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN - * - * 除了3天就会失效的临时素材外,开发者有时需要永久保存一些素材,届时就可以通过本接口新增永久素材。 - * 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 - * 请注意: - * 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 - * 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 - * 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 - * 4、调用该接口需https协议 - *- * - * @param news 上传的图文消息, 请看{@link WxMpMaterialNews} - * @return the wx mp material upload result - * @throws WxErrorException the wx error exception - * @deprecated 关于永久图文素材相关接口下线的公告 : https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11644831863qFQSh&version=&token=2085564289&lang=zh_CN - */ - @Deprecated - WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException; - /** *
* 获取声音或者图片永久素材
@@ -179,8 +154,8 @@ public interface WxMpMaterialService {
*
*
* @param mediaId 永久素材的id
- * @return the input stream
- * @throws WxErrorException the wx error exception
+ * @return 素材内容的输入流,可用于读取图片或语音文件
+ * @throws WxErrorException 微信API调用异常
*/
InputStream materialImageOrVoiceDownload(String mediaId) throws WxErrorException;
@@ -193,8 +168,8 @@ public interface WxMpMaterialService {
*
*
* @param mediaId 永久素材的id
- * @return the wx mp material video info result
- * @throws WxErrorException the wx error exception
+ * @return 视频素材信息,包含标题、描述和下载地址
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMaterialVideoInfoResult materialVideoInfo(String mediaId) throws WxErrorException;
@@ -207,27 +182,11 @@ public interface WxMpMaterialService {
*
*
* @param mediaId 永久素材的id
- * @return the wx mp material news
- * @throws WxErrorException the wx error exception
+ * @return 图文素材信息,包含文章列表和标题等
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException;
- /**
- * - * 修改永久图文素材 - * - * 详情请见: 修改永久图文素材 - * 接口url格式:https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=ACCESS_TOKEN - *- * - * @param wxMpMaterialArticleUpdate 用来更新图文素材的bean, 请看{@link WxMpMaterialArticleUpdate} - * @return the boolean - * @throws WxErrorException the wx error exception - * @deprecated 关于永久图文素材相关接口下线的公告 : https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11644831863qFQSh&version=&token=2085564289&lang=zh_CN - */ - @Deprecated - boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException; - /** *
* 删除永久素材
@@ -241,8 +200,8 @@ public interface WxMpMaterialService {
*
*
* @param mediaId 永久素材的id
- * @return the boolean
- * @throws WxErrorException the wx error exception
+ * @return 删除是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常
*/
boolean materialDelete(String mediaId) throws WxErrorException;
@@ -259,8 +218,8 @@ public interface WxMpMaterialService {
* 接口url格式:https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN
*
*
- * @return the wx mp material count result
- * @throws WxErrorException the wx error exception
+ * @return 素材统计结果,包含各类素材的数量
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMaterialCountResult materialCount() throws WxErrorException;
@@ -272,10 +231,10 @@ public interface WxMpMaterialService {
* 接口url格式:https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN
*
*
- * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
+ * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材返回
* @param count 返回素材的数量,取值在1到20之间
- * @return the wx mp material news batch get result
- * @throws WxErrorException the wx error exception
+ * @return 图文素材列表,包含文章列表和标题等信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMaterialNewsBatchGetResult materialNewsBatchGet(int offset, int count) throws WxErrorException;
@@ -288,10 +247,10 @@ public interface WxMpMaterialService {
*
*
* @param type 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
- * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
+ * @param offset 从全部素材的该偏移位置开始返回,0表示从第一个素材返回
* @param count 返回素材的数量,取值在1到20之间
- * @return the wx mp material file batch get result
- * @throws WxErrorException the wx error exception
+ * @return 其他媒体素材列表,包含图片、语音、视频等素材信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMaterialFileBatchGetResult materialFileBatchGet(String type, int offset, int count) throws WxErrorException;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
index ea8cab7e50..289cb6a067 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
@@ -2,9 +2,6 @@
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.card.CardUpdateResult;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormRequest;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormResult;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardUpdateRequest;
import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult;
import me.chanjar.weixin.mp.bean.card.membercard.*;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
index 3e78893005..ad1813ee85 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMenuService.java
@@ -19,9 +19,9 @@ public interface WxMpMenuService {
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
*
*
- * @param menu the menu
- * @return 如果是个性化菜单 ,则返回menuid,否则返回null
- * @throws WxErrorException the wx error exception
+ * @param menu 菜单对象,包含菜单结构和配置信息
+ * @return 如果是个性化菜单,则返回menuid,否则返回null
+ * @throws WxErrorException 微信API调用异常
*/
String menuCreate(WxMenu menu) throws WxErrorException;
@@ -33,9 +33,9 @@ public interface WxMpMenuService {
* 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
*
*
- * @param json the json
- * @return 如果是个性化菜单 ,则返回menuid,否则返回null
- * @throws WxErrorException the wx error exception
+ * @param json 菜单配置的JSON字符串,包含菜单结构和配置信息
+ * @return 如果是个性化菜单,则返回menuid,否则返回null
+ * @throws WxErrorException 微信API调用异常
*/
String menuCreate(String json) throws WxErrorException;
@@ -45,7 +45,7 @@ public interface WxMpMenuService {
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
*
*
- * @throws WxErrorException the wx error exception
+ * @throws WxErrorException 微信API调用异常
*/
void menuDelete() throws WxErrorException;
@@ -55,8 +55,8 @@ public interface WxMpMenuService {
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
*
*
- * @param menuId 个性化菜单的menuid
- * @throws WxErrorException the wx error exception
+ * @param menuId 个性化菜单的menuid,通过创建个性化菜单时返回
+ * @throws WxErrorException 微信API调用异常
*/
void menuDelete(String menuId) throws WxErrorException;
@@ -66,8 +66,8 @@ public interface WxMpMenuService {
* 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
*
*
- * @return the wx mp menu
- * @throws WxErrorException the wx error exception
+ * @return 当前公众号的自定义菜单配置
+ * @throws WxErrorException 微信API调用异常
*/
WxMpMenu menuGet() throws WxErrorException;
@@ -77,9 +77,9 @@ public interface WxMpMenuService {
* 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
*
*
- * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。
- * @return the wx menu
- * @throws WxErrorException the wx error exception
+ * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号
+ * @return 匹配到的菜单配置
+ * @throws WxErrorException 微信API调用异常
*/
WxMenu menuTryMatch(String userid) throws WxErrorException;
@@ -98,8 +98,8 @@ public interface WxMpMenuService {
* https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
*
*
- * @return the self menu info
- * @throws WxErrorException the wx error exception
+ * @return 自定义菜单配置信息,包含菜单结构和配置详情
+ * @throws WxErrorException 微信API调用异常
*/
WxMpGetSelfMenuInfoResult getSelfMenuInfo() throws WxErrorException;
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
index 847f6e7ecf..df923512c9 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
@@ -22,8 +22,8 @@ public interface WxMpQrcodeService {
*
* @param sceneId 场景值ID,临时二维码时为32位非0整型
* @param expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
- * @return the wx mp qr code ticket
- * @throws WxErrorException the wx error exception
+ * @return 二维码ticket,可用于获取二维码图片
+ * @throws WxErrorException 微信API调用异常
*/
WxMpQrCodeTicket qrCodeCreateTmpTicket(int sceneId, Integer expireSeconds) throws WxErrorException;
@@ -36,8 +36,8 @@ public interface WxMpQrcodeService {
*
* @param sceneStr 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
* @param expireSeconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
- * @return the wx mp qr code ticket
- * @throws WxErrorException the wx error exception
+ * @return 二维码ticket,可用于获取二维码图片
+ * @throws WxErrorException 微信API调用异常
*/
WxMpQrCodeTicket qrCodeCreateTmpTicket(String sceneStr, Integer expireSeconds) throws WxErrorException;
@@ -48,8 +48,8 @@ public interface WxMpQrcodeService {
*
*
* @param sceneId 场景值ID,最大值为100000(目前参数只支持1--100000)
- * @return the wx mp qr code ticket
- * @throws WxErrorException the wx error exception
+ * @return 二维码ticket,可用于获取二维码图片
+ * @throws WxErrorException 微信API调用异常
*/
WxMpQrCodeTicket qrCodeCreateLastTicket(int sceneId) throws WxErrorException;
@@ -60,8 +60,8 @@ public interface WxMpQrcodeService {
*
*
* @param sceneStr 参数。字符串类型长度现在为1到64
- * @return the wx mp qr code ticket
- * @throws WxErrorException the wx error exception
+ * @return 二维码ticket,可用于获取二维码图片
+ * @throws WxErrorException 微信API调用异常
*/
WxMpQrCodeTicket qrCodeCreateLastTicket(String sceneStr) throws WxErrorException;
@@ -71,9 +71,9 @@ public interface WxMpQrcodeService {
* 详情请见: 生成带参数的二维码
*
*
- * @param ticket 二维码ticket
- * @return the file
- * @throws WxErrorException the wx error exception
+ * @param ticket 二维码ticket,通过创建二维码接口获取
+ * @return 二维码图片文件,jpg格式
+ * @throws WxErrorException 微信API调用异常
*/
File qrCodePicture(WxMpQrCodeTicket ticket) throws WxErrorException;
@@ -85,11 +85,12 @@ public interface WxMpQrcodeService {
*
* @param ticket 二维码ticket
* @param needShortUrl 是否需要压缩的二维码地址
- * @return the string
- * @throws WxErrorException the wx error exception
+ * @return 二维码图片的URL地址
+ * @throws WxErrorException 微信API调用异常
+ * @deprecated 请使用 {@link #qrCodePictureUrl(String)} 方法
*/
@Deprecated
- String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;
+ String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;
/**
*
@@ -97,9 +98,9 @@ public interface WxMpQrcodeService {
* 详情请见: 生成带参数的二维码
*
*
- * @param ticket 二维码ticket
- * @return the string
- * @throws WxErrorException the wx error exception
+ * @param ticket 二维码ticket,通过创建二维码接口获取
+ * @return 二维码图片的URL地址
+ * @throws WxErrorException 微信API调用异常
*/
String qrCodePictureUrl(String ticket) throws WxErrorException;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index 6df78c12d2..468dced138 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -37,7 +37,7 @@ public interface WxMpService extends WxService {
* @param longData 需要转换的长信息,不超过4KB
* @param expireSeconds 短key有效期(单位秒),最大值为2592000(即30天),默认为2592000(30天)
* @return shortKey 短key,15字节,base62编码(0-9/a-z/A-Z)
- * @throws WxErrorException .
+ * @throws WxErrorException 微信API调用异常
*/
String genShorten(String longData, Integer expireSeconds) throws WxErrorException;
@@ -47,9 +47,9 @@ public interface WxMpService extends WxService {
* 详情请见: https://developers.weixin.qq.com/doc/offiaccount/Account_Management/KEY_Shortener.html
*
*
- * @param shortKey 短key
- * @return WxMpShortKeyResult 解析结果
- * @throws WxErrorException .
+ * @param shortKey 短key,15字节,base62编码(0-9/a-z/A-Z)
+ * @return WxMpShortKeyResult 解析结果,包含原始长信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpShortKeyResult fetchShorten(String shortKey) throws WxErrorException;
@@ -59,19 +59,19 @@ public interface WxMpService extends WxService {
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
*
*
- * @param timestamp 时间戳
- * @param nonce 随机串
- * @param signature 签名
- * @return 是否验证通过 boolean
+ * @param timestamp 时间戳,字符串格式
+ * @param nonce 随机串,字符串格式
+ * @param signature 签名,字符串格式
+ * @return 是否验证通过,true表示验证通过,false表示验证失败
*/
boolean checkSignature(String timestamp, String nonce, String signature);
/**
* 获取access_token, 不强制刷新access_token.
*
- * @return token access token
- * @throws WxErrorException .
- * @see #getAccessToken(boolean) #getAccessToken(boolean)#getAccessToken(boolean)#getAccessToken(boolean)
+ * @return token access token,字符串格式
+ * @throws WxErrorException 微信API调用异常
+ * @see #getAccessToken(boolean) 获取access_token,可选择是否强制刷新
*/
String getAccessToken() throws WxErrorException;
@@ -87,21 +87,21 @@ public interface WxMpService extends WxService {
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
*
*
- * @param forceRefresh 是否强制刷新
- * @return token access token
- * @throws WxErrorException .
+ * @param forceRefresh 是否强制刷新,true表示强制刷新,false表示使用缓存
+ * @return token access token,字符串格式
+ * @throws WxErrorException 微信API调用异常
*/
String getAccessToken(boolean forceRefresh) throws WxErrorException;
/**
* 获得ticket,不强制刷新ticket.
*
- * @param type ticket 类型
- * @return ticket ticket
- * @throws WxErrorException .
- * @see #getTicket(TicketType, boolean) #getTicket(TicketType, boolean)#getTicket(TicketType, boolean)#getTicket(TicketType, boolean)
+ * @param ticketType ticket 类型,通过TicketType枚举指定
+ * @return ticket ticket,字符串格式
+ * @throws WxErrorException 微信API调用异常
+ * @see #getTicket(TicketType, boolean) 获得ticket,可选择是否强制刷新
*/
- String getTicket(TicketType type) throws WxErrorException;
+ String getTicket(TicketType ticketType) throws WxErrorException;
/**
*
@@ -109,19 +109,19 @@ public interface WxMpService extends WxService {
* 获得时会检查 Token是否过期,如果过期了,那么就刷新一下,否则就什么都不干
*
*
- * @param type ticket类型
- * @param forceRefresh 强制刷新
- * @return ticket ticket
- * @throws WxErrorException .
+ * @param ticketType ticket类型,通过TicketType枚举指定
+ * @param forceRefresh 强制刷新,true表示强制刷新,false表示使用缓存
+ * @return ticket ticket,字符串格式
+ * @throws WxErrorException 微信API调用异常
*/
- String getTicket(TicketType type, boolean forceRefresh) throws WxErrorException;
+ String getTicket(TicketType ticketType, boolean forceRefresh) throws WxErrorException;
/**
* 获得jsapi_ticket,不强制刷新jsapi_ticket.
*
- * @return jsapi ticket
- * @throws WxErrorException .
- * @see #getJsapiTicket(boolean) #getJsapiTicket(boolean)#getJsapiTicket(boolean)#getJsapiTicket(boolean)
+ * @return jsapi ticket,字符串格式
+ * @throws WxErrorException 微信API调用异常
+ * @see #getJsapiTicket(boolean) 获得jsapi_ticket,可选择是否强制刷新
*/
String getJsapiTicket() throws WxErrorException;
@@ -133,9 +133,9 @@ public interface WxMpService extends WxService {
* 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
*
*
- * @param forceRefresh 强制刷新
- * @return jsapi ticket
- * @throws WxErrorException .
+ * @param forceRefresh 强制刷新,true表示强制刷新,false表示使用缓存
+ * @return jsapi ticket,字符串格式
+ * @throws WxErrorException 微信API调用异常
*/
String getJsapiTicket(boolean forceRefresh) throws WxErrorException;
@@ -146,9 +146,9 @@ public interface WxMpService extends WxService {
* 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
*
*
- * @param url 地址
- * @return 生成的签名对象 wx jsapi signature
- * @throws WxErrorException .
+ * @param url 当前网页的URL,不包括#及其后面部分
+ * @return 生成的签名对象,包含签名、时间戳、随机串等信息
+ * @throws WxErrorException 微信API调用异常
*/
WxJsapiSignature createJsapiSignature(String url) throws WxErrorException;
@@ -158,9 +158,10 @@ public interface WxMpService extends WxService {
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=长链接转短链接接口
*
*
- * @param longUrl 长url
- * @return 生成的短地址 string
- * @throws WxErrorException .
+ * @param longUrl 长url,需要转换的原始URL
+ * @return 生成的短地址,字符串格式
+ * @throws WxErrorException 微信API调用异常
+ * @deprecated 请使用 {@link #genShorten(String, Integer)} 方法
*/
@Deprecated
String shortUrl(String longUrl) throws WxErrorException;
@@ -171,9 +172,9 @@ public interface WxMpService extends WxService {
* 详情请见:http://mp.weixin.qq.com/wiki/index.php?title=语义理解
*
*
- * @param semanticQuery 查询条件
- * @return 查询结果 wx mp semantic query result
- * @throws WxErrorException .
+ * @param semanticQuery 查询条件,包含查询内容、类型等信息
+ * @return 查询结果,包含语义理解的结果和建议回复
+ * @throws WxErrorException 微信API调用异常
*/
WxMpSemanticQueryResult semanticQuery(WxMpSemanticQuery semanticQuery) throws WxErrorException;
@@ -187,7 +188,7 @@ public interface WxMpService extends WxService {
* @param redirectUri 用户授权完成后的重定向链接,无需urlencode, 方法内会进行encode
* @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔,网页应用目前仅填写snsapi_login即可
* @param state 非必填,用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验
- * @return url string
+ * @return url 构造好的授权登录URL,字符串格式
*/
String buildQrConnectUrl(String redirectUri, String scope, String state);
@@ -197,8 +198,8 @@ public interface WxMpService extends WxService {
* http://mp.weixin.qq.com/wiki/0/2ad4b6bfd29f30f71d39616c2a0fcedc.html
*
*
- * @return 微信服务器ip地址数组 string [ ]
- * @throws WxErrorException .
+ * @return 微信服务器ip地址数组,包含所有微信服务器IP地址
+ * @throws WxErrorException 微信API调用异常
*/
String[] getCallbackIP() throws WxErrorException;
@@ -209,10 +210,10 @@ public interface WxMpService extends WxService {
* 为了帮助开发者排查回调连接失败的问题,提供这个网络检测的API。它可以对开发者URL做域名解析,然后对所有IP进行一次ping操作,得到丢包率和耗时。
*
*
- * @param action 执行的检测动作
- * @param operator 指定平台从某个运营商进行检测
- * @return 检测结果 wx net check result
- * @throws WxErrorException .
+ * @param action 执行的检测动作,可选值:all(全部检测)、dns(仅域名解析)、ping(仅网络连通性检测)
+ * @param operator 指定平台从某个运营商进行检测,可选值:CHINANET(中国电信)、UNICOM(中国联通)、CAP(中国联通)、CUCC(中国联通)
+ * @return 检测结果,包含丢包率和耗时等信息
+ * @throws WxErrorException 微信API调用异常
*/
WxNetCheckResult netCheck(String action, String operator) throws WxErrorException;
@@ -232,8 +233,8 @@ public interface WxMpService extends WxService {
* https://api.weixin.qq.com/cgi-bin/get_current_autoreply_info?access_token=ACCESS_TOKEN
*
*
- * @return 公众号的自动回复规则 current auto reply info
- * @throws WxErrorException .
+ * @return 公众号的自动回复规则,包含关注后自动回复、消息自动回复、关键词自动回复等信息
+ * @throws WxErrorException 微信API调用异常
*/
WxMpCurrentAutoReplyInfo getCurrentAutoReplyInfo() throws WxErrorException;
@@ -245,8 +246,8 @@ public interface WxMpService extends WxService {
*
*
*
- * @param appid 公众号的APPID
- * @throws WxErrorException the wx error exception
+ * @param appid 公众号的APPID,需要清零调用的公众号的appid
+ * @throws WxErrorException 微信API调用异常
*/
void clearQuota(String appid) throws WxErrorException;
@@ -257,53 +258,53 @@ public interface WxMpService extends WxService {
* 可以参考,{@link MediaUploadRequestExecutor}的实现方法
*
*
- * @param the type parameter
* @author Binary Wang
*/
-public interface WxMpStoreService
+ * 提供微信模板消息的发送、行业设置、模板管理等功能。
+ * 模板消息用于在用户触发特定事件后,向用户发送重要的服务通知。
+ *
+ * 详情请见:模板消息开发文档
+ *
+ * 提供微信公众号用户标签的创建、查询、更新、删除等功能。
+ * 通过标签可以方便地对用户进行分组管理和精准营销。
+ * 一个公众号最多可以创建100个标签。
+ *
+ * 详情请见:用户标签管理
+ *
* 创建门店
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java
index 5605c93651..d84737909e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpTemplateMsgService.java
@@ -8,105 +8,178 @@
import java.util.List;
/**
- *
* 模板消息接口
- * http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
+ *
+ * @author Binary Wang
*/
public interface WxMpTemplateMsgService {
- /**
- *
- * 设置所属行业
- * 官方文档中暂未告知响应内容
- * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- *
- *
- * @param wxMpIndustry 行业信息
- * @return 是否成功 industry
- * @throws WxErrorException .
- */
- boolean setIndustry(WxMpTemplateIndustry wxMpIndustry) throws WxErrorException;
+ /**
+ *
+ * 设置所属行业
+ * 官方文档中暂未告知响应内容
+ *
+ *
+ * @param wxMpIndustry 行业信息
+ * @return 是否成功设置行业
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 设置所属行业
+ */
+ boolean setIndustry(WxMpTemplateIndustry wxMpIndustry) throws WxErrorException;
- /***
- *
- * 获取设置的行业信息
- * 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- *
- *
- * @return wxMpIndustry industry
- * @throws WxErrorException .
- */
- WxMpTemplateIndustry getIndustry() throws WxErrorException;
+ /**
+ *
+ * 获取设置的行业信息
+ *
+ *
+ * @return 行业信息对象
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 获取设置的行业信息
+ */
+ WxMpTemplateIndustry getIndustry() throws WxErrorException;
- /**
- *
- * 发送模板消息
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- *
- *
- * @param templateMessage 模板消息
- * @return 消息Id string
- * @throws WxErrorException .
- */
- String sendTemplateMsg(WxMpTemplateMessage templateMessage) throws WxErrorException;
+ /**
+ *
+ * 发送模板消息
+ *
+ *
+ * @param templateMessage 模板消息对象
+ * @return 消息ID,可用于查询模板消息发送状态
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 发送模板消息
+ */
+ String sendTemplateMsg(WxMpTemplateMessage templateMessage) throws WxErrorException;
- /**
- *
- * 获得模板ID
- * 从行业模板库选择模板到账号后台,获得模板ID的过程可在MP中完成
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- * 接口地址格式:https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN
- *
- *
- * @param shortTemplateId 模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式
- * @return templateId 模板Id
- * @throws WxErrorException .
- * @deprecated 请使用 addTemplate(java.lang.String, java.util.List)
- */
- @Deprecated
- String addTemplate(String shortTemplateId) throws WxErrorException;
+ /**
+ *
+ * 获得模板ID
+ * 从行业模板库选择模板到账号后台,获得模板ID的过程可在MP中完成
+ *
+ *
+ * @param shortTemplateId 模板库中模板的编号,有"TM**"和"OPENTMTM**"等形式
+ * @return 模板ID
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @deprecated 请使用 {@link #addTemplate(String, List)}
+ * @see 获得模板ID
+ */
+ @Deprecated
+ String addTemplate(String shortTemplateId) throws WxErrorException;
- /**
- *
- * 获得模板ID
- * 从类目模板库选择模板到账号后台,获得模板ID的过程可在MP中完成
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- * 接口地址格式:https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN
- *
- *
- * @param shortTemplateId 模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式,对于类目模板,为纯数字ID
- * @param keywordNameList 选用的类目模板的关键词,按顺序传入,如果为空,或者关键词不在模板库中,会返回40246错误码
- * @return templateId 模板Id
- * @throws WxErrorException .
- */
- String addTemplate(String shortTemplateId, List
+ * 获得模板ID
+ * 从类目模板库选择模板到账号后台,获得模板ID的过程可在MP中完成
+ *
+ *
+ * @param shortTemplateId 模板库中模板的编号,有"TM**"和"OPENTMTM**"等形式,对于类目模板,为纯数字ID
+ * @param keywordNameList 选用的类目模板的关键词,按顺序传入,如果为空,或者关键词不在模板库中,会返回40246错误码
+ * @return 模板ID
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 获得模板ID
+ */
+ String addTemplate(String shortTemplateId, List
- * 获取模板列表
- * 获取已添加至账号下所有模板列表,可在MP中查看模板列表信息,为方便第三方开发者,提供通过接口调用的方式来获取账号下所有模板信息
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- * 接口地址格式:https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=ACCESS_TOKEN
- *
- *
- * @return templateId 模板Id
- * @throws WxErrorException .
- */
- List
+ * 获取模板列表
+ * 获取已添加至账号下所有模板列表,可在MP中查看模板列表信息,为方便第三方开发者,提供通过接口调用的方式来获取账号下所有模板信息
+ *
+ *
+ * @return 模板列表,包含所有已添加的模板信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 获取模板列表
+ */
+ List
- * 删除模板
- * 删除模板可在MP中完成,为方便第三方开发者,提供通过接口调用的方式来删除某账号下的模板
- * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN
- * 接口地址格式:https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token=ACCESS_TOKEN
- *
- *
- * @param templateId 模板Id
- * @return . boolean
- * @throws WxErrorException .
- */
- boolean delPrivateTemplate(String templateId) throws WxErrorException;
+ /**
+ *
+ * 删除模板
+ * 删除模板可在MP中完成,为方便第三方开发者,提供通过接口调用的方式来删除某账号下的模板
+ *
+ *
+ * @param templateId 模板ID
+ * @return 是否成功删除
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 删除模板
+ */
+ boolean delPrivateTemplate(String templateId) throws WxErrorException;
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
index 882fe93c00..d696c512ee 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpUserService.java
@@ -22,9 +22,9 @@ public interface WxMpUserService {
* 接口地址:https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=ACCESS_TOKEN
*
*
- * @param openid 用户openid
- * @param remark 备注名
- * @throws WxErrorException the wx error exception
+ * @param openid 用户openid,标识具体的用户
+ * @param remark 备注名,长度限制为30字符以内
+ * @throws WxErrorException 微信API调用异常
*/
void userUpdateRemark(String openid, String remark) throws WxErrorException;
@@ -36,9 +36,9 @@ public interface WxMpUserService {
* 接口地址:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
*
*
- * @param openid 用户openid
- * @return the wx mp user
- * @throws WxErrorException the wx error exception
+ * @param openid 用户openid,标识具体的用户
+ * @return 用户基本信息,包含昵称、头像、性别、关注时间等
+ * @throws WxErrorException 微信API调用异常
*/
WxMpUser userInfo(String openid) throws WxErrorException;
@@ -50,10 +50,10 @@ public interface WxMpUserService {
* 接口地址:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
*
*
- * @param openid 用户openid
+ * @param openid 用户openid,标识具体的用户
* @param lang 语言,zh_CN 简体(默认),zh_TW 繁体,en 英语
- * @return the wx mp user
- * @throws WxErrorException the wx error exception
+ * @return 用户基本信息,包含昵称、头像、性别、关注时间等
+ * @throws WxErrorException 微信API调用异常
*/
WxMpUser userInfo(String openid, String lang) throws WxErrorException;
@@ -66,9 +66,9 @@ public interface WxMpUserService {
* 接口地址:https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN
*
*
- * @param openidList 用户openid列表
- * @return the list
- * @throws WxErrorException the wx error exception
+ * @param openidList 用户openid列表,最多100个
+ * @return 用户基本信息列表,包含每个用户的基本信息
+ * @throws WxErrorException 微信API调用异常
*/
List
* 创建标签
* 一个公众号,最多可以创建100个标签。
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/create?access_token=ACCESS_TOKEN
*
*
* @param name 标签名字(30个字符以内)
- * @return the wx user tag
- * @throws WxErrorException the wx error exception
+ * @return 创建的标签对象,包含标签ID等信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 创建标签接口
*/
WxUserTag tagCreate(String name) throws WxErrorException;
/**
*
* 获取公众号已创建的标签
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/get?access_token=ACCESS_TOKEN
*
*
- * @return the list
- * @throws WxErrorException the wx error exception
+ * @return 标签列表,包含所有已创建的标签信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 获取标签接口
*/
List
* 编辑标签
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN
+ * 可以修改标签的名称,但不能修改标签ID。
*
*
- * @param tagId the tag id
- * @param name the name
- * @return the boolean
- * @throws WxErrorException the wx error exception
+ * @param tagId 标签ID,不能为null
+ * @param name 新的标签名字(30个字符以内)
+ * @return 操作是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 编辑标签接口
*/
Boolean tagUpdate(Long tagId, String name) throws WxErrorException;
/**
*
* 删除标签
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=ACCESS_TOKEN
+ * 删除标签后,该标签下的所有用户将被取消标签。
*
*
- * @param tagId the tag id
- * @return the boolean
- * @throws WxErrorException the wx error exception
+ * @param tagId 标签ID,不能为null
+ * @return 操作是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 删除标签接口
*/
Boolean tagDelete(Long tagId) throws WxErrorException;
/**
*
* 获取标签下粉丝列表
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=ACCESS_TOKEN
+ * 可用于获取某个标签下的所有用户信息,支持分页查询。
*
*
- * @param tagId the tag id
- * @param nextOpenid the next openid
- * @return the wx tag list user
- * @throws WxErrorException the wx error exception
+ * @param tagId 标签ID,不能为null
+ * @param nextOpenid 第一个拉取用户的openid,不填从头开始拉取
+ * @return 标签下粉丝列表对象,包含用户信息和分页信息
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 获取标签下粉丝列表接口
*/
- WxTagListUser tagListUser(Long tagId, String nextOpenid)
- throws WxErrorException;
+ WxTagListUser tagListUser(Long tagId, String nextOpenid) throws WxErrorException;
/**
*
* 批量为用户打标签
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN
+ * 可以为多个用户同时打上同一个标签。
*
*
- * @param tagId the tag id
- * @param openids the openids
- * @return the boolean
- * @throws WxErrorException the wx error exception
+ * @param tagId 标签ID,不能为null
+ * @param openids 用户openid数组,不能为null或空数组
+ * @return 操作是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 批量为用户打标签接口
*/
boolean batchTagging(Long tagId, String[] openids) throws WxErrorException;
/**
*
* 批量为用户取消标签
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=ACCESS_TOKEN
+ * 可以为多个用户同时取消同一个标签。
*
*
- * @param tagId the tag id
- * @param openids the openids
- * @return the boolean
- * @throws WxErrorException the wx error exception
+ * @param tagId 标签ID,不能为null
+ * @param openids 用户openid数组,不能为null或空数组
+ * @return 操作是否成功,true表示成功,false表示失败
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 批量为用户取消标签接口
*/
boolean batchUntagging(Long tagId, String[] openids) throws WxErrorException;
-
/**
*
* 获取用户身上的标签列表
- * 详情请见:用户标签管理
- * 接口url格式: https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token=ACCESS_TOKEN
+ * 可查询某个用户被打上的所有标签ID。
*
*
- * @param openid the openid
- * @return 标签Id的列表 list
- * @throws WxErrorException the wx error exception
+ * @param openid 用户的openid,不能为null或空字符串
+ * @return 标签ID的列表,表示该用户被打上的所有标签
+ * @throws WxErrorException 微信API调用异常,可能包括:
+ *
+ *
+ * @see 用户标签管理
+ * @see 获取用户身上的标签列表接口
*/
List
- * Created by BinaryWang on 2018/6/9.
- *
+ * Created by BinaryWang on 2018/6/9.
*
* @author Binary Wang
*/
@RequiredArgsConstructor
public class WxMpAiOpenServiceImpl implements WxMpAiOpenService {
- private final WxMpService wxMpService;
+ private final WxMpService wxMpService;
- @Override
- public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
- if (lang == null) {
- lang = AiLangType.zh_CN;
+ @Override
+ public void uploadVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
+ if (lang == null) {
+ lang = AiLangType.zh_CN;
+ }
+
+ this.wxMpService.execute(VoiceUploadRequestExecutor.create(this.wxMpService.getRequestHttp()),
+ String.format(VOICE_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), "mp3", voiceId, lang.getCode()),
+ voiceFile);
}
- this.wxMpService.execute(VoiceUploadRequestExecutor.create(this.wxMpService.getRequestHttp()),
- String.format(VOICE_UPLOAD_URL.getUrl(this.wxMpService.getWxMpConfigStorage()), "mp3", voiceId, lang.getCode()),
- voiceFile);
- }
+ @Override
+ public String queryRecognitionResult(String voiceId, AiLangType lang) throws WxErrorException {
+ if (lang == null) {
+ lang = AiLangType.zh_CN;
+ }
- @Override
- public String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
- this.uploadVoice(voiceId, lang, voiceFile);
- return this.queryRecognitionResult(voiceId, lang);
- }
+ final String response = this.wxMpService.get(VOICE_QUERY_RESULT_URL,
+ String.format("voice_id=%s&lang=%s", voiceId, lang.getCode()));
+ WxError error = WxError.fromJson(response, WxType.MP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
- @Override
- public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException {
- String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(this.wxMpService.getWxMpConfigStorage()),
- langFrom.getCode(), langTo.getCode()), content);
+ return GsonParser.parse(response).get("result").getAsString();
+ }
- WxError error = WxError.fromJson(response, WxType.MP);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
+ @Override
+ public String recogniseVoice(String voiceId, AiLangType lang, File voiceFile) throws WxErrorException {
+ this.uploadVoice(voiceId, lang, voiceFile);
+ return this.queryRecognitionResult(voiceId, lang);
}
- return GsonParser.parse(response).get("to_content").getAsString();
- }
+ @Override
+ public String translate(AiLangType langFrom, AiLangType langTo, String content) throws WxErrorException {
+ String response = this.wxMpService.post(String.format(TRANSLATE_URL.getUrl(this.wxMpService.getWxMpConfigStorage()),
+ langFrom.getCode(), langTo.getCode()), content);
- @Override
- public String queryRecognitionResult(String voiceId, AiLangType lang) throws WxErrorException {
- if (lang == null) {
- lang = AiLangType.zh_CN;
- }
+ WxError error = WxError.fromJson(response, WxType.MP);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
- final String response = this.wxMpService.get(VOICE_QUERY_RESULT_URL,
- String.format("voice_id=%s&lang=%s", voiceId, lang.getCode()));
- WxError error = WxError.fromJson(response, WxType.MP);
- if (error.getErrorCode() != 0) {
- throw new WxErrorException(error);
+ return GsonParser.parse(response).get("to_content").getAsString();
}
-
- return GsonParser.parse(response).get("result").getAsString();
- }
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
index 2ac835bbc4..8fce1d4736 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
@@ -114,7 +114,7 @@ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkCon
param.addProperty("code", code);
param.addProperty("check_consume", checkConsume);
String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_GET, param.toString());
- JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
+ JsonElement tmpJsonElement = JsonParser.parseString(responseContent);
return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
new TypeToken>() {
}.getType());
if (isExclude) {
- if (list.size() > 0) {
+ if (!list.isEmpty()) {
if (list.get(list.size() - 1).contains("\n")) {
list.remove(list.size() - 1);
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImpl.java
index ea1785f233..679146c4a9 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImpl.java
@@ -86,8 +86,8 @@ public WxImgProcAiCropResult aiCrop(String imgUrl, String ratios) throws WxError
ratios = "";
}
- final String result = this.wxMpService.get(String.format(AI_CROP.getUrl(this.wxMpService.getWxMpConfigStorage()),
- imgUrl, ratios), null);
+ final String result = this.wxMpService.post(String.format(AI_CROP.getUrl(this.wxMpService.getWxMpConfigStorage()),
+ imgUrl, ratios), "");
return WxImgProcAiCropResult.fromJson(result);
}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
index cde4df5b67..24a88e3bff 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
@@ -144,7 +144,7 @@ public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorExcep
if (result != null && result.getNumber() == number) {
Long msgId = result.getMsgId();
WxMpKfMsgList followingResult = this.kfMsgList(startTime, endTime, msgId, number);
- while (followingResult != null && followingResult.getRecords().size() > 0) {
+ while (followingResult != null && !followingResult.getRecords().isEmpty()) {
result.getRecords().addAll(followingResult.getRecords());
result.setNumber(result.getNumber() + followingResult.getNumber());
result.setMsgId(followingResult.getMsgId());
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
index 45e1c5c4b1..dfaf7d8a98 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
@@ -83,15 +83,6 @@ public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMateria
return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material);
}
- @Override
- public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException {
- if (news == null || news.isEmpty()) {
- throw new IllegalArgumentException("news is empty!");
- }
- String responseContent = this.wxMpService.post(NEWS_ADD_URL, news.toJson());
- return WxMpMaterialUploadResult.fromJson(responseContent);
- }
-
@Override
public InputStream materialImageOrVoiceDownload(String mediaId) throws WxErrorException {
return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor
@@ -111,17 +102,6 @@ public WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException
MATERIAL_GET_URL, mediaId);
}
- @Override
- public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException {
- String responseText = this.wxMpService.post(NEWS_UPDATE_URL, wxMpMaterialArticleUpdate.toJson());
- WxError wxError = WxError.fromJson(responseText, WxType.MP);
- if (wxError.getErrorCode() == 0) {
- return true;
- } else {
- throw new WxErrorException(wxError);
- }
- }
-
@Override
public boolean materialDelete(String mediaId) throws WxErrorException {
return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()),
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
index 4f4471b2bb..7a01c6a014 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
@@ -24,11 +24,6 @@
import me.chanjar.weixin.mp.bean.card.BaseInfo;
import me.chanjar.weixin.mp.bean.card.CardUpdateResult;
import me.chanjar.weixin.mp.bean.card.DateInfo;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCard;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormRequest;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormResult;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardCreateRequest;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardUpdateRequest;
import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult;
import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType;
import me.chanjar.weixin.mp.bean.card.enums.CardColor;
@@ -222,7 +217,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro
String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_USER_INFO_GET, jsonObject.toString());
log.debug("{}", responseContent);
- JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
+ JsonElement tmpJsonElement = JsonParser.parseString(responseContent);
return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
new TypeToken