diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000000..cec0d76c6b
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,198 @@
+# WxJava - WeChat Java SDK Development Instructions
+
+WxJava is a comprehensive WeChat Java SDK supporting multiple WeChat platforms including Official Accounts (公众号), Mini Programs (小程序), WeChat Pay (微信支付), Enterprise WeChat (企业微信), Open Platform (开放平台), and Channel/Video (视频号). This is a Maven multi-module project with Spring Boot and Solon framework integrations.
+
+**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the information here.**
+
+## Working Effectively
+
+### Prerequisites and Environment Setup
+- **Java Requirements**: JDK 8+ required (project uses Java 8 as minimum target)
+- **Maven**: Maven 3.6+ recommended (Maven 3.9.11 validated)
+- **IDE**: IntelliJ IDEA recommended (project optimized for IDEA)
+
+### Bootstrap, Build, and Validate
+Execute these commands in sequence after cloning:
+
+```bash
+# 1. Basic compilation (NEVER CANCEL - takes 4-5 minutes)
+mvn clean compile -DskipTests=true --no-transfer-progress
+# Timeout: Set 8+ minutes. Actual time: ~4 minutes
+
+# 2. Full package build (NEVER CANCEL - takes 2-3 minutes)
+mvn clean package -DskipTests=true --no-transfer-progress
+# Timeout: Set 5+ minutes. Actual time: ~2 minutes
+
+# 3. Code quality validation (NEVER CANCEL - takes 45-60 seconds)
+mvn checkstyle:check --no-transfer-progress
+# Timeout: Set 3+ minutes. Actual time: ~50 seconds
+```
+
+**CRITICAL TIMING NOTES:**
+- **NEVER CANCEL** any Maven build command
+- Compilation phase takes longest (~4 minutes) due to 34 modules
+- Full builds are faster on subsequent runs due to incremental compilation
+- Always use `--no-transfer-progress` to reduce log noise
+
+### Testing Structure
+- **Test Framework**: TestNG (not JUnit)
+- **Test Files**: 298 test files across all modules
+- **Default Behavior**: Tests are DISABLED by default in 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* 获取打卡数据 - * 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..7f9b693938 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 @@ -66,9 +66,9 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S ListlibList = 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 { 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 58bf20873f..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 @@ -99,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)); 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..af6a7e1408 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 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/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/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 8a9d2130d6..c88cb7b9be 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 @@ -603,7 +603,7 @@ public static class File implements Serializable { private String sdkFileId; @SerializedName("filesize") - private Integer fileSize; + private Long fileSize; /** * From json file. 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/WxCpOaApprovalTemplateResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java index d10594a546..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 @@ -17,7 +17,7 @@ /** * 审批模板详情 * - * @author gyv12345 @163.com / Wang_Wong + * @author gyv12345@163.com / Wang_Wong */ @Data @Builder @@ -121,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/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/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/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/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 3aecf72120..fb6f8ef686 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"; } /** @@ -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. */ 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 BaseWxCpTpServiceImplimplements 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..63d5e95bae --- /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.authenticator(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) + .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/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/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/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/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 "; + + 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 = "\n" + + "\t \n" + + "\t 1425284517 \n" + + "\t\n" + + "\t \n" + + "\t \n" + + " " + + " "; + WxCpXmlMessage wxMessageNumeric = WxCpXmlMessage.fromXml(xmlWithNumeric); + assertEquals(wxMessageNumeric.getMsgId(), "1234567890123456"); + + // Test with string msgId (new format - the actual issue case) + String xmlWithString = "" + + " " + + " 1348831860 " + + "" + + " " + + " 1234567890123456 " + + "" + + " "; + 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/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/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 cfe52b9686..8a9cb02dc0 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@" + + " " + + " 1348831860 " + + "" + + " " + + " CAIQg/PKxgYY2sC9tpuAgAMg9/zKaw== " + + "com.github.binarywang wx-java -4.7.2.B +4.7.8.B weixin-java-miniapp @@ -31,6 +31,11 @@okhttp provided
* 触发云函数。注意: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
- * 数据库插入记录 - * + * 数据库插入记录。 * 文档地址: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
- * 数据库查询记录 - * + * 数据库查询记录。 * 文档地址: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
- * 变更数据库索引 - * + * 变更数据库索引。 * 文档地址: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
- * 数据库导入 + * 数据库导入。 + * 文档地址: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/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/WxMaOrderManagementService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java index d82cfd19cc..91980e9427 100644 --- 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 @@ -2,7 +2,6 @@ import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath; import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult; -import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse; import me.chanjar.weixin.common.error.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 a5446361a3..ef3a46bad9 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,563 +37,572 @@ 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}的实现方法 - *- * - * @param
- * 设置当微信系统响应系统繁忙时,要等待多少 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
+ * 小程序 - 微信客服 相关接口 + * 负责处理 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/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/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 index 7fcf73f5a3..27d7c01487 100644 --- 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 @@ -4,7 +4,6 @@ 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.bean.shop.response.WxMaOrderShippingInfoBaseResponse; 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/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 WxMinishopResultaddSpu(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..9734e25933 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,8 +58,8 @@ public HttpHost getRequestHttpProxy() { } @Override - public HttpType getRequestType() { - return HttpType.APACHE_HTTP; + public HttpClientType getRequestType() { + return HttpClientType.APACHE_HTTP; } @Override @@ -74,27 +73,12 @@ protected String doGetAccessTokenRequest() throws IOException { 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 @@ -104,33 +88,18 @@ protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOEx 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) { - } - } + 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..d23d865cf9 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,8 +43,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-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..1053b809e9 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.*; @@ -58,8 +58,8 @@ public OkHttpProxyInfo getRequestHttpProxy() { } @Override - public HttpType getRequestType() { - return HttpType.OK_HTTP; + public HttpClientType getRequestType() { + return HttpClientType.OK_HTTP; } @Override 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/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/WxMaMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java index 75d8174caf..d95882a240 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 @@ -212,6 +212,51 @@ 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; + /** * 不要直接使用这个字段, * 这个字段只是为了适配 SubscribeMsgPopupEvent SubscribeMsgChangeEvent SubscribeMsgSentEvent @@ -261,7 +306,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, 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和绑定时间戳。 + * + * 字段说明: + *
+ *
+ * @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/order/WxMaOrderManagementGetOrderDetailPath.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java index 02c53a53f8..b301e356e8 100644 --- 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 @@ -4,8 +4,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; -import java.io.Serializable; - /** * @author xzh * @Description 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; + /** + *- errCode: 错误码
+ *- entityName: 小程序主体名称,未绑定时不返回
+ *- corpid: 企业ID,未绑定时不返回
+ *- bindTime: 接受绑定时间戳(毫秒)
+ *+ * 必填:否 + * 说明:根据剧目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 ListcomplaintOrderInfo; + @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/constant/WxMaApiUrlConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java index d61ade73c3..79806dbd84 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 @@ -626,7 +626,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"; @@ -885,6 +885,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"; } /** 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 { - private static final Logger logger = - LoggerFactory.getLogger(ApacheApiSignaturePostRequestExecutor.class); +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class ApacheApiSignaturePostRequestExecutor extends ApiSignaturePostRequestExecutor { - public ApacheApiSignaturePostRequestExecutor(RequestHttp, ?> requestHttp) { + public ApacheApiSignaturePostRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -49,8 +46,7 @@ public WxMaApiResponse execute( } if (postEntity != null) { - StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); - entity.setContentType("application/json; charset=utf-8"); + StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8)); httpPost.setEntity(entity); } @@ -64,8 +60,6 @@ public WxMaApiResponse execute( } } return this.handleResponse(wxType, responseContent, respHeaders); - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java index 58c7beabee..fff1be7fc4 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java @@ -63,8 +63,6 @@ public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxTyp } return IOUtils.toByteArray(inputStream); - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java index c7f57b2f68..fbc0edcfbe 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java @@ -71,8 +71,6 @@ public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); } return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg", Paths.get(filePath).toFile()); - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java index ac3ffd7c71..59b35567bb 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java @@ -9,7 +9,6 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; @@ -24,34 +23,30 @@ */ public class ApacheUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor { - public ApacheUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { - super(requestHttp); - } + public ApacheUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } - @Override - public WxMaUploadAuthMaterialResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException { - HttpPost httpPost = new HttpPost(uri); - if (requestHttp.getRequestHttpProxy() != null) { - RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); - httpPost.setConfig(config); - } - if (file != null) { - HttpEntity entity = MultipartEntityBuilder - .create() - .addBinaryBody("media", file) - .setMode(HttpMultipartMode.RFC6532) - .build(); - httpPost.setEntity(entity); - } - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent, wxType); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMaUploadAuthMaterialResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); - } + @Override + public WxMaUploadAuthMaterialResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + if (file != null) { + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.RFC6532) + .build(); + httpPost.setEntity(entity); + } + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); } + return WxMaUploadAuthMaterialResult.fromJson(responseContent); + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java index a9ffd1af39..2ca23ae325 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; @@ -22,9 +21,8 @@ */ public class ApacheVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor { - public ApacheVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { + public ApacheVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); - } @Override @@ -54,15 +52,11 @@ public WxMaVodSingleFileUploadResult execute(String uri, File file, WxType wxTyp httpPost.setEntity(entityBuilder.build()); } - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent, wxType); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMaVodSingleFileUploadResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); } + return WxMaVodSingleFileUploadResult.fromJson(responseContent); } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java index e27840cd59..f6c1ec36b6 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; @@ -22,7 +21,7 @@ */ public class ApacheVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor { - public ApacheVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { + public ApacheVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { super(requestHttp, uploadId, partNumber, resourceType); } @@ -45,15 +44,12 @@ public WxMaVodUploadPartResult execute(String uri, File file, WxType wxType) thr httpPost.setEntity(entityBuilder.build()); } - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent, wxType); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - return WxMaVodUploadPartResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); + + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); } + return WxMaVodUploadPartResult.fromJson(responseContent); } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java index 8e3ade961e..c01a7ab5de 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java @@ -1,23 +1,28 @@ package cn.binarywang.wx.miniapp.executor; import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; -import java.io.IOException; -import java.rmi.RemoteException; -import java.util.Map; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.Map; + public abstract class ApiSignaturePostRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public ApiSignaturePostRequestExecutor(RequestHttp requestHttp) { + public ApiSignaturePostRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -54,16 +59,21 @@ public WxMaApiResponse handleResponse( return response; } - public static ApiSignaturePostRequestExecutor create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static ApiSignaturePostRequestExecutor, ?> create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new ApacheApiSignaturePostRequestExecutor(requestHttp); + return new ApacheApiSignaturePostRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new JoddApiSignaturePostRequestExecutor(requestHttp); + return new JoddApiSignaturePostRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new OkHttpApiSignaturePostRequestExecutor(requestHttp); + return new OkHttpApiSignaturePostRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new HttpComponentsApiSignaturePostRequestExecutor( + (RequestHttp ) requestHttp); default: - throw new IllegalArgumentException("非法请求参数"); + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsApiSignaturePostRequestExecutor.java new file mode 100644 index 0000000000..23d2231855 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsApiSignaturePostRequestExecutor.java @@ -0,0 +1,63 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.WxMaApiResponse; +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.hc.Utf8ResponseHandler; +import org.apache.hc.client5.http.ClientProtocolException; +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.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.StringEntity; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class HttpComponentsApiSignaturePostRequestExecutor extends ApiSignaturePostRequestExecutor { + + public HttpComponentsApiSignaturePostRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMaApiResponse execute( + String uri, Map headers, String postEntity, WxType wxType) + throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + if (headers != null) { + headers.forEach(httpPost::addHeader); + } + + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8)); + httpPost.setEntity(entity); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + Map respHeaders = new HashMap<>(); + Header[] rHeaders = response.getHeaders(); + if (rHeaders != null) { + for (Header h : rHeaders) { + respHeaders.putIfAbsent(h.getName(), h.getValue()); + } + } + return this.handleResponse(wxType, responseContent, respHeaders); + } catch (HttpException httpException) { + throw new ClientProtocolException(httpException.getMessage(), httpException); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeBytesRequestExecutor.java new file mode 100644 index 0000000000..655296fdaf --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeBytesRequestExecutor.java @@ -0,0 +1,70 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import org.apache.commons.io.IOUtils; +import org.apache.hc.client5.http.ClientProtocolException; +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.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.StringEntity; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author altusea + */ +public class HttpComponentsQrcodeBytesRequestExecutor extends QrcodeBytesRequestExecutor { + + public HttpComponentsQrcodeBytesRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + /** + * 执行http请求. + * + * @param uri uri + * @param qrcodeWrapper 数据 + * @param wxType 微信模块类型 + * @return 响应结果 + * @throws WxErrorException 自定义异常 + * @throws IOException io异常 + */ + @Override + public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + httpPost.setConfig( + RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() + ); + } + + httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson())); + + try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0 + && ContentType.APPLICATION_JSON.getMimeType() + .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent, wxType)); + } + + return IOUtils.toByteArray(inputStream); + } catch (HttpException httpException) { + throw new ClientProtocolException(httpException.getMessage(), httpException); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeFileRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeFileRequestExecutor.java new file mode 100644 index 0000000000..10d01b1cfd --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeFileRequestExecutor.java @@ -0,0 +1,79 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import org.apache.commons.lang3.StringUtils; +import org.apache.hc.client5.http.ClientProtocolException; +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.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.StringEntity; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Paths; +import java.util.UUID; + +/** + * @author altusea + */ +public class HttpComponentsQrcodeFileRequestExecutor extends QrcodeRequestExecutor { + + private final String filePath; + + public HttpComponentsQrcodeFileRequestExecutor(RequestHttp requestHttp, String filePath) { + super(requestHttp); + this.filePath = filePath; + } + + /** + * 执行http请求. + * + * @param uri uri + * @param qrcodeWrapper 数据 + * @param wxType 微信模块类型 + * @return 响应结果 + * @throws WxErrorException 自定义异常 + * @throws IOException io异常 + */ + @Override + public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + httpPost.setConfig( + RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build() + ); + } + + httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson(), ContentType.APPLICATION_JSON)); + + try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0 + && ContentType.APPLICATION_JSON.getMimeType() + .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent, wxType)); + } + if (StringUtils.isBlank(filePath)) { + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg", Paths.get(filePath).toFile()); + } catch (HttpException httpException) { + throw new ClientProtocolException(httpException.getMessage(), httpException); + } + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsUploadAuthMaterialRequestExecutor.java new file mode 100644 index 0000000000..8bfed3b5fa --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsUploadAuthMaterialRequestExecutor.java @@ -0,0 +1,51 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.WxMaUploadAuthMaterialResult; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.IOException; + +/** + * @author altusea + */ +public class HttpComponentsUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor { + + public HttpComponentsUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMaUploadAuthMaterialResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + if (file != null) { + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.EXTENDED) + .build(); + httpPost.setEntity(entity); + } + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMaUploadAuthMaterialResult.fromJson(responseContent); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodSingleUploadRequestExecutor.java new file mode 100644 index 0000000000..3f9139d459 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodSingleUploadRequestExecutor.java @@ -0,0 +1,59 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.vod.WxMaVodSingleFileUploadResult; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.IOException; + +public class HttpComponentsVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor { + + public HttpComponentsVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { + super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); + } + + @Override + public WxMaVodSingleFileUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + if (file != null) { + MultipartEntityBuilder entityBuilder = MultipartEntityBuilder + .create() + .setMode(HttpMultipartMode.EXTENDED) + .addTextBody("media_name", mediaName) + .addTextBody("media_type", mediaType) + .addBinaryBody("media_data", file); + + if (coverType != null) { + entityBuilder.addTextBody("cover_type", coverType); + } + if (coverData != null) { + entityBuilder.addBinaryBody("cover_data", coverData); + } + if (sourceContext != null) { + entityBuilder.addTextBody("source_context", sourceContext); + } + + httpPost.setEntity(entityBuilder.build()); + } + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMaVodSingleFileUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodUploadPartRequestExecutor.java new file mode 100644 index 0000000000..eb2cf8e9db --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodUploadPartRequestExecutor.java @@ -0,0 +1,52 @@ +package cn.binarywang.wx.miniapp.executor; + +import cn.binarywang.wx.miniapp.bean.vod.WxMaVodUploadPartResult; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.IOException; + +public class HttpComponentsVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor { + + public HttpComponentsVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { + super(requestHttp, uploadId, partNumber, resourceType); + + } + + @Override + public WxMaVodUploadPartResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + if (file != null) { + MultipartEntityBuilder entityBuilder = MultipartEntityBuilder + .create() + .setMode(HttpMultipartMode.EXTENDED) + .addTextBody("upload_id", uploadId) + .addTextBody("part_number", String.valueOf(partNumber)) + .addTextBody("resource_type", String.valueOf(resourceType)) + .addBinaryBody("data", file); + + httpPost.setEntity(entityBuilder.build()); + } + + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, wxType); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMaVodUploadPartResult.fromJson(responseContent); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java index b7568bc21d..d8724a6ac8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java @@ -20,7 +20,7 @@ public class JoddApiSignaturePostRequestExecutor private static final Logger logger = LoggerFactory.getLogger(JoddApiSignaturePostRequestExecutor.class); - public JoddApiSignaturePostRequestExecutor(RequestHttp, ?> requestHttp) { + public JoddApiSignaturePostRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java index d63e29c5d4..b121932d74 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java @@ -11,8 +11,6 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.fs.FileUtils; import me.chanjar.weixin.common.util.http.RequestHttp; -import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; -import okhttp3.*; import org.apache.commons.lang3.StringUtils; import java.io.ByteArrayInputStream; diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java index cff63972e3..874a96f2c4 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java @@ -20,7 +20,7 @@ */ public class JoddHttpUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor { - public JoddHttpUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { + public JoddHttpUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java index ed47a9fc67..cb71076c60 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java @@ -19,7 +19,7 @@ */ public class JoddHttpVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor { - public JoddHttpVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { + public JoddHttpVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java index 36e53b66bf..e86a1d5b98 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java @@ -19,7 +19,7 @@ */ public class JoddHttpVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor { - public JoddHttpVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { + public JoddHttpVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { super(requestHttp, uploadId, partNumber, resourceType); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java index 10c75a26bd..f9d1262821 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java @@ -18,7 +18,7 @@ public class OkHttpApiSignaturePostRequestExecutor private static final Logger logger = LoggerFactory.getLogger(OkHttpApiSignaturePostRequestExecutor.class); - public OkHttpApiSignaturePostRequestExecutor(RequestHttp, ?> requestHttp) { + public OkHttpApiSignaturePostRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java index 698fb78894..67d0d99b3f 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java @@ -17,7 +17,7 @@ */ public class OkHttpUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor { - public OkHttpUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { + public OkHttpUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java index 78fbdd3d25..d6e8a6880f 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java @@ -16,7 +16,7 @@ */ public class OkHttpVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor { - public OkHttpVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { + public OkHttpVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java index c9e991d082..59d4aa932d 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java @@ -16,7 +16,7 @@ */ public class OkHttpVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor { - public OkHttpVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { + public OkHttpVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { super(requestHttp, uploadId, partNumber, resourceType); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java index a4a5112565..4d95a6daae 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java @@ -6,6 +6,8 @@ import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; import java.io.IOException; @@ -16,7 +18,7 @@ public abstract class QrcodeBytesRequestExecutor implements RequestExecuto protected RequestHttp requestHttp; - public QrcodeBytesRequestExecutor(RequestHttp requestHttp) { + public QrcodeBytesRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -25,16 +27,19 @@ public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler< handler.handle(this.execute(uri, data, wxType)); } - public static RequestExecutor create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new ApacheQrcodeBytesRequestExecutor(requestHttp); - case JODD_HTTP: - return null; + return new ApacheQrcodeBytesRequestExecutor( + (RequestHttp ) requestHttp); case OK_HTTP: - return new OkHttpQrcodeBytesRequestExecutor(requestHttp); + return new OkHttpQrcodeBytesRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new HttpComponentsQrcodeBytesRequestExecutor( + (RequestHttp ) requestHttp); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java index bf85004ac5..ec1d0fd158 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java @@ -6,6 +6,10 @@ import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; +import org.apache.http.HttpHost; +import org.apache.http.impl.client.CloseableHttpClient; import java.io.File; import java.io.IOException; @@ -25,29 +29,34 @@ public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler< handler.handle(this.execute(uri, data, wxType)); } - - public static RequestExecutor create(RequestHttp requestHttp, String path) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp, String path) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new ApacheQrcodeFileRequestExecutor(requestHttp, path); + return new ApacheQrcodeFileRequestExecutor( + (RequestHttp ) requestHttp, path); case OK_HTTP: - return new OkHttpQrcodeFileRequestExecutor(requestHttp, path); - case JODD_HTTP: + return new OkHttpQrcodeFileRequestExecutor((RequestHttp ) requestHttp, path); + case HTTP_COMPONENTS: + return new HttpComponentsQrcodeFileRequestExecutor( + (RequestHttp ) requestHttp, path); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } - public static RequestExecutor create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new ApacheQrcodeFileRequestExecutor(requestHttp, null); - case JODD_HTTP: - return null; + return new ApacheQrcodeFileRequestExecutor((RequestHttp ) requestHttp, null); case OK_HTTP: - return new OkHttpQrcodeFileRequestExecutor(requestHttp, null); + return new OkHttpQrcodeFileRequestExecutor((RequestHttp ) requestHttp, null); + case HTTP_COMPONENTS: + return new HttpComponentsQrcodeFileRequestExecutor( + (RequestHttp ) requestHttp, null); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java index 35bdcd9ed1..4d232ced21 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java @@ -1,11 +1,15 @@ package cn.binarywang.wx.miniapp.executor; import cn.binarywang.wx.miniapp.bean.WxMaUploadAuthMaterialResult; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; import java.io.File; import java.io.IOException; @@ -19,27 +23,32 @@ * @since 2024/01/07 */ public abstract class UploadAuthMaterialRequestExecutor implements RequestExecutor { - protected RequestHttp requestHttp; + protected RequestHttp requestHttp; - public UploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { - this.requestHttp = requestHttp; - } + public UploadAuthMaterialRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } - @Override - public void execute(String uri, File data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException { - handler.handle(this.execute(uri, data, wxType)); - } + @Override + public void execute(String uri, File data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data, wxType)); + } - public static RequestExecutor create(RequestHttp requestHttp) { - switch (requestHttp.getRequestType()) { - case APACHE_HTTP: - return new ApacheUploadAuthMaterialRequestExecutor(requestHttp); - case JODD_HTTP: - return new JoddHttpUploadAuthMaterialRequestExecutor(requestHttp); - case OK_HTTP: - return new OkHttpUploadAuthMaterialRequestExecutor(requestHttp); - default: - return null; - } + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { + switch (requestHttp.getRequestType()) { + case APACHE_HTTP: + return new ApacheUploadAuthMaterialRequestExecutor( + (RequestHttp ) requestHttp); + case JODD_HTTP: + return new JoddHttpUploadAuthMaterialRequestExecutor((RequestHttp ) requestHttp); + case OK_HTTP: + return new OkHttpUploadAuthMaterialRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new HttpComponentsUploadAuthMaterialRequestExecutor( + (RequestHttp ) requestHttp); + default: + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java index 40c73b0064..578fc8949c 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java @@ -1,11 +1,15 @@ package cn.binarywang.wx.miniapp.executor; import cn.binarywang.wx.miniapp.bean.vod.WxMaVodSingleFileUploadResult; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; import java.io.File; import java.io.IOException; @@ -27,7 +31,7 @@ public abstract class VodSingleUploadRequestExecutor implements RequestExe protected String sourceContext; protected File coverData; - public VodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { + public VodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { this.requestHttp = requestHttp; this.mediaName = mediaName; this.mediaType = mediaType; @@ -37,16 +41,24 @@ public VodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, } - public static RequestExecutor create(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new ApacheVodSingleUploadRequestExecutor(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); + return new ApacheVodSingleUploadRequestExecutor( + (RequestHttp ) requestHttp, + mediaName, mediaType, coverType, coverData, sourceContext); case JODD_HTTP: - return new JoddHttpVodSingleUploadRequestExecutor(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); + return new JoddHttpVodSingleUploadRequestExecutor((RequestHttp ) requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); case OK_HTTP: - return new OkHttpVodSingleUploadRequestExecutor(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); + return new OkHttpVodSingleUploadRequestExecutor( + (RequestHttp ) requestHttp, mediaName, mediaType, coverType, coverData, sourceContext); + case HTTP_COMPONENTS: + return new HttpComponentsVodSingleUploadRequestExecutor( + (RequestHttp ) requestHttp, + mediaName, mediaType, coverType, coverData, sourceContext); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } @@ -55,5 +67,4 @@ public void execute(String uri, File data, ResponseHandler implements RequestExecu protected Integer partNumber; protected Integer resourceType; - public VodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { + public VodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { this.requestHttp = requestHttp; this.uploadId = uploadId; this.partNumber = partNumber; @@ -27,16 +31,23 @@ public VodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, In } - public static RequestExecutor create(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp, String uploadId, Integer partNumber, Integer resourceType) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new ApacheVodUploadPartRequestExecutor(requestHttp, uploadId, partNumber, resourceType); + return new ApacheVodUploadPartRequestExecutor( + (RequestHttp ) requestHttp, + uploadId, partNumber, resourceType); case JODD_HTTP: - return new JoddHttpVodUploadPartRequestExecutor(requestHttp, uploadId, partNumber, resourceType); + return new JoddHttpVodUploadPartRequestExecutor((RequestHttp ) requestHttp, uploadId, partNumber, resourceType); case OK_HTTP: - return new OkHttpVodUploadPartRequestExecutor(requestHttp, uploadId, partNumber, resourceType); + return new OkHttpVodUploadPartRequestExecutor((RequestHttp ) requestHttp, uploadId, partNumber, resourceType); + case HTTP_COMPONENTS: + return new HttpComponentsVodUploadPartRequestExecutor( + (RequestHttp ) requestHttp, + uploadId, partNumber, resourceType); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } @@ -45,5 +56,4 @@ public void execute(String uri, File data, ResponseHandler getAsMap(JsonObject object, String memberName) { JsonArray array = object.getAsJsonArray(memberName); - if (array != null && array.size() > 0) { + if (array != null && !array.isEmpty()) { Map map = new LinkedHashMap<>(array.size()); for (JsonElement element : array) { JsonObject elementObject = element.getAsJsonObject(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java index 2e71f9eb4e..d316bbfeb1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java @@ -35,7 +35,7 @@ public WxMaRetainInfo deserialize(JsonElement json, Type type, JsonDeserializati private Map getAsMap(JsonObject object, String memberName) { JsonArray array = object.getAsJsonArray(memberName); - if (array != null && array.size() > 0) { + if (array != null && !array.isEmpty()) { Map map = new LinkedHashMap<>(array.size()); for (JsonElement element : array) { JsonObject elementObject = element.getAsJsonObject(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java index 377f8e35ef..f875be5a9e 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java @@ -24,7 +24,7 @@ public WxMaSubscribeMsgEvent.WxMaSubscribeMsgEventJson deserialize(JsonElement j WxMaSubscribeMsgEvent.WxMaSubscribeMsgEventJson result = new WxMaSubscribeMsgEvent.WxMaSubscribeMsgEventJson(); if (json.isJsonArray()) { JsonArray array = json.getAsJsonArray(); - if (array.size() > 0) { + if (!array.isEmpty()) { JsonObject obj = array.get(0).getAsJsonObject(); MsgEventTypeEnum eventType = detectMsgEventType(obj); for (int i = 0; i < array.size(); ++i) { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java index c99fd67ba3..edcc272ae1 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java @@ -50,7 +50,7 @@ private WxMaUserPortrait.Item getPortraitItem(JsonObject object) { private Map getAsMap(JsonObject object, String memberName) { JsonArray array = object.getAsJsonArray(memberName); - if (array != null && array.size() > 0) { + if (array != null && !array.isEmpty()) { Map map = new LinkedHashMap<>(array.size()); for (JsonElement element : array) { JsonObject elementObject = element.getAsJsonObject(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java index 3d81b6d66a..fd369f517a 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java @@ -7,7 +7,6 @@ import lombok.Data; import me.chanjar.weixin.common.api.WxErrorExceptionHandler; import me.chanjar.weixin.common.api.WxMessageDuplicateChecker; -import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateCheckerSingleton; import me.chanjar.weixin.common.session.InternalSession; import me.chanjar.weixin.common.session.InternalSessionManager; @@ -125,7 +124,7 @@ public WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map 0) { + if (!futures.isEmpty()) { this.executorService.submit(() -> { for (Future> future : futures) { try { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java index 15dd8654c0..68bd6286d6 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java @@ -7,12 +7,7 @@ * created on 2020-08-16 */ public class WxMaConfigHolder { - private static final ThreadLocal THREAD_LOCAL = new ThreadLocal () { - @Override - protected String initialValue() { - return "default"; - } - }; + private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(() -> "default"); public static String get() { return THREAD_LOCAL.get(); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java index 0222265e44..08346dbbb8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java @@ -10,8 +10,6 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import com.google.common.base.CharMatcher; -import com.google.common.io.BaseEncoding; import me.chanjar.weixin.common.error.WxRuntimeException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java index 0c980fda55..1533f2a0b6 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java @@ -1,6 +1,7 @@ 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.bean.xpay.*; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.test.ApiTestModule; @@ -119,6 +120,7 @@ public void testDownloadBill() throws Exception { WxMaXPayDownloadBillResponse response = this.wxService.getWxMaXPayService().downloadBill(request, sigParams); assertNotNull(response); } + @Test public void testRefundOrder() throws Exception { WxMaXPayRefundOrderRequest request = WxMaXPayRefundOrderRequest.builder() @@ -217,4 +219,209 @@ public void testQueryPublishGoods() throws Exception { assertNotNull(response); } + @Test + public void testQueryBizBalance() throws Exception { + WxMaXPayQueryBizBalanceRequest request = WxMaXPayQueryBizBalanceRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayQueryBizBalanceResponse response = this.wxService.getWxMaXPayService().queryBizBalance(request, sigParams); + assertNotNull(response); + } + + @Test + public void testQueryTransferAccount() throws Exception { + WxMaXPayQueryTransferAccountRequest request = WxMaXPayQueryTransferAccountRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayQueryTransferAccountResponse response = this.wxService.getWxMaXPayService().queryTransferAccount(request, sigParams); + assertNotNull(response); + } + + @Test + public void testQueryAdverFunds() throws Exception { + WxMaXPayQueryAdverFundsRequest request = WxMaXPayQueryAdverFundsRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .page(0) + .pageSize(10) + .filter(new WxMaXPayQueryAdverFundsRequest.Filter()) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayQueryAdverFundsResponse response = this.wxService.getWxMaXPayService().queryAdverFunds(request, sigParams); + assertNotNull(response); + } + + @Test + public void testCreateFundsBill() throws Exception { + WxMaXPayCreateFundsBillRequest request = WxMaXPayCreateFundsBillRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .transferAmount(0) + .transferAccountUid(0L) + .transferAccountName("") + .transferAccountAgencyId(0) + .requestId("") + .settleBegin(0L) + .settleEnd(0L) + .authorizeAdvertise(0) + .fundType(0) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayCreateFundsBillResponse response = this.wxService.getWxMaXPayService().createFundsBill(request, sigParams); + assertNotNull(response); + } + + @Test + public void testBindTransferAccount() throws Exception { + WxMaXPayBindTransferAccountRequest request = WxMaXPayBindTransferAccountRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .transferAccountOrgName("") + .transferAccountUid(0L) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaBaseResponse response = this.wxService.getWxMaXPayService().bindTransferAccount(request, sigParams); + assertNotNull(response); + } + + @Test + public void testQueryFundsBill() throws Exception { + WxMaXPayQueryFundsBillRequest request = WxMaXPayQueryFundsBillRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .page(0) + .pageSize(10) + .filter(new WxMaXPayQueryFundsBillRequest.Filter()) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayQueryFundsBillResponse response = this.wxService.getWxMaXPayService().queryFundsBill(request, sigParams); + assertNotNull(response); + } + + + @Test + public void testQueryRecoverBill() throws Exception { + WxMaXPayQueryRecoverBillRequest request = WxMaXPayQueryRecoverBillRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .page(0) + .pageSize(10) + .filter(new WxMaXPayQueryRecoverBillRequest.Filter()) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayQueryRecoverBillResponse response = this.wxService.getWxMaXPayService().queryRecoverBill(request, sigParams); + assertNotNull(response); + } + + @Test + public void testGetComplaintList() throws Exception { + WxMaXPayGetComplaintListRequest request = WxMaXPayGetComplaintListRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .beginDate("") + .endDate("") + .offset(0) + .limit(10) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayGetComplaintListResponse response = this.wxService.getWxMaXPayService().getComplaintList(request, sigParams); + assertNotNull(response); + } + + @Test + public void testGetComplaintDetail() throws Exception { + WxMaXPayGetComplaintDetailRequest request = WxMaXPayGetComplaintDetailRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .complaintId("") + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayGetComplaintDetailResponse response = this.wxService.getWxMaXPayService().getComplaintDetail(request, sigParams); + assertNotNull(response); + } + + @Test + public void testGetNegotiationHistory() throws Exception { + WxMaXPayGetNegotiationHistoryRequest request = WxMaXPayGetNegotiationHistoryRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .limit(10) + .offset(0) + .complaintId("") + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayGetNegotiationHistoryResponse response = this.wxService.getWxMaXPayService().getNegotiationHistory(request, sigParams); + assertNotNull(response); + } + + @Test + public void testResponseComplaint() throws Exception { + WxMaXPayResponseComplaintRequest request = WxMaXPayResponseComplaintRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .complaintId("") + .responseContent("") + .responseImages(new ArrayList<>()) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaBaseResponse response = this.wxService.getWxMaXPayService().responseComplaint(request, sigParams); + assertNotNull(response); + } + + @Test + public void testCompleteComplaint() throws Exception { + WxMaXPayCompleteComplaintRequest request = WxMaXPayCompleteComplaintRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .complaintId("") + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaBaseResponse response = this.wxService.getWxMaXPayService().completeComplaint(request, sigParams); + assertNotNull(response); + } + + @Test + public void testUploadVpFile() throws Exception { + WxMaXPayUploadVpFileRequest request = WxMaXPayUploadVpFileRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .base64Img("") + .fileName("") + .imgUrl("") + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayUploadVpFileResponse response = this.wxService.getWxMaXPayService().uploadVpFile(request, sigParams); + assertNotNull(response); + } + + @Test + public void testGetUploadFileSign() throws Exception { + WxMaXPayGetUploadFileSignRequest request = WxMaXPayGetUploadFileSignRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .wxpayUrl("") + .complaintId("") + .convertCos(true) + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey(""); + WxMaXPayGetUploadFileSignResponse response = this.wxService.getWxMaXPayService().getUploadFileSign(request, sigParams); + assertNotNull(response); + } + + @Test + public void testDownloadAdverfundsOrder() throws Exception { + WxMaXPayDownloadAdverfundsOrderRequest request = WxMaXPayDownloadAdverfundsOrderRequest.builder() + .env(WxMaConstants.XPayEnv.PRODUCT) + .fundId("") + .build(); + WxMaXPaySigParams sigParams = new WxMaXPaySigParams(); + sigParams.setAppKey("123"); + WxMaXPayDownloadAdverfundsOrderResponse response = this.wxService.getWxMaXPayService().downloadAdverfundsOrder(request, sigParams); + assertNotNull(response); + } + } diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index 0aecd36da2..1fb7271d37 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java -4.7.2.B +4.7.8.B weixin-java-mp @@ -31,6 +31,11 @@okhttp provided
- * 新增永久图文素材 - * - * 详情请见: 新增永久素材 - * 接口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; - /** *
* 获取声音或者图片永久素材 @@ -212,22 +188,6 @@ public interface WxMpMaterialService { */ 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; - /** ** 删除永久素材 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/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java index 847f6e7ecf..ed8c5e6a79 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 @@ -89,7 +89,7 @@ public interface WxMpQrcodeService { * @throws WxErrorException the wx error exception */ @Deprecated - String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException; + String qrCodePictureUrl(String ticket, boolean needShortUrl) 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..47a24b7931 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 @@ -528,7 +528,7 @@ public interface WxMpService extends WxService { * * @return RequestHttp对象 request http */ - RequestHttp getRequestHttp(); + RequestHttp, ?> getRequestHttp(); /** * 返回群发消息相关接口方法的实现类对象,以方便调用其各个接口. diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java index 44ca69f3f3..0010932ca7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java @@ -11,11 +11,9 @@ * 门店管理的相关接口代码. * Created by Binary Wang on 2016-09-23. * - * @paramthe type parameter - * @param the type parameter * @author Binary Wang */ -public interface WxMpStoreService
{ +public interface WxMpStoreService { /** * * 创建门店 diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java index b2719301ec..63ca608eba 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java @@ -188,7 +188,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature) return SHA1.gen(this.getWxMpConfigStorage().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; } } @@ -649,7 +649,7 @@ public void setMaxRetryTimes(int maxRetryTimes) { } @Override - public RequestHttp getRequestHttp() { + public RequestHttpgetRequestHttp() { return this; } 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()); @@ -145,7 +145,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa param.addProperty("openid", openId); param.addProperty("is_mark", isMark); String responseContent = this.getWxMpService().post(WxMpApiUrl.Card.CARD_CODE_MARK, param.toString()); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonElement tmpJsonElement = JsonParser.parseString(responseContent); WxMpCardResult cardResult = WxMpGsonBuilder.create().fromJson(tmpJsonElement, new TypeToken () { }.getType()); @@ -166,7 +166,7 @@ public String getCardDetail(String cardId) throws WxErrorException { if (!"0".equals(errcode)) { String errmsg = json.get("errmsg").getAsString(); throw new WxErrorException(WxError.builder() - .errorCode(Integer.valueOf(errcode)).errorMsg(errmsg) + .errorCode(Integer.parseInt(errcode)).errorMsg(errmsg) .build()); } @@ -257,7 +257,7 @@ public WxMpCardDeleteResult deleteCard(String cardId) throws WxErrorException { @Override public WxMpCardCodeDepositResult cardCodeDeposit(String cardId, List codeList) throws WxErrorException { checkCardId(cardId); - if (codeList.size() == 0 || codeList.size() > 100) { + if (codeList.isEmpty() || codeList.size() > 100) { throw new WxErrorException(WxError.builder().errorCode(40109).errorMsg("code数量为0或者code数量超过100个").build()); } JsonObject param = new JsonObject(); @@ -283,7 +283,7 @@ public WxMpCardCodeDepositCountResult cardCodeDepositCount(String cardId) throws @Override public WxMpCardCodeCheckcodeResult cardCodeCheckcode(String cardId, List codeList) throws WxErrorException { checkCardId(cardId); - if (codeList.size() == 0 || codeList.size() > 100) { + if (codeList.isEmpty() || codeList.size() > 100) { throw new WxErrorException(WxError.builder().errorCode(40109).errorMsg("code数量为0或者code数量超过100个").build()); } JsonObject param = new JsonObject(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java index dd6256c3e8..94491a72f8 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java @@ -121,7 +121,7 @@ public WxMpGuideConfig getGuideConfig(String account, String openid) throws WxEr @Override public void setGuideAcctConfig(boolean isDelete, List blackKeyWord, String guideAutoReply) throws WxErrorException { JsonObject jsonObject1 = null; - if (blackKeyWord != null && blackKeyWord.size() > 0) { + if (blackKeyWord != null && !blackKeyWord.isEmpty()) { jsonObject1 = new JsonObject(); JsonArray jsonArray = new JsonArray(); blackKeyWord.forEach(jsonArray::add); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java index 11b0e4d2de..4680bee320 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java @@ -91,7 +91,7 @@ public List getGuideBuyerTag(String account, String openid, String userO 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
() { }.getType()); @@ -234,7 +229,7 @@ public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessa String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage)); - JsonElement tmpJsonElement = new JsonParser().parse(responseContent); + JsonElement tmpJsonElement = JsonParser.parseString(responseContent); return WxMpGsonBuilder.create().fromJson(tmpJsonElement, new TypeToken () { }.getType()); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java index 4631a2e2cc..361c0f52d1 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java @@ -12,7 +12,6 @@ import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.invoice.merchant.*; import me.chanjar.weixin.mp.enums.WxMpApiUrl; -import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; import java.util.Map; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java index 7bad648cb5..5719f4bb46 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java @@ -2,7 +2,6 @@ import com.google.gson.JsonObject; import lombok.RequiredArgsConstructor; -import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpQrcodeService; import me.chanjar.weixin.mp.api.WxMpService; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java index 750f787137..c61fd09b9f 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java @@ -1,18 +1,17 @@ package me.chanjar.weixin.mp.api.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.ApacheBasicResponseHandler; import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest; import me.chanjar.weixin.mp.config.WxMpConfigStorage; 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; @@ -40,8 +39,8 @@ public HttpHost getRequestHttpProxy() { } @Override - public HttpType getRequestType() { - return HttpType.APACHE_HTTP; + public HttpClientType getRequestType() { + return HttpClientType.APACHE_HTTP; } @Override @@ -68,61 +67,31 @@ public void initHttp() { protected String doGetAccessTokenRequest() throws IOException { String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().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 = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()); - 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); - } - WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest(); - wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId()); - wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().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) { - } - } + HttpPost httpPost = new HttpPost(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpPost.setConfig(config); } + WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest(); + wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId()); + wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().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-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpComponentsImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpComponentsImpl.java new file mode 100644 index 0000000000..bbf065acfc --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpComponentsImpl.java @@ -0,0 +1,94 @@ +package me.chanjar.weixin.mp.api.impl; + +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.mp.bean.WxMpStableAccessTokenRequest; +import me.chanjar.weixin.mp.config.WxMpConfigStorage; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.StringEntity; + +import java.io.IOException; + +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL; +import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_STABLE_ACCESS_TOKEN_URL; + +/** + * apache http client方式实现. + * + * @author altusea + */ +public class WxMpServiceHttpComponentsImpl extends BaseWxMpServiceImpl { + 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() { + WxMpConfigStorage configStorage = this.getWxMpConfigStorage(); + HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get(); + + apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost()) + .httpProxyPort(configStorage.getHttpProxyPort()) + .httpProxyUsername(configStorage.getHttpProxyUsername()) + .httpProxyPassword(configStorage.getHttpProxyPassword().toCharArray()); + + if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) { + this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort()); + } + + this.httpClient = apacheHttpClientBuilder.build(); + } + + @Override + protected String doGetAccessTokenRequest() throws IOException { + String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().getSecret()); + + HttpGet httpGet = new HttpGet(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + return getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE); + } + + @Override + protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException { + String url = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()); + + HttpPost httpPost = new HttpPost(url); + if (this.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest(); + wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId()); + wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().getSecret()); + wxMaAccessTokenRequest.setGrantType("client_credential"); + wxMaAccessTokenRequest.setForceRefresh(forceRefresh); + + httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON)); + return getRequestHttpClient().execute(httpPost, BasicResponseHandler.INSTANCE); + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java index b174c4bdf9..7f67b3478b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java @@ -5,7 +5,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 me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest; import me.chanjar.weixin.mp.config.WxMpConfigStorage; @@ -35,8 +35,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-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java index 86555aa4a1..8bd4b2a227 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java @@ -1,6 +1,6 @@ package me.chanjar.weixin.mp.api.impl; -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.mp.bean.WxMpStableAccessTokenRequest; @@ -33,8 +33,8 @@ public OkHttpProxyInfo getRequestHttpProxy() { } @Override - public HttpType getRequestType() { - return HttpType.OK_HTTP; + public HttpClientType getRequestType() { + return HttpClientType.OK_HTTP; } @Override diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java index e1378efc5c..a71a753ecd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java @@ -86,7 +86,7 @@ public List listAll() throws WxErrorException { if (list.getTotalCount() > limit) { int begin = limit; WxMpStoreListResult followingList = this.list(begin, limit); - while (followingList.getBusinessList().size() > 0) { + while (!followingList.getBusinessList().isEmpty()) { stores.addAll(followingList.getBusinessList()); begin += limit; if (begin >= list.getTotalCount()) { diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java index 0b75bb996b..2eca3fccea 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java @@ -46,11 +46,7 @@ public boolean updateShopWifiInfo(int shopId, String oldSsid, String ssid, Strin if (password != null) { json.addProperty("password", password); } - try { - this.wxMpService.post(BIZWIFI_SHOP_UPDATE, json.toString()); - return true; - } catch (WxErrorException e) { - throw e; - } + this.wxMpService.post(BIZWIFI_SHOP_UPDATE, json.toString()); + return true; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java index 4cd6430000..3c053480dd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java @@ -26,7 +26,7 @@ public static WxMpShakeInfoResult fromJson(String json) { } @Data - public class ShakeInfoData implements Serializable { + public static class ShakeInfoData implements Serializable { private static final long serialVersionUID = -4828142206067489488L; private String page_id; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java index 3ae9cf8937..999cac43ce 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java @@ -9,7 +9,7 @@ public enum BusinessServiceType { BIZ_SERVICE_WITH_PET("可带宠物"), BIZ_SERVICE_FREE_WIFI("可带宠物"); - private String description; + private final String description; BusinessServiceType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java index 35263188e0..61fb137701 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java @@ -9,7 +9,7 @@ public enum CardCodeType { CODE_TYPE_BARCODE("一维码"), CODE_TYPE_QRCODE("二维码"); - private String description; + private final String description; CardCodeType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java index a694d4d372..594a78b58b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java @@ -22,7 +22,7 @@ public enum CardColor { Color101("#cf3e36"), Color102("#5E6671"); - private String type; + private final String type; CardColor(String type) { this.type = type; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java index 42804b635b..e4f69d42a4 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java @@ -11,7 +11,7 @@ public enum CardFieldType { CUSTOM_FIELD("自定义选项"), RICH_FIELD("自定义富文本类型"); - private String description; + private final String description; CardFieldType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java index 7659864939..eac1625d6c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java @@ -11,7 +11,7 @@ public enum CardRichFieldType { FORM_FIELD_SELECT("自定义选择项"), FORM_FIELD_CHECK_BOX("自定义多选"); - private String description; + private final String description; CardRichFieldType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java index ec5b9fcfbc..429dcacdea 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java @@ -9,7 +9,7 @@ public enum CardSceneType { SCENE_IVR("自动回复"), SCENE_CARD_CUSTOM_CELL("卡券自定义cell"); - private String description; + private final String description; CardSceneType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java index 4108b7d4c2..bcb414aa6c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java @@ -7,7 +7,7 @@ public enum CardStatusType { CARD_STATUS_DELETE("卡券被商户删除"), CARD_STATUS_DISPATCH("在公众平台投放过的卡券"); - private String description; + private final String description; CardStatusType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java index c34bd58ace..9dc7f5d427 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java @@ -23,7 +23,7 @@ public enum CardWechatFieldType { USER_FORM_INFO_FLAG_INCOME("收入"), USER_FORM_INFO_FLAG_HABIT("兴趣爱好"); - private String description; + private final String description; CardWechatFieldType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java index 53f3df8cf9..e6bea61685 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java @@ -14,7 +14,7 @@ public enum CustomFieldNameType { FIELD_NAME_TYPE_SET_POINTS("集点"), FIELD_NAME_TYPE_TIMS("次数"); - private String description; + private final String description; CustomFieldNameType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java index bd8a23551c..93893dfa12 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java @@ -5,7 +5,7 @@ public enum DateInfoType { DATE_TYPE_FIX_TIME_RANGE("固定日期"), DATE_TYPE_FIX_TERM("固定时长"); - private String description; + private final String description; DateInfoType(String description) { this.description = description; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java index a0b65c8842..128e2d2528 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java @@ -21,7 +21,7 @@ public class BaseResp extends AbstractDeviceBean { private String errMsg; @Data - private class BaseInfo { + private static class BaseInfo { @SerializedName("device_type") private String deviceType; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java index 80a7d37d4b..db37c66d10 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java @@ -23,6 +23,13 @@ @NoArgsConstructor @AllArgsConstructor public class WxMpDraftArticles implements ToJson, Serializable { + /** + * 文章类型,分别有图文消息(news)、图片消息(newspic),不填默认为图文消息(news) + * + * @see me.chanjar.weixin.common.api.WxConsts.ArticleType + */ + @SerializedName("article_type") + private String articleType; /** * 标题 */ @@ -78,18 +85,31 @@ public class WxMpDraftArticles implements ToJson, Serializable { */ @SerializedName("thumb_url") private String thumbUrl; - /** * 封面裁剪为2.35:1规格的坐标字段。以原始图片(thumb_media_id)左上角(0,0),右下角(1,1)建立平面坐标系,经过裁剪后的图片,其左上角所在的坐标即为(X1,Y1),右下角所在的坐标则为(X2,Y2),用分隔符_拼接为X1_Y1_X2_Y2,每个坐标值的精度为不超过小数点后6位数字。示例见下图,图中(X1,Y1) 等于(0.1945,0),(X2,Y2)等于(1,0.5236),所以请求参数值为0.1945_0_1_0.5236。 */ @SerializedName("pic_crop_235_1") private String picCrop2351; - /** * 封面裁剪为1:1规格的坐标字段,裁剪原理同pic_crop_235_1,裁剪后的图片必须符合规格要求。 */ @SerializedName("pic_crop_1_1") private String picCrop11; + /** + * 图片消息里的图片相关信息,图片数量最多为20张,首张图片即为封面图 + */ + @SerializedName("image_info") + private WxMpDraftImageInfo imageInfo; + /** + * 封面图裁剪信息 + */ + @SerializedName("cover_info") + private WxMpDraftCoverInfo coverInfo; + /** + * 商品相关信息 + */ + @SerializedName("product_info") + private WxMpDraftProductInfo productInfo; public static WxMpDraftArticles fromJson(String json) { return WxGsonBuilder.create().fromJson(json, WxMpDraftArticles.class); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftCoverInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftCoverInfo.java new file mode 100644 index 0000000000..9b2ba09325 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftCoverInfo.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.mp.bean.draft; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 草稿箱能力-图片消息里的封面裁剪信息 + * + * @author 阿杆 + * created on 2025/5/23 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpDraftCoverInfo implements Serializable { + + private static final long serialVersionUID = -1676442833397632638L; + + /** + * 封面裁剪信息,裁剪比例ratio支持:“1_1”,“16_9”,“2.35_1”。 + * 以图片左上角(0,0),右下角(1,1)建立平面坐标系,经过裁剪后的图片,其左上角所在的坐标填入x1,y1参数,右下角所在的坐标填入x2,y2参数 + */ + @SerializedName("crop_percent_list") + private List cropPercentList; + + public static WxMpDraftCoverInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpDraftCoverInfo.class); + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CropPercent implements Serializable { + private static final long serialVersionUID = 8495528870408737871L; + private String ratio; + private String x1; + private String y1; + private String x2; + private String y2; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftImageInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftImageInfo.java new file mode 100644 index 0000000000..0f2af9f45b --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftImageInfo.java @@ -0,0 +1,51 @@ +package me.chanjar.weixin.mp.bean.draft; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 草稿箱能力-图片消息里的图片相关信息 + * + * @author 阿杆 + * created on 2025/5/23 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpDraftImageInfo implements Serializable { + + private static final long serialVersionUID = -1997245511033770476L; + + /** + * 图片列表 + */ + @SerializedName("image_list") + private List imageList; + + public static WxMpDraftImageInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpDraftImageInfo.class); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ImageItem implements Serializable { + private static final long serialVersionUID = 4180558781166966752L; + /** + * 图片消息里的图片素材id(必须是永久MediaID) + */ + @SerializedName("image_media_id") + private String imageMediaId; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftProductInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftProductInfo.java new file mode 100644 index 0000000000..1d6016d7a1 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftProductInfo.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.mp.bean.draft; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; + +import java.io.Serializable; + +/** + * 草稿箱能力-商品相关信息 + * + * @author 阿杆 + * created on 2025/5/23 + */ +@Data +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +public class WxMpDraftProductInfo implements Serializable { + private static final long serialVersionUID = 8637785998127610863L; + + /** + * 文末插入商品相关信息 + */ + @SerializedName("footer_product_info") + private FooterProductInfo footerProductInfo; + + public static WxMpDraftProductInfo fromJson(String json) { + return WxGsonBuilder.create().fromJson(json, WxMpDraftProductInfo.class); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class FooterProductInfo { + /** + * 商品key + */ + @SerializedName("product_key") + private String productKey; + } + +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java index cd701d1efc..72e6e615f7 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java @@ -15,7 +15,7 @@ public class WxMpMapConfigImpl extends WxMpDefaultConfigImpl { private static final long serialVersionUID = 5311395137835650104L; - private static final ConcurrentHashMap CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(1); + private final ConcurrentHashMap CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(1); private static final String MAP_KEY = "access_token"; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java index b37772b01a..5049e88565 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java @@ -21,7 +21,7 @@ public enum AiLangType { */ en_US("en_US"); - private String code; + private final String code; AiLangType(String code) { this.code = code; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java index 568f3cdedb..bb360eba3a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java @@ -14,7 +14,7 @@ public enum WxCardType { GIFT("GIFT"), GENERAL_COUPON("GENERAL_COUPON"); - private String code; + private final String code; WxCardType(String code) { this.code = code; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java index b5e0dd8847..1a2f7a9d3c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java @@ -5,12 +5,7 @@ * created on 2019-03-20 22:06 */ public class WxMpConfigStorageHolder { - private static final ThreadLocal THREAD_LOCAL = new ThreadLocal () { - @Override - protected String initialValue() { - return "default"; - } - }; + private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(() -> "default"); public static String get() { return THREAD_LOCAL.get(); diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java index b14023ef91..99d759f32f 100755 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java @@ -17,8 +17,6 @@ */ package me.chanjar.weixin.mp.util.crypto; -import com.google.common.base.CharMatcher; -import com.google.common.io.BaseEncoding; import me.chanjar.weixin.mp.config.WxMpConfigStorage; import org.apache.commons.lang3.StringUtils; diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java index 72fcaf1b3f..3d5cc58e7a 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; 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.CloseableHttpClient; @@ -21,7 +20,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialDeleteApacheHttpRequestExecutor extends MaterialDeleteRequestExecutor { - public MaterialDeleteApacheHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialDeleteApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -36,16 +35,11 @@ public Boolean execute(String uri, String materialId, WxType wxType) throws WxEr Map params = new HashMap<>(); params.put("media_id", materialId); httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent, WxType.MP); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return true; - } - } finally { - httpPost.releaseConnection(); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); } + return true; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..46f8f16988 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteHttpComponentsRequestExecutor.java @@ -0,0 +1,42 @@ +package me.chanjar.weixin.mp.util.requestexecuter.material; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +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.util.HashMap; +import java.util.Map; + +public class MaterialDeleteHttpComponentsRequestExecutor extends MaterialDeleteRequestExecutor { + public MaterialDeleteHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return true; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java index 318299bb34..5e8d5ee8f5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java @@ -4,7 +4,6 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.StringPool; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; @@ -18,7 +17,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialDeleteJoddHttpRequestExecutor extends MaterialDeleteRequestExecutor { - public MaterialDeleteJoddHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialDeleteJoddHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java index ed9aaa8a84..7ad3ebb6fd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java @@ -23,7 +23,7 @@ public class MaterialDeleteOkhttpRequestExecutor extends MaterialDeleteRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MaterialDeleteOkhttpRequestExecutor(RequestHttp requestHttp) { + public MaterialDeleteOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java index 18e696938b..a6dea564e2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java @@ -1,17 +1,21 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; -import java.io.IOException; - +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; + +import java.io.IOException; public abstract class MaterialDeleteRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public MaterialDeleteRequestExecutor(RequestHttp requestHttp) { + public MaterialDeleteRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -20,16 +24,21 @@ public void execute(String uri, String data, ResponseHandler handler, W handler.handle(this.execute(uri, data, wxType)); } - public static RequestExecutor create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new MaterialDeleteApacheHttpRequestExecutor(requestHttp); + return new MaterialDeleteApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new MaterialDeleteJoddHttpRequestExecutor(requestHttp); + return new MaterialDeleteJoddHttpRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new MaterialDeleteOkhttpRequestExecutor(requestHttp); + return new MaterialDeleteOkhttpRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new MaterialDeleteHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java index a4c92cd55c..0059e17295 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java @@ -29,7 +29,7 @@ public class MaterialNewsInfoApacheHttpRequestExecutor extends MaterialNewsInfoRequestExecutor { - public MaterialNewsInfoApacheHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialNewsInfoApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -51,8 +51,6 @@ public WxMpMaterialNews execute(String uri, String materialId, WxType wxType) th } else { return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); } - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..ddf3ad6762 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoHttpComponentsRequestExecutor.java @@ -0,0 +1,46 @@ +package me.chanjar.weixin.mp.util.requestexecuter.material; + +import com.google.common.collect.ImmutableMap; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; +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; + +@Slf4j +public class MaterialNewsInfoHttpComponentsRequestExecutor extends MaterialNewsInfoRequestExecutor { + + public MaterialNewsInfoHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialNews execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(ImmutableMap.of("media_id", materialId)))); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + log.debug("响应原始数据:{}", responseContent); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java index 780c0734e1..d1be53b923 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java @@ -5,7 +5,6 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.StringPool; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.enums.WxType; @@ -15,8 +14,6 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -26,7 +23,7 @@ */ @Slf4j public class MaterialNewsInfoJoddHttpRequestExecutor extends MaterialNewsInfoRequestExecutor { - public MaterialNewsInfoJoddHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialNewsInfoJoddHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java index 2e3f14dddd..25e0074e9e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java @@ -22,7 +22,7 @@ */ @Slf4j public class MaterialNewsInfoOkhttpRequestExecutor extends MaterialNewsInfoRequestExecutor { - public MaterialNewsInfoOkhttpRequestExecutor(RequestHttp requestHttp) { + public MaterialNewsInfoOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java index 41374809c6..ca06327abd 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java @@ -1,18 +1,22 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; -import java.io.IOException; - +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; +import okhttp3.OkHttpClient; + +import java.io.IOException; public abstract class MaterialNewsInfoRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { + public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -21,17 +25,21 @@ public void execute(String uri, String data, ResponseHandler h handler.handle(this.execute(uri, data, wxType)); } - public static RequestExecutor create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new MaterialNewsInfoApacheHttpRequestExecutor(requestHttp); + return new MaterialNewsInfoApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new MaterialNewsInfoJoddHttpRequestExecutor(requestHttp); + return new MaterialNewsInfoJoddHttpRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new MaterialNewsInfoOkhttpRequestExecutor(requestHttp); + return new MaterialNewsInfoOkhttpRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new MaterialNewsInfoHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - //TODO 需要优化抛出异常 - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java index 6a31484420..bf1b42fb9b 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java @@ -8,7 +8,6 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; -import org.apache.http.Consts; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; @@ -22,13 +21,14 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Map; /** * Created by ecoolper on 2017/5/5. */ public class MaterialUploadApacheHttpRequestExecutor extends MaterialUploadRequestExecutor { - public MaterialUploadApacheHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialUploadApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -56,7 +56,7 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxTyp Map form = material.getForm(); if (material.getForm() != null) { multipartEntityBuilder.addPart("description", - new StringBody(WxGsonBuilder.create().toJson(form), ContentType.create("text/plain", Consts.UTF_8))); + new StringBody(WxGsonBuilder.create().toJson(form), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8))); } httpPost.setEntity(multipartEntityBuilder.build()); @@ -68,8 +68,6 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxTyp } else { return WxMpMaterialUploadResult.fromJson(responseContent); } - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..05ae0fe506 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadHttpComponentsRequestExecutor.java @@ -0,0 +1,67 @@ +package me.chanjar.weixin.mp.util.requestexecuter.material; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterial; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.entity.mime.StringBody; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +public class MaterialUploadHttpComponentsRequestExecutor extends MaterialUploadRequestExecutor { + public MaterialUploadHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig response = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(response); + } + + if (material == null) { + throw new WxErrorException("非法请求,material参数为空"); + } + + File file = material.getFile(); + if (file == null || !file.exists()) { + throw new FileNotFoundException(); + } + + MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create(); + multipartEntityBuilder + .addBinaryBody("media", file) + .setMode(HttpMultipartMode.EXTENDED); + Map form = material.getForm(); + if (material.getForm() != null) { + multipartEntityBuilder.addPart("description", + new StringBody(WxGsonBuilder.create().toJson(form), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8))); + } + httpPost.setEntity(multipartEntityBuilder.build()); + + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialUploadResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java index d4c4dfbf89..23740328f2 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java @@ -4,7 +4,6 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.StringPool; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; @@ -24,7 +23,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialUploadJoddHttpRequestExecutor extends MaterialUploadRequestExecutor { - public MaterialUploadJoddHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialUploadJoddHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java index 7416f94f0e..20e4622415 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java @@ -23,7 +23,7 @@ public class MaterialUploadOkhttpRequestExecutor extends MaterialUploadRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MaterialUploadOkhttpRequestExecutor(RequestHttp requestHttp) { + public MaterialUploadOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java index 9044d052a8..76ad3f88fa 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java @@ -1,14 +1,18 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; -import java.io.IOException; - +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMpMaterial; import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult; +import okhttp3.OkHttpClient; + +import java.io.IOException; /** * @author codepiano @@ -16,7 +20,7 @@ public abstract class MaterialUploadRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public MaterialUploadRequestExecutor(RequestHttp requestHttp) { + public MaterialUploadRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -25,16 +29,21 @@ public void execute(String uri, WxMpMaterial data, ResponseHandler create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new MaterialUploadApacheHttpRequestExecutor(requestHttp); + return new MaterialUploadApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new MaterialUploadJoddHttpRequestExecutor(requestHttp); + return new MaterialUploadJoddHttpRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new MaterialUploadOkhttpRequestExecutor(requestHttp); + return new MaterialUploadOkhttpRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new MaterialUploadHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java index 7034379fbe..387ed50c9e 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java @@ -9,7 +9,6 @@ import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; 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.CloseableHttpClient; @@ -22,7 +21,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialVideoInfoApacheHttpRequestExecutor extends MaterialVideoInfoRequestExecutor { - public MaterialVideoInfoApacheHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialVideoInfoApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -37,16 +36,12 @@ public WxMpMaterialVideoInfoResult execute(String uri, String materialId, WxType Map params = new HashMap<>(); params.put("media_id", materialId); httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent, WxType.MP); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } else { - return WxMpMaterialVideoInfoResult.fromJson(responseContent); - } - } finally { - httpPost.releaseConnection(); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..2a147609d5 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoHttpComponentsRequestExecutor.java @@ -0,0 +1,44 @@ +package me.chanjar.weixin.mp.util.requestexecuter.material; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +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.util.HashMap; +import java.util.Map; + +public class MaterialVideoInfoHttpComponentsRequestExecutor extends MaterialVideoInfoRequestExecutor { + public MaterialVideoInfoHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMpMaterialVideoInfoResult execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } else { + return WxMpMaterialVideoInfoResult.fromJson(responseContent); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java index 9149d46794..1ea90199fb 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java @@ -4,7 +4,6 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.StringPool; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; @@ -19,7 +18,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialVideoInfoJoddHttpRequestExecutor extends MaterialVideoInfoRequestExecutor { - public MaterialVideoInfoJoddHttpRequestExecutor(RequestHttp requestHttp) { + public MaterialVideoInfoJoddHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java index 2e38ab003b..d548fcb4ae 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java @@ -20,7 +20,7 @@ public class MaterialVideoInfoOkhttpRequestExecutor extends MaterialVideoInfoRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MaterialVideoInfoOkhttpRequestExecutor(RequestHttp requestHttp) { + public MaterialVideoInfoOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java index 5ea6fae0b2..b4073c7fec 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java @@ -1,19 +1,22 @@ package me.chanjar.weixin.mp.util.requestexecuter.material; - -import java.io.IOException; - +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult; +import okhttp3.OkHttpClient; + +import java.io.IOException; public abstract class MaterialVideoInfoRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { + public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -22,16 +25,21 @@ public void execute(String uri, String data, ResponseHandler create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new MaterialVideoInfoApacheHttpRequestExecutor(requestHttp); + return new MaterialVideoInfoApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new MaterialVideoInfoJoddHttpRequestExecutor(requestHttp); + return new MaterialVideoInfoJoddHttpRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new MaterialVideoInfoOkhttpRequestExecutor(requestHttp); + return new MaterialVideoInfoOkhttpRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new MaterialVideoInfoHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java index d11591edf1..05395319cc 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java @@ -26,7 +26,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialVoiceAndImageDownloadApacheHttpRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { - public MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + public MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } @@ -57,8 +57,6 @@ public InputStream execute(String uri, String materialId, WxType wxType) throws } } return new ByteArrayInputStream(responseContent); - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..ac7df1a0ce --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor.java @@ -0,0 +1,64 @@ +package me.chanjar.weixin.mp.util.requestexecuter.material; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.json.WxGsonBuilder; +import org.apache.commons.io.IOUtils; +import org.apache.hc.client5.http.ClientProtocolException; +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.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.StringEntity; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor + extends MaterialVoiceAndImageDownloadRequestExecutor { + public MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + super(requestHttp, tmpDirFile); + } + + @Override + public InputStream execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException { + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + Map params = new HashMap<>(); + params.put("media_id", materialId); + httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params))); + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { + // 下载媒体文件出错 + byte[] responseContent = IOUtils.toByteArray(inputStream); + String responseContentString = new String(responseContent, StandardCharsets.UTF_8); + if (responseContentString.length() <= 215) { + try { + WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class); + if (wxError.getErrorCode() != 0) { + throw new WxErrorException(wxError); + } + } catch (com.google.gson.JsonSyntaxException ex) { + return new ByteArrayInputStream(responseContent); + } + } + return new ByteArrayInputStream(responseContent); + } catch (HttpException httpException) { + throw new ClientProtocolException(httpException.getMessage(), httpException); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java index c946e9b4b6..b1264864e5 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java @@ -4,7 +4,6 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.StringPool; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; @@ -23,7 +22,7 @@ * Created by ecoolper on 2017/5/5. */ public class MaterialVoiceAndImageDownloadJoddHttpRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { - public MaterialVoiceAndImageDownloadJoddHttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + public MaterialVoiceAndImageDownloadJoddHttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java index b77958a4e9..3823440490 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java @@ -8,8 +8,6 @@ import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import okhttp3.*; -import okio.BufferedSink; -import okio.Okio; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +20,7 @@ public class MaterialVoiceAndImageDownloadOkhttpRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MaterialVoiceAndImageDownloadOkhttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + public MaterialVoiceAndImageDownloadOkhttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { super(requestHttp, tmpDirFile); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java index b482ddbcd1..42994a7423 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java @@ -4,17 +4,21 @@ import java.io.IOException; import java.io.InputStream; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; +import okhttp3.OkHttpClient; public abstract class MaterialVoiceAndImageDownloadRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; protected File tmpDirFile; - public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { + public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { this.requestHttp = requestHttp; this.tmpDirFile = tmpDirFile; } @@ -24,16 +28,21 @@ public void execute(String uri, String data, ResponseHandler handle handler.handle(this.execute(uri, data, wxType)); } - public static RequestExecutor create(RequestHttp requestHttp, File tmpDirFile) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp, File tmpDirFile) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(requestHttp, tmpDirFile); + return new MaterialVoiceAndImageDownloadApacheHttpRequestExecutor( + (RequestHttp ) requestHttp, tmpDirFile); case JODD_HTTP: - return new MaterialVoiceAndImageDownloadJoddHttpRequestExecutor(requestHttp, tmpDirFile); + return new MaterialVoiceAndImageDownloadJoddHttpRequestExecutor((RequestHttp ) requestHttp, tmpDirFile); case OK_HTTP: - return new MaterialVoiceAndImageDownloadOkhttpRequestExecutor(requestHttp, tmpDirFile); + return new MaterialVoiceAndImageDownloadOkhttpRequestExecutor((RequestHttp ) requestHttp, tmpDirFile); + case HTTP_COMPONENTS: + return new MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp, tmpDirFile); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java index 7c4ba18598..495f144f3d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java @@ -11,7 +11,6 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; @@ -25,7 +24,7 @@ * @author ecoolper */ public class MediaImgUploadApacheHttpRequestExecutor extends MediaImgUploadRequestExecutor { - public MediaImgUploadApacheHttpRequestExecutor(RequestHttp requestHttp) { + public MediaImgUploadApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -56,8 +55,6 @@ public WxMediaImgUploadResult execute(String uri, File data, WxType wxType) thro } return WxMediaImgUploadResult.fromJson(responseContent); - } finally { - httpPost.releaseConnection(); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..be1d12631d --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpComponentsRequestExecutor.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.mp.util.requestexecuter.media; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.IOException; + +public class MediaImgUploadHttpComponentsRequestExecutor extends MediaImgUploadRequestExecutor { + public MediaImgUploadHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public WxMediaImgUploadResult execute(String uri, File data, WxType wxType) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException("文件对象为空"); + } + + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", data) + .setMode(HttpMultipartMode.EXTENDED) + .build(); + httpPost.setEntity(entity); + + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + + return WxMediaImgUploadResult.fromJson(responseContent); + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java index 1ca4c7c8bf..138d8b5d3d 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java @@ -4,7 +4,6 @@ import jodd.http.HttpRequest; import jodd.http.HttpResponse; import jodd.http.ProxyInfo; -import jodd.util.StringPool; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; @@ -22,7 +21,7 @@ * @author ecoolper */ public class MediaImgUploadHttpRequestExecutor extends MediaImgUploadRequestExecutor { - public MediaImgUploadHttpRequestExecutor(RequestHttp requestHttp) { + public MediaImgUploadHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java index 27677b74b4..7a6a980afe 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java @@ -21,7 +21,7 @@ public class MediaImgUploadOkhttpRequestExecutor extends MediaImgUploadRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public MediaImgUploadOkhttpRequestExecutor(RequestHttp requestHttp) { + public MediaImgUploadOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java index b5f42e0f8d..40a9d47155 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java @@ -3,12 +3,16 @@ import java.io.File; import java.io.IOException; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import okhttp3.OkHttpClient; /** * @author miller @@ -16,7 +20,7 @@ public abstract class MediaImgUploadRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public MediaImgUploadRequestExecutor(RequestHttp requestHttp) { + public MediaImgUploadRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -25,16 +29,21 @@ public void execute(String uri, File data, ResponseHandler create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new MediaImgUploadApacheHttpRequestExecutor(requestHttp); + return new MediaImgUploadApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new MediaImgUploadHttpRequestExecutor(requestHttp); + return new MediaImgUploadHttpRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new MediaImgUploadOkhttpRequestExecutor(requestHttp); + return new MediaImgUploadOkhttpRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new MediaImgUploadHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java index 2c8e5b5721..3ff6a5a369 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java @@ -26,7 +26,7 @@ * Created by ecoolper on 2017/5/5. */ public class QrCodeApacheHttpRequestExecutor extends QrCodeRequestExecutor { - public QrCodeApacheHttpRequestExecutor(RequestHttp requestHttp) { + public QrCodeApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -59,8 +59,6 @@ public File execute(String uri, WxMpQrCodeTicket ticket, WxType wxType) throws W } } return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); - } finally { - httpGet.releaseConnection(); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..fbf8af0783 --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeHttpComponentsRequestExecutor.java @@ -0,0 +1,67 @@ +package me.chanjar.weixin.mp.util.requestexecuter.qrcode; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import org.apache.hc.client5.http.ClientProtocolException; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * @author altusea + */ +public class QrCodeHttpComponentsRequestExecutor extends QrCodeRequestExecutor { + public QrCodeHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public File execute(String uri, WxMpQrCodeTicket ticket, WxType wxType) throws WxErrorException, IOException { + if (ticket != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") + ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8") + : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8"); + } + + HttpGet httpGet = new HttpGet(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet); + InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) { + Header[] contentTypeHeader = response.getHeaders("Content-Type"); + if (contentTypeHeader != null && contentTypeHeader.length > 0) { + // 出错 + if (ContentType.TEXT_PLAIN.getMimeType().equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MP)); + } + } + return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg"); + } catch (HttpException httpException) { + throw new ClientProtocolException(httpException.getMessage(), httpException); + } + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java index 32d3d3ca75..9fcf7768ae 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java @@ -5,7 +5,6 @@ import jodd.http.HttpResponse; import jodd.http.ProxyInfo; import jodd.net.MimeTypes; -import jodd.util.StringPool; import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxError; @@ -26,7 +25,7 @@ * Created by ecoolper on 2017/5/5. */ public class QrCodeJoddHttpRequestExecutor extends QrCodeRequestExecutor { - public QrCodeJoddHttpRequestExecutor(RequestHttp requestHttp) { + public QrCodeJoddHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java index f6f2036ce1..42289e775c 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java @@ -27,7 +27,7 @@ public class QrCodeOkhttpRequestExecutor extends QrCodeRequestExecutor { private final Logger logger = LoggerFactory.getLogger(this.getClass()); - public QrCodeOkhttpRequestExecutor(RequestHttp requestHttp) { + public QrCodeOkhttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java index 4ca5dbc0c1..6407ac11ad 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java @@ -3,13 +3,16 @@ import java.io.File; import java.io.IOException; +import jodd.http.HttpConnectionProvider; +import jodd.http.ProxyInfo; import me.chanjar.weixin.common.enums.WxType; -import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo; import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket; +import okhttp3.OkHttpClient; /** * 获得QrCode图片 请求执行器. @@ -19,7 +22,7 @@ public abstract class QrCodeRequestExecutor implements RequestExecutor { protected RequestHttp requestHttp; - public QrCodeRequestExecutor(RequestHttp requestHttp) { + public QrCodeRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -28,16 +31,21 @@ public void execute(String uri, WxMpQrCodeTicket data, ResponseHandler han handler.handle(this.execute(uri, data, wxType)); } - public static RequestExecutor create(RequestHttp requestHttp) throws WxErrorException { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new QrCodeApacheHttpRequestExecutor(requestHttp); + return new QrCodeApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); case JODD_HTTP: - return new QrCodeJoddHttpRequestExecutor(requestHttp); + return new QrCodeJoddHttpRequestExecutor((RequestHttp ) requestHttp); case OK_HTTP: - return new QrCodeOkhttpRequestExecutor(requestHttp); + return new QrCodeOkhttpRequestExecutor((RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new QrCodeHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - throw new WxErrorException("不支持的http框架"); + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java index 06aa1fcda1..f384f8f567 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java @@ -8,9 +8,7 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; @@ -26,7 +24,7 @@ * @author Binary Wang */ public class VoiceUploadApacheHttpRequestExecutor extends VoiceUploadRequestExecutor { - public VoiceUploadApacheHttpRequestExecutor(RequestHttp requestHttp) { + public VoiceUploadApacheHttpRequestExecutor(RequestHttp requestHttp) { super(requestHttp); } @@ -49,16 +47,11 @@ public Boolean execute(String uri, File data, WxType wxType) throws WxErrorExcep .build(); httpPost.setEntity(entity); - try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { - String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); - WxError error = WxError.fromJson(responseContent, WxType.MP); - if (error.getErrorCode() != 0) { - throw new WxErrorException(error); - } - - return true; - } finally { - httpPost.releaseConnection(); + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); } + return true; } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadHttpComponentsRequestExecutor.java new file mode 100644 index 0000000000..1775f04aef --- /dev/null +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadHttpComponentsRequestExecutor.java @@ -0,0 +1,50 @@ +package me.chanjar.weixin.mp.util.requestexecuter.voice; + +import me.chanjar.weixin.common.enums.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHost; + +import java.io.File; +import java.io.IOException; + +public class VoiceUploadHttpComponentsRequestExecutor extends VoiceUploadRequestExecutor { + public VoiceUploadHttpComponentsRequestExecutor(RequestHttp requestHttp) { + super(requestHttp); + } + + @Override + public Boolean execute(String uri, File data, WxType wxType) throws WxErrorException, IOException { + if (data == null) { + throw new WxErrorException("文件对象为空"); + } + + HttpPost httpPost = new HttpPost(uri); + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + HttpEntity entity = MultipartEntityBuilder + .create() + .addBinaryBody("media", data) + .setMode(HttpMultipartMode.EXTENDED) + .build(); + httpPost.setEntity(entity); + + String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE); + WxError error = WxError.fromJson(responseContent, WxType.MP); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return true; + } +} diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java index fa48c953f6..e8eb7cb9e9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java @@ -1,14 +1,14 @@ package me.chanjar.weixin.mp.util.requestexecuter.voice; -import java.io.File; -import java.io.IOException; - import me.chanjar.weixin.common.enums.WxType; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.RequestExecutor; import me.chanjar.weixin.common.util.http.RequestHttp; import me.chanjar.weixin.common.util.http.ResponseHandler; +import java.io.File; +import java.io.IOException; + /** * * Created by BinaryWang on 2018/6/9. @@ -19,7 +19,7 @@ public abstract class VoiceUploadRequestExecutorimplements RequestExecutor { protected RequestHttp requestHttp; - public VoiceUploadRequestExecutor(RequestHttp requestHttp) { + public VoiceUploadRequestExecutor(RequestHttp requestHttp) { this.requestHttp = requestHttp; } @@ -28,14 +28,17 @@ public void execute(String uri, File data, ResponseHandler handler, WxT handler.handle(this.execute(uri, data, wxType)); } - public static RequestExecutor create(RequestHttp requestHttp) { + @SuppressWarnings("unchecked") + public static RequestExecutor create(RequestHttp, ?> requestHttp) { switch (requestHttp.getRequestType()) { case APACHE_HTTP: - return new VoiceUploadApacheHttpRequestExecutor(requestHttp); - case JODD_HTTP: - case OK_HTTP: + return new VoiceUploadApacheHttpRequestExecutor( + (RequestHttp ) requestHttp); + case HTTP_COMPONENTS: + return new VoiceUploadHttpComponentsRequestExecutor( + (RequestHttp ) requestHttp); default: - return null; + throw new IllegalArgumentException("不支持的http执行器类型:" + requestHttp.getRequestType()); } } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java index 89b2224053..4beced7c7c 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java @@ -8,7 +8,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.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; @@ -237,7 +237,7 @@ public Object getRequestHttpProxy() { } @Override - public HttpType getRequestType() { + public HttpClientType getRequestType() { return null; } }; diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java index 15966d6727..77288d8d3b 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java @@ -1,6 +1,7 @@ package me.chanjar.weixin.mp.api.impl; import com.google.inject.Inject; +import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.test.ApiTestModule; @@ -23,15 +24,15 @@ public class WxMpDraftServiceImplTest { /** - * 1.先上传一个永久图片素材:me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest.testUploadMaterial + * 1.先上传一个永久图片素材:{@link me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest#testUploadMaterial} * 2.后续图文需要设置一个永久素材id */ - final String thumbMediaId = "zUUtT8ZYeXzZ4slFbtnAkh7Yd-f45DbFoF9ERzVC6s4"; + final String thumbMediaId = "-V3dxNv-eyJlImuJjWrmaTPt76BS6jHrL6-cGBlFPaXxAuv0qeJYV2p6Ezirr0zS"; /** * 新增草稿后返回的id,后续查询、修改、删除,获取等需要使用 */ - final String mediaId = "zUUtT8ZYeXzZ4slFbtnAkpgGKyqnTsjtUvMdVBRWJVk"; + final String mediaId = "-V3dxNv-eyJlImuJjWrmaZLwMkTKfDEhzq5NURU02H-k1qHMJ0lh9p0UU46w3rbd"; @Inject protected WxMpService wxService; @@ -114,6 +115,7 @@ public void testListDraft() throws WxErrorException { ,"total_count":1,"item_count":1} */ + System.out.println(draftList); assertThat(draftList).isNotNull(); } @@ -124,5 +126,101 @@ public void testCountDraft() throws WxErrorException { assertThat(countDraft).isNotNull(); } + //-----以下是图片类型草稿测试 + + /** + * 先上传一个永久图片素材:{@link me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest#testUploadMaterial} + * 这里的图片,使用的是 mm.jpeg + */ + @Test + public void testAddDraftPic() throws WxErrorException { + List draftArticleList = new ArrayList<>(); + ArrayList imageItems = new ArrayList<>(); + imageItems.add(new WxMpDraftImageInfo.ImageItem(thumbMediaId)); + + ArrayList cropPercents = new ArrayList<>(); + cropPercents.add(new WxMpDraftCoverInfo.CropPercent("1_1", "0.1", "0", "1", "0.9")); + + WxMpDraftArticles draftArticle = WxMpDraftArticles.builder() + .articleType(WxConsts.ArticleType.NEWS_PIC) + .title("新建图片草稿") + .content("图片消息的具体内容") + // 打开评论、所有人可评论 + .needOpenComment(1).onlyFansCanComment(0) + .imageInfo(WxMpDraftImageInfo.builder().imageList(imageItems).build()) + .coverInfo(WxMpDraftCoverInfo.builder().cropPercentList(cropPercents).build()) + .productInfo(WxMpDraftProductInfo.builder().footerProductInfo(new WxMpDraftProductInfo.FooterProductInfo("")).build()) + .build(); + draftArticleList.add(draftArticle); + + WxMpAddDraft addDraft = WxMpAddDraft.builder().articles(draftArticleList).build(); + String mediaId = this.wxService.getDraftService().addDraft(addDraft); + System.out.println(mediaId); + assertThat(mediaId).isNotNull(); + } + + @Test + public void testGetDraftPic() throws WxErrorException { + final WxMpDraftInfo draftInfo = this.wxService.getDraftService().getDraft(mediaId); + assertThat(draftInfo).isNotNull(); + System.out.println(draftInfo.toJson()); + // 【响应数据】:{ + // "news_item": [ + // { + // "article_type": "newspic", + // "title": "新建图片草稿", + // "content": "图片消息的具体内容", + // "thumb_media_id": "-V3dxNv-eyJlImuJjWrmaTPt76BS6jHrL6-cGBlFPaXxAuv0qeJYV2p6Ezirr0zS", + // "need_open_comment": 1, + // "only_fans_can_comment": 0, + // "url": "http://mp.weixin.qq.com/s?__biz=MzkyNTg4NDM1NA==&tempkey=MTMyM18rUktkOHFIQm5Kd3U5Rk1yS2NRYWtyZWUyNDNwS2MxZTZ3VXBKTkVScExpUFdGYzN2X0IzOEl1NGxEMGFpYld6NmdvbE9UUzlyYUdiVklvWTQ2YlRzSkkzQlpWMEZpcG9JRWp5LWZCVVNoWURodUlfWnE4VWZVQnlPd2VaUkg5SGREYUd3TW1wQkhlbTFuenBvRzFIbUxhMEJVbEo0Z3oyd2tnSGJBfn4%3D&chksm=423e8b9e75490288e8388c9ee91d6dad462bbce654742edd316622ab2b2fcfc593a4db58577b#rd", + // "thumb_url": "http://mmbiz.qpic.cn/sz_mmbiz_jpg/s7FE7rYN42QgPuJeXX9MfNuJBiaoalrWv8fj4AEqnK0WBM3KzqS0DsqHIW4epA3cx1PGjpco87BTssgQibvSNBIQ/0?wx_fmt=jpeg", + // "image_info": { + // "image_list": [ + // { + // "image_media_id": "-V3dxNv-eyJlImuJjWrmaTPt76BS6jHrL6-cGBlFPaXxAuv0qeJYV2p6Ezirr0zS" + // } + // ] + // } + // } + // ] + // } + } + + @Test + public void testUpdateDraftPic() throws WxErrorException { + ArrayList imageItems = new ArrayList<>(); + imageItems.add(new WxMpDraftImageInfo.ImageItem(thumbMediaId)); + ArrayList cropPercents = new ArrayList<>(); + cropPercents.add(new WxMpDraftCoverInfo.CropPercent("1_1", "0.3", "0", "1", "0.7")); + + WxMpDraftArticles draftArticle = WxMpDraftArticles.builder() + .articleType(WxConsts.ArticleType.NEWS_PIC) + .title("修改图片草稿") + .content("修改后的图片消息的具体内容") + // 打开评论、所有人可评论 + .needOpenComment(1).onlyFansCanComment(0) + .imageInfo(WxMpDraftImageInfo.builder().imageList(imageItems).build()) + .coverInfo(WxMpDraftCoverInfo.builder().cropPercentList(cropPercents).build()) + .productInfo(WxMpDraftProductInfo.builder().footerProductInfo(new WxMpDraftProductInfo.FooterProductInfo("")).build()) + .build(); + + WxMpUpdateDraft updateDraft = WxMpUpdateDraft.builder() + .mediaId(mediaId) + .index(0) + .articles(draftArticle) + .build(); + Boolean updateDraftResult = this.wxService.getDraftService().updateDraft(updateDraft); + assertThat(updateDraftResult).isTrue(); + } + + @Test + public void testDelDraftPic() throws WxErrorException { + Boolean delDraftResult = this.wxService.getDraftService().delDraft(mediaId); + System.out.println(delDraftResult); + // 【响应数据】:{"errcode":0,"errmsg":"ok"} + assertThat(delDraftResult).isTrue(); + } + } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImplTest.java index 21ca3236f5..f15a231e57 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpImgProcServiceImplTest.java @@ -61,14 +61,14 @@ public void testSuperResolution2() throws Exception { @Test public void testAiCrop() throws WxErrorException { - final WxImgProcAiCropResult result = this.mpService.getImgProcService().aiCrop("https://gitee.com/binary/weixin-java-tools/raw/master/images/qrcodes/mp.png"); + final WxImgProcAiCropResult result = this.mpService.getImgProcService().aiCrop("https://gitee.com/binary/weixin-java-tools/images/banners/wiki.jpg"); assertThat(result).isNotNull(); System.out.println(result); } @Test public void testAiCrop2() throws WxErrorException { - final WxImgProcAiCropResult result = this.mpService.getImgProcService().aiCrop("https://gitee.com/binary/weixin-java-tools/raw/master/images/qrcodes/mp.png", "1,2.35"); + final WxImgProcAiCropResult result = this.mpService.getImgProcService().aiCrop("https://gitee.com/binary/weixin-java-tools/images/banners/wiki.jpg", "1,2.35"); assertThat(result).isNotNull(); System.out.println(result); } diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMapConfigImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMapConfigImplTest.java new file mode 100644 index 0000000000..167c0e019c --- /dev/null +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMapConfigImplTest.java @@ -0,0 +1,58 @@ +package me.chanjar.weixin.mp.api.impl; + +import com.google.inject.Inject; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.test.ApiTestModule; +import me.chanjar.weixin.mp.config.impl.WxMpMapConfigImpl; +import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +/** + * 测试 ConcurrentHashMap 保存配置信息 + * @author jimmyjimmy-sw + */ +@Test +@Guice(modules = ApiTestModule.class) +public class WxMpMapConfigImplTest { + + @Inject + private WxMpService wxService; + + /** + * 测试多租户保存 WxMpMapConfigImpl 到 WxMpService,切换之后能获取到租户各自AppId对应的token + * @throws WxErrorException + */ + @Test + public void testAppidSwitch() throws WxErrorException { + // 保存租户A的配置信息,并获取token + WxMpMapConfigImpl configAppA = new WxMpMapConfigImpl(); + String appidA = "APPID_A"; + configAppA.setAppId(appidA); + configAppA.setSecret("APP_SECRET_A"); + configAppA.useStableAccessToken(true); + String tokenA = "TOKEN_A"; + configAppA.updateAccessToken(tokenA,60 * 60 * 1); + wxService.addConfigStorage(appidA, configAppA); + WxMpConfigStorageHolder.set(appidA); + assertEquals(this.wxService.getAccessToken(),tokenA); + + // 保存租户B的配置信息,并获取token + WxMpMapConfigImpl configAppB = new WxMpMapConfigImpl(); + String appidB = "APPID_B"; + configAppB.setAppId(appidB); + configAppB.setSecret("APP_SECRET_B"); + configAppB.useStableAccessToken(true); + String tokenB = "TOKEN_B"; + configAppB.updateAccessToken(tokenB,60 * 60 * 1); + wxService.addConfigStorage(appidB, configAppB); + WxMpConfigStorageHolder.set(appidB); + assertEquals(this.wxService.getAccessToken(),tokenB); + + // 上下文切换到租户A 获取租户A的token + WxMpConfigStorageHolder.set(appidA); + assertEquals(this.wxService.getAccessToken(),tokenA); + } +} diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java index 707f1df311..8068a5a302 100644 --- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java +++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java @@ -135,11 +135,6 @@ public void testAddNews() throws WxErrorException { wxMpMaterialNewsMultiple.addArticle(article1); wxMpMaterialNewsMultiple.addArticle(article2); - - WxMpMaterialUploadResult resSingle = this.wxService.getMaterialService().materialNewsUpload(wxMpMaterialNewsSingle); - this.singleNewsMediaId = resSingle.getMediaId(); - WxMpMaterialUploadResult resMulti = this.wxService.getMaterialService().materialNewsUpload(wxMpMaterialNewsMultiple); - this.multiNewsMediaId = resMulti.getMediaId(); } @Test(dependsOnMethods = {"testAddNews"}) @@ -201,8 +196,6 @@ public void testUpdateNewsInfo() throws WxErrorException { wxMpMaterialArticleUpdateSingle.setMediaId(this.singleNewsMediaId); wxMpMaterialArticleUpdateSingle.setArticles(articleSingle); wxMpMaterialArticleUpdateSingle.setIndex(0); - boolean resultSingle = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateSingle); - assertTrue(resultSingle); wxMpMaterialNewsSingle = this.wxService.getMaterialService() .materialNewsInfo(this.singleNewsMediaId); assertNotNull(wxMpMaterialNewsSingle); @@ -218,8 +211,6 @@ public void testUpdateNewsInfo() throws WxErrorException { wxMpMaterialArticleUpdateMulti.setMediaId(this.multiNewsMediaId); wxMpMaterialArticleUpdateMulti.setArticles(articleMulti); wxMpMaterialArticleUpdateMulti.setIndex(1); - boolean resultMulti = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateMulti); - assertTrue(resultMulti); wxMpMaterialNewsMultiple = this.wxService.getMaterialService() .materialNewsInfo(this.multiNewsMediaId); assertNotNull(wxMpMaterialNewsMultiple); diff --git a/weixin-java-open/README.md b/weixin-java-open/README.md index dd69161849..6ca65dfef3 100644 --- a/weixin-java-open/README.md +++ b/weixin-java-open/README.md @@ -1,3 +1,38 @@ +# 微信开放平台模块 (weixin-java-open) + +## 模块说明 + +本模块主要用于**微信第三方平台**的开发,适用于以下场景: + +### 适用场景 +1. **第三方平台开发**:作为第三方平台,代替多个公众号或小程序进行管理和开发 +2. **代公众号实现业务**:通过授权代替公众号进行消息管理、素材管理等操作 +3. **代小程序实现业务**:通过授权代替小程序进行代码管理、基本信息设置等操作 + +### 移动应用开发说明 + +**如果您要开发移动应用(iOS/Android App)并接入微信功能,请注意:** + +- **微信登录**: + - 移动应用的微信登录(网页授权)需要在**微信开放平台**(open.weixin.qq.com)创建移动应用 + - 服务端处理 OAuth 授权时使用本模块 `weixin-java-open` + - 移动端需集成微信官方SDK(iOS/Android),本项目仅提供服务端SDK + +- **微信支付**: + - 使用 `weixin-java-pay` 模块,参考 [微信支付文档](../weixin-java-pay/) + - 移动应用支付使用 APP 支付类型(TradeType.APP) + +- **微信分享**: + - 需集成微信官方移动端SDK,本项目不涉及客户端功能 + +**参考资料**: +- [微信开放平台官方文档](https://open.weixin.qq.com/) +- [移动应用接入指南](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html) + +--- + +## 代码示例 + 消息机制未实现,下面为通知回调中设置的代码部分 以下代码可通过腾讯全网发布测试用例 diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index f7fac62e64..0e815f1076 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java -4.7.2.B +4.7.8.B weixin-java-open @@ -48,6 +48,11 @@okhttp provided
+ * 字段名:微信订单号 + * 变量名:transaction_id + * 是否必填:否 + * 类型:string(32) + * 描述: + * 微信支付订单号,大于6个月的订单,必填 + * 示例值:4208450740201411110007820472 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java index b136844f86..0b0d093e3c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java @@ -4,7 +4,6 @@ import lombok.*; import java.io.Serializable; -import java.util.Date; /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java index fa6ca553e9..2ab481849e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class BusiFavorCouponCodeRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *
* 字段名:批次号 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java index ca45a091c4..bca9ea932e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class BusiFavorCouponCodeResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:批次号 @@ -130,8 +130,8 @@ public class BusiFavorCouponCodeResult implements Serializable { @Data @NoArgsConstructor - public static class FailCode { - public static final float serialVersionUID = 1L; + public static class FailCode implements Serializable { + private static final long serialVersionUID = 1L; /** ** 字段名:上传失败的券code diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java index 11319e56b4..8af44901e0 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java @@ -4,6 +4,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + /** * H5发券请求对象 *@@ -14,8 +16,8 @@ */ @Data @NoArgsConstructor -public class BusiFavorCouponsUrlRequest { - public static final float serialVersionUID = 1L; +public class BusiFavorCouponsUrlRequest implements Serializable { + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java index ab8a8ba2a5..9d365054e9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java @@ -4,6 +4,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + /** * 核销用户券请求对象 *@@ -14,8 +16,8 @@ */ @Data @NoArgsConstructor -public class BusiFavorCouponsUseRequest { - public static final float serialVersionUID = 1L; +public class BusiFavorCouponsUseRequest implements Serializable { + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java index 3dad3fe5d1..0a53cd33d1 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java @@ -17,7 +17,7 @@ @Data @NoArgsConstructor public class BusiFavorQueryOneUserCouponsRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:用户标识 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java index 6db7d303a9..566957eb51 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java @@ -20,7 +20,7 @@ @Data @NoArgsConstructor public class BusiFavorQueryOneUserCouponsResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:批次归属商户号 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java index 600a48c8de..0c417c425a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java @@ -17,7 +17,7 @@ @Data @NoArgsConstructor public class BusiFavorQueryUserCouponsRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:用户标识 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java index 9b5f57b040..c2906be27e 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class BusiFavorQueryUserCouponsResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:+结果集 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java index f8f342de1c..6f1824f646 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.marketing; +import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result; import com.google.gson.annotations.SerializedName; import lombok.Data; import lombok.NoArgsConstructor; @@ -13,7 +14,7 @@ */ @NoArgsConstructor @Data -public class FavorCouponsGetResult implements Serializable { +public class FavorCouponsGetResult extends BaseWxPayV3Result { private static final long serialVersionUID = 1L; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java index 855edc8528..375dd308d8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java @@ -1,6 +1,7 @@ package com.github.binarywang.wxpay.bean.marketing; import com.github.binarywang.wxpay.bean.marketing.enums.BackgroundColorEnum; +import com.github.binarywang.wxpay.bean.marketing.enums.JumpTargetEnum; import com.github.binarywang.wxpay.bean.marketing.enums.StockTypeEnum; import com.github.binarywang.wxpay.bean.marketing.enums.TradeTypeEnum; import com.google.gson.annotations.SerializedName; @@ -392,6 +393,24 @@ public static class PatternInfo implements Serializable { */ @SerializedName(value = "coupon_image") private String couponImage; + + /** + * 卡包跳转目标 + */ + @SerializedName("jump_target") + private JumpTargetEnum jumpTarget; + + /** + * 小程序appid + */ + @SerializedName("mini_program_appid") + private String miniProgramAppid; + + /** + * 小程序path + */ + @SerializedName("mini_program_path") + private String miniProgramPath; } @Data diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java index 74ac6fd205..381056b5a9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.marketing; +import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result; import com.google.gson.annotations.SerializedName; import lombok.Data; import lombok.NoArgsConstructor; @@ -13,7 +14,7 @@ */ @NoArgsConstructor @Data -public class FavorStocksCreateResult implements Serializable { +public class FavorStocksCreateResult extends BaseWxPayV3Result { private static final long serialVersionUID = 1L; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java index 294f273def..591afa7e51 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.bean.marketing; +import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result; import com.google.gson.annotations.SerializedName; import lombok.Data; import lombok.NoArgsConstructor; @@ -14,7 +15,7 @@ */ @NoArgsConstructor @Data -public class FavorStocksGetResult implements Serializable { +public class FavorStocksGetResult extends BaseWxPayV3Result { private static final long serialVersionUID = 1L; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java index 2718b32770..487291a739 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java @@ -17,7 +17,7 @@ @Data @NoArgsConstructor public class AvailableWeek implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *@@ -46,12 +46,12 @@ public class AvailableWeek implements Serializable { **/ @SerializedName(value = "available_day_time") - private AvailableDayTime availableDayTime; + private AvailableDayTimeItem[] availableDayTime; @Data @NoArgsConstructor - public static class AvailableDayTime implements Serializable { - public static final float serialVersionUID = 1L; + public static class AvailableDayTimeItem implements Serializable { + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java index 31833c1188..f41692c068 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class CouponAvailableTime implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java index 4ddd196e56..0b11010493 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java @@ -18,7 +18,7 @@ @NoArgsConstructor public class IrregularyAvaliableTime implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java index d9ba753346..b37765f8f2 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java @@ -52,6 +52,16 @@ public enum BackgroundColorEnum { */ COLOR080("COLOR080", "#EE903C"), + /** + * 颜色 #F08500 + */ + COLOR081("COLOR081", "#F08500"), + + /** + * 颜色 #A9D92D + */ + COLOR082("COLOR082", "#A9D92D"), + /** * 颜色 #DD6549 */ @@ -61,8 +71,17 @@ public enum BackgroundColorEnum { * 颜色 #CC463D */ COLOR100("COLOR100", "#CC463D"), - ; + /** + * 颜色 #CF3E36 + */ + COLOR101("COLOR101", "#CF3E36"), + + /** + * 颜色 #5E6671 + */ + COLOR102("COLOR102", "#5E6671"), + ; /** * 色值 */ diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/JumpTargetEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/JumpTargetEnum.java new file mode 100644 index 0000000000..dce0b34556 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/JumpTargetEnum.java @@ -0,0 +1,34 @@ +package com.github.binarywang.wxpay.bean.marketing.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 卡包跳转目标 + * + * @author wangerwei + */ +@Getter +@AllArgsConstructor +public enum JumpTargetEnum { + + /** + * PAYMENT_CODE:点击“立即使用”跳转至微信支付付款码 + */ + PAYMENT_CODE("PAYMENT_CODE"), + + /** + * MINI_PROGRAM:点击“立即使用”跳转至配置的商家小程序(需要指定小程序appid和path) + */ + MINI_PROGRAM("MINI_PROGRAM"), + + /** + * DEFAULT_PAGE:点击“立即使用”跳转至默认页面 + */ + DEFAULT_PAGE("DEFAULT_PAGE"); + + /** + * 批次类型 + */ + private final String value; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java index 9aa51ce742..bbb4e93ab4 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java @@ -23,7 +23,7 @@ @Data @NoArgsConstructor public class BatchDetailsRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:微信支付批次单号 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java index 437def08f2..4ca7958ed5 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java @@ -7,7 +7,6 @@ import me.chanjar.weixin.common.util.json.WxGsonBuilder; import java.io.Serializable; -import java.util.Date; /** *@@ -26,7 +25,7 @@ @Data @NoArgsConstructor public class BatchDetailsResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; @Override public String toString() { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java index 9f53843d66..127c38cdc6 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class BatchNumberRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java index 1defcca943..a59ccbc85f 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java @@ -20,7 +20,7 @@ @Data @NoArgsConstructor public class BatchNumberResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; @Override public String toString() { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java index ea83328308..fc0b97d7bb 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java @@ -20,7 +20,7 @@ @Data @NoArgsConstructor public class BillReceiptResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; @Override public String toString() { diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java index 50ca1feac7..3f147abd00 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java @@ -21,7 +21,7 @@ @Data @NoArgsConstructor public class DownloadRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java index 1f4d8134f4..cc419d3a4f 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java @@ -20,7 +20,7 @@ @Data @NoArgsConstructor public class ElectronicReceiptsRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:受理类型 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java index 114b1982c3..4e0581108c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java @@ -20,7 +20,7 @@ @Data @NoArgsConstructor public class ElectronicReceiptsResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:受理类型 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java index fe6450b22e..a319d3f4b3 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java @@ -20,7 +20,7 @@ @Data @NoArgsConstructor public class MerchantBatchRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:商家批次单号 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java index bd06b5db4b..0e8418cca9 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java @@ -19,7 +19,7 @@ @Data @NoArgsConstructor public class PartnerTransferRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** *diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java index cca369b408..d9c8019462 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class PartnerTransferResult implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:商家批次单号 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java index deda24d426..1995ac1656 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java @@ -18,7 +18,7 @@ @Data @NoArgsConstructor public class ReceiptBillRequest implements Serializable { - public static final float serialVersionUID = 1L; + private static final long serialVersionUID = 1L; /** ** 字段名:商家批次单号 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java index bd9a6f3ecf..27e8c1e1ec 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java @@ -387,7 +387,7 @@ protected void composeCoupons() { if (this.couponCount == null || this.couponCount == 0) { return; } - this.couponList = new ArrayList(couponCount); + this.couponList = new ArrayList<>(couponCount); for (int i = 0; i < this.couponCount; i++) { WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon(); coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i)); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java index ae86b8c854..8615a2e461 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java @@ -273,7 +273,7 @@ public String toString() { **/ @XStreamAlias("refund_recv_accout") - private String refundRecvAccout; + private String refundRecvAccount; /** *@@ -324,7 +324,7 @@ public void loadXML(Document d) { settlementRefundFee = readXmlInteger(d, "settlement_refund_fee"); refundStatus = readXmlString(d, "refund_status"); successTime = readXmlString(d, "success_time"); - refundRecvAccout = readXmlString(d, "refund_recv_accout"); + refundRecvAccount = readXmlString(d, "refund_recv_accout"); refundAccount = readXmlString(d, "refund_account"); refundRequestSource = readXmlString(d, "refund_request_source"); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/Device.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/Device.java new file mode 100644 index 0000000000..3060b0ff47 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/Device.java @@ -0,0 +1,38 @@ +package com.github.binarywang.wxpay.bean.payscore; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 设备信息 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Device implements Serializable { + + private static final long serialVersionUID = -4510224826631515321L; + + + /** + * 服务开始的设备ID + */ + @SerializedName("start_device_id") + private String startDeviceId; + + /** + * 服务结束的设备ID + */ + @SerializedName("end_device_id") + private String endDeviceId; + + /** + * 物料编码 + */ + @SerializedName("materiel_no") + private String materielNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java index feeabaac16..be44427dfc 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java @@ -4,7 +4,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import me.chanjar.weixin.common.util.json.WxGsonBuilder; import java.io.Serializable; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java index 3c58a62e80..020ed05cb7 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java @@ -42,6 +42,7 @@ public String toJson() { * openid : oUpF8uMuAJO_M2pxb1Q9zNjWeS6o * need_user_confirm : true * profitSharing : false:不分账,默认:false,true:分账 + * device : {"start_device_id":"202501","end_device_id":"202502","materiel_no":"212323232"} */ @SerializedName("out_order_no") private String outOrderNo; @@ -95,4 +96,6 @@ public String toJson() { */ @SerializedName("complete_time") private String completeTime; + @SerializedName("device") + private Device device; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java index d3d8c07d37..505d7e28d4 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java @@ -12,7 +12,7 @@ public class ReceiverList implements Serializable { private static final long serialVersionUID = -1316860887694489921L; - ArrayList list; + ArrayListlist; private ReceiverList() { } @@ -23,7 +23,7 @@ private ReceiverList() { */ public static ReceiverList getInstance() { ReceiverList receiverList = new ReceiverList(); - receiverList.list = new ArrayList(); + receiverList.list = new ArrayList<>(); return receiverList; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java index b8de4f5d5b..98e99b3e2c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java @@ -1,16 +1,10 @@ package com.github.binarywang.wxpay.bean.profitsharing.request; -import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; -import com.github.binarywang.wxpay.constant.WxPayConstants; -import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.v3.SpecEncrypt; import com.google.gson.annotations.SerializedName; -import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.*; -import me.chanjar.weixin.common.annotation.Required; import java.io.Serializable; -import java.util.Map; /** * 添加/删除分账接受方请求对象 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java index 95b5e67fc9..1cc72b1fa8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java @@ -3,14 +3,10 @@ import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; import com.github.binarywang.wxpay.constant.WxPayConstants; import com.github.binarywang.wxpay.exception.WxPayException; -import com.github.binarywang.wxpay.v3.SpecEncrypt; -import com.google.gson.Gson; -import com.google.gson.annotations.SerializedName; import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.*; import me.chanjar.weixin.common.annotation.Required; -import java.io.Serializable; import java.util.Map; /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java index 437a82e18f..6c222ddc54 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java @@ -92,7 +92,7 @@ protected void loadXml(Document d) { } @Data - public class Receiver { + public static class Receiver { /** * 分账接收方类型 */ diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java index 996bb5e789..141a2df94b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java @@ -1,13 +1,8 @@ package com.github.binarywang.wxpay.bean.profitsharing.result; -import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; import com.github.binarywang.wxpay.v3.SpecEncrypt; import com.google.gson.annotations.SerializedName; -import com.thoughtworks.xstream.annotations.XStreamAlias; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import org.w3c.dom.Document; import java.io.Serializable; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java index 5eeeb36604..526a961e47 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java @@ -20,9 +20,9 @@ import java.io.Serializable; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES; @@ -147,21 +147,21 @@ public void setWorkWxSign(String workWxSign) { * @return the integer */ public static Integer yuanToFen(String yuan) { - return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue(); + return new BigDecimal(yuan).setScale(2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).intValue(); } /** * 元转分 */ public static Integer yuan2Fen(BigDecimal yuan) { - return yuan.multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue(); + return yuan.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).intValue(); } /** * 分转元 */ public static BigDecimal fen2Yuan(BigDecimal fen) { - return fen.divide(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + return fen.divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP); } /** diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java index b397f0f1c0..428878dc77 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java @@ -87,5 +87,33 @@ public static class SubOrders implements Serializable { */ @SerializedName(value = "out_trade_no") private String outTradeNo; + /** + * + * 字段名:二级商户号 + * 变量名:sub_mchid + * 是否必填:是 + * 类型:string[1,32] + * 描述: + * 二级商户商户号,由微信支付生成并下发。服务商子商户的商户号,被合单方。直连商户不用传二级商户号。 + * 示例值:1900000109 + *+ */ + @SerializedName(value = "sub_mchid") + private String subMchid; + /** + *+ * 字段名:子商户应用ID + * 变量名:sub_appid + * 是否必填:是 + * 类型:string[1,32] + * 描述: + * 子商户申请的应用ID,全局唯一。请求基础下单接口时请注意APPID的应用属性,例如公众号场景下, + * 需使用应用属性为公众号的APPID 若sub_openid有传的情况下, + * sub_appid必填,且sub_appid需与sub_openid对应 + * 示例值:wxd678efh567hg6999 + *+ */ + @SerializedName(value = "sub_appid") + private String subAppid; } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java index c522c90d88..8f3e8ebd10 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java @@ -6,7 +6,6 @@ import lombok.experimental.Accessors; import java.io.Serializable; -import java.util.List; /** * 微信支付服务商退款请求 diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java new file mode 100644 index 0000000000..296d3a8646 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java @@ -0,0 +1,57 @@ +package com.github.binarywang.wxpay.bean.request; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + *+ * 境外微信支付统一下单请求参数对象. + * 参考文档:https://pay.weixin.qq.com/doc/global/v3/zh/4013014223 + *+ * + * @author Binary Wang + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class WxPayUnifiedOrderV3GlobalRequest extends WxPayUnifiedOrderV3Request implements Serializable { + private static final long serialVersionUID = 1L; + + /** + *+ * 字段名:交易类型 + * 变量名:trade_type + * 是否必填:是 + * 类型:string[1,16] + * 描述: + * 交易类型,取值如下: + * JSAPI--JSAPI支付 + * NATIVE--Native支付 + * APP--APP支付 + * H5--H5支付 + * 示例值:JSAPI + *+ */ + @SerializedName(value = "trade_type") + private String tradeType; + + /** + *+ * 字段名:商户类目 + * 变量名:merchant_category_code + * 是否必填:是 + * 类型:string[1,32] + * 描述: + * 商户类目,境外商户必填 + * 示例值:5812 + *+ */ + @SerializedName(value = "merchant_category_code") + private String merchantCategoryCode; +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java index 98dae388ef..8ac588de81 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java @@ -250,6 +250,12 @@ public static class Payer implements Serializable { */ @SerializedName(value = "openid") private String openid; + + /** + * 实名支付用户身份标识 + */ + @SerializedName(value = "identity") + private Identity identity; } @Data @@ -572,4 +578,36 @@ public static class SettleInfo implements Serializable { @SerializedName(value = "profit_sharing") private Boolean profitSharing; } + + + @Data + @NoArgsConstructor + public static class Identity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 证件类型 + * IDCARD:身份证 + * HONGKONG_MACAO:港澳回乡证 + * HONGKONG_MACAO_RESIDENT:港澳居住证 + * TAIWAN_RESIDENT:台湾居住证 + * FOREIGN_RESIDENT:外国人永居证 + * OVERSEA_PASSPORT:护照 + */ + @SerializedName(value = "type") + private String type; + /** + * 证件号 + * 证件号,如身份证号。 + * 示例值:43102119910910512X + */ + @SerializedName(value = "number") + private String number; + /** + * 证件姓名。 + * 示例值:周星星 + */ + @SerializedName(value = "name") + private String name; + } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java index 0c288b5507..109fab66bc 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java @@ -194,7 +194,7 @@ private void loadBasicXML(Document d) { protected static Integer readXmlInteger(Node d, String tagName) { String content = readXmlString(d, tagName); - if (content == null || content.trim().length() == 0) { + if (content == null || content.trim().isEmpty()) { return null; } return Integer.parseInt(content); @@ -232,7 +232,7 @@ public static String readXmlString(Document d, String tagName) { protected static Integer readXmlInteger(Document d, String tagName) { String content = readXmlString(d, tagName); - if (content == null || content.trim().length() == 0) { + if (content == null || content.trim().isEmpty()) { return null; } @@ -241,7 +241,7 @@ protected static Integer readXmlInteger(Document d, String tagName) { protected static Long readXmlLong(Document d, String tagName) { String content = readXmlString(d, tagName); - if (content == null || content.trim().length() == 0) { + if (content == null || content.trim().isEmpty()) { return null; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayV3Result.java new file mode 100644 index 0000000000..88724b939e --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayV3Result.java @@ -0,0 +1,42 @@ +package com.github.binarywang.wxpay.bean.result; + +import lombok.Data; + +import java.io.Serializable; + +/** + *+ * 微信支付v3结果共用属性类. + * 用于保存原始JSON响应内容,便于访问API返回的新增字段. + *+ * + * @author Binary Wang + */ +@Data +public abstract class BaseWxPayV3Result implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 原始JSON字符串. + * 保存微信支付v3 API返回的原始JSON内容,便于访问未在Result类中定义的字段. + */ + private String rawJsonString; + + /** + * 获取原始JSON响应内容. + * + * @return 原始JSON字符串 + */ + public String getRawJsonString() { + return rawJsonString; + } + + /** + * 设置原始JSON响应内容. + * + * @param rawJsonString 原始JSON字符串 + */ + public void setRawJsonString(String rawJsonString) { + this.rawJsonString = rawJsonString; + } +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java index 288e8b933f..f2d96804d2 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java @@ -224,7 +224,7 @@ protected void composeCoupons() { if (this.couponCount == null || this.couponCount == 0) { return; } - this.couponList = new ArrayList(couponCount); + this.couponList = new ArrayList<>(couponCount); for (int i = 0; i < this.couponCount; i++) { WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon(); coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i)); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java index f625462e16..3ce0079f5b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java @@ -147,7 +147,7 @@ protected void composeCoupons() { if (this.couponCount == null || this.couponCount == 0) { return; } - this.couponList = new ArrayList(couponCount); + this.couponList = new ArrayList<>(couponCount); for (int i = 0; i < this.couponCount; i++) { WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon(); coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i)); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java new file mode 100644 index 0000000000..fd33b240f1 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java @@ -0,0 +1,36 @@ +package com.github.binarywang.wxpay.bean.result.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 境外微信支付方式 + * Overseas WeChat Pay trade types with global endpoints + * + * @author Binary Wang + */ +@Getter +@AllArgsConstructor +public enum GlobalTradeTypeEnum { + /** + * APP + */ + APP("/global/v3/transactions/app"), + /** + * JSAPI 或 小程序 + */ + JSAPI("/global/v3/transactions/jsapi"), + /** + * NATIVE + */ + NATIVE("/global/v3/transactions/native"), + /** + * H5 + */ + H5("/global/v3/transactions/h5"); + + /** + * 境外下单url + */ + private final String url; +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java new file mode 100644 index 0000000000..b0d9276a32 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java @@ -0,0 +1,141 @@ +package com.github.binarywang.wxpay.config; + +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.v3.auth.*; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * 验证器构建. + * + * @author holy + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +class VerifierBuilder { + /** + * 构建验证器. + *+ * 场景 + *
+ * 1. 老商户号,只有平台证书,未开通公钥 (已验证) + * 2. 新商户号,被强制开通公钥,没有平台证书 (已验证) + * 3. 老商户号,有平台证书,主动开通公钥 (未验证,具备条件的朋友,可以帮忙验证下) + * ... + *+ * + * @param certSerialNo c + * @param mchId m + * @param apiV3Key a + * @param merchantPrivateKey m + * @param wxPayHttpProxy w + * @param certAutoUpdateTime c + * @param payBaseUrl p + * @param publicKeyId p + * @param publicKey p + * @return v + * @throws WxPayException e + */ + @SuppressWarnings("java:S107") + static Verifier build( + // 平台证书 - 依赖参数 + String certSerialNo, + String mchId, + String apiV3Key, + PrivateKey merchantPrivateKey, + WxPayHttpProxy wxPayHttpProxy, + int certAutoUpdateTime, + String payBaseUrl, + // 公钥 - 依赖参数 + String publicKeyId, + PublicKey publicKey + ) throws WxPayException { + Verifier certificatesVerifier = null; + Exception ex = null; + + // 构建平台证书验证器 + // (沿用旧逻辑)优先构建平台证书验证器,因为公钥验证器需要平台证书验证器 (见以下 .setOtherVerifier ) + // 新商户号默认无平台证书,已确认无法构建平台证书验证器,会抛出异常;老商户号,有平台证书主动开通公钥的情况,待具备条件的朋友验证 + // 建议公钥模式稳定后,优先构建公钥验证器,以免每次都尝试构建平台证书验证器,且失败 {@link com.github.binarywang.wxpay.v3.auth.PublicCertificateVerifier.verify} + if (merchantPrivateKey != null && StringUtils.isNoneBlank(certSerialNo, apiV3Key)) { + try { + certificatesVerifier = getCertificatesVerifier( + certSerialNo, mchId, apiV3Key, merchantPrivateKey, wxPayHttpProxy, certAutoUpdateTime, payBaseUrl + ); + } catch (Exception e) { + ex = e; + } + } + + // 构建公钥验证器 + if (publicKey != null && StringUtils.isNotBlank(publicKeyId)) { + try { + certificatesVerifier = getPublicCertVerifier(publicKeyId, publicKey, certificatesVerifier); + } catch (Exception e) { + ex = e; + } + } + if (certificatesVerifier != null) { + return certificatesVerifier; + } + + // 有异常时抛出 + if (ex != null) { + throw new WxPayException(ex.getMessage(), ex); + } + + // 没有证书验证器时。不确定是否抛出异常,沿用之前逻辑,返回 null + return null; + } + + /** + * 针对完全使用公钥的场景 + * @param publicKeyId 公钥id + * @param publicKey 公钥 + * @return + */ + static Verifier buildPublicCertVerifier(String publicKeyId, PublicKey publicKey) { + return getPublicCertVerifier(publicKeyId, publicKey, null); + } + + /** + * 获取证书验证器. + * + * @param certSerialNo certSerialNo + * @param mchId mchId + * @param apiV3Key apiV3Key + * @param merchantPrivateKey merchantPrivateKey + * @param wxPayHttpProxy wxPayHttpProxy + * @param certAutoUpdateTime certAutoUpdateTime + * @param payBaseUrl payBaseUrl + * @return verifier + */ + private static AutoUpdateCertificatesVerifier getCertificatesVerifier( + String certSerialNo, String mchId, String apiV3Key, PrivateKey merchantPrivateKey, + WxPayHttpProxy wxPayHttpProxy, int certAutoUpdateTime, String payBaseUrl + ) { + return new AutoUpdateCertificatesVerifier( + new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), + apiV3Key.getBytes(StandardCharsets.UTF_8), certAutoUpdateTime, + payBaseUrl, wxPayHttpProxy); + } + + /** + * 获取公钥验证器. + * + * @param publicKeyId id + * @param publicKey key + * @param certificatesVerifier verifier + * @return verifier + */ + private static Verifier getPublicCertVerifier(String publicKeyId, PublicKey publicKey, Verifier certificatesVerifier) { + Verifier publicCertificatesVerifier = new PublicCertificateVerifier(publicKey, publicKeyId); + publicCertificatesVerifier.setOtherVerifier(certificatesVerifier); + certificatesVerifier = publicCertificatesVerifier; + return certificatesVerifier; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java index 35558d5636..ee44780590 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java @@ -4,7 +4,8 @@ import com.github.binarywang.wxpay.util.HttpProxyUtils; import com.github.binarywang.wxpay.util.ResourcesUtils; import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder; -import com.github.binarywang.wxpay.v3.auth.*; +import com.github.binarywang.wxpay.v3.auth.Verifier; +import com.github.binarywang.wxpay.v3.auth.WxPayValidator; import com.github.binarywang.wxpay.v3.util.PemUtils; import lombok.Data; import lombok.EqualsAndHashCode; @@ -13,13 +14,21 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.conn.ssl.DefaultHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.ssl.SSLContexts; import javax.net.ssl.SSLContext; import java.io.*; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; @@ -45,7 +54,7 @@ public class WxPayConfig { /** * 微信支付接口请求地址域名部分. */ - private String payBaseUrl = DEFAULT_PAY_BASE_URL; + private String apiHostUrl = DEFAULT_PAY_BASE_URL; /** * http请求连接超时时间. @@ -185,11 +194,32 @@ public class WxPayConfig { private CloseableHttpClient apiV3HttpClient; + + /** + * 用于普通支付接口的可复用HttpClient,使用连接池 + */ + private CloseableHttpClient httpClient; + + /** + * 用于需要SSL证书的支付接口的可复用HttpClient,使用连接池 + */ + private CloseableHttpClient sslHttpClient; + /** * 支持扩展httpClientBuilder */ private HttpClientBuilderCustomizer httpClientBuilderCustomizer; private HttpClientBuilderCustomizer apiV3HttpClientBuilderCustomizer; + + /** + * HTTP连接池最大连接数,默认20 + */ + private int maxConnTotal = 20; + + /** + * HTTP连接池每个路由的最大连接数,默认10 + */ + private int maxConnPerRoute = 10; /** * 私钥信息 */ @@ -227,17 +257,27 @@ public class WxPayConfig { */ private Verifier verifier; + /** + * 是否将全部v3接口的请求都添加Wechatpay-Serial请求头,默认不添加 + */ + private boolean strictlyNeedWechatPaySerial = false; + + /** + * 是否完全使用公钥模式(用以微信从平台证书到公钥的灰度切换),默认不使用 + */ + private boolean fullPublicKeyModel = false; + /** * 返回所设置的微信支付接口请求地址域名. * * @return 微信支付接口请求地址域名 */ - public String getPayBaseUrl() { - if (StringUtils.isEmpty(this.payBaseUrl)) { + public String getApiHostUrl() { + if (StringUtils.isEmpty(this.apiHostUrl)) { return DEFAULT_PAY_BASE_URL; } - return this.payBaseUrl; + return this.apiHostUrl; } @SneakyThrows @@ -284,32 +324,31 @@ public CloseableHttpClient initApiV3HttpClient() throws WxPayException { if (StringUtils.isBlank(this.getApiV3Key())) { throw new WxPayException("请确保apiV3Key值已设置"); } - - // 尝试从p12证书中加载私钥和证书 - PrivateKey merchantPrivateKey = null; - X509Certificate certificate = null; - Object[] objects = this.p12ToPem(); - if (objects != null) { - merchantPrivateKey = (PrivateKey) objects[0]; - certificate = (X509Certificate) objects[1]; - this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase(); - } try { - if (merchantPrivateKey == null) { - try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(), - this.privateKeyContent, "privateKeyPath")) { - merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream); - } + PrivateKey merchantPrivateKey = null; + PublicKey publicKey = null; + + // 不使用完全公钥模式时,同时兼容平台证书和公钥 + X509Certificate certificate = null; + // 尝试从p12证书中加载私钥和证书 + Object[] objects = this.p12ToPem(); + if (objects != null) { + merchantPrivateKey = (PrivateKey) objects[0]; + certificate = (X509Certificate) objects[1]; + this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase(); } - if (certificate == null && StringUtils.isBlank(this.getCertSerialNo())) { + if (certificate == null && StringUtils.isBlank(this.getCertSerialNo()) && StringUtils.isNotBlank(this.getPrivateCertPath())) { try (InputStream certInputStream = this.loadConfigInputStream(this.getPrivateCertString(), this.getPrivateCertPath(), this.privateCertContent, "privateCertPath")) { certificate = PemUtils.loadCertificate(certInputStream); } this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase(); } - PublicKey publicKey = null; + if (this.getPublicKeyString() != null || this.getPublicKeyPath() != null || this.publicKeyContent != null) { + if (StringUtils.isBlank(this.getPublicKeyId())) { + throw new WxPayException("请确保和publicKeyId配套使用"); + } try (InputStream pubInputStream = this.loadConfigInputStream(this.getPublicKeyString(), this.getPublicKeyPath(), this.publicKeyContent, "publicKeyPath")) { @@ -317,18 +356,26 @@ public CloseableHttpClient initApiV3HttpClient() throws WxPayException { } } + // 加载api私钥 + if (merchantPrivateKey == null && (StringUtils.isNotBlank(this.getPrivateKeyPath()) || StringUtils.isNotBlank(this.getPrivateKeyString()) || null != this.privateKeyContent)) { + try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(), + this.privateKeyContent, "privateKeyPath")) { + merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream); + } + } + //构造Http Proxy正向代理 WxPayHttpProxy wxPayHttpProxy = getWxPayHttpProxy(); + // 构造证书验签器 Verifier certificatesVerifier; - if (publicKey == null) { - certificatesVerifier = - new AutoUpdateCertificatesVerifier( - new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)), - this.getApiV3Key().getBytes(StandardCharsets.UTF_8), this.getCertAutoUpdateTime(), - this.getPayBaseUrl(), wxPayHttpProxy); + if (this.fullPublicKeyModel) { + // 使用完全公钥模式时,只加载公钥相关配置,避免下载平台证书使灰度切换无法达到100%覆盖 + certificatesVerifier = VerifierBuilder.buildPublicCertVerifier(this.publicKeyId, publicKey); } else { - certificatesVerifier = new PublicCertificateVerifier(publicKey, publicKeyId); + certificatesVerifier = VerifierBuilder.build( + this.getCertSerialNo(), this.getMchId(), this.getApiV3Key(), merchantPrivateKey, wxPayHttpProxy, + this.getCertAutoUpdateTime(), this.getApiHostUrl(), this.getPublicKeyId(), publicKey); } WxPayV3HttpClientBuilder wxPayV3HttpClientBuilder = WxPayV3HttpClientBuilder.create() @@ -382,7 +429,7 @@ private InputStream loadConfigInputStream(String configString, String configPath if (configContent != null) { return new ByteArrayInputStream(configContent); } - + if (StringUtils.isNotEmpty(configString)) { configContent = Base64.getDecoder().decode(configString); return new ByteArrayInputStream(configContent); @@ -481,4 +528,111 @@ private Object[] p12ToPem() { return null; } + + /** + * 初始化使用连接池的HttpClient + * + * @return CloseableHttpClient + * @throws WxPayException 初始化异常 + */ + public CloseableHttpClient initHttpClient() throws WxPayException { + if (this.httpClient != null) { + return this.httpClient; + } + + // 创建连接池管理器 + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(this.maxConnTotal); + connectionManager.setDefaultMaxPerRoute(this.maxConnPerRoute); + + // 创建HttpClient构建器 + org.apache.http.impl.client.HttpClientBuilder httpClientBuilder = HttpClients.custom() + .setConnectionManager(connectionManager); + + // 配置代理 + configureProxy(httpClientBuilder); + + // 提供自定义httpClientBuilder的能力 + Optional.ofNullable(httpClientBuilderCustomizer).ifPresent(e -> { + e.customize(httpClientBuilder); + }); + + this.httpClient = httpClientBuilder.build(); + return this.httpClient; + } + + /** + * 初始化使用连接池且支持SSL的HttpClient + * + * @return CloseableHttpClient + * @throws WxPayException 初始化异常 + */ + public CloseableHttpClient initSslHttpClient() throws WxPayException { + if (this.sslHttpClient != null) { + return this.sslHttpClient; + } + + // 初始化SSL上下文 + SSLContext sslContext = this.getSslContext(); + if (null == sslContext) { + sslContext = this.initSSLContext(); + } + + // 创建支持SSL的连接池管理器 + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(this.maxConnTotal); + connectionManager.setDefaultMaxPerRoute(this.maxConnPerRoute); + + // 创建HttpClient构建器,配置SSL + org.apache.http.impl.client.HttpClientBuilder httpClientBuilder = HttpClients.custom() + .setConnectionManager(connectionManager) + .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier())); + + // 配置代理 + configureProxy(httpClientBuilder); + + // 提供自定义httpClientBuilder的能力 + Optional.ofNullable(httpClientBuilderCustomizer).ifPresent(e -> { + e.customize(httpClientBuilder); + }); + + this.sslHttpClient = httpClientBuilder.build(); + return this.sslHttpClient; + } + + /** + * 配置HTTP代理 + */ + private void configureProxy(org.apache.http.impl.client.HttpClientBuilder httpClientBuilder) { + if (StringUtils.isNotBlank(this.getHttpProxyHost()) && this.getHttpProxyPort() > 0) { + if (StringUtils.isEmpty(this.getHttpProxyUsername())) { + this.setHttpProxyUsername("whatever"); + } + + // 使用代理服务器 需要用户认证的代理服务器 + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(new AuthScope(this.getHttpProxyHost(), this.getHttpProxyPort()), + new UsernamePasswordCredentials(this.getHttpProxyUsername(), this.getHttpProxyPassword())); + httpClientBuilder.setDefaultCredentialsProvider(provider) + .setProxy(new HttpHost(this.getHttpProxyHost(), this.getHttpProxyPort())); + } + } + + /** + * 获取用于普通支付接口的HttpClient + * + * @return CloseableHttpClient + */ + public CloseableHttpClient getHttpClient() { + return httpClient; + } + + /** + * 获取用于SSL支付接口的HttpClient + * + * @return CloseableHttpClient + */ + public CloseableHttpClient getSslHttpClient() { + return sslHttpClient; + } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java index 0f01358633..e3e28e9183 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java @@ -39,7 +39,6 @@ public WxPayOrderNotifyResultConverter(Mapper mapper, ReflectionProvider reflect } @Override - @SuppressWarnings("rawtypes") public boolean canConvert(Class type) { return type.equals(WxPayOrderNotifyResult.class); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java new file mode 100644 index 0000000000..8d74e5a4ef --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java @@ -0,0 +1,249 @@ +package com.github.binarywang.wxpay.example; + +import com.github.binarywang.wxpay.bean.notify.SignatureHeader; +import com.github.binarywang.wxpay.bean.transfer.*; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.TransferService; +import com.github.binarywang.wxpay.service.WxPayService; +import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; + +/** + * 新版商户转账API使用示例 + * + * 从2025年1月15日开始,微信支付推出了新版的商户转账API + * 新开通的商户号只能使用最新版本的商户转账接口 + * + * @author WxJava Team + * @since 2025-01-15 + */ +public class NewTransferApiExample { + + private final TransferService transferService; + + public NewTransferApiExample(WxPayConfig config) { + // 初始化微信支付服务 + WxPayService wxPayService = new WxPayServiceImpl(); + wxPayService.setConfig(config); + + // 获取新版转账服务 + this.transferService = wxPayService.getTransferService(); + } + + /** + * 发起单笔转账示例 + * 新版API使用 /v3/fund-app/mch-transfer/transfer-bills 接口 + */ + public void transferExample() { + try { + // 构建转账请求 + TransferBillsRequest request = TransferBillsRequest.newBuilder() + .appid("wx1234567890123456") // 应用ID + .outBillNo("TRANSFER_" + System.currentTimeMillis()) // 商户转账单号,确保唯一 + .transferSceneId("1005") // 转账场景ID(1005=佣金报酬) + .openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o") // 收款用户的openid + .userName("张三") // 收款用户真实姓名(可选,会自动加密) + .transferAmount(100) // 转账金额,单位:分(此处为1元) + .transferRemark("佣金报酬") // 转账备注,用户可见 + .notifyUrl("https://your-domain.com/transfer/notify") // 异步通知地址(可选) + .userRecvPerception("Y") // 用户收款感知:Y=会收到通知,N=不会收到通知 + .build(); + + // 发起转账 + TransferBillsResult result = transferService.transferBills(request); + + // 输出结果 + System.out.println("=== 转账发起成功 ==="); + System.out.println("商户单号: " + result.getOutBillNo()); + System.out.println("微信转账单号: " + result.getTransferBillNo()); + System.out.println("创建时间: " + result.getCreateTime()); + System.out.println("状态: " + result.getState()); + System.out.println("跳转领取页面信息: " + result.getPackageInfo()); + + } catch (WxPayException e) { + System.err.println("转账失败: " + e.getMessage()); + System.err.println("错误代码: " + e.getErrCode()); + System.err.println("错误描述: " + e.getErrCodeDes()); + } + } + + /** + * 通过商户单号查询转账结果 + */ + public void queryByOutBillNoExample() { + try { + String outBillNo = "TRANSFER_1642567890123"; + TransferBillsGetResult result = transferService.getBillsByOutBillNo(outBillNo); + + System.out.println("=== 查询转账结果(商户单号)==="); + System.out.println("商户单号: " + result.getOutBillNo()); + System.out.println("微信转账单号: " + result.getTransferBillNo()); + System.out.println("状态: " + result.getState()); + System.out.println("转账金额: " + result.getTransferAmount() + "分"); + System.out.println("用户openid: " + result.getOpenid()); + System.out.println("转账备注: " + result.getTransferRemark()); + + } catch (WxPayException e) { + System.err.println("查询失败: " + e.getMessage()); + } + } + + /** + * 通过微信转账单号查询转账结果 + */ + public void queryByTransferBillNoExample() { + try { + String transferBillNo = "1000000000000000000000000001"; + TransferBillsGetResult result = transferService.getBillsByTransferBillNo(transferBillNo); + + System.out.println("=== 查询转账结果(微信单号)==="); + System.out.println("微信转账单号: " + result.getTransferBillNo()); + System.out.println("状态: " + result.getState()); + System.out.println("失败原因: " + result.getFailReason()); + + } catch (WxPayException e) { + System.err.println("查询失败: " + e.getMessage()); + } + } + + /** + * 撤销转账示例 + * 注意:只有在特定状态下才能撤销 + */ + public void cancelTransferExample() { + try { + String outBillNo = "TRANSFER_1642567890123"; + TransferBillsCancelResult result = transferService.transformBillsCancel(outBillNo); + + System.out.println("=== 撤销转账结果 ==="); + System.out.println("商户单号: " + result.getOutBillNo()); + System.out.println("状态: " + result.getState()); + System.out.println("更新时间: " + result.getUpdateTime()); + + } catch (WxPayException e) { + System.err.println("撤销失败: " + e.getMessage()); + } + } + + /** + * 处理转账回调通知示例 + * 这个方法通常在您的Web服务器的回调接口中调用 + */ + public void handleNotifyExample(String notifyData, String timestamp, String nonce, String signature, String serial) { + try { + // 构建签名头信息 + SignatureHeader header = new SignatureHeader(); + header.setTimeStamp(timestamp); + header.setNonce(nonce); + header.setSignature(signature); + header.setSerial(serial); + + // 解析并验签回调数据 + TransferBillsNotifyResult notifyResult = transferService.parseTransferBillsNotifyResult(notifyData, header); + + System.out.println("=== 处理转账回调通知 ==="); + System.out.println("商户单号: " + notifyResult.getResult().getOutBillNo()); + System.out.println("微信转账单号: " + notifyResult.getResult().getTransferBillNo()); + System.out.println("状态: " + notifyResult.getResult().getState()); + System.out.println("转账金额: " + notifyResult.getResult().getTransferAmount() + "分"); + System.out.println("更新时间: " + notifyResult.getResult().getUpdateTime()); + + // 根据状态处理业务逻辑 + switch (notifyResult.getResult().getState()) { + case "SUCCESS": + System.out.println("转账成功,进行业务处理..."); + // 更新订单状态、发送通知等 + break; + case "FAIL": + System.out.println("转账失败,失败原因: " + notifyResult.getResult().getFailReason()); + // 处理失败逻辑 + break; + default: + System.out.println("其他状态: " + notifyResult.getResult().getState()); + } + + } catch (WxPayException e) { + System.err.println("回调处理失败: " + e.getMessage()); + } + } + + /** + * 批量转账示例(使用传统API) + * 注意:新商户可能无法使用此API,建议使用新版单笔转账API + */ + public void batchTransferExample() { + try { + // 构建转账明细列表 + TransferBatchesRequest.TransferDetail detail1 = TransferBatchesRequest.TransferDetail.newBuilder() + .outDetailNo("DETAIL_" + System.currentTimeMillis() + "_1") + .transferAmount(100) // 1元 + .transferRemark("佣金1") + .openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o") + .userName("张三") + .build(); + + TransferBatchesRequest.TransferDetail detail2 = TransferBatchesRequest.TransferDetail.newBuilder() + .outDetailNo("DETAIL_" + System.currentTimeMillis() + "_2") + .transferAmount(200) // 2元 + .transferRemark("佣金2") + .openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6p") + .userName("李四") + .build(); + + // 构建批量转账请求 + TransferBatchesRequest batchRequest = TransferBatchesRequest.newBuilder() + .appid("wx1234567890123456") + .outBatchNo("BATCH_" + System.currentTimeMillis()) + .batchName("佣金批量发放") + .batchRemark("2024年1月佣金") + .totalAmount(300) // 总金额:3元 + .totalNum(2) // 总笔数:2笔 + .transferDetailList(java.util.Arrays.asList(detail1, detail2)) + .transferSceneId("1005") // 转账场景ID + .build(); + + // 发起批量转账 + TransferBatchesResult batchResult = transferService.transferBatches(batchRequest); + + System.out.println("=== 批量转账发起成功 ==="); + System.out.println("商户批次单号: " + batchResult.getOutBatchNo()); + System.out.println("微信批次单号: " + batchResult.getBatchId()); + System.out.println("批次状态: " + batchResult.getBatchStatus()); + + } catch (WxPayException e) { + System.err.println("批量转账失败: " + e.getMessage()); + } + } + + /** + * 使用配置示例 + */ + public static void main(String[] args) { + // 配置微信支付参数 + WxPayConfig config = new WxPayConfig(); + config.setAppId("wx1234567890123456"); // 应用ID + config.setMchId("1234567890"); // 商户ID + config.setApiV3Key("your_api_v3_key_32_chars"); // APIv3密钥 + config.setPrivateKeyPath("path/to/private.pem"); // 商户私钥文件路径 + config.setCertSerialNo("your_certificate_serial"); // 商户证书序列号 + + // 创建示例实例 + NewTransferApiExample example = new NewTransferApiExample(config); + + // 运行示例 + System.out.println("新版商户转账API使用示例"); + System.out.println("==============================="); + + // 1. 发起单笔转账 + example.transferExample(); + + // 2. 查询转账结果 + // example.queryByOutBillNoExample(); + + // 3. 撤销转账 + // example.cancelTransferExample(); + + // 4. 批量转账(传统API) + // example.batchTransferExample(); + } +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java index 168e43696a..1a1ddb120a 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java @@ -166,4 +166,22 @@ public interface WxEntrustPapService { * @throws WxPayException the wx pay exception */ WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWithholdOrderQueryRequest) throws WxPayException; + + /** + *+ * 签约、解约结果通知解析 + * 详见:签约、解约结果通知 + * 注意: + * 1、同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是:当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。 + * 2、如果在所有通知频率(0/10/10/10/30/30/30/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300(单位:秒))后没有收到微信侧回调,商户应调用查询订单接口确认订单状态。 + * 特别提醒: + * 1、商户系统对于签约、解约结果通知的内容一定要做签名验证,并校验返回的商户协议号和用户openid信息是否一致,防止数据泄露导致出现“假通知”,造成损失。 + * 2、当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。 + *+ * + * @param xmlData the wx withhold order query request + * @return wx sign result + * @throws WxPayException the wx pay exception + */ + WxSignQueryResult parseSignNotifyResult(String xmlData) throws WxPayException; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 8ceac2b6ba..c73fb843e8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum; import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.constant.WxPayConstants; @@ -640,6 +641,17 @@ public interface WxPayService { */T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException; + /** + * 境外微信支付调用统一下单接口,并组装生成支付所需参数对象. + * + * @param 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段 + * @param tradeType the global trade type + * @param request 境外统一下单请求参数 + * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段 + * @throws WxPayException the wx pay exception + */ + T createOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException; + /** * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" * @@ -660,6 +672,16 @@ public interface WxPayService { */ WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; + /** + * 境外微信支付在发起支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param tradeType the global trade type + * @param request 境外请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) + * @return the wx pay unified order result + * @throws WxPayException the wx pay exception + */ + WxPayUnifiedOrderV3Result unifiedOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException; + /** * * 合单支付API(APP支付、JSAPI支付、H5支付、NATIVE支付). diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java index 077562f03c..f32083a632 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java @@ -11,6 +11,7 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum; import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfigHolder; @@ -30,11 +31,10 @@ import com.google.gson.GsonBuilder; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxRuntimeException; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.ConstructorUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; @@ -59,14 +59,13 @@ * * @author Binary Wang */ +@Slf4j public abstract class BaseWxPayServiceImpl implements WxPayService { private static final String TOTAL_FUND_COUNT = "资金流水总笔数"; private static final Gson GSON = new GsonBuilder().create(); - final Logger log = LoggerFactory.getLogger(this.getClass()); - - static ThreadLocalwxApiData = new ThreadLocal<>(); + static final ThreadLocal wxApiData = new ThreadLocal<>(); @Setter @@ -209,7 +208,7 @@ public WxPayService switchoverTo(String mchId, String appId) { throw new WxRuntimeException(String.format("无法找到对应mchId=【%s】,appId=【%s】的商户号配置信息,请核实!", mchId, appId)); } - private String getConfigKey(String mchId, String appId) { + public String getConfigKey(String mchId, String appId) { return mchId + "_" + appId; } @@ -219,9 +218,9 @@ public String getPayBaseUrl() { if (StringUtils.isNotBlank(this.getConfig().getApiV3Key())) { throw new WxRuntimeException("微信支付V3 目前不支持沙箱模式!"); } - return this.getConfig().getPayBaseUrl() + "/xdc/apiv2sandbox"; + return this.getConfig().getApiHostUrl() + "/xdc/apiv2sandbox"; } - return this.getConfig().getPayBaseUrl(); + return this.getConfig().getApiHostUrl(); } @Override @@ -251,7 +250,7 @@ public WxPayRefundResult refundV2(WxPayRefundRequest request) throws WxPayExcept @Override public WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds", this.getPayBaseUrl()); - String response = this.postV3(url, GSON.toJson(request)); + String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayRefundV3Result.class); } @@ -294,21 +293,21 @@ public WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) thr @Override public WxPayRefundQueryV3Result refundQueryV3(String outRefundNo) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), outRefundNo); - String response = this.getV3(url); + String response = this.getV3WithWechatPaySerial(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @Override public WxPayRefundQueryV3Result refundQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), request.getOutRefundNo()); - String response = this.getV3(url); + String response = this.getV3WithWechatPaySerial(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @Override public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(), request.getSubMchid()); - String response = this.getV3(url); + String response = this.getV3WithWechatPaySerial(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @@ -323,14 +322,13 @@ public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData, String sign log.debug("微信支付异步通知请求参数:{}", xmlData); WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); if (signType == null) { - String configKey = this.getConfigKey(result.getMchId(), result.getAppid()); + this.switchover(result.getMchId(), result.getAppid()); if (result.getSignType() != null) { // 如果解析的通知对象中signType有值,则使用它进行验签 signType = result.getSignType(); - } else if (configMap.get(configKey).getSignType() != null) { + } else if (this.getConfig().getSignType() != null) { // 如果配置中signType有值,则使用它进行验签 - signType = configMap.get(configKey).getSignType(); - this.switchover(result.getMchId(), result.getAppid()); + signType = this.getConfig().getSignType(); } } @@ -524,7 +522,7 @@ public WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) th url = String.format("%s/v3/pay/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId()); } String query = String.format("?mchid=%s", request.getMchid()); - String response = this.getV3(url + query); + String response = this.getV3WithWechatPaySerial(url + query); return GSON.fromJson(response, WxPayOrderQueryV3Result.class); } @@ -549,14 +547,14 @@ public WxPayPartnerOrderQueryV3Result queryPartnerOrderV3(WxPayPartnerOrderQuery url = String.format("%s/v3/pay/partner/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId()); } String query = String.format("?sp_mchid=%s&sub_mchid=%s", request.getSpMchId(), request.getSubMchId()); - String response = this.getV3(url + query); + String response = this.getV3WithWechatPaySerial(url + query); return GSON.fromJson(response, WxPayPartnerOrderQueryV3Result.class); } @Override public CombineQueryResult queryCombine(String combineOutTradeNo) throws WxPayException { String url = String.format("%s/v3/combine-transactions/out-trade-no/%s", this.getPayBaseUrl(), combineOutTradeNo); - String response = this.getV3(url); + String response = this.getV3WithWechatPaySerial(url); return GSON.fromJson(response, CombineQueryResult.class); } @@ -610,7 +608,7 @@ public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException request.setMchid(this.getConfig().getMchId()); } String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo()); - this.postV3(url, GSON.toJson(request)); + this.postV3WithWechatpaySerial(url, GSON.toJson(request)); } @Override @@ -622,13 +620,13 @@ public void closePartnerOrderV3(WxPayPartnerOrderCloseV3Request request) throws request.setSubMchId(this.getConfig().getSubMchId()); } String url = String.format("%s/v3/pay/partner/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo()); - this.postV3(url, GSON.toJson(request)); + this.postV3WithWechatpaySerial(url, GSON.toJson(request)); } @Override public void closeCombine(CombineCloseRequest request) throws WxPayException { String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo()); - this.postV3(url, GSON.toJson(request)); + this.postV3WithWechatpaySerial(url, GSON.toJson(request)); } @Override @@ -749,6 +747,14 @@ public T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOr return result.getPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey()); } + @Override + public T createOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException { + WxPayUnifiedOrderV3Result result = this.unifiedOrderV3Global(tradeType, request); + // Convert GlobalTradeTypeEnum to TradeTypeEnum for getPayInfo method + TradeTypeEnum domesticTradeType = TradeTypeEnum.valueOf(tradeType.name()); + return result.getPayInfo(domesticTradeType, request.getAppid(), request.getMchid(), this.getConfig().getPrivateKey()); + } + @Override public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getSpAppid())) { @@ -772,7 +778,7 @@ public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, } String url = this.getPayBaseUrl() + tradeType.getBasePartnerUrl(); - String response = this.postV3(url, GSON.toJson(request)); + String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class); } @@ -789,7 +795,29 @@ public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUn } String url = this.getPayBaseUrl() + tradeType.getPartnerUrl(); - String response = this.postV3(url, GSON.toJson(request)); + String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); + return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class); + } + + @Override + public WxPayUnifiedOrderV3Result unifiedOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException { + if (StringUtils.isBlank(request.getAppid())) { + request.setAppid(this.getConfig().getAppId()); + } + if (StringUtils.isBlank(request.getMchid())) { + request.setMchid(this.getConfig().getMchId()); + } + if (StringUtils.isBlank(request.getNotifyUrl())) { + request.setNotifyUrl(this.getConfig().getNotifyUrl()); + } + if (StringUtils.isBlank(request.getTradeType())) { + request.setTradeType(tradeType.name()); + } + + // Use global WeChat Pay base URL for overseas payments + String globalBaseUrl = "https://apihk.mch.weixin.qq.com"; + String url = globalBaseUrl + tradeType.getUrl(); + String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class); } @@ -802,7 +830,7 @@ public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransac request.setCombineMchid(this.getConfig().getMchId()); } String url = this.getPayBaseUrl() + tradeType.getCombineUrl(); - String response = this.postV3(url, GSON.toJson(request)); + String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); return GSON.fromJson(response, CombineTransactionsResult.class); } @@ -1115,7 +1143,7 @@ public WxPayApplyBillV3Result applyTradeBill(WxPayApplyTradeBillV3Request reques } else { url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType(), request.getTarType()); } - String response = this.getV3(url); + String response = this.getV3WithWechatPaySerial(url); return GSON.fromJson(response, WxPayApplyBillV3Result.class); } @@ -1127,7 +1155,7 @@ public WxPayApplyBillV3Result applyFundFlowBill(WxPayApplyFundFlowBillV3Request } else { url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&account_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType(), request.getTarType()); } - String response = this.getV3(url); + String response = this.getV3WithWechatPaySerial(url); return GSON.fromJson(response, WxPayApplyBillV3Result.class); } @@ -1156,7 +1184,7 @@ public WxPayCodepayResult codepay(WxPayCodepayRequest request) throws WxPayExcep request.setMchid(this.getConfig().getMchId()); } String url = String.format("%s/v3/pay/transactions/codepay", this.getPayBaseUrl()); - String body = this.postV3(url, GSON.toJson(request)); + String body = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); return GSON.fromJson(body, WxPayCodepayResult.class); } @@ -1182,7 +1210,7 @@ public WxPayOrderReverseV3Result reverseOrderV3(WxPayOrderReverseV3Request reque } // 拼接参数请求路径并发送 String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/reverse", this.getPayBaseUrl(), request.getOutTradeNo()); - String response = this.postV3(url, GSON.toJson(request)); + String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayOrderReverseV3Result.class); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java index a9ee5d236d..dff607922b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java @@ -44,7 +44,7 @@ public BrandBatchesQueryResult queryBrandWxBatches(BrandWxBatchesQueryRequest re if (request.getNeedQueryDetail() != null) { url = String.format("%s?need_query_detail=%b", url, request.getNeedQueryDetail()); } - if (request.getDetailState() != null && request.getDetailState().length() != 0) { + if (request.getDetailState() != null && !request.getDetailState().isEmpty()) { url = String.format("%s&detail_state=%s", url, request.getDetailState()); } @@ -68,7 +68,7 @@ public BrandBatchesQueryResult queryBrandMerchantBatches(BrandMerchantBatchesQue if (request.getNeedQueryDetail() != null) { url = String.format("%s?need_query_detail=%b", url, request.getNeedQueryDetail()); } - if (request.getDetailState() != null && request.getDetailState().length() != 0) { + if (request.getDetailState() != null && !request.getDetailState().isEmpty()) { url = String.format("%s&detail_state=%s", url, request.getDetailState()); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java index d25ed7c0a2..f596d4cf8c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java @@ -4,7 +4,6 @@ import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.CustomDeclarationService; import com.github.binarywang.wxpay.service.WxPayService; -import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import lombok.RequiredArgsConstructor; diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java index 36dc08d6f6..479520d7f7 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java @@ -294,7 +294,7 @@ public RefundQueryResult queryRefundByRefundId(String subMchid, String refundId) @Override public ReturnAdvanceResult refundsReturnAdvance(String subMchid, String refundId) throws WxPayException { String url = String.format("%s/v3/ecommerce/refunds/%s/return-advance", this.payService.getPayBaseUrl(), refundId); - Map request = new HashMap(); + Map request = new HashMap<>(); request.put("sub_mchid",subMchid); String response = this.payService.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, ReturnAdvanceResult.class); @@ -489,7 +489,7 @@ private String parseURLPair(Object o) { public static Map