From 9850151dfad79f6fa18835291f9321b59e87e1a7 Mon Sep 17 00:00:00 2001 From: f00lish Date: Fri, 6 Nov 2020 09:44:36 +0800 Subject: [PATCH 01/18] =?UTF-8?q?:bug:=20#1856=20=E3=80=90=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E3=80=91=E4=BF=AE=E5=A4=8D=E7=94=B5?= =?UTF-8?q?=E5=95=86=E6=94=B6=E4=BB=98=E9=80=9A=E6=9F=A5=E8=AF=A2=E9=80=80?= =?UTF-8?q?=E6=AC=BE=E7=8A=B6=E6=80=81=E7=9A=84=E6=8E=A5=E5=8F=A3=E5=9C=B0?= =?UTF-8?q?=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binarywang/wxpay/service/impl/EcommerceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a41ee81b06..67976caf31 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 @@ -226,7 +226,7 @@ public RefundQueryResult queryRefundByRefundId(String subMchid, String refundId) @Override public RefundQueryResult queryRefundByOutRefundNo(String subMchid, String outRefundNo) throws WxPayException { - String url = String.format("%s/v3/ecommerce/applyments/out-request-no/%s?sub_mchid=%s", this.payService.getPayBaseUrl(), outRefundNo, subMchid); + String url = String.format("%s/v3/ecommerce/refunds/out-refund-no/%s?sub_mchid=%s", this.payService.getPayBaseUrl(), outRefundNo, subMchid); String response = this.payService.getV3(URI.create(url)); return GSON.fromJson(response, RefundQueryResult.class); } From 3b439113acf14c7e739df1914c7497844018d459 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 8 Nov 2020 15:12:52 +0800 Subject: [PATCH 02/18] =?UTF-8?q?:art:=20#1857=20=E3=80=90=E4=BC=81?= =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E3=80=91=E8=8E=B7=E5=8F=96=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E9=83=A8=E9=97=A8=E6=88=90=E5=91=98=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E=E5=80=BC=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E5=BA=94=E7=94=A8=E4=B8=93=E6=9C=89?= =?UTF-8?q?=E7=9A=84open=5Fuserid=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weixin/cp/api/WxCpUserService.java | 28 ++++++++++++++----- .../me/chanjar/weixin/cp/bean/WxCpUser.java | 4 +++ .../cp/util/json/WxCpUserGsonAdapter.java | 1 + 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java index c8b2aae672..4804dbc818 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpUserService.java @@ -25,19 +25,24 @@ public interface WxCpUserService { * * * @param userId 用户id + * @throws WxErrorException the wx error exception */ void authenticate(String userId) throws WxErrorException; /** *
-   * 获取部门成员(详情).
+   * 获取部门成员详情
+   * 请求方式:GET(HTTPS)
+   * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD
    *
-   * http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
+   * 文档地址:https://work.weixin.qq.com/api/doc/90000/90135/90201
    * 
* * @param departId 必填。部门id * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @return the list + * @throws WxErrorException the wx error exception */ List listByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; @@ -51,6 +56,8 @@ public interface WxCpUserService { * @param departId 必填。部门id * @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员 * @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加 + * @return the list + * @throws WxErrorException the wx error exception */ List listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException; @@ -58,6 +65,7 @@ public interface WxCpUserService { * 新建用户. * * @param user 用户对象 + * @throws WxErrorException the wx error exception */ void create(WxCpUser user) throws WxErrorException; @@ -65,6 +73,7 @@ public interface WxCpUserService { * 更新用户. * * @param user 用户对象 + * @throws WxErrorException the wx error exception */ void update(WxCpUser user) throws WxErrorException; @@ -75,6 +84,7 @@ public interface WxCpUserService { * * * @param userIds 员工UserID列表。对应管理端的帐号 + * @throws WxErrorException the wx error exception */ void delete(String... userIds) throws WxErrorException; @@ -82,6 +92,8 @@ public interface WxCpUserService { * 获取用户. * * @param userid 用户id + * @return the by id + * @throws WxErrorException the wx error exception */ WxCpUser getById(String userid) throws WxErrorException; @@ -97,6 +109,8 @@ public interface WxCpUserService { * @param userIds 成员ID列表, 最多支持1000个。 * @param partyIds 部门ID列表,最多支持100个。 * @param tagIds 标签ID列表,最多支持100个。 + * @return the wx cp invite result + * @throws WxErrorException the wx error exception */ WxCpInviteResult invite(List userIds, List partyIds, List tagIds) throws WxErrorException; @@ -114,9 +128,8 @@ public interface WxCpUserService { * * @param userId 企业内的成员id * @param agentId 非必填,整型,仅用于发红包。其它场景该参数不要填,如微信支付、企业转账、电子发票 - * @return map对象,可能包含以下值: - * - openid 企业微信成员userid对应的openid,若有传参agentid,则是针对该agentid的openid。否则是针对企业微信corpid的openid - * - appid 应用的appid,若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到 + * @return map对象 ,可能包含以下值: - openid 企业微信成员userid对应的openid,若有传参agentid,则是针对该agentid的openid。否则是针对企业微信corpid的openid - appid 应用的appid,若请求包中不包含agentid则不返回appid。该appid在使用微信红包时会用到 + * @throws WxErrorException the wx error exception */ Map userId2Openid(String userId, Integer agentId) throws WxErrorException; @@ -134,6 +147,7 @@ public interface WxCpUserService { * * @param openid 在使用微信支付、微信红包和企业转账之后,返回结果的openid * @return userid 该openid在企业微信对应的成员userid + * @throws WxErrorException the wx error exception */ String openid2UserId(String openid) throws WxErrorException; @@ -149,7 +163,7 @@ public interface WxCpUserService { * * * @param mobile 手机号码。长度为5~32个字节 - * @return userid mobile对应的成员userid + * @return userid mobile对应的成员userid * @throws WxErrorException . */ String getUserId(String mobile) throws WxErrorException; @@ -164,7 +178,7 @@ public interface WxCpUserService { * * * @param userId 外部联系人的userid - * @return 联系人详情 + * @return 联系人详情 external contact * @throws WxErrorException . */ WxCpExternalContactInfo getExternalContact(String userId) throws WxErrorException; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java index 221f49aa86..a0ecac2683 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpUser.java @@ -33,6 +33,10 @@ public class WxCpUser implements Serializable { private String avatar; private String thumbAvatar; private String mainDepartment; + /** + * 全局唯一。对于同一个服务商,不同应用获取到企业内同一个成员的open_userid是相同的,最多64个字节。仅第三方应用可获取 + */ + private String openUserId; /** * 地址。长度最大128个字符 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 835f89cc50..7df4cd78fa 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 @@ -86,6 +86,7 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC 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")); if (GsonHelper.isNotNull(o.get(EXTRA_ATTR))) { From 6037002c27e5ed7fe6a1037705e5955f3f83313d Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sun, 8 Nov 2020 17:08:50 +0800 Subject: [PATCH 03/18] =?UTF-8?q?:bookmark:=20=E5=8F=91=E5=B8=83=203.9.8.B?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- spring-boot-starters/pom.xml | 2 +- .../wx-java-miniapp-spring-boot-starter/pom.xml | 2 +- spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml | 2 +- spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml | 2 +- spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml | 2 +- weixin-graal/pom.xml | 2 +- weixin-java-common/pom.xml | 2 +- weixin-java-cp/pom.xml | 2 +- weixin-java-miniapp/pom.xml | 2 +- weixin-java-mp/pom.xml | 2 +- weixin-java-open/pom.xml | 2 +- weixin-java-pay/pom.xml | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 41f9662542..0fafc56690 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 4.0.0 com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B pom WxJava - Weixin/Wechat Java SDK 微信开发Java SDK diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml index 013e127e56..1201828186 100644 --- a/spring-boot-starters/pom.xml +++ b/spring-boot-starters/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B pom wx-java-spring-boot-starters diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml index a9a30fb17f..49f7680937 100644 --- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.7.B + 3.9.8.B 4.0.0 diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml index 17d64b6c65..f59a9eaf7e 100644 --- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.7.B + 3.9.8.B 4.0.0 diff --git a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml index d2cafea7a7..4bc26e154a 100644 --- a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.7.B + 3.9.8.B 4.0.0 diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml index 9940a0ee96..03704fffb9 100644 --- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml +++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ wx-java-spring-boot-starters com.github.binarywang - 3.9.7.B + 3.9.8.B 4.0.0 diff --git a/weixin-graal/pom.xml b/weixin-graal/pom.xml index f80cf79483..942ab745ee 100644 --- a/weixin-graal/pom.xml +++ b/weixin-graal/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B weixin-graal diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml index e9a3a090e7..65b6ca0398 100644 --- a/weixin-java-common/pom.xml +++ b/weixin-java-common/pom.xml @@ -6,7 +6,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B weixin-java-common diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml index 55e063ab21..ab11231d50 100644 --- a/weixin-java-cp/pom.xml +++ b/weixin-java-cp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B weixin-java-cp diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index a2a4b3b93d..728e009f8c 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B weixin-java-miniapp diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml index e19a906660..30753569ab 100644 --- a/weixin-java-mp/pom.xml +++ b/weixin-java-mp/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B weixin-java-mp diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml index 631d98d3be..ca27b1a707 100644 --- a/weixin-java-open/pom.xml +++ b/weixin-java-open/pom.xml @@ -7,7 +7,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B weixin-java-open diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml index 1e608f60bb..5c85efcc10 100644 --- a/weixin-java-pay/pom.xml +++ b/weixin-java-pay/pom.xml @@ -5,7 +5,7 @@ com.github.binarywang wx-java - 3.9.7.B + 3.9.8.B 4.0.0 From bf4c8c206449809b13128281313bfaec892ece9f Mon Sep 17 00:00:00 2001 From: Pancras Date: Tue, 10 Nov 2020 10:21:41 +0800 Subject: [PATCH 04/18] =?UTF-8?q?:art:=20=E4=BF=AE=E5=A4=8Dout=5Ftrade=5Fn?= =?UTF-8?q?o=20=E5=AD=97=E6=AE=B5=E5=91=BD=E5=90=8D=E4=B8=8D=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: vcpgfw --- .../wxpay/bean/ecommerce/PartnerTransactionsRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java index b1ace4d577..bde15dc39b 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java @@ -100,7 +100,7 @@ public class PartnerTransactionsRequest implements Serializable { * */ @SerializedName(value = "out_trade_no") - private String out_trade_no; + private String outTradeNo; /** *

From e9125872d1895d35e2d5f6e8d22fd0db6f8efdec Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Tue, 10 Nov 2020 15:38:49 +0800
Subject: [PATCH 05/18] :memo:  add more cases

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index c5f82fc0e7..ab7ada780b 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,7 @@
 - 维沃吼吼
 - 王朝社区(比亚迪新能源社区)
 - 极吼吼手机上门回收换新
+- 未来信封 
 
 
 #### 公众号:
@@ -138,6 +139,7 @@
 - YshopMall
 - 好行景区直通车以及全国40多个公众号
 - 我奥篮球公众号
+- 未来信封官微
 
 #### 企业号/企业微信:
 - HTC企业微信

From 4af70b2c7c3d3e299cc134987543067096530e76 Mon Sep 17 00:00:00 2001
From: winter 
Date: Tue, 10 Nov 2020 16:27:43 +0800
Subject: [PATCH 06/18] =?UTF-8?q?:bug:=20#1861=E3=80=90=E5=BE=AE=E4=BF=A1?=
 =?UTF-8?q?=E6=94=AF=E4=BB=98=E3=80=91=E6=94=AF=E4=BB=98=E5=88=86=E5=90=8E?=
 =?UTF-8?q?=E4=BB=98=E8=B4=B9=E9=A1=B9=E7=9B=AE=E8=AF=B7=E6=B1=82=E7=B1=BB?=
 =?UTF-8?q?=E7=9A=84amount=E5=B1=9E=E6=80=A7=E6=94=B9=E4=B8=BAInteger?=
 =?UTF-8?q?=EF=BC=8C=E5=85=81=E8=AE=B8=E4=B8=BA=E7=A9=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/github/binarywang/wxpay/bean/payscore/PostPayment.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PostPayment.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PostPayment.java
index 3486c14012..e40960a056 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PostPayment.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/PostPayment.java
@@ -26,7 +26,7 @@ public class PostPayment implements Serializable {
   @SerializedName("name")
   private String name;
   @SerializedName("amount")
-  private int amount;
+  private Integer amount;
   @SerializedName("description")
   private String description;
   @SerializedName("count")

From f3019121548754f1c44fe75806b5e361b1966127 Mon Sep 17 00:00:00 2001
From: JoeWoo 
Date: Wed, 11 Nov 2020 23:48:38 +0800
Subject: [PATCH 07/18] =?UTF-8?q?:bug:=20#1864=20=E3=80=90=E5=BE=AE?=
 =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E3=80=91WxPayConfig=E7=B1=BB?=
 =?UTF-8?q?=E7=9A=84hashCode=E5=92=8Cequals=E6=96=B9=E6=B3=95=E7=A7=BB?=
 =?UTF-8?q?=E9=99=A4=20verifier=20=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/github/binarywang/wxpay/config/WxPayConfig.java     | 2 ++
 .../com/github/binarywang/wxpay/config/WxPayConfigTest.java | 6 ++++++
 2 files changed, 8 insertions(+)

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 2586088194..8fed27452e 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
@@ -6,6 +6,7 @@
 import com.github.binarywang.wxpay.v3.util.PemUtils;
 import jodd.util.ResourcesUtil;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.SneakyThrows;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.RegExUtils;
@@ -28,6 +29,7 @@
  * @author Binary Wang (https://github.com/binarywang)
  */
 @Data
+@EqualsAndHashCode(exclude = "verifier")
 public class WxPayConfig {
   private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com";
   private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!";
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java
index fb46c58a4d..8b5a621b89 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java
@@ -31,4 +31,10 @@ public void testInitSSLContext() throws Exception {
     this.testInitSSLContext_classpath();
     this.testInitSSLContext_http();
   }
+
+  @Test
+  @SuppressWarnings("ResultOfMethodCallIgnored")
+  public void testHashCode() {
+    payConfig.hashCode();
+  }
 }

From edc04cb0ae98c460b35eecfb1fe36f8107667865 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BE=AE=E5=90=8C=E7=A7=91=E6=8A=80?=
 <30375770+lipengjun92@users.noreply.github.com>
Date: Wed, 11 Nov 2020 23:50:31 +0800
Subject: [PATCH 08/18] =?UTF-8?q?:new:=20#1863=20=E3=80=90=E5=B0=8F?=
 =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E3=80=91=E5=A2=9E=E5=8A=A0=E5=88=A0=E9=99=A4?=
 =?UTF-8?q?=E7=9B=B4=E6=92=AD=E9=97=B4=E3=80=81=E7=BC=96=E8=BE=91=E7=9B=B4?=
 =?UTF-8?q?=E6=92=AD=E9=97=B4=E3=80=81=E8=8E=B7=E5=8F=96=E7=9B=B4=E6=92=AD?=
 =?UTF-8?q?=E9=97=B4=E6=8E=A8=E6=B5=81=E5=9C=B0=E5=9D=80=E3=80=81=E8=8E=B7?=
 =?UTF-8?q?=E5=8F=96=E7=9B=B4=E6=92=AD=E9=97=B4=E5=88=86=E4=BA=AB=E4=BA=8C?=
 =?UTF-8?q?=E7=BB=B4=E7=A0=81=E7=AD=89=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../wx/miniapp/api/WxMaLiveService.java       | 59 +++++++++++++++++++
 .../miniapp/api/impl/WxMaLiveServiceImpl.java | 50 ++++++++++++++++
 .../miniapp/bean/live/WxMaLiveRoomInfo.java   |  8 +++
 .../api/impl/WxMaLiveServiceImplTest.java     | 47 ++++++++++++++-
 4 files changed, 162 insertions(+), 2 deletions(-)

diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java
index c013958ee4..3047c9a3b2 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java
@@ -18,6 +18,10 @@ public interface WxMaLiveService {
   String GET_LIVE_INFO = "https://api.weixin.qq.com/wxa/business/getliveinfo";
   String CREATE_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/create";
   String ADD_GOODS = "https://api.weixin.qq.com/wxaapi/broadcast/room/addgoods";
+  String DELETE_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/deleteroom";
+  String EDIT_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/editroom";
+  String GET_PUSH_URL = "https://api.weixin.qq.com/wxaapi/broadcast/room/getpushurl";
+  String GET_SHARED_CODE = "https://api.weixin.qq.com/wxaapi/broadcast/room/getsharedcode";
 
   /**
    * 创建直播间
@@ -33,6 +37,61 @@ public interface WxMaLiveService {
    */
   Integer createRoom(WxMaLiveRoomInfo roomInfo) throws WxErrorException;
 
+  /**
+   * 删除直播间
+   * 
+   * 调用额度:10000次/一天
+   * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/framework/liveplayer/studio-api.html#5
+   * http请求方式:POST https://api.weixin.qq.com/wxaapi/broadcast/room/deleteroom?access_token=ACCESS_TOKEN
+   * 
+ * + * @param roomId 直播间id + * @return . + * @throws WxErrorException . + */ + boolean deleteRoom(Integer roomId) throws WxErrorException; + + /** + * 编辑直播间 + *
+   * 调用此接口编辑直播间,调用额度:10000次/一天
+   * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/framework/liveplayer/studio-api.html#6
+   * http请求方式:POST https://api.weixin.qq.com/wxaapi/broadcast/room/editroom?access_token=ACCESS_TOKEN
+   * 
+ * + * @param roomInfo 直播间信息 + * @return . + * @throws WxErrorException . + */ + boolean editRoom(WxMaLiveRoomInfo roomInfo) throws WxErrorException; + + /** + * 获取直播间推流地址 + *
+   * 调用额度:10000次/一天
+   * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/framework/liveplayer/studio-api.html#7
+   * http请求方式:GET https://api.weixin.qq.com/wxaapi/broadcast/room/getpushurl?access_token=ACCESS_TOKEN
+   * 
+ * + * @param roomId 直播间id + * @return . + * @throws WxErrorException . + */ + String getPushUrl(Integer roomId) throws WxErrorException; + + /** + * 获取直播间分享二维码 + *
+   * 调用额度:10000次/一天
+   * 文档地址:https://developers.weixin.qq.com/miniprogram/dev/framework/liveplayer/studio-api.html#8
+   * http请求方式:GET https://api.weixin.qq.com/wxaapi/broadcast/room/getsharedcode?access_token=ACCESS_TOKEN
+   * 
+ * + * @param roomId 直播间id + * @return . + * @throws WxErrorException . + */ + String getSharedCode(Integer roomId, String params) throws WxErrorException; /** * 获取直播房间列表.(分页) * diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java index c2bbc97e32..84aaab708f 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java @@ -5,6 +5,7 @@ import cn.binarywang.wx.miniapp.bean.live.WxMaLiveResult; import cn.binarywang.wx.miniapp.bean.live.WxMaLiveRoomInfo; import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder; +import com.google.common.base.Joiner; import com.google.gson.JsonObject; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -40,6 +41,55 @@ public Integer createRoom(WxMaLiveRoomInfo roomInfo) throws WxErrorException { return jsonObject.get("roomId").getAsInt(); } + @Override + public boolean deleteRoom(Integer roomId) throws WxErrorException { + Map map = new HashMap<>(2); + map.put("id", roomId); + String responseContent = this.wxMaService.post(DELETE_ROOM, WxMaGsonBuilder.create().toJson(map)); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + return true; + } + + @Override + public boolean editRoom(WxMaLiveRoomInfo roomInfo) throws WxErrorException { + String responseContent = this.wxMaService.post(EDIT_ROOM, WxMaGsonBuilder.create().toJson(roomInfo)); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + return true; + } + + @Override + public String getPushUrl(Integer roomId) throws WxErrorException { + Map map = new HashMap<>(2); + map.put("roomId", roomId); + String responseContent = this.wxMaService.get(GET_PUSH_URL, Joiner.on("&").withKeyValueSeparator("=").join(map)); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + return jsonObject.get("pushAddr").getAsString(); + } + + @Override + public String getSharedCode(Integer roomId, String params) throws WxErrorException { + Map map = new HashMap<>(2); + map.put("roomId", roomId); + if (null != params) { + map.put("params", params); + } + String responseContent = this.wxMaService.get(GET_SHARED_CODE, Joiner.on("&").withKeyValueSeparator("=").join(map)); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get("errcode").getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + return jsonObject.get("cdnUrl").getAsString(); + } + @Override public WxMaLiveResult getLiveInfo(Integer start, Integer limit) throws WxErrorException { JsonObject jsonObject = getLiveInfo(start, limit, null); diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java index c393d5dbd5..97f30f4377 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java @@ -11,6 +11,10 @@ public class WxMaLiveRoomInfo implements Serializable { private static final long serialVersionUID = 7745775280267417154L; + /** + * 直播间ID + */ + private Integer id; /** * 直播间名字,最短3个汉字,最长17个汉字,1个汉字相当于2个字符 **/ @@ -39,6 +43,10 @@ public class WxMaLiveRoomInfo implements Serializable { * 主播副号微信号,如果未实名认证,需要先前往“小程序直播”小程序进行实名验证, 小程序二维码链接:https://res.wx.qq.com/op_res/BbVNeczA1XudfjVqCVoKgfuWe7e3aUhokktRVOqf_F0IqS6kYR--atCpVNUUC3zr **/ private String subAnchorWechat; + /** + * 创建者微信号,不传入则此直播间所有成员可见。传入则此房间仅创建者、管理员、超管、直播间主播可见 + **/ + private String createrWechat; /** * 分享图,填入mediaID(mediaID获取后,三天内有效);图片mediaID的获取,请参考以下文档: https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html;直播间分享图,图片规则:建议像素800*640,大小不超过1M; **/ diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImplTest.java index d93a540b2b..1d43b50bee 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImplTest.java @@ -37,12 +37,13 @@ public void createRoom() throws Exception { roomInfo.setName("订阅通知直播间"); roomInfo.setCoverImg(mediaUpload.getMediaId()); Calendar c = Calendar.getInstance(); - c.set(2020, Calendar.SEPTEMBER, 10, 8, 0); + c.set(2020, Calendar.DECEMBER, 10, 8, 0); roomInfo.setStartTime(c.getTimeInMillis() / 1000); - c.set(2020, Calendar.SEPTEMBER, 10, 12, 0); + c.set(2020, Calendar.DECEMBER, 10, 12, 0); roomInfo.setEndTime(c.getTimeInMillis() / 1000); roomInfo.setAnchorName("鹏军_专业小程序开发"); roomInfo.setAnchorWechat("pengjun939961241"); + roomInfo.setCreaterWechat("pengjun939961241"); roomInfo.setShareImg(mediaUpload.getMediaId()); roomInfo.setType(1); roomInfo.setScreenType(1); @@ -53,6 +54,48 @@ public void createRoom() throws Exception { System.out.println(roomId); } + @Test + public void deletRoom() throws Exception { + this.wxService.getLiveService().deleteRoom(29); + } + + @Test + public void editRoom() throws Exception { + //上传临时素材 +// WxMediaUploadResult mediaUpload = this.wxService.getMediaService().uploadMedia("image", new File("E:\\1.png")); + + WxMaLiveRoomInfo roomInfo = new WxMaLiveRoomInfo(); + roomInfo.setId(39); + roomInfo.setName("修改订阅通知直播间"); + roomInfo.setCoverImg("http://mmbiz.qpic.cn/mmbiz_png/omYktZNGamuBLBYlP2FjpIL2AHoiayH8HXeZRibtXDMesHn5aevEaM4etUVwfnX1HHqrXBDY3KPgT8MIlqbtqX8Q/0"); + Calendar c = Calendar.getInstance(); + c.set(2021, Calendar.SEPTEMBER, 10, 8, 0); + roomInfo.setStartTime(c.getTimeInMillis() / 1000); + c.set(2021, Calendar.SEPTEMBER, 10, 12, 0); + roomInfo.setEndTime(c.getTimeInMillis() / 1000); + roomInfo.setAnchorName("鹏军_专业小程序开发"); + roomInfo.setAnchorWechat("pengjun939961241"); + roomInfo.setShareImg("http://mmbiz.qpic.cn/mmbiz_png/omYktZNGamuBLBYlP2FjpIL2AHoiayH8HXeZRibtXDMesHn5aevEaM4etUVwfnX1HHqrXBDY3KPgT8MIlqbtqX8Q/0"); + roomInfo.setType(1); + roomInfo.setScreenType(1); + roomInfo.setCloseLike(0); + roomInfo.setCloseGoods(0); + roomInfo.setCloseComment(0); + boolean editRoom = this.wxService.getLiveService().editRoom(roomInfo); + System.out.println(editRoom); + } + @Test + public void getPushUrl() throws Exception { + String result = this.wxService.getLiveService().getPushUrl(39); + System.out.println(result); + } + + @Test + public void getSharedCode() throws Exception { + String result = this.wxService.getLiveService().getSharedCode(39, null); + System.out.println(result); + } + @Test public void getLiveInfo() throws Exception { WxMaLiveResult list = this.wxService.getLiveService().getLiveInfo(0, 10); From a2074a4d391144ded325529c20567b560a663501 Mon Sep 17 00:00:00 2001 From: xworks Date: Thu, 12 Nov 2020 17:30:27 +0800 Subject: [PATCH 09/18] =?UTF-8?q?:art:=20#1867=E3=80=90=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E3=80=91=E4=BC=98=E5=8C=96=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E5=BA=94=E7=94=A8=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/xml/StringArrayConverter.java | 30 ++ .../cp/bean/message/WxCpTpXmlMessage.java | 357 ++++++++++++++++++ .../weixin/cp/config/WxCpTpConfigStorage.java | 83 ++-- .../config/impl/WxCpTpDefaultConfigImpl.java | 171 ++++++--- .../config/impl/WxCpTpRedissonConfigImpl.java | 278 ++++++++++++++ .../weixin/cp/constant/WxCpApiPathConsts.java | 2 + .../weixin/cp/constant/WxCpTpConsts.java | 52 +++ .../cp/tp/message/WxCpTpMessageHandler.java | 1 - .../tp/message/WxCpTpMessageInterceptor.java | 1 - .../cp/tp/message/WxCpTpMessageMatcher.java | 3 +- .../cp/tp/message/WxCpTpMessageRouter.java | 55 +-- .../tp/message/WxCpTpMessageRouterRule.java | 60 ++- .../weixin/cp/tp/service/WxCpTpService.java | 33 ++ .../service/impl/BaseWxCpTpServiceImpl.java | 72 +++- .../cp/api/WxCpTpMessageRouterTest.java | 57 +++ .../cp/bean/message/WxCpTpXmlMessageTest.java | 234 ++++++++++++ 16 files changed, 1372 insertions(+), 117 deletions(-) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/StringArrayConverter.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpTpConsts.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/StringArrayConverter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/StringArrayConverter.java new file mode 100644 index 0000000000..44d2926f42 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/StringArrayConverter.java @@ -0,0 +1,30 @@ +package me.chanjar.weixin.common.util.xml; + +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import com.thoughtworks.xstream.converters.basic.StringConverter; + + +/** + * String 数组转换 + * @author chily.lin + */ +public class StringArrayConverter extends StringConverter { + @Override + public boolean canConvert(Class type) { + return type == String[].class; + } + + @Override + public String toString(Object obj) { + return ""; + } + + @Override + public Object fromString(String str) { + final Iterable iterable = Splitter.on(",").split(str); + String[] results = Iterables.toArray(iterable, String.class); + return results; + } +} 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 6ee1395380..c8273e9a98 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 @@ -1,13 +1,17 @@ package me.chanjar.weixin.cp.bean.message; import java.io.Serializable; +import java.util.List; import java.util.Map; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamConverter; +import com.thoughtworks.xstream.converters.basic.IntConverter; import lombok.Data; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.util.XmlUtils; +import me.chanjar.weixin.common.util.xml.IntegerArrayConverter; +import me.chanjar.weixin.common.util.xml.StringArrayConverter; import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; import me.chanjar.weixin.cp.util.xml.XStreamTransformer; @@ -52,6 +56,359 @@ public class WxCpTpXmlMessage implements Serializable { @XStreamConverter(value = XStreamCDataConverter.class) protected String authCorpId; + @XStreamAlias("ChangeType") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String changeType; + + @XStreamAlias("UserID") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String userID; + + @XStreamAlias("Department") + @XStreamConverter(value = IntegerArrayConverter.class) + protected Integer[] department; + + @XStreamAlias("MainDepartment") + @XStreamConverter(value = IntConverter.class) + protected Integer mainDepartment; + + @XStreamAlias("IsLeaderInDept") + @XStreamConverter(value = IntegerArrayConverter.class) + protected Integer[] isLeaderInDept; + + @XStreamAlias("Mobile") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String mobile; + + @XStreamAlias("Position") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String position; + + @XStreamAlias("Gender") + @XStreamConverter(value = IntConverter.class) + protected Integer gender; + + @XStreamAlias("Email") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String email; + + @XStreamAlias("Status") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String status; + + @XStreamAlias("Avatar") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String avatar; + + @XStreamAlias("Alias") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String alias; + + @XStreamAlias("Telephone") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String telephone; + + @XStreamAlias("Id") + @XStreamConverter(value = IntConverter.class) + protected Integer id; + + @XStreamAlias("Name") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String name; + + @XStreamAlias("ParentId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String parentId; + + @XStreamAlias("Order") + @XStreamConverter(value = XStreamCDataConverter.class) + protected Integer order; + + @XStreamAlias("TagId") + @XStreamConverter(value = IntConverter.class) + protected Integer tagId; + + @XStreamAlias("AddUserItems") + @XStreamConverter(value = StringArrayConverter.class) + protected String[] addUserItems; + + @XStreamAlias("DelUserItems") + @XStreamConverter(value = StringArrayConverter.class) + protected String[] delUserItems; + + @XStreamAlias("AddPartyItems") + @XStreamConverter(value = IntegerArrayConverter.class) + protected Integer[] addPartyItems; + + @XStreamAlias("DelPartyItems") + @XStreamConverter(value = IntegerArrayConverter.class) + protected Integer[] delPartyItems; + + //ref: https://work.weixin.qq.com/api/doc/90001/90143/90585 + @XStreamAlias("ServiceCorpId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String serviceCorpId; + + @XStreamAlias("RegisterCode") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String registerCode; + + @XStreamAlias("ContactSync") + protected ContactSync contactSync; + + @XStreamAlias("AuthUserInfo") + protected AuthUserInfo authUserInfo; + + @XStreamAlias("TemplateId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String templateId; + + @XStreamAlias("CreateTime") + protected Long createTime; + + @XStreamAlias("ToUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String toUserName; + + @XStreamAlias("FromUserName") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String fromUserName; + + @XStreamAlias("MsgType") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String msgType; + + @XStreamAlias("Event") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String event; + + @XStreamAlias("BatchJob") + protected BatchJob batchJob; + + @XStreamAlias("ExternalUserID") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String externalUserID; + + @XStreamAlias("WelcomeCode") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String welcomeCode; + + @XStreamAlias("FromUser") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String fromUser; + + @XStreamAlias("Content") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String content; + + @XStreamAlias("MsgId") + protected String msgId; + + @XStreamAlias("AgentID") + protected Integer agentID; + + @XStreamAlias("PicUrl") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String picUrl; + + @XStreamAlias("MediaId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String mediaId; + + @XStreamAlias("Format") + @XStreamConverter(value = XStreamCDataConverter.class) + private String format; + + @XStreamAlias("ThumbMediaId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String thumbMediaId; + + @XStreamAlias("Location_X") + private Double locationX; + + @XStreamAlias("Location_Y") + private Double locationY; + + @XStreamAlias("Scale") + private Double scale; + + @XStreamAlias("Label") + @XStreamConverter(value = XStreamCDataConverter.class) + private String label; + + @XStreamAlias("Title") + @XStreamConverter(value = XStreamCDataConverter.class) + private String title; + + @XStreamAlias("Description") + @XStreamConverter(value = XStreamCDataConverter.class) + private String description; + + @XStreamAlias("Url") + @XStreamConverter(value = XStreamCDataConverter.class) + private String url; + + @XStreamAlias("EventKey") + @XStreamConverter(value = XStreamCDataConverter.class) + private String eventKey; + + @XStreamAlias("Latitude") + private Double latitude; + + @XStreamAlias("Longitude") + private Double longitude; + + @XStreamAlias("Precision") + private Double precision; + + @XStreamAlias("AppType") + @XStreamConverter(value = XStreamCDataConverter.class) + private String appType; + + @XStreamAlias("ScanCodeInfo") + private WxCpXmlMessage.ScanCodeInfo scanCodeInfo = new WxCpXmlMessage.ScanCodeInfo(); + + @XStreamAlias("SendPicsInfo") + private WxCpXmlMessage.SendPicsInfo sendPicsInfo = new WxCpXmlMessage.SendPicsInfo(); + + @XStreamAlias("SendLocationInfo") + private WxCpXmlMessage.SendLocationInfo sendLocationInfo = new WxCpXmlMessage.SendLocationInfo(); + + @XStreamAlias("ApprovalInfo") + private ApprovalInfo approvalInfo = new ApprovalInfo(); + + @XStreamAlias("TaskId") + @XStreamConverter(value = XStreamCDataConverter.class) + private String taskId; + + @Data + @XStreamAlias("ContactSync") + public static class ContactSync { + @XStreamAlias("AccessToken") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String accessToken; + + @XStreamAlias("ExpiresIn") + protected Integer expiresIn; + } + + @Data + @XStreamAlias("AuthUserInfo") + public static class AuthUserInfo { + @XStreamAlias("UserId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String userId; + } + + @Data + @XStreamAlias("BatchJob") + public static class BatchJob { + @XStreamAlias("JobId") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String JobId; + + @XStreamAlias("JobType") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String jobType; + + @XStreamAlias("ErrCode") + @XStreamConverter(value = IntConverter.class) + protected Integer errCode; + + @XStreamAlias("ErrMsg") + @XStreamConverter(value = XStreamCDataConverter.class) + protected String errMsg; + } + + @Data + @XStreamAlias("ApprovalInfo") + public static class ApprovalInfo { + @XStreamAlias("ThirdNo") + protected Long thirdNo; + + @XStreamAlias("OpenSpName") + protected String openSpName; + + @XStreamAlias("OpenTemplateId") + protected Integer openTemplateId; + + @XStreamAlias("OpenSpStatus") + protected Integer openSpStatus; + + @XStreamAlias("ApplyTime") + protected Long applyTime; + + @XStreamAlias("ApplyUserName") + protected String applyUserName; + + @XStreamAlias("ApplyUserId") + protected Integer applyUserId; + + @XStreamAlias("ApplyUserParty") + protected String applyUserParty; + + @XStreamAlias("ApplyUserImage") + protected String applyUserImage; + + @XStreamAlias("ApprovalNodes") + protected List approvalNodes; + + @XStreamAlias("NotifyNodes") + protected List notifyNodes; + + @XStreamAlias("approverstep") + protected Integer approverstep; + + //自建/第三方应用调用审批流程引擎,状态通知 + //ref: https://work.weixin.qq.com/api/doc/90001/90143/90376#审批状态通知事件 + //1.自建/第三方应用调用审批流程引擎发起申请之后,审批状态发生变化时 + //2.自建/第三方应用调用审批流程引擎发起申请之后,在“审批中”状态,有任意审批人进行审批操作时 + @Data + @XStreamAlias("ApprovalNode") + public static class ApprovalNode { + @XStreamAlias("NodeStatus") + protected Integer nodeStatus; + + @XStreamAlias("NodeAttr") + protected Integer nodeAttr; + + @XStreamAlias("NodeType") + protected Integer nodeType; + + @XStreamAlias("Items") + protected List items; + + @Data + @XStreamAlias("Item") + public static class Item { + @XStreamAlias("ItemName") + protected String itemName; + @XStreamAlias("ItemUserId") + protected Integer itemUserId; + @XStreamAlias("ItemImage") + protected String itemImage; + @XStreamAlias("ItemStatus") + protected Integer itemStatus; + @XStreamAlias("ItemSpeech") + protected String itemSpeech; + @XStreamAlias("ItemOpTime") + protected Long itemOpTime; + } + } + + @Data + @XStreamAlias("NotifyNode") + public static class NotifyNode { + @XStreamAlias("ItemName") + protected String itemName; + @XStreamAlias("ItemUserId") + protected Integer itemUserId; + @XStreamAlias("ItemImage") + protected String itemImage; + } + } + + public static WxCpTpXmlMessage fromXml(String xml) { //修改微信变态的消息内容格式,方便解析 //xml = xml.replace("", ""); 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 40c29ed0c9..0fda376633 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 @@ -26,67 +26,76 @@ public interface WxCpTpConfigStorage { */ String getApiUrl(String path); - String getSuiteAccessToken(); - - boolean isSuiteAccessTokenExpired(); - /** - * 强制将suite access token过期掉. + * 第三方应用的suite access token相关 */ + String getSuiteAccessToken(); + boolean isSuiteAccessTokenExpired(); + //强制将suite access token过期掉. void expireSuiteAccessToken(); - void updateSuiteAccessToken(WxAccessToken suiteAccessToken); + void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds); - void updateSuiteAccessToken(String suiteAccessToken, int expiresIn); - + /** + * 第三方应用的suite ticket相关 + */ String getSuiteTicket(); - boolean isSuiteTicketExpired(); + //强制将suite ticket过期掉. + void expireSuiteTicket(); + //应该是线程安全的 + void updateSuiteTicket(String suiteTicket, int expiresInSeconds); /** - * 强制将suite ticket过期掉. + * 第三方应用的其他配置,来自于企微配置 */ - void expireSuiteTicket(); + String getSuiteId(); + String getSuiteSecret(); + // 第三方应用的token,用来检查应用的签名 + String getToken(); + //第三方应用的EncodingAESKey,用来检查签名 + String getAesKey(); /** - * 应该是线程安全的. + * 企微服务商企业ID & 企业secret */ - void updateSuiteTicket(String suiteTicket, int expiresInSeconds); - String getCorpId(); - String getCorpSecret(); - String getSuiteId(); - - String getSuiteSecret(); - - String getToken(); + /** + * 授权企业的access token相关 + */ + String getAccessToken(String authCorpId); + boolean isAccessTokenExpired(String authCorpId); + void updateAccessToken(String authCorpId, String accessToken, int expiredInSeconds); - String getAesKey(); + /** + * 授权企业的js api ticket相关 + */ + String getAuthCorpJsApiTicket(String authCorpId); + boolean isAuthCorpJsApiTicketExpired(String authCorpId); + void updateAuthCorpJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds); - long getExpiresTime(); + /** + * 授权企业的第三方应用js api ticket相关 + */ + String getAuthSuiteJsApiTicket(String authCorpId); + boolean isAuthSuiteJsApiTicketExpired(String authCorpId); + void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds);; + /** + * 网络代理相关 + */ String getHttpProxyHost(); - int getHttpProxyPort(); - String getHttpProxyUsername(); - String getHttpProxyPassword(); - - File getTmpDirFile(); - - /** - * http client builder. - * - * @return ApacheHttpClientBuilder - */ ApacheHttpClientBuilder getApacheHttpClientBuilder(); - /** - * 是否自动刷新token - * @return . - */ boolean autoRefreshToken(); + + // 毫无相关性的代码 + @Deprecated + File getTmpDirFile(); + } 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 be4b046a48..a748e301db 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 @@ -7,6 +7,8 @@ import java.io.File; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化. @@ -24,25 +26,34 @@ public class WxCpTpDefaultConfigImpl implements WxCpTpConfigStorage, Serializabl private volatile String token; private volatile String suiteAccessToken; + private volatile long suiteAccessTokenExpiresTime; private volatile String aesKey; - private volatile long expiresTime; + private volatile String suiteTicket; + private volatile long suiteTicketExpiresTime; private volatile String oauth2redirectUri; + private volatile Map authCorpAccessTokenMap = new HashMap<>(); + private volatile Map authCorpAccessTokenExpireTimeMap = new HashMap<>(); + + private volatile Map authCorpJsApiTicketMap = new HashMap<>(); + private volatile Map authCorpJsApiTicketExpireTimeMap = new HashMap<>(); + + private volatile Map authSuiteJsApiTicketMap = new HashMap<>(); + private volatile Map authSuiteJsApiTicketExpireTimeMap = new HashMap<>(); + private volatile String httpProxyHost; private volatile int httpProxyPort; private volatile String httpProxyUsername; private volatile String httpProxyPassword; - private volatile String suiteTicket; - private volatile long suiteTicketExpiresTime; - private volatile File tmpDirFile; private volatile ApacheHttpClientBuilder apacheHttpClientBuilder; private volatile String baseApiUrl; + @Override public void setBaseApiUrl(String baseUrl) { this.baseApiUrl = baseUrl; @@ -67,12 +78,12 @@ public void setSuiteAccessToken(String suiteAccessToken) { @Override public boolean isSuiteAccessTokenExpired() { - return System.currentTimeMillis() > this.expiresTime; + return System.currentTimeMillis() > this.suiteAccessTokenExpiresTime; } @Override public void expireSuiteAccessToken() { - this.expiresTime = 0; + this.suiteAccessTokenExpiresTime = 0; } @Override @@ -83,66 +94,58 @@ public synchronized void updateSuiteAccessToken(WxAccessToken suiteAccessToken) @Override public synchronized void updateSuiteAccessToken(String suiteAccessToken, int expiresInSeconds) { this.suiteAccessToken = suiteAccessToken; - this.expiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; + this.suiteAccessTokenExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; } - @Override - public String getCorpId() { - return this.corpId; + @Deprecated + public void setSuiteAccessTokenExpiresTime(long suiteAccessTokenExpiresTime) { + this.suiteAccessTokenExpiresTime = suiteAccessTokenExpiresTime; } - public void setCorpId(String corpId) { - this.corpId = corpId; + @Override + public String getSuiteTicket() { + return this.suiteTicket; } @Override - public String getCorpSecret() { - return this.corpSecret; + public boolean isSuiteTicketExpired() { + return System.currentTimeMillis() > this.suiteTicketExpiresTime; } - public void setCorpSecret(String corpSecret) { - this.corpSecret = corpSecret; + @Override + public void expireSuiteTicket() { + this.suiteTicketExpiresTime = 0; } @Override - public String getSuiteTicket() { - return this.suiteTicket; + public synchronized void updateSuiteTicket(String suiteTicket, int expiresInSeconds) { + this.suiteTicket = suiteTicket; + // 预留200秒的时间 + this.suiteTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; } + + @Deprecated public void setSuiteTicket(String suiteTicket) { this.suiteTicket = suiteTicket; } + @Deprecated public long getSuiteTicketExpiresTime() { return this.suiteTicketExpiresTime; } + @Deprecated public void setSuiteTicketExpiresTime(long suiteTicketExpiresTime) { this.suiteTicketExpiresTime = suiteTicketExpiresTime; } - @Override - public boolean isSuiteTicketExpired() { - return System.currentTimeMillis() > this.suiteTicketExpiresTime; - } - - @Override - public synchronized void updateSuiteTicket(String suiteTicket, int expiresInSeconds) { - this.suiteTicket = suiteTicket; - // 预留200秒的时间 - this.suiteTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L; - } - - @Override - public void expireSuiteTicket() { - this.suiteTicketExpiresTime = 0; - } - @Override public String getSuiteId() { return this.suiteId; } + @Deprecated public void setSuiteId(String corpId) { this.suiteId = corpId; } @@ -152,6 +155,7 @@ public String getSuiteSecret() { return this.suiteSecret; } + @Deprecated public void setSuiteSecret(String corpSecret) { this.suiteSecret = corpSecret; } @@ -161,26 +165,107 @@ public String getToken() { return this.token; } + @Deprecated public void setToken(String token) { this.token = token; } @Override - public long getExpiresTime() { - return this.expiresTime; + public String getAesKey() { + return this.aesKey; + } + + @Deprecated + public void setAesKey(String aesKey) { + this.aesKey = aesKey; + } + + + @Override + public String getCorpId() { + return this.corpId; } - public void setExpiresTime(long expiresTime) { - this.expiresTime = expiresTime; + @Deprecated + public void setCorpId(String corpId) { + this.corpId = corpId; } @Override - public String getAesKey() { - return this.aesKey; + public String getCorpSecret() { + return this.corpSecret; } - public void setAesKey(String aesKey) { - this.aesKey = aesKey; + @Deprecated + public void setCorpSecret(String corpSecret) { + this.corpSecret = corpSecret; + } + + + @Override + public String getAccessToken(String authCorpId) { + return authCorpAccessTokenMap.get(authCorpId); + } + + @Override + public boolean isAccessTokenExpired(String authCorpId) { + return System.currentTimeMillis() > authCorpAccessTokenExpireTimeMap.get(authCorpId); + } + + @Override + public void updateAccessToken(String authCorpId, String accessToken, int expiredInSeconds) { + authCorpAccessTokenMap.put(authCorpId, accessToken); + // 预留200秒的时间 + authCorpAccessTokenExpireTimeMap.put(authCorpId, System.currentTimeMillis() + (expiredInSeconds - 200) * 1000L); + } + + + @Override + public String getAuthCorpJsApiTicket(String authCorpId) { + return this.authCorpJsApiTicketMap.get(authCorpId); + } + + @Override + public boolean isAuthCorpJsApiTicketExpired(String authCorpId) { + Long t = this.authCorpJsApiTicketExpireTimeMap.get(authCorpId); + if (t == null) { + return System.currentTimeMillis() > t; + } + else { + return true; + } + } + + @Override + public void updateAuthCorpJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) { + // 应该根据不同的授权企业做区分 + authCorpJsApiTicketMap.put(authCorpId, jsApiTicket); + // 预留200秒的时间 + authCorpJsApiTicketExpireTimeMap.put(authCorpId, System.currentTimeMillis() + (expiredInSeconds - 200) * 1000L); + } + + @Override + public String getAuthSuiteJsApiTicket(String authCorpId) { + return authSuiteJsApiTicketMap.get(authCorpId); + } + + @Override + public boolean isAuthSuiteJsApiTicketExpired(String authCorpId) { + Long t = authSuiteJsApiTicketExpireTimeMap.get(authCorpId); + if (t == null) { + return System.currentTimeMillis() > t; + } + else { + return true; + } + } + + @Override + public void updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) { + // 应该根据不同的授权企业做区分 + authSuiteJsApiTicketMap.put(authCorpId, jsApiTicket); + // 预留200秒的时间 + authSuiteJsApiTicketExpireTimeMap.put(authCorpId, System.currentTimeMillis() + (expiredInSeconds - 200) * 1000L); } public void setOauth2redirectUri(String oauth2redirectUri) { 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 new file mode 100644 index 0000000000..3b1414d9b4 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java @@ -0,0 +1,278 @@ +package me.chanjar.weixin.cp.config.impl; + + +import lombok.Builder; +import lombok.NonNull; +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.config.WxCpTpConfigStorage; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.File; +import java.io.Serializable; +import java.util.concurrent.TimeUnit; + +/** + * 企业微信各种固定、授权配置的Redisson存储实现 + */ +@Builder +public class WxCpTpRedissonConfigImpl implements WxCpTpConfigStorage, Serializable { + + @NonNull + private final WxRedisOps wxRedisOps; + + //redis里面key的统一前缀 + private final String keyPrefix = ""; + + 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 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; + + @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 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; + } + + + /** + * 授权企业的access token相关 + */ + @Override + public String getAccessToken(String authCorpId) { + return wxRedisOps.getValue(keyWithPrefix(authCorpId) + accessTokenKey); + } + + @Override + public boolean isAccessTokenExpired(String authCorpId) { + //没有设置或者TTL为0,都是过期 + return wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == 0L + || wxRedisOps.getExpire(keyWithPrefix(authCorpId) + accessTokenKey) == -2; + } + + @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 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 updateAuthSuiteJsApiTicket(String authCorpId, String jsApiTicket, int expiredInSeconds) { + wxRedisOps.setValue(keyWithPrefix(authCorpId) + authSuiteJsApiTicketKey, jsApiTicket, expiredInSeconds, 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 ApacheHttpClientBuilder getApacheHttpClientBuilder() { + return this.apacheHttpClientBuilder; + } + + @Override + public boolean autoRefreshToken() { + return false; + } + + @Override + public String toString() { + //TODO: + return WxCpGsonBuilder.create().toJson(this); + } + + private String keyWithPrefix(String key) { + return keyPrefix + key; + } +} 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 97e30f0346..00d88940f2 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 @@ -140,6 +140,8 @@ public static class Tp { public static final String GET_PROVIDER_TOKEN = "/cgi-bin/service/get_provider_token"; public static final String GET_PREAUTH_CODE = "/cgi-bin/service/get_pre_auth_code"; public static final String GET_AUTH_INFO = "/cgi-bin/service/get_auth_info"; + public static final String GET_AUTH_CORP_JSAPI_TICKET = "/cgi-bin/get_jsapi_ticket"; + public static final String GET_SUITE_JSAPI_TICKET = "/cgi-bin/ticket/get"; } @UtilityClass diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpTpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpTpConsts.java new file mode 100644 index 0000000000..40270270cf --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpTpConsts.java @@ -0,0 +1,52 @@ +package me.chanjar.weixin.cp.constant; + +import lombok.experimental.UtilityClass; + +public class WxCpTpConsts { + + + @UtilityClass + public static class InfoType { + /** + * 推送更新suite_ticket + */ + public static final String SUITE_TICKET = "suite_ticket"; + + /** + * 从企业微信应用市场发起授权时,授权成功通知 + */ + public static final String CREATE_AUTH = "create_auth"; + + /** + * 从企业微信应用市场发起授权时,变更授权通知 + */ + public static final String CHANGE_AUTH = "change_auth"; + + /** + * 从企业微信应用市场发起授权时,取消授权通知 + */ + public static final String CANCEL_AUTH = "cancel_auth"; + + /** + * 通讯录变更通知 + */ + public static final String CHANGE_CONTACT = "change_contact"; + + /** + * 用户进行企业微信的注册,注册完成回调通知 + */ + public static final String REGISTER_CORP = "register_corp"; + + /** + * 异步任务回调通知 + */ + public static final String BATCH_JOB_RESULT = "batch_job_result"; + + /** + * 外部联系人变更通知 + */ + public static final String CHANGE_EXTERNAL_CONTACT = "change_external_contact"; + + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageHandler.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageHandler.java index eea6bd966c..639a743350 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageHandler.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageHandler.java @@ -3,7 +3,6 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage; import me.chanjar.weixin.cp.tp.service.WxCpTpService; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageInterceptor.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageInterceptor.java index 62975951bc..feac10dbb6 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageInterceptor.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageInterceptor.java @@ -3,7 +3,6 @@ import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage; import me.chanjar.weixin.cp.tp.service.WxCpTpService; import java.util.Map; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageMatcher.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageMatcher.java index 8f7decf4b3..57e35f1946 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageMatcher.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageMatcher.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.cp.tp.message; +import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage; import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage; /** @@ -15,6 +16,6 @@ public interface WxCpTpMessageMatcher { * @param message the message * @return the boolean */ - boolean match(WxCpXmlMessage message); + boolean match(WxCpTpXmlMessage message); } 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 ad9d0ff0ae..5b045082a8 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 @@ -10,9 +10,7 @@ import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.util.LogExceptionHandler; import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage; -import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage; import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage; -import me.chanjar.weixin.cp.message.WxCpMessageRouterRule; import me.chanjar.weixin.cp.tp.service.WxCpTpService; import org.apache.commons.lang3.StringUtils; @@ -25,20 +23,22 @@ /** *
  * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
+ * 和WxCpMessageRouter的rule相比,多了infoType和changeType维度的匹配
  *
  * 说明:
  * 1. 配置路由规则时要按照从细到粗的原则,否则可能消息可能会被提前处理
- * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpMessageRouterRule#next()}
- * 3. 规则的结束必须用{@link WxCpMessageRouterRule#end()}或者{@link WxCpMessageRouterRule#next()},否则不会生效
+ * 2. 默认情况下消息只会被处理一次,除非使用 {@link WxCpTpMessageRouterRule#next()}
+ * 3. 规则的结束必须用{@link WxCpTpMessageRouterRule#end()}或者{@link WxCpTpMessageRouterRule#next()},否则不会生效
  *
  * 使用方法:
- * WxCpMessageRouter router = new WxCpMessageRouter();
+ * WxCpTpMessageRouter router = new WxCpTpMessageRouter();
  * router
  *   .rule()
  *       .msgType("MSG_TYPE").event("EVENT").eventKey("EVENT_KEY").content("CONTENT")
  *       .interceptor(interceptor, ...).handler(handler, ...)
  *   .end()
  *   .rule()
+ *       .infoType("INFO_TYPE").changeType("CHANGE_TYPE")
  *       // 另外一个匹配规则
  *   .end()
  * ;
@@ -55,7 +55,7 @@ public class WxCpTpMessageRouter {
   private static final int DEFAULT_THREAD_POOL_SIZE = 100;
   private final List rules = new ArrayList<>();
 
-  private final WxCpTpService wxCpService;
+  private final WxCpTpService wxCpTpService;
 
   private ExecutorService executorService;
 
@@ -68,13 +68,13 @@ public class WxCpTpMessageRouter {
   /**
    * 构造方法.
    */
-  public WxCpTpMessageRouter(WxCpTpService wxCpService) {
-    this.wxCpService = wxCpService;
+  public WxCpTpMessageRouter(WxCpTpService wxCpTpService) {
+    this.wxCpTpService = wxCpTpService;
     ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("WxCpTpMessageRouter-pool-%d").build();
     this.executorService = new ThreadPoolExecutor(DEFAULT_THREAD_POOL_SIZE, DEFAULT_THREAD_POOL_SIZE,
       0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), namedThreadFactory);
     this.messageDuplicateChecker = new WxMessageInMemoryDuplicateChecker();
-    this.sessionManager = wxCpService.getSessionManager();
+    this.sessionManager = wxCpTpService.getSessionManager();
     this.exceptionHandler = new LogExceptionHandler();
   }
 
@@ -160,11 +160,11 @@ public WxCpXmlOutMessage route(final WxCpTpXmlMessage wxMessage, final Map {
-            rule.service(wxMessage, context, WxCpTpMessageRouter.this.wxCpService, WxCpTpMessageRouter.this.sessionManager, WxCpTpMessageRouter.this.exceptionHandler);
+            rule.service(wxMessage, context, WxCpTpMessageRouter.this.wxCpTpService, WxCpTpMessageRouter.this.sessionManager, WxCpTpMessageRouter.this.exceptionHandler);
           })
         );
       } else {
-        res = rule.service(wxMessage, context, this.wxCpService, this.sessionManager, this.exceptionHandler);
+        res = rule.service(wxMessage, context, this.wxCpTpService, this.sessionManager, this.exceptionHandler);
         // 在同步操作结束,session访问结束
         log.debug("End session access: async=false, sessionId={}", wxMessage.getSuiteId());
         sessionEndAccess(wxMessage);
@@ -200,17 +200,30 @@ public WxCpXmlOutMessage route(final WxCpTpXmlMessage wxMessage) {
 
   private boolean isMsgDuplicated(WxCpTpXmlMessage wxMessage) {
     StringBuilder messageId = new StringBuilder();
-    if (StringUtils.isNotEmpty(wxMessage.getSuiteId())) {
-      messageId.append("-").append(wxMessage.getSuiteId());
-    }
-
-    if (StringUtils.isNotEmpty(wxMessage.getInfoType())) {
-      messageId.append("-").append(wxMessage.getInfoType());
-    }
+      if (wxMessage.getInfoType() != null) {
+        messageId.append(wxMessage.getInfoType())
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getSuiteId()))
+          .append("-").append(wxMessage.getTimeStamp())
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getAuthCorpId()))
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getUserID()))
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getChangeType()))
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getServiceCorpId()));
+      }
 
-    if (StringUtils.isNotEmpty(wxMessage.getTimeStamp())) {
-      messageId.append("-").append(wxMessage.getTimeStamp());
-    }
+      if (wxMessage.getMsgType() != null) {
+        if (wxMessage.getMsgId() != null) {
+          messageId.append(wxMessage.getMsgId())
+            .append("-").append(wxMessage.getCreateTime())
+            .append("-").append(wxMessage.getFromUserName());
+        }
+        else {
+          messageId.append(wxMessage.getMsgType())
+            .append("-").append(wxMessage.getCreateTime())
+            .append("-").append(wxMessage.getFromUserName())
+            .append("-").append(StringUtils.trimToEmpty(wxMessage.getEvent()))
+            .append("-").append(StringUtils.trimToEmpty(wxMessage.getEventKey()));
+        }
+      }
 
     return this.messageDuplicateChecker.isDuplicate(messageId.toString());
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouterRule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouterRule.java
index 257cc1212d..1b7d7fbf77 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouterRule.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouterRule.java
@@ -6,10 +6,11 @@
 import me.chanjar.weixin.common.session.WxSessionManager;
 import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage;
 import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
-import me.chanjar.weixin.cp.message.WxCpMessageMatcher;
 import me.chanjar.weixin.cp.tp.service.WxCpTpService;
+import org.apache.commons.lang3.StringUtils;
 
 import java.util.*;
+import java.util.regex.Pattern;
 
 /**
  * The type Wx cp message router rule.
@@ -22,15 +23,34 @@ public class WxCpTpMessageRouterRule {
 
   private boolean async = true;
 
-  private WxCpMessageMatcher matcher;
+  private String fromUser;
+
+  private String msgType;
+
+  private String event;
+
+  private String eventKey;
+
+  private String eventKeyRegex;
+
+  private String content;
+
+  private String rContent;
+
+  private WxCpTpMessageMatcher matcher;
 
   private boolean reEnter = false;
 
+  private Integer agentId;
+
+  private String infoType;
+
+  private String changeType;
+
   private List handlers = new ArrayList<>();
 
   private List interceptors = new ArrayList<>();
   private String suiteId;
-  private String infoType;
   private String authCode;
   private String suiteTicket;
 
@@ -64,13 +84,24 @@ public WxCpTpMessageRouterRule infoType(String infoType) {
     return this;
   }
 
+  /**
+   * 如果changeType等于这个type,符合rule的条件之一
+   * @param changeType
+   * @return
+   */
+  public WxCpTpMessageRouterRule changeType(String changeType) {
+    this.changeType = changeType;
+    return this;
+  }
+
+
   /**
    * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候
    *
    * @param matcher the matcher
    * @return the wx cp message router rule
    */
-  public WxCpTpMessageRouterRule matcher(WxCpMessageMatcher matcher) {
+  public WxCpTpMessageRouterRule matcher(WxCpTpMessageMatcher matcher) {
     this.matcher = matcher;
     return this;
   }
@@ -154,13 +185,30 @@ public WxCpTpMessageRouter next() {
   protected boolean test(WxCpTpXmlMessage wxMessage) {
     return
       (this.suiteId == null || this.suiteId.equals(wxMessage.getSuiteId()))
+        &&
+        (this.fromUser == null || this.fromUser.equals(wxMessage.getFromUserName()))
+        &&
+        (this.agentId == null || this.agentId.equals(wxMessage.getAgentID()))
+        &&
+        (this.msgType == null || this.msgType.equalsIgnoreCase(wxMessage.getMsgType()))
         &&
         (this.infoType == null || this.infoType.equals(wxMessage.getInfoType()))
         &&
         (this.suiteTicket == null || this.suiteTicket.equalsIgnoreCase(wxMessage.getSuiteTicket()))
         &&
-        (this.authCode == null || this.authCode.equalsIgnoreCase(wxMessage.getAuthCode()))
-      ;
+        (this.eventKeyRegex == null || Pattern.matches(this.eventKeyRegex, StringUtils.trimToEmpty(wxMessage.getEventKey())))
+        &&
+        (this.content == null || this.content.equals(StringUtils.trimToNull(wxMessage.getContent())))
+        &&
+        (this.rContent == null || Pattern.matches(this.rContent, StringUtils.trimToEmpty(wxMessage.getContent())))
+        &&
+        (this.infoType == null || this.infoType.equals(wxMessage.getInfoType()))
+        &&
+        (this.changeType == null || this.changeType.equals(wxMessage.getChangeType()))
+        &&
+        (this.matcher == null || this.matcher.match(wxMessage))
+        &&
+        (this.authCode == null || this.authCode.equalsIgnoreCase(wxMessage.getAuthCode()));
   }
 
   /**
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 26da1ddd48..8e8cbd6fab 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
@@ -73,12 +73,35 @@ public interface WxCpTpService {
    * 详情请见:https://work.weixin.qq.com/api/doc#90001/90143/90628
    * 
* + * @Deprecated 由于无法主动刷新,所以这个接口实际已经没有意义,需要在接收企业微信的主动推送后,保存这个ticket + * @see #setSuiteTicket(String) + * * @param forceRefresh 强制刷新 * @return the suite ticket * @throws WxErrorException the wx error exception */ + @Deprecated String getSuiteTicket(boolean forceRefresh) throws WxErrorException; + /** + *
+   * 保存企业微信定时推送的suite_ticket,(每10分钟)
+   * 详情请见:https://work.weixin.qq.com/api/doc#90001/90143/90628
+   * 
+ * + * @param suiteTicket + * @throws WxErrorException + */ + void setSuiteTicket(String suiteTicket) throws WxErrorException; + + /** + * 获取应用的 jsapi ticket + * + * @param authCorpId 授权企业的cropId + * @return jsapi ticket + */ + String getSuiteJsApiTicket(String authCorpId) throws WxErrorException; + /** * 小程序登录凭证校验 * @@ -144,6 +167,14 @@ public interface WxCpTpService { */ WxCpTpAuthInfo getAuthInfo(String authCorpId, String permanentCode) throws WxErrorException; + /** + * 获取授权企业的 jsapi ticket + * + * @param authCorpId 授权企业的cropId + * @return jsapi ticket + */ + String getAuthCorpJsApiTicket(String authCorpId) throws WxErrorException; + /** * 当本Service没有实现某个API的时候,可以用这个,针对所有微信API中的GET请求. * @@ -209,8 +240,10 @@ public interface WxCpTpService { /** * 获取WxMpConfigStorage 对象. * + * @Deprecated storage应该在service内部使用,提供这个接口,容易破坏这个封装 * @return WxMpConfigStorage wx cp tp config storage */ + @Deprecated WxCpTpConfigStorage getWxCpTpConfigStorage(); /** 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 a0c0b26495..6c2399067a 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 @@ -45,11 +45,17 @@ public abstract class BaseWxCpTpServiceImpl implements WxCpTpService, Requ */ protected final Object globalSuiteAccessTokenRefreshLock = new Object(); + /** - * 全局的是否正在刷新jsapi_ticket的锁. + * 全局刷新suite ticket的锁 */ protected final Object globalSuiteTicketRefreshLock = new Object(); + /** + * 全局的是否正在刷新jsapi_ticket的锁. + */ + protected final Object globalJsApiTicketRefreshLock = new Object(); + protected WxCpTpConfigStorage configStorage; private WxSessionManager sessionManager = new StandardSessionManager(); @@ -79,7 +85,12 @@ public String getSuiteAccessToken() throws WxErrorException { @Override public String getSuiteTicket() throws WxErrorException { - return getSuiteTicket(false); + if (this.configStorage.isSuiteTicketExpired()) { + // 本地suite ticket 不存在或者过期 + WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP); + throw new WxErrorException(wxError); + } + return this.configStorage.getSuiteTicket(); } @Override @@ -88,15 +99,62 @@ public String getSuiteTicket(boolean forceRefresh) throws WxErrorException { // if (forceRefresh) { // this.configStorage.expireSuiteTicket(); // } + return getSuiteTicket(); + } - if (this.configStorage.isSuiteTicketExpired()) { - // 本地suite ticket 不存在或者过期 - WxError wxError = WxError.fromJson("{\"errcode\":40085, \"errmsg\":\"invaild suite ticket\"}", WxType.CP); - throw new WxErrorException(wxError); + @Override + public void setSuiteTicket(String suiteTicket) throws WxErrorException { + synchronized (globalSuiteTicketRefreshLock) { + this.configStorage.updateSuiteTicket(suiteTicket, 10 * 60); } - return this.configStorage.getSuiteTicket(); } + @Override + public String getSuiteJsApiTicket(String authCorpId) throws WxErrorException { + if (this.configStorage.isSuiteAccessTokenExpired()) { + + String resp = get(configStorage.getApiUrl(GET_SUITE_JSAPI_TICKET), + "type=agent_config&access_token=" + this.configStorage.getAccessToken(authCorpId)); + + JsonObject jsonObject = GsonParser.parse(resp); + if (jsonObject.get("errcode").getAsInt() == 0) { + String jsApiTicket = jsonObject.get("ticket").getAsString(); + int expiredInSeconds = jsonObject.get("expires_in").getAsInt(); + synchronized (globalJsApiTicketRefreshLock) { + configStorage.updateAuthSuiteJsApiTicket(authCorpId, jsApiTicket, expiredInSeconds); + } + } + else { + throw new WxErrorException(WxError.fromJson(resp)); + } + } + + return configStorage.getSuiteAccessToken(); + } + + @Override + public String getAuthCorpJsApiTicket(String authCorpId) throws WxErrorException { + if (this.configStorage.isSuiteAccessTokenExpired()) { + + String resp = get(configStorage.getApiUrl(GET_AUTH_CORP_JSAPI_TICKET), + "access_token=" + this.configStorage.getAccessToken(authCorpId)); + + JsonObject jsonObject = GsonParser.parse(resp); + if (jsonObject.get("errcode").getAsInt() == 0) { + String jsApiTicket = jsonObject.get("ticket").getAsString(); + int expiredInSeconds = jsonObject.get("expires_in").getAsInt(); + + synchronized (globalJsApiTicketRefreshLock) { + configStorage.updateAuthCorpJsApiTicket(authCorpId, jsApiTicket, expiredInSeconds); + } + } + else { + throw new WxErrorException(WxError.fromJson(resp)); + } + } + + return configStorage.getSuiteAccessToken(); + } @Override public WxCpMaJsCode2SessionResult jsCode2Session(String jsCode) throws WxErrorException { diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java new file mode 100644 index 0000000000..f6ab29df7f --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpTpMessageRouterTest.java @@ -0,0 +1,57 @@ +package me.chanjar.weixin.cp.api; + +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.session.WxSessionManager; +import me.chanjar.weixin.cp.bean.message.WxCpTpXmlMessage; +import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage; +import me.chanjar.weixin.cp.tp.message.WxCpTpMessageHandler; +import me.chanjar.weixin.cp.tp.message.WxCpTpMessageRouter; +import me.chanjar.weixin.cp.tp.service.WxCpTpService; +import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceImpl; +import org.testng.annotations.Test; + +import java.util.Map; + +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertNull; + +public class WxCpTpMessageRouterTest { + + + @Test + public void testMessageRouter() { + WxCpTpService service = new WxCpTpServiceImpl(); + WxCpTpMessageRouter router = new WxCpTpMessageRouter(service); + + String xml = "\n" + + " \n" + + " \n" + + " \n" + + " 1403610513\n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + + router.rule().infoType("change_contact").changeType("update_tag").handler(new WxCpTpMessageHandler() { + @Override + public WxCpXmlOutMessage handle(WxCpTpXmlMessage wxMessage, Map context, WxCpTpService wxCpService, WxSessionManager sessionManager) throws WxErrorException { + System.out.println("handler enter"); + assertNotNull(wxCpService); + return null; + } + }).end(); + + assertNull(router.route(wxXmlMessage)); + + + System.out.println("over"); + } + +} 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 new file mode 100644 index 0000000000..1e4a1450ac --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java @@ -0,0 +1,234 @@ +package me.chanjar.weixin.cp.bean.message; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +public class WxCpTpXmlMessageTest { + + @Test + public void testUserNotifyXML() { + String xml = "\n" + + " \n" + + " \n" + + " \n" + + " 1403610513\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 0\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " <![CDATA[企业微信]]>\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + assertEquals(wxXmlMessage.getSuiteId(), "ww4asffe99e54c0f4c"); + assertEquals(wxXmlMessage.getPosition(), "产品经理"); + assertEquals(wxXmlMessage.getGender(), Integer.valueOf(1)); + assertEquals(wxXmlMessage.getTelephone(), "020-111111"); + } + + + @Test + public void testRegisterCorp() { + String xml = "\n" + + " \n" + + " \n" + + " 1502682173\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1800\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + assertEquals(wxXmlMessage.getServiceCorpId(), "wwddddccc7775555aab"); + assertEquals(wxXmlMessage.getInfoType(), "register_corp"); + assertEquals(wxXmlMessage.getRegisterCode(), "pIKi3wRPNWCGF-pyP-YU5KWjDDD"); + assertNotNull(wxXmlMessage.getContactSync()); + assertEquals(wxXmlMessage.getContactSync().getAccessToken(), "accesstoken000001"); + assertEquals(wxXmlMessage.getContactSync().getExpiresIn(), Integer.valueOf(1800)); + assertNotNull(wxXmlMessage.getAuthUserInfo()); + assertEquals(wxXmlMessage.getAuthUserInfo().getUserId(), "zhangshan"); + assertEquals(wxXmlMessage.getTemplateId(), "tpl1test"); + } + + @Test + public void tagNotifyTest() { + String xml = "\n" + + " \n" + + " \n" + + " \n" + + " 1403610513\n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + + assertEquals(wxXmlMessage.getTagId(), Integer.valueOf(1)); + assertNotNull(wxXmlMessage.getAddUserItems()); + assertEquals(wxXmlMessage.getAddUserItems()[0], "zhangsan"); + assertEquals(wxXmlMessage.getAddUserItems()[1], "lisi"); + + assertNotNull(wxXmlMessage.getDelUserItems()); + assertNotNull(wxXmlMessage.getDelUserItems()[0], "zhangsan1"); + assertNotNull(wxXmlMessage.getDelUserItems()[0], "lisi1"); + + assertNotNull(wxXmlMessage.getAddPartyItems()); + assertEquals(wxXmlMessage.getAddPartyItems()[0], Integer.valueOf(1)); + assertEquals(wxXmlMessage.getAddPartyItems()[1], Integer.valueOf(2)); + + } + + + @Test + public void enterAppTest() { + String xml = "\n" + + "\n" + + "1408091189\n" + + "\n" + + "\n" + + "\n" + + "1\n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + assertEquals(wxXmlMessage.getToUserName(), "toUser"); + assertEquals(wxXmlMessage.getFromUserName(), "FromUser"); + assertEquals(wxXmlMessage.getCreateTime(), Long.valueOf(1408091189)); + assertEquals(wxXmlMessage.getEvent(), "enter_agent"); + assertEquals(wxXmlMessage.getEventKey(), ""); + assertEquals(wxXmlMessage.getAgentID(), Integer.valueOf(1)); + } + + @Test + public void textMessageTest() { + String xml = "\n" + + " \n" + + " \n" + + " 1348831860\n" + + " \n" + + " \n" + + " 1234567890123456\n" + + " 1\n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + assertEquals(wxXmlMessage.getToUserName(), "toUser"); + assertEquals(wxXmlMessage.getFromUserName(), "fromUser"); + assertEquals(wxXmlMessage.getCreateTime(), Long.valueOf(1348831860)); + assertEquals(wxXmlMessage.getMsgType(), "text"); + assertEquals(wxXmlMessage.getMsgId(), "1234567890123456"); + } + + @Test + public void ApprovalInfoTest() { + String xml = "\n" + + " wwddddccc7775555aaa \n" + + " sys \n" + + " 1527838022 \n" + + " event \n" + + " open_approval_change\n" + + " 1\n" + + " \n" + + " 201806010001 \n" + + " 付款 \n" + + " 1234567890 \n" + + " 1 \n" + + " 1527837645 \n" + + " xiaoming \n" + + " 1 \n" + + " 产品部 \n" + + " http://www.qq.com/xxx.png \n" + + " \n" + + " \n" + + " 1 \n" + + " 1 \n" + + " 1 \n" + + " \n" + + " \n" + + " xiaohong \n" + + " 2 \n" + + " http://www.qq.com/xxx.png \n" + + " 1 \n" + + " \n" + + " 0 \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " xiaogang \n" + + " 3 \n" + + " http://www.qq.com/xxx.png \n" + + " \n" + + " \n" + + " 0 \n" + + " \n" + + ""; + + WxCpTpXmlMessage wxXmlMessage = WxCpTpXmlMessage.fromXml(xml); + assertEquals(wxXmlMessage.getToUserName(), "wwddddccc7775555aaa"); + assertEquals(wxXmlMessage.getFromUserName(), "sys"); + assertEquals(wxXmlMessage.getCreateTime(), Long.valueOf(1527838022)); + assertEquals(wxXmlMessage.getEvent(), "open_approval_change"); + + assertNotNull(wxXmlMessage.getApprovalInfo()); + assertEquals(wxXmlMessage.getApprovalInfo().getThirdNo(), Long.valueOf(201806010001L)); + assertEquals(wxXmlMessage.getApprovalInfo().getOpenSpName(), "付款"); + assertEquals(wxXmlMessage.getApprovalInfo().getThirdNo(), Long.valueOf(201806010001L)); + assertEquals(wxXmlMessage.getApprovalInfo().getApplyTime(), Long.valueOf(1527837645)); + assertEquals(wxXmlMessage.getApprovalInfo().getApplyUserName(), "xiaoming"); + + assertNotNull(wxXmlMessage.getApprovalInfo().getApprovalNodes()); + assertNotNull(wxXmlMessage.getApprovalInfo().getApprovalNodes().get(0)); + assertEquals(wxXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getNodeAttr(), Integer.valueOf(1)); + assertEquals(wxXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getNodeType(), Integer.valueOf(1)); + + assertNotNull(wxXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getItems()); + assertEquals(wxXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getItems().get(0).getItemName(), "xiaohong"); + assertEquals(wxXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getItems().get(0).getItemOpTime(), Long.valueOf(0)); + + assertNotNull(wxXmlMessage.getApprovalInfo().getNotifyNodes().get(0)); + assertEquals(wxXmlMessage.getApprovalInfo().getNotifyNodes().get(0).getItemImage(), "http://www.qq.com/xxx.png"); + assertEquals(wxXmlMessage.getApprovalInfo().getNotifyNodes().get(0).getItemUserId(), Integer.valueOf(3)); + } +} From c60533066112b0cb227ad22509ce6f3d46ef8fb2 Mon Sep 17 00:00:00 2001 From: GaoMinzhu <31923767+GaoMinzhu@users.noreply.github.com> Date: Fri, 13 Nov 2020 12:57:38 +0800 Subject: [PATCH 10/18] =?UTF-8?q?:new:=20#1869=20=E3=80=90=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E3=80=91=E5=A2=9E=E5=8A=A0=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E7=9B=B4=E6=92=AD=E9=97=B4=E5=B0=8F=E5=8A=A9=E6=89=8B=E7=9A=84?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wx/miniapp/api/WxMaLiveService.java | 66 +++++++++++++++ .../miniapp/api/impl/WxMaLiveServiceImpl.java | 83 +++++++++++++++---- .../bean/live/WxMaAssistantResult.java | 49 +++++++++++ .../bean/live/WxMaLiveAssistantInfo.java | 38 +++++++++ 4 files changed, 222 insertions(+), 14 deletions(-) create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaAssistantResult.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveAssistantInfo.java diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java index 3047c9a3b2..96e6d879b4 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaLiveService.java @@ -1,5 +1,7 @@ package cn.binarywang.wx.miniapp.api; +import cn.binarywang.wx.miniapp.bean.live.WxMaAssistantResult; +import cn.binarywang.wx.miniapp.bean.live.WxMaLiveAssistantInfo; import cn.binarywang.wx.miniapp.bean.live.WxMaLiveResult; import cn.binarywang.wx.miniapp.bean.live.WxMaLiveRoomInfo; import me.chanjar.weixin.common.error.WxErrorException; @@ -22,6 +24,10 @@ public interface WxMaLiveService { String EDIT_ROOM = "https://api.weixin.qq.com/wxaapi/broadcast/room/editroom"; String GET_PUSH_URL = "https://api.weixin.qq.com/wxaapi/broadcast/room/getpushurl"; String GET_SHARED_CODE = "https://api.weixin.qq.com/wxaapi/broadcast/room/getsharedcode"; + String ADD_ASSISTANT = "https://api.weixin.qq.com/wxaapi/broadcast/room/addassistant"; + String MODIFY_ASSISTANT = "https://api.weixin.qq.com/wxaapi/broadcast/room/modifyassistant"; + String REMOVE_ASSISTANT = "https://api.weixin.qq.com/wxaapi/broadcast/room/removeassistant"; + String GET_ASSISTANT_LIST = "https://api.weixin.qq.com/wxaapi/broadcast/room/getassistantlist"; /** * 创建直播间 @@ -150,4 +156,64 @@ public interface WxMaLiveService { * @throws WxErrorException . */ boolean addGoodsToRoom(Integer roomId, List goodsIds) throws WxErrorException; + /** + * 添加管理直播间小助手 + *

+ * 调用接口往指定直播间添加管理直播间小助手 + * 调用频率 + * 调用额度:10000次/一天 + *

+ * http请求方式:POST https://api.weixin.qq.com/wxaapi/broadcast/room/addassistant?access_token=ACCESS_TOKEN + *

+   * @param roomId 房间ID
+   * @param users 数组列表,可传入多个,"users": [{"username":"testwechat","nickname":"testnick"}]
+   * @return 添加管理直播间小助手是否成功
+   * @throws WxErrorException .
+   */
+  boolean addAssistant(Integer roomId, List users) throws WxErrorException;
+  /**
+   * 修改直播间小助手昵称
+   * 

+ * 调用接口修改直播间小助手昵称 + * 调用频率 + * 调用额度:10000次/一天 + *

+ * http请求方式:POST https://api.weixin.qq.com/wxaapi/broadcast/room/modifyassistant?access_token=ACCESS_TOKEN + *

+   * @param roomId 房间ID
+   * @param username 小助手微信号
+   * @param nickname 小助手直播间昵称
+   * @return 修改小助手昵称是否成功
+   * @throws WxErrorException .
+   */
+  boolean modifyAssistant(Integer roomId, String username,String nickname) throws WxErrorException;
+  /**
+   * 删除直播间小助手
+   * 

+ * 删除直播间小助手 + * 调用频率 + * 调用额度:10000次/一天 + *

+ * http请求方式:POST https://api.weixin.qq.com/wxaapi/broadcast/room/removeassistant?access_token=ACCESS_TOKEN + *

+   * @param roomId 房间ID
+   * @param username 小助手微信号
+   * @return 删除小助手昵称是否成功
+   * @throws WxErrorException .
+   */
+  boolean removeAssistant(Integer roomId, String username) throws WxErrorException;
+  /**
+   * 查询直播间小助手
+   * 

+ * 查询直播间小助手 + * 调用频率 + * 调用额度:10000次/一天 + *

+ * http请求方式:POST https://api.weixin.qq.com/wxaapi/broadcast/room/getassistantlist?access_token=ACCESS_TOKEN + *

+   * @param roomId 房间ID
+   * @return 小助手列表
+   * @throws WxErrorException .
+   */
+  List getAssistantList(Integer roomId) throws WxErrorException;
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java
index 84aaab708f..e3af028253 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveServiceImpl.java
@@ -2,6 +2,8 @@
 
 import cn.binarywang.wx.miniapp.api.WxMaLiveService;
 import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.live.WxMaAssistantResult;
+import cn.binarywang.wx.miniapp.bean.live.WxMaLiveAssistantInfo;
 import cn.binarywang.wx.miniapp.bean.live.WxMaLiveResult;
 import cn.binarywang.wx.miniapp.bean.live.WxMaLiveRoomInfo;
 import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
@@ -90,12 +92,6 @@ public String getSharedCode(Integer roomId, String params) throws WxErrorExcepti
     return jsonObject.get("cdnUrl").getAsString();
   }
 
-  @Override
-  public WxMaLiveResult getLiveInfo(Integer start, Integer limit) throws WxErrorException {
-    JsonObject jsonObject = getLiveInfo(start, limit, null);
-    return WxMaLiveResult.fromJson(jsonObject.toString());
-  }
-
   @Override
   public List getLiveInfos() throws WxErrorException {
     List results = new ArrayList<>();
@@ -124,6 +120,13 @@ public List getLiveInfos() throws WxErrorException {
     return results;
   }
 
+  @Override
+  public WxMaLiveResult getLiveInfo(Integer start, Integer limit) throws WxErrorException {
+    JsonObject jsonObject = getLiveInfo(start, limit, null);
+    return WxMaLiveResult.fromJson(jsonObject.toString());
+  }
+
+
   @Override
   public WxMaLiveResult getLiveReplay(String action, Integer roomId, Integer start, Integer limit) throws WxErrorException {
     Map map = new HashMap<>(4);
@@ -132,7 +135,19 @@ public WxMaLiveResult getLiveReplay(String action, Integer roomId, Integer start
     JsonObject jsonObject = getLiveInfo(start, limit, map);
     return WxMaLiveResult.fromJson(jsonObject.toString());
   }
-
+  private JsonObject getLiveInfo(Integer start, Integer limit, Map map) throws WxErrorException {
+    if (map == null) {
+      map = new HashMap(2);
+    }
+    map.put("start", start);
+    map.put("limit", limit);
+    String responseContent = wxMaService.post(GET_LIVE_INFO, WxMaGsonBuilder.create().toJson(map));
+    JsonObject jsonObject = GsonParser.parse(responseContent);
+    if (jsonObject.get("errcode").getAsInt() != 0) {
+      throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+    }
+    return jsonObject;
+  }
   @Override
   public WxMaLiveResult getLiveReplay(Integer roomId, Integer start, Integer limit) throws WxErrorException {
     return getLiveReplay("get_replay", roomId, start, limit);
@@ -151,17 +166,57 @@ public boolean addGoodsToRoom(Integer roomId, List goodsIds) throws WxE
     return true;
   }
 
-  private JsonObject getLiveInfo(Integer start, Integer limit, Map map) throws WxErrorException {
-    if (map == null) {
-      map = new HashMap(2);
+  @Override
+  public boolean addAssistant(Integer roomId, List users) throws WxErrorException {
+    Map map = new HashMap<>(2);
+    map.put("roomId", roomId);
+    map.put("users", users);
+    String responseContent = this.wxMaService.post(ADD_ASSISTANT, WxMaGsonBuilder.create().toJson(map));
+    JsonObject jsonObject = GsonParser.parse(responseContent);
+    if (jsonObject.get("errcode").getAsInt() != 0) {
+      throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
     }
-    map.put("start", start);
-    map.put("limit", limit);
-    String responseContent = wxMaService.post(GET_LIVE_INFO, WxMaGsonBuilder.create().toJson(map));
+    return true;
+  }
+
+  @Override
+  public boolean modifyAssistant(Integer roomId, String username,String nickname) throws WxErrorException {
+    Map map = new HashMap<>(2);
+    map.put("roomId", roomId);
+    map.put("username",username);
+    map.put("nickname", nickname);
+    String responseContent = this.wxMaService.post(MODIFY_ASSISTANT, WxMaGsonBuilder.create().toJson(map));
     JsonObject jsonObject = GsonParser.parse(responseContent);
     if (jsonObject.get("errcode").getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
     }
-    return jsonObject;
+    return true;
+  }
+
+  @Override
+  public boolean removeAssistant(Integer roomId,String username) throws WxErrorException {
+    Map map = new HashMap<>(2);
+    map.put("roomId", roomId);
+    map.put("username",username);
+    String responseContent = this.wxMaService.post(REMOVE_ASSISTANT, WxMaGsonBuilder.create().toJson(map));
+    JsonObject jsonObject = GsonParser.parse(responseContent);
+    if (jsonObject.get("errcode").getAsInt() != 0) {
+      throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+    }
+    return true;
   }
+
+  @Override
+  public List getAssistantList(Integer roomId) throws WxErrorException {
+    Map map = new HashMap<>(2);
+    map.put("roomId", roomId);
+    String responseContent = this.wxMaService.post(GET_ASSISTANT_LIST, WxMaGsonBuilder.create().toJson(map));
+    JsonObject jsonObject = GsonParser.parse(responseContent);
+    if (jsonObject.get("errcode").getAsInt() != 0) {
+      throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+    }
+    return WxMaAssistantResult.fromJson(responseContent).getList();
+  }
+
+
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaAssistantResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaAssistantResult.java
new file mode 100644
index 0000000000..4137efc9fd
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaAssistantResult.java
@@ -0,0 +1,49 @@
+package cn.binarywang.wx.miniapp.bean.live;
+
+import cn.binarywang.wx.miniapp.util.json.WxMaGsonBuilder;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 直播间小助手用户信息
+ */
+@Data
+public class WxMaAssistantResult implements Serializable {
+  private static final long serialVersionUID = 5829108618580715870L;
+
+  private Integer count;
+  private Integer maxCount;
+  private Integer errcode;
+
+  private List list;
+
+  public static WxMaAssistantResult fromJson(String json) {
+    return WxMaGsonBuilder.create().fromJson(json, WxMaAssistantResult.class);
+  }
+  @Data
+  public static class Assistant implements Serializable {
+    private static final long serialVersionUID = 6362128855371134033L;
+    /**
+     * 修改时间
+     */
+    private Long timestamp;
+    /**
+     * 头像
+     **/
+    private String headimg;
+    /**
+     * 用户昵称
+     **/
+    private String nickname;
+    /**
+     * 微信号
+     **/
+    private String alias;
+    /**
+     * openid
+     **/
+    private String openid;
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveAssistantInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveAssistantInfo.java
new file mode 100644
index 0000000000..bfd727ca82
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveAssistantInfo.java
@@ -0,0 +1,38 @@
+package cn.binarywang.wx.miniapp.bean.live;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 直播间小助手用户信息
+ */
+@Data
+public class WxMaLiveAssistantInfo implements Serializable {
+  private static final long serialVersionUID = -5603581848069320808L;
+  /**
+   * 修改时间
+   */
+  private Long timestamp;
+  /**
+   * 头像
+   **/
+  private String headimg;
+  /**
+   * 用户微信号
+   **/
+  private String username;
+  /**
+   * 用户昵称
+   **/
+  private String nickname;
+  /**
+   * 微信号
+   **/
+  private String alias;
+  /**
+   * openid
+   **/
+  private String openid;
+
+}

From 30aca49ab916276d3eb07efdf5269480994a1c1d Mon Sep 17 00:00:00 2001
From: f00lish 
Date: Fri, 13 Nov 2020 12:59:49 +0800
Subject: [PATCH 11/18] =?UTF-8?q?:new:=20#1868=20=E3=80=90=E5=BE=AE?=
 =?UTF-8?q?=E4=BF=A1=E6=94=AF=E4=BB=98=E3=80=91=E5=A2=9E=E5=8A=A0=E9=80=9A?=
 =?UTF-8?q?=E7=94=A8=E4=B8=8A=E4=BC=A0=E5=9B=BE=E7=89=87=E6=8E=A5=E5=8F=A3?=
 =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E4=BC=A0=E5=85=A5=E6=B5=81=E5=92=8C?=
 =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8D=E5=8F=82=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../wxpay/service/MerchantMediaService.java   | 15 +++++++++++
 .../impl/MerchantMediaServiceImpl.java        | 25 ++++++++++++++++---
 2 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java
index 429ece394d..0e35dbb68b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/MerchantMediaService.java
@@ -5,6 +5,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 
 /**
  * 
@@ -27,5 +28,19 @@ public interface MerchantMediaService {
    */
   ImageUploadResult imageUploadV3(File imageFile) throws WxPayException, IOException;
 
+  /**
+   * 
+   * 通用接口-图片上传API
+   * 文档详见: https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/tool/chapter3_1.shtml
+   * 接口链接:https://api.mch.weixin.qq.com/v3/merchant/media/upload
+   * 
+ * + * @param inputStream 需要上传的图片文件流 + * @param fileName 需要上传的图片文件名 + * @return ImageUploadResult 微信返回的媒体文件标识Id。示例值:6uqyGjGrCf2GtyXP8bxrbuH9-aAoTjH-rKeSl3Lf4_So6kdkQu4w8BYVP3bzLtvR38lxt4PjtCDXsQpzqge_hQEovHzOhsLleGFQVRF-U_0 + * @throws WxPayException the wx pay exception + */ + ImageUploadResult imageUploadV3(InputStream inputStream, String fileName) throws WxPayException, IOException; + } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java index 863b706a28..811d61f6b5 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantMediaServiceImpl.java @@ -9,10 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URI; /** @@ -41,4 +38,24 @@ public ImageUploadResult imageUploadV3(File imageFile) throws WxPayException,IOE } } + @Override + public ImageUploadResult imageUploadV3(InputStream inputStream, String fileName) throws WxPayException, IOException { + String url = String.format("%s/v3/merchant/media/upload", this.payService.getPayBaseUrl()); + try(ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + byte[] buffer = new byte[2048]; + int len; + while ((len = inputStream.read(buffer)) > -1) { + bos.write(buffer, 0, len); + } + bos.flush(); + byte[] data = bos.toByteArray(); + String sha256 = DigestUtils.sha256Hex(data); + WechatPayUploadHttpPost request = new WechatPayUploadHttpPost.Builder(URI.create(url)) + .withImage(fileName, sha256, new ByteArrayInputStream(data)) + .build(); + String result = this.payService.postV3(url, request); + return ImageUploadResult.fromJson(result); + } + } + } From 6d556f8b1d3bd43d1ff99bacf2676c32fa7a83a2 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Sat, 14 Nov 2020 15:22:01 +0800 Subject: [PATCH 12/18] =?UTF-8?q?:art:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=EF=BC=8C=E9=83=A8=E5=88=86=E7=B1=BB=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E6=8E=A5=E5=8F=A3=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wx/miniapp/bean/WxMaTemplateData.java | 6 +++++- .../ecommerce/PartnerTransactionsRequest.java | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java index 040edda4d0..9ead69646d 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaTemplateData.java @@ -3,6 +3,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; + /** *
  * 参考文档 https://developers.weixin.qq.com/miniprogram/dev/api-backend/templateMessage.send.html
@@ -13,7 +15,9 @@
  */
 @Data
 @NoArgsConstructor
-public class WxMaTemplateData {
+public class WxMaTemplateData implements Serializable {
+  private static final long serialVersionUID = 855214313056578490L;
+
   private String name;
   private String value;
   private String color;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java
index bde15dc39b..ccfcc5f600 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/PartnerTransactionsRequest.java
@@ -13,11 +13,14 @@
  * 
  * 文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/e_transactions.shtml
  * 
+ * + * @author cloudX */ @Data @NoArgsConstructor public class PartnerTransactionsRequest implements Serializable { private static final long serialVersionUID = -1550405819444680465L; + /** *
    * 字段名:服务商公众号ID
@@ -225,6 +228,7 @@ public class PartnerTransactionsRequest implements Serializable {
   @Data
   @NoArgsConstructor
   public static class Discount implements Serializable {
+    private static final long serialVersionUID = 1090134053810201492L;
 
     /**
      * 
@@ -254,7 +258,7 @@ public static class Discount implements Serializable {
      * 
*/ @SerializedName(value = "invoice_id") - private Integer invoiceId; + private String invoiceId; /** *
@@ -274,6 +278,7 @@ public static class Discount implements Serializable {
   @Data
   @NoArgsConstructor
   public static class Amount implements Serializable {
+    private static final long serialVersionUID = -4967636398225864273L;
 
     /**
      * 
@@ -308,6 +313,7 @@ public static class Amount implements Serializable {
   @Data
   @NoArgsConstructor
   public static class Payer implements Serializable {
+    private static final long serialVersionUID = -3946401119476159971L;
 
     /**
      * 
@@ -341,7 +347,9 @@ public static class Payer implements Serializable {
 
   @Data
   @NoArgsConstructor
-  public static class SettleInfo implements Serializable{
+  public static class SettleInfo implements Serializable {
+    private static final long serialVersionUID = 4438958789491671746L;
+
     /**
      * 
      * 字段名:是否指定分账
@@ -378,6 +386,7 @@ public static class SettleInfo implements Serializable{
   @Data
   @NoArgsConstructor
   public static class GoodsDetail implements Serializable {
+    private static final long serialVersionUID = -2574001236925022932L;
 
     /**
      * 
@@ -453,6 +462,8 @@ public static class GoodsDetail implements Serializable {
   @Data
   @NoArgsConstructor
   public static class SceneInfo implements Serializable {
+    private static final long serialVersionUID = 4678263124015070957L;
+
     /**
      * 
      * 字段名:商户端设备号
@@ -514,6 +525,7 @@ public static class SceneInfo implements Serializable {
   @Data
   @NoArgsConstructor
   public static class H5Info implements Serializable {
+    private static final long serialVersionUID = -6865738707329486532L;
 
     /**
      * 
@@ -593,6 +605,7 @@ public static class H5Info implements Serializable {
   @Data
   @NoArgsConstructor
   public static class StoreInfo implements Serializable {
+    private static final long serialVersionUID = -8002411737407580701L;
 
     /**
      * 

From 5986698d4254c5e00631d4605c01ffbc8d938f40 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 15 Nov 2020 22:18:15 +0800
Subject: [PATCH 13/18] =?UTF-8?q?:art:=20=E5=A2=9E=E5=8A=A0=E7=82=B9?=
 =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E7=A4=BA=E4=BE=8B=E4=BB=A3?=
 =?UTF-8?q?=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../api/impl/WxOpenOAuth2ServiceImplTest.java | 25 ++++++++++++++-----
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenOAuth2ServiceImplTest.java b/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenOAuth2ServiceImplTest.java
index 17387fcc1f..c32eb1fcfe 100644
--- a/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenOAuth2ServiceImplTest.java
+++ b/weixin-java-open/src/test/java/me/chanjar/weixin/open/api/impl/WxOpenOAuth2ServiceImplTest.java
@@ -1,9 +1,10 @@
 package me.chanjar.weixin.open.api.impl;
 
+import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
-import static org.testng.Assert.*;
-
 /**
  * 单元测试.
  *
@@ -11,28 +12,40 @@
  * @date 2020-10-19
  */
 public class WxOpenOAuth2ServiceImplTest {
+  private final WxOpenOAuth2ServiceImpl service = new WxOpenOAuth2ServiceImpl("123", "");
+
+  @BeforeTest
+  public void init() {
+    this.service.setWxOpenConfigStorage(new WxOpenInMemoryConfigStorage());
+  }
 
   @Test
   public void testBuildAuthorizationUrl() {
+    this.service.buildAuthorizationUrl("", "", "");
   }
 
   @Test
-  public void testGetAccessToken() {
+  public void testGetAccessToken() throws WxErrorException {
+    this.service.getAccessToken("a");
   }
 
   @Test
-  public void testTestGetAccessToken() {
+  public void testTestGetAccessToken() throws WxErrorException {
+    this.service.getAccessToken("", "", "");
   }
 
   @Test
-  public void testRefreshAccessToken() {
+  public void testRefreshAccessToken() throws WxErrorException {
+    this.service.refreshAccessToken("");
   }
 
   @Test
-  public void testGetUserInfo() {
+  public void testGetUserInfo() throws WxErrorException {
+    this.service.getUserInfo(new WxOAuth2AccessToken(), "");
   }
 
   @Test
   public void testValidateAccessToken() {
+    this.service.validateAccessToken(new WxOAuth2AccessToken());
   }
 }

From 384dd35b9aa960264b1ce212bf644af2a5235f06 Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Sun, 15 Nov 2020 22:26:22 +0800
Subject: [PATCH 14/18] =?UTF-8?q?:bookmark:=20=E5=8F=91=E5=B8=83=203.9.9.B?=
 =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                                         | 2 +-
 spring-boot-starters/pom.xml                                    | 2 +-
 .../wx-java-miniapp-spring-boot-starter/pom.xml                 | 2 +-
 spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml     | 2 +-
 spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml   | 2 +-
 spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml    | 2 +-
 weixin-graal/pom.xml                                            | 2 +-
 weixin-java-common/pom.xml                                      | 2 +-
 weixin-java-cp/pom.xml                                          | 2 +-
 weixin-java-miniapp/pom.xml                                     | 2 +-
 weixin-java-mp/pom.xml                                          | 2 +-
 weixin-java-open/pom.xml                                        | 2 +-
 weixin-java-pay/pom.xml                                         | 2 +-
 13 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/pom.xml b/pom.xml
index 0fafc56690..4cf6d238d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
   4.0.0
   com.github.binarywang
   wx-java
-  3.9.8.B
+  3.9.9.B
   pom
   WxJava - Weixin/Wechat Java SDK
   微信开发Java SDK
diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml
index 1201828186..a7028adf4f 100644
--- a/spring-boot-starters/pom.xml
+++ b/spring-boot-starters/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
   pom
   wx-java-spring-boot-starters
diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml
index 49f7680937..73fd0fdde5 100644
--- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java-spring-boot-starters
     com.github.binarywang
-    3.9.8.B
+    3.9.9.B
   
   4.0.0
 
diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml
index f59a9eaf7e..f5ab99b1ed 100644
--- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java-spring-boot-starters
     com.github.binarywang
-    3.9.8.B
+    3.9.9.B
   
   4.0.0
 
diff --git a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml
index 4bc26e154a..7cd8aa016b 100644
--- a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java-spring-boot-starters
     com.github.binarywang
-    3.9.8.B
+    3.9.9.B
   
   4.0.0
 
diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml
index 03704fffb9..9cb011a3c9 100644
--- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   
     wx-java-spring-boot-starters
     com.github.binarywang
-    3.9.8.B
+    3.9.9.B
   
   4.0.0
 
diff --git a/weixin-graal/pom.xml b/weixin-graal/pom.xml
index 942ab745ee..43b28ab1e7 100644
--- a/weixin-graal/pom.xml
+++ b/weixin-graal/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
 
   weixin-graal
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index 65b6ca0398..11b2b4abc8 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
 
   weixin-java-common
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index ab11231d50..fa884a6f35 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
 
   weixin-java-cp
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index 728e009f8c..232f5cf83e 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
 
   weixin-java-miniapp
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 30753569ab..27bbd195ab 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
 
   weixin-java-mp
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index ca27b1a707..3193581288 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
 
   weixin-java-open
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index 5c85efcc10..3050ec8f6a 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   
     com.github.binarywang
     wx-java
-    3.9.8.B
+    3.9.9.B
   
   4.0.0
 

From 940f69a763fafba38492e45ecb33d89b2dd1551e Mon Sep 17 00:00:00 2001
From: Binary Wang 
Date: Mon, 16 Nov 2020 17:52:42 +0800
Subject: [PATCH 15/18] =?UTF-8?q?:arrow=5Fup:=20=E5=8D=87=E7=BA=A7xstream?=
 =?UTF-8?q?=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 4cf6d238d3..589fc3bef5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -177,7 +177,7 @@
       
         com.thoughtworks.xstream
         xstream
-        1.4.11.1
+        1.4.14
       
       
         com.google.guava

From 64d67bb42f5e80fe9f3058179a8f8e904ac97896 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 17 Nov 2020 08:57:12 +0800
Subject: [PATCH 16/18] :arrow_up: Bump xstream

Bumps [xstream](https://github.com/x-stream/xstream) from 1.4.10-java7 to 1.4.13-java7.
- [Release notes](https://github.com/x-stream/xstream/releases)
- [Commits](https://github.com/x-stream/xstream/commits)

Signed-off-by: dependabot[bot] 

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
 others/weixin-java-osgi/pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/others/weixin-java-osgi/pom.xml b/others/weixin-java-osgi/pom.xml
index 039e32e734..da6907f46a 100644
--- a/others/weixin-java-osgi/pom.xml
+++ b/others/weixin-java-osgi/pom.xml
@@ -28,7 +28,7 @@
     
       com.thoughtworks.xstream
       xstream
-      1.4.10-java7
+      1.4.13-java7
       provided
       
         

From c80e77c04785f4923723b888febce80088768f3e Mon Sep 17 00:00:00 2001
From: huangxm129 <40385667+huangxm129@users.noreply.github.com>
Date: Tue, 17 Nov 2020 09:47:45 +0800
Subject: [PATCH 17/18] =?UTF-8?q?:new:=20#1873=20=E3=80=90=E4=BC=81?=
 =?UTF-8?q?=E4=B8=9A=E5=BE=AE=E4=BF=A1=E3=80=91=E7=AC=AC=E4=B8=89=E6=96=B9?=
 =?UTF-8?q?=E5=BA=94=E7=94=A8=E5=A2=9E=E5=8A=A0=E7=BD=91=E9=A1=B5=E6=8E=88?=
 =?UTF-8?q?=E6=9D=83=E7=99=BB=E9=99=86=E8=8E=B7=E5=8F=96=E8=AE=BF=E9=97=AE?=
 =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=BA=AB=E4=BB=BD=E5=92=8C=E8=8E=B7=E5=8F=96?=
 =?UTF-8?q?=E8=AE=BF=E9=97=AE=E7=94=A8=E6=88=B7=E6=95=8F=E6=84=9F=E4=BF=A1?=
 =?UTF-8?q?=E6=81=AF=E7=9A=84=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../weixin/cp/bean/WxCpTpUserDetail.java      | 58 ++++++++++++++++++
 .../weixin/cp/bean/WxCpTpUserInfo.java        | 61 +++++++++++++++++++
 .../weixin/cp/constant/WxCpApiPathConsts.java |  2 +
 .../weixin/cp/tp/service/WxCpTpService.java   | 25 ++++++--
 .../service/impl/BaseWxCpTpServiceImpl.java   | 15 +++++
 5 files changed, 157 insertions(+), 4 deletions(-)
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserDetail.java
 create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java

diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserDetail.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserDetail.java
new file mode 100644
index 0000000000..440e7b4df5
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserDetail.java
@@ -0,0 +1,58 @@
+package me.chanjar.weixin.cp.bean;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ *
+ * @author huangxiaoming
+ */
+@Data
+public class WxCpTpUserDetail extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -5028321625140879571L;
+  /**
+   * 用户所属企业的corpid
+   */
+  @SerializedName("corpid")
+  private String corpId;
+
+  /**
+   * 成员UserID
+   */
+  @SerializedName("userid")
+  private String userId;
+
+  /**
+   * 成员姓名
+   */
+  @SerializedName("name")
+  private String name;
+
+  /**
+   * 性别。0表示未定义,1表示男性,2表示女性
+   */
+  @SerializedName("gender")
+  private String gender;
+
+  /**
+   * 头像url。仅在用户同意snsapi_privateinfo授权时返回
+   */
+  @SerializedName("avatar")
+  private String avatar;
+
+  /**
+   * 员工个人二维码(扫描可添加为外部联系人),仅在用户同意snsapi_privateinfo授权时返回
+   */
+  @SerializedName("qr_code")
+  private String qrCode;
+
+  public static WxCpTpUserDetail fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpTpUserDetail.class);
+  }
+
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java
new file mode 100644
index 0000000000..6739082faf
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java
@@ -0,0 +1,61 @@
+package me.chanjar.weixin.cp.bean;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * @author huangxiaoming
+ */
+@Data
+public class WxCpTpUserInfo extends WxCpBaseResp {
+
+  private static final long serialVersionUID = -5028321625140879571L;
+
+  /**
+   * 用户所属企业的corpid
+   */
+  @SerializedName("CorpId")
+  private String corpId;
+
+  /**
+   * 用户在企业内的UserID,如果该企业与第三方应用有授权关系时,返回明文UserId,否则返回密文UserId
+   */
+  @SerializedName("UserId")
+  private String userId;
+
+  /**
+   * 手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)
+   */
+  @SerializedName("DeviceId")
+  private String deviceId;
+
+  /**
+   * 成员票据,最大为512字节。
+   * scope为snsapi_userinfo或snsapi_privateinfo,且用户在应用可见范围之内时返回此参数。
+   * 后续利用该参数可以获取用户信息或敏感信息,参见:https://work.weixin.qq.com/api/doc/90001/90143/91122
+   */
+  @SerializedName("user_ticket")
+  private String userTicket;
+
+  /**
+   * user_ticket的有效时间(秒),随user_ticket一起返回
+   */
+  @SerializedName("expires_in")
+  private String expiresIn;
+
+  /**
+   * 全局唯一。对于同一个服务商,不同应用获取到企业内同一个成员的open_userid是相同的,最多64个字节。仅第三方应用可获取
+   */
+  @SerializedName("open_userid")
+  private String openUserId;
+
+  public static WxCpTpUserInfo fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpTpUserInfo.class);
+  }
+
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+}
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 00d88940f2..f1e1902e05 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
@@ -142,6 +142,8 @@ public static class Tp {
     public static final String GET_AUTH_INFO = "/cgi-bin/service/get_auth_info";
     public static final String GET_AUTH_CORP_JSAPI_TICKET = "/cgi-bin/get_jsapi_ticket";
     public static final String GET_SUITE_JSAPI_TICKET = "/cgi-bin/ticket/get";
+    public static final String GET_USERINFO3RD = "/cgi-bin/service/getuserinfo3rd";
+    public static final String GET_USERDETAIL3RD = "/cgi-bin/service/getuserdetail3rd";
   }
 
   @UtilityClass
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 8e8cbd6fab..9bc3684ef6 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
@@ -6,10 +6,7 @@
 import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
-import me.chanjar.weixin.cp.bean.WxCpMaJsCode2SessionResult;
-import me.chanjar.weixin.cp.bean.WxCpTpAuthInfo;
-import me.chanjar.weixin.cp.bean.WxCpTpCorp;
-import me.chanjar.weixin.cp.bean.WxCpTpPermanentCodeInfo;
+import me.chanjar.weixin.cp.bean.*;
 import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
 
 /**
@@ -266,4 +263,24 @@ public interface WxCpTpService {
    * @return WxSessionManager session manager
    */
   WxSessionManager getSessionManager();
+
+  /**
+   * 
+   * 获取访问用户身份
+   * 
+ * + * @param code + * @return + */ + WxCpTpUserInfo getUserInfo3rd(String code) throws WxErrorException; + + /** + *
+   * 获取访问用户敏感信息
+   * 
+ * + * @param userTicket + * @return + */ + WxCpTpUserDetail getUserDetail3rd(String userTicket) throws WxErrorException; } 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 6c2399067a..c3bbe95c65 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 @@ -342,4 +342,19 @@ public WxSessionManager getSessionManager() { return this.sessionManager; } + @Override + public WxCpTpUserInfo getUserInfo3rd(String code) throws WxErrorException{ + String url = configStorage.getApiUrl(GET_USERINFO3RD); + String result = get(url+"?code="+code,null); + return WxCpTpUserInfo.fromJson(result); + } + + @Override + public WxCpTpUserDetail getUserDetail3rd(String userTicket) throws WxErrorException{ + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("user_ticket", userTicket); + String result = post(configStorage.getApiUrl(GET_USERDETAIL3RD), jsonObject.toString()); + return WxCpTpUserDetail.fromJson(result); + } + } From b351ef761c2e2270e56581943c7705a3e9725ea7 Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Tue, 17 Nov 2020 15:09:08 +0800 Subject: [PATCH 18/18] =?UTF-8?q?:bug:=20=E4=BF=AE=E5=A4=8D=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E9=94=99=E8=AF=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java index 97f30f4377..ca387946eb 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/live/WxMaLiveRoomInfo.java @@ -86,7 +86,7 @@ public class WxMaLiveRoomInfo implements Serializable { /** * 是否关闭分享 【0:开启,1:关闭】默认开启分享(直播开始后不允许修改) **/ - private Integer loseShare; + private Integer closeShare; /** * closeKf Number 否 是否关闭客服 【0:开启,1:关闭】 默认关闭客服 **/