From 2392cee28c1eda30c5e8bc20c00adfab135785a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:11:19 +0000 Subject: [PATCH 1/2] Initial plan From 08a6540362b7793f2e5ca126414d6e1d53e4418d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:17:45 +0000 Subject: [PATCH 2/2] =?UTF-8?q?feat(miniapp):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B=E5=BA=8F=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=8D=A1=E7=89=87=E6=B6=88=E6=81=AF=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现以下三个服务卡片消息 API: - 激活与更新服务卡片(setUserNotify) - 更新服务卡片扩展信息(setUserNotifyExt) - 查询服务卡片状态(getUserNotify) Agent-Logs-Url: https://github.com/binarywang/WxJava/sessions/63aeccb8-2684-4ea7-8b6b-9db7d362044a Co-authored-by: binarywang <1343140+binarywang@users.noreply.github.com> --- .../wx/miniapp/api/WxMaSubscribeService.java | 44 +++++++++ .../api/impl/WxMaSubscribeServiceImpl.java | 32 +++++++ .../bean/WxMaGetUserNotifyRequest.java | 66 +++++++++++++ .../miniapp/bean/WxMaGetUserNotifyResult.java | 60 ++++++++++++ .../bean/WxMaServiceNotifyExtRequest.java | 82 ++++++++++++++++ .../bean/WxMaServiceNotifyRequest.java | 93 +++++++++++++++++++ .../miniapp/constant/WxMaApiUrlConstants.java | 9 ++ .../impl/WxMaSubscribeServiceImplTest.java | 41 ++++++++ 8 files changed, 427 insertions(+) create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyRequest.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyResult.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyExtRequest.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyRequest.java diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSubscribeService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSubscribeService.java index e6b1ed16a2..1dbb9f64c9 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSubscribeService.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaSubscribeService.java @@ -1,5 +1,9 @@ package cn.binarywang.wx.miniapp.api; +import cn.binarywang.wx.miniapp.bean.WxMaGetUserNotifyRequest; +import cn.binarywang.wx.miniapp.bean.WxMaGetUserNotifyResult; +import cn.binarywang.wx.miniapp.bean.WxMaServiceNotifyExtRequest; +import cn.binarywang.wx.miniapp.bean.WxMaServiceNotifyRequest; import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; import me.chanjar.weixin.common.bean.subscribemsg.CategoryData; import me.chanjar.weixin.common.bean.subscribemsg.PubTemplateKeyword; @@ -113,4 +117,44 @@ public interface WxMaSubscribeService { */ void sendSubscribeMsg(WxMaSubscribeMessage subscribeMessage) throws WxErrorException; + /** + *
+ * 激活与更新服务卡片 + * + * 详情请见: 激活与更新服务卡片 + * 接口url格式: POST https://api.weixin.qq.com/wxa/setusernotify?access_token=ACCESS_TOKEN + *+ * + * @param request 请求参数 + * @throws WxErrorException . + */ + void setUserNotify(WxMaServiceNotifyRequest request) throws WxErrorException; + + /** + *
+ * 更新服务卡片扩展信息 + * + * 详情请见: 更新服务卡片扩展信息 + * 接口url格式: POST https://api.weixin.qq.com/wxa/setusernotifyext?access_token=ACCESS_TOKEN + *+ * + * @param request 请求参数 + * @throws WxErrorException . + */ + void setUserNotifyExt(WxMaServiceNotifyExtRequest request) throws WxErrorException; + + /** + *
+ * 查询服务卡片状态 + * + * 详情请见: 查询服务卡片状态 + * 接口url格式: POST https://api.weixin.qq.com/wxa/getusernotify?access_token=ACCESS_TOKEN + *+ * + * @param request 请求参数 + * @return 服务卡片状态 + * @throws WxErrorException . + */ + WxMaGetUserNotifyResult getUserNotify(WxMaGetUserNotifyRequest request) throws WxErrorException; + } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java index a7db154a68..edf4d5ba10 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java @@ -2,6 +2,10 @@ import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.WxMaSubscribeService; +import cn.binarywang.wx.miniapp.bean.WxMaGetUserNotifyRequest; +import cn.binarywang.wx.miniapp.bean.WxMaGetUserNotifyResult; +import cn.binarywang.wx.miniapp.bean.WxMaServiceNotifyExtRequest; +import cn.binarywang.wx.miniapp.bean.WxMaServiceNotifyRequest; import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.bean.subscribemsg.CategoryData; @@ -89,4 +93,32 @@ public void sendSubscribeMsg(WxMaSubscribeMessage subscribeMessage) throws WxErr throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); } } + + @Override + public void setUserNotify(WxMaServiceNotifyRequest request) throws WxErrorException { + String responseContent = this.service.post(SERVICE_NOTIFY_SET_URL, request.toJson()); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + } + + @Override + public void setUserNotifyExt(WxMaServiceNotifyExtRequest request) throws WxErrorException { + String responseContent = this.service.post(SERVICE_NOTIFY_SET_EXT_URL, request.toJson()); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + } + + @Override + public WxMaGetUserNotifyResult getUserNotify(WxMaGetUserNotifyRequest request) throws WxErrorException { + String responseContent = this.service.post(SERVICE_NOTIFY_GET_URL, request.toJson()); + JsonObject jsonObject = GsonParser.parse(responseContent); + if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) { + throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp)); + } + return WxMaGsonBuilder.create().fromJson(responseContent, WxMaGetUserNotifyResult.class); + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyRequest.java new file mode 100644 index 0000000000..abc7518e02 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyRequest.java @@ -0,0 +1,66 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 查询服务卡片状态请求. + * + *
接口文档: + * + * 查询服务卡片状态 + * + * @author GitHub Copilot + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaGetUserNotifyRequest implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户身份标识符. + *
+ * 参数:openid + * 是否必填:是 + *+ */ + @SerializedName("openid") + private String openid; + + /** + * 动态更新令牌. + *
+ * 参数:notify_code + * 是否必填:是 + *+ */ + @SerializedName("notify_code") + private String notifyCode; + + /** + * 卡片ID. + *
+ * 参数:notify_type + * 是否必填:是 + *+ */ + @SerializedName("notify_type") + private Integer notifyType; + + /** + * 转为 JSON 字符串. + * + * @return JSON 字符串 + */ + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyResult.java new file mode 100644 index 0000000000..0090eb19b4 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaGetUserNotifyResult.java @@ -0,0 +1,60 @@ +package cn.binarywang.wx.miniapp.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 查询服务卡片状态响应. + * + *
接口文档: + * + * 查询服务卡片状态 + * + * @author GitHub Copilot + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class WxMaGetUserNotifyResult extends WxMaBaseResponse { + private static final long serialVersionUID = 1L; + + /** + * 卡片状态信息. + */ + @SerializedName("notify_info") + private NotifyInfo notifyInfo; + + /** + * 卡片状态详情. + */ + @Data + public static class NotifyInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 卡片ID. + */ + @SerializedName("notify_type") + private Integer notifyType; + + /** + * 上次有效推送的卡片状态与状态相关字段,没推送过为空字符串. + */ + @SerializedName("content_json") + private String contentJson; + + /** + * code 状态:0 正常;1 有风险;2 异常;10 用户拒收本次code. + */ + @SerializedName("code_state") + private Integer codeState; + + /** + * code 过期时间,秒级时间戳. + */ + @SerializedName("code_expire_time") + private Long codeExpireTime; + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyExtRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyExtRequest.java new file mode 100644 index 0000000000..56315ce95e --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyExtRequest.java @@ -0,0 +1,82 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 更新服务卡片扩展信息请求. + * + *
接口文档: + * + * 更新服务卡片扩展信息 + * + * @author GitHub Copilot + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaServiceNotifyExtRequest implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户身份标识符. + *
+ * 参数:openid + * 是否必填:是 + * 描述:用户身份标识符。 + * 当使用微信支付订单号作为 code 时,需要与实际支付用户一致; + * 当通过前端获取 code 时,需要与点击 button 的用户一致。 + *+ */ + @SerializedName("openid") + private String openid; + + /** + * 卡片ID. + *
+ * 参数:notify_type + * 是否必填:是 + * 描述:卡片ID。 + *+ */ + @SerializedName("notify_type") + private Integer notifyType; + + /** + * 动态更新令牌. + *
+ * 参数:notify_code + * 是否必填:是 + * 描述:动态更新令牌。 + *+ */ + @SerializedName("notify_code") + private String notifyCode; + + /** + * 扩展信息. + *
+ * 参数:ext_json + * 是否必填:是 + * 描述:扩展信息,不同卡片的定义不同。 + *+ */ + @SerializedName("ext_json") + private String extJson; + + /** + * 转为 JSON 字符串. + * + * @return JSON 字符串 + */ + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyRequest.java new file mode 100644 index 0000000000..e15e0782f9 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaServiceNotifyRequest.java @@ -0,0 +1,93 @@ +package cn.binarywang.wx.miniapp.bean; + +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 激活与更新服务卡片请求. + * + *
接口文档: + * + * 激活与更新服务卡片 + * + * @author GitHub Copilot + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class WxMaServiceNotifyRequest implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户身份标识符. + *
+ * 参数:openid + * 是否必填:是 + * 描述:用户身份标识符。 + * 当使用微信支付订单号作为 code 时,需要与实际支付用户一致; + * 当通过前端获取 code 时,需要与点击 button 的用户一致。 + *+ */ + @SerializedName("openid") + private String openid; + + /** + * 卡片ID. + *
+ * 参数:notify_type + * 是否必填:是 + * 描述:卡片ID。 + *+ */ + @SerializedName("notify_type") + private Integer notifyType; + + /** + * 动态更新令牌. + *
+ * 参数:notify_code + * 是否必填:是 + * 描述:动态更新令牌。 + *+ */ + @SerializedName("notify_code") + private String notifyCode; + + /** + * 卡片状态与状态相关字段. + *
+ * 参数:content_json + * 是否必填:是 + * 描述:卡片状态与状态相关字段,不同卡片的定义不同。 + *+ */ + @SerializedName("content_json") + private String contentJson; + + /** + * 微信支付订单号验证字段(可选). + *
+ * 参数:check_json + * 是否必填:否 + * 描述:微信支付订单号验证字段。当将微信支付订单号作为 notify_code 时,在激活时需要传入。 + *+ */ + @SerializedName("check_json") + private String checkJson; + + /** + * 转为 JSON 字符串. + * + * @return JSON 字符串 + */ + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java index 40633ea6df..4d20d6b46a 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java @@ -358,6 +358,15 @@ public interface Subscribe { /** 发送订阅消息 */ String SUBSCRIBE_MSG_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send"; + + /** 激活与更新服务卡片 */ + String SERVICE_NOTIFY_SET_URL = "https://api.weixin.qq.com/wxa/setusernotify"; + + /** 更新服务卡片扩展信息 */ + String SERVICE_NOTIFY_SET_EXT_URL = "https://api.weixin.qq.com/wxa/setusernotifyext"; + + /** 查询服务卡片状态 */ + String SERVICE_NOTIFY_GET_URL = "https://api.weixin.qq.com/wxa/getusernotify"; } public interface User { diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImplTest.java index 10993e5651..602e339c23 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImplTest.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImplTest.java @@ -1,6 +1,10 @@ package cn.binarywang.wx.miniapp.api.impl; import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaGetUserNotifyRequest; +import cn.binarywang.wx.miniapp.bean.WxMaGetUserNotifyResult; +import cn.binarywang.wx.miniapp.bean.WxMaServiceNotifyExtRequest; +import cn.binarywang.wx.miniapp.bean.WxMaServiceNotifyRequest; import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; import me.chanjar.weixin.common.bean.subscribemsg.CategoryData; import me.chanjar.weixin.common.bean.subscribemsg.PubTemplateKeyword; @@ -71,4 +75,41 @@ public void testSendSubscribeMsg() throws WxErrorException { // TODO 待完善补充 this.wxService.getSubscribeService().sendSubscribeMsg(WxMaSubscribeMessage.builder().build()); } + + @Test + public void testSetUserNotify() throws WxErrorException { + // TODO 待完善补充,需要真实的 openid、notify_type、notify_code、content_json 参数 + WxMaServiceNotifyRequest request = WxMaServiceNotifyRequest.builder() + .openid("test_openid") + .notifyType(1) + .notifyCode("test_notify_code") + .contentJson("{}") + .build(); + this.wxService.getSubscribeService().setUserNotify(request); + } + + @Test + public void testSetUserNotifyExt() throws WxErrorException { + // TODO 待完善补充,需要真实的 openid、notify_type、notify_code、ext_json 参数 + WxMaServiceNotifyExtRequest request = WxMaServiceNotifyExtRequest.builder() + .openid("test_openid") + .notifyType(1) + .notifyCode("test_notify_code") + .extJson("{}") + .build(); + this.wxService.getSubscribeService().setUserNotifyExt(request); + } + + @Test + public void testGetUserNotify() throws WxErrorException { + // TODO 待完善补充,需要真实的 openid、notify_type、notify_code 参数 + WxMaGetUserNotifyRequest request = WxMaGetUserNotifyRequest.builder() + .openid("test_openid") + .notifyCode("test_notify_code") + .notifyType(1) + .build(); + WxMaGetUserNotifyResult result = this.wxService.getSubscribeService().getUserNotify(request); + assertThat(result).isNotNull(); + System.out.println(result); + } }