From ebb9ccdebe2471cd86941f68bd6d308427f22e76 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:33:09 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20#3376=20=E3=80=90=E5=B0=8F=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F=E3=80=91=E5=AE=8C=E5=96=84=E4=BA=8B=E4=BB=B6=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E6=8E=A8=E9=80=81=E5=AF=B9json=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../miniapp/message/WxMaJsonOutMessage.java | 67 +++++++++++++++++++ .../miniapp/message/WxMaMessageHandler.java | 6 +- .../wx/miniapp/message/WxMaMessageRouter.java | 6 +- .../message/WxMaMessageRouterRule.java | 4 +- .../wx/miniapp/message/WxMaOutMessage.java | 43 ++++++++++++ .../wx/miniapp/message/WxMaXmlOutMessage.java | 22 +++++- .../wx/miniapp/demo/WxMaDemoServer.java | 19 +++--- .../wx/miniapp/demo/WxMaPortalServlet.java | 18 +++-- .../message/WxMaJsonOutMessageTest.java | 56 ++++++++++++++++ 9 files changed, 218 insertions(+), 23 deletions(-) create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessage.java create mode 100644 weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaOutMessage.java create mode 100644 weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessageTest.java diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessage.java new file mode 100644 index 000000000..3f9bbe200 --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessage.java @@ -0,0 +1,67 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; +import cn.binarywang.wx.miniapp.util.crypt.WxMaCryptUtils; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 微信小程序输出给微信服务器的JSON格式消息. + * + * @author Binary Wang + */ +@Data +@Accessors(chain = true) +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WxMaJsonOutMessage implements WxMaOutMessage { + private static final long serialVersionUID = 4241135225946919154L; + + protected String toUserName; + protected String fromUserName; + protected Long createTime; + protected String msgType; + + /** + * 转换成JSON格式. + */ + @Override + public String toJson() { + return WxMaGsonBuilder.create().toJson(this); + } + + /** + * 转换成XML格式(对于JSON消息类型,返回JSON格式). + */ + @Override + public String toXml() { + // JSON消息类型默认返回JSON格式 + return toJson(); + } + + /** + * 转换成加密的JSON格式. + */ + @Override + public String toEncryptedJson(WxMaConfig config) { + String plainJson = toJson(); + WxMaCryptUtils pc = new WxMaCryptUtils(config); + return pc.encrypt(plainJson); + } + + /** + * 转换成加密的XML格式(对于JSON消息类型,返回加密的JSON格式). + */ + @Override + public String toEncryptedXml(WxMaConfig config) { + // JSON消息类型默认返回加密的JSON格式 + return toEncryptedJson(config); + } +} \ No newline at end of file diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java index 9fdd95693..c222692e8 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageHandler.java @@ -20,10 +20,10 @@ public interface WxMaMessageHandler { * @param context 上下文 * @param service 服务类 * @param sessionManager session管理器 - * @return 输出消息 + * @return 输出消息,可以是XML格式或JSON格式 * @throws WxErrorException 异常 */ - WxMaXmlOutMessage handle(WxMaMessage message, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException; + WxMaOutMessage handle(WxMaMessage message, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException; } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java index fd369f517..b46003d98 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java @@ -107,7 +107,7 @@ public class WxMaMessageRouter { /** * 处理微信消息. */ - public WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map context) { + public WxMaOutMessage route(final WxMaMessage wxMessage, final Map context) { if (isMsgDuplicated(wxMessage)) { // 如果是重复消息,那么就不做处理 return null; @@ -129,7 +129,7 @@ public class WxMaMessageRouter { } final List> futures = new ArrayList<>(); - WxMaXmlOutMessage result = null; + WxMaOutMessage result = null; for (final WxMaMessageRouterRule rule : matchRules) { // 返回最后一个非异步的rule的执行结果 if (rule.isAsync()) { @@ -168,7 +168,7 @@ public class WxMaMessageRouter { return result; } - public WxMaXmlOutMessage route(final WxMaMessage wxMessage) { + public WxMaOutMessage route(final WxMaMessage wxMessage) { return this.route(wxMessage, new HashMap<>(2)); } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java index 99181e043..ebff3fb50 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouterRule.java @@ -201,7 +201,7 @@ public class WxMaMessageRouterRule { /** * 处理微信推送过来的消息. */ - protected WxMaXmlOutMessage service(WxMaMessage wxMessage, + protected WxMaOutMessage service(WxMaMessage wxMessage, Map context, WxMaService wxMaService, WxSessionManager sessionManager, @@ -210,7 +210,7 @@ public class WxMaMessageRouterRule { context = new HashMap<>(16); } - WxMaXmlOutMessage outMessage = null; + WxMaOutMessage outMessage = null; try { // 如果拦截器不通过 for (WxMaMessageInterceptor interceptor : this.interceptors) { diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaOutMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaOutMessage.java new file mode 100644 index 000000000..595db304c --- /dev/null +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaOutMessage.java @@ -0,0 +1,43 @@ +package cn.binarywang.wx.miniapp.message; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; + +import java.io.Serializable; + +/** + * 微信小程序输出消息的通用接口,支持XML和JSON两种格式. + * + * @author Binary Wang + */ +public interface WxMaOutMessage extends Serializable { + + /** + * 转换成XML格式. + * + * @return XML格式的消息 + */ + String toXml(); + + /** + * 转换成JSON格式. + * + * @return JSON格式的消息 + */ + String toJson(); + + /** + * 转换成加密的XML格式. + * + * @param config 配置对象 + * @return 加密后的XML格式消息 + */ + String toEncryptedXml(WxMaConfig config); + + /** + * 转换成加密的JSON格式. + * + * @param config 配置对象 + * @return 加密后的JSON格式消息 + */ + String toEncryptedJson(WxMaConfig config); +} diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java index a6c2b828a..b66563a95 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaXmlOutMessage.java @@ -26,7 +26,7 @@ import java.io.Serializable; @Builder @AllArgsConstructor @NoArgsConstructor -public class WxMaXmlOutMessage implements Serializable { +public class WxMaXmlOutMessage implements WxMaOutMessage { private static final long serialVersionUID = 4241135225946919153L; @XStreamAlias("ToUserName") @@ -45,16 +45,36 @@ public class WxMaXmlOutMessage implements Serializable { protected String msgType; @SuppressWarnings("unchecked") + @Override public String toXml() { return XStreamTransformer.toXml((Class) this.getClass(), this); } + /** + * 转换成JSON格式(对于XML消息类型,返回XML格式). + */ + @Override + public String toJson() { + // XML消息类型默认返回XML格式 + return toXml(); + } + /** * 转换成加密的xml格式. */ + @Override public String toEncryptedXml(WxMaConfig config) { String plainXml = toXml(); WxMaCryptUtils pc = new WxMaCryptUtils(config); return pc.encrypt(plainXml); } + + /** + * 转换成加密的JSON格式(对于XML消息类型,返回加密的XML格式). + */ + @Override + public String toEncryptedJson(WxMaConfig config) { + // XML消息类型默认返回加密的XML格式 + return toEncryptedXml(config); + } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java index 7784cf3a1..a1a796c71 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaDemoServer.java @@ -8,6 +8,7 @@ import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.message.WxMaMessageHandler; import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; +import cn.binarywang.wx.miniapp.message.WxMaOutMessage; import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage; import cn.binarywang.wx.miniapp.test.TestConfig; import me.chanjar.weixin.common.api.WxConsts; @@ -32,8 +33,8 @@ public class WxMaDemoServer { private static final WxMaMessageHandler logHandler = new WxMaMessageHandler() { @Override - public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + public WxMaOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { System.out.println("收到消息:" + wxMessage.toString()); service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson()) .toUser(wxMessage.getFromUser()).build()); @@ -43,8 +44,8 @@ public class WxMaDemoServer { private static final WxMaMessageHandler textHandler = new WxMaMessageHandler() { @Override - public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) + public WxMaOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息") .toUser(wxMessage.getFromUser()).build()); @@ -55,8 +56,8 @@ public class WxMaDemoServer { private static final WxMaMessageHandler picHandler = new WxMaMessageHandler() { @Override - public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + public WxMaOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { try { WxMediaUploadResult uploadResult = service.getMediaService() .uploadMedia(WxMaConstants.MediaType.IMAGE, "png", @@ -76,8 +77,8 @@ public class WxMaDemoServer { private static final WxMaMessageHandler qrcodeHandler = new WxMaMessageHandler() { @Override - public WxMaXmlOutMessage handle(WxMaMessage wxMessage, Map context, - WxMaService service, WxSessionManager sessionManager) throws WxErrorException { + public WxMaOutMessage handle(WxMaMessage wxMessage, Map context, + WxMaService service, WxSessionManager sessionManager) throws WxErrorException { try { final File file = service.getQrcodeService().createQrcode("123", 430); WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia(WxMaConstants.MediaType.IMAGE, file); @@ -96,7 +97,7 @@ public class WxMaDemoServer { private static final WxMaMessageHandler customerServiceMessageHandler = new WxMaMessageHandler() { @Override - public WxMaXmlOutMessage handle(WxMaMessage message, Map context, WxMaService service, WxSessionManager sessionManager) { + public WxMaOutMessage handle(WxMaMessage message, Map context, WxMaService service, WxSessionManager sessionManager) { return new WxMaXmlOutMessage() .setMsgType(WxConsts.XmlMsgType.TRANSFER_CUSTOMER_SERVICE) .setFromUserName(message.getToUser()) diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java index c209082d4..cf004510c 100644 --- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/demo/WxMaPortalServlet.java @@ -5,7 +5,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaMessage; import cn.binarywang.wx.miniapp.config.WxMaConfig; import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.binarywang.wx.miniapp.message.WxMaMessageRouter; -import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage; +import cn.binarywang.wx.miniapp.message.WxMaOutMessage; import lombok.AllArgsConstructor; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -62,9 +62,13 @@ public class WxMaPortalServlet extends HttpServlet { inMessage = WxMaMessage.fromXml(request.getInputStream()); } - final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage); + final WxMaOutMessage outMessage = this.messageRouter.route(inMessage); if (outMessage != null) { - response.getWriter().write(outMessage.toXml()); + if (isJson) { + response.getWriter().write(outMessage.toJson()); + } else { + response.getWriter().write(outMessage.toXml()); + } return; } @@ -82,9 +86,13 @@ public class WxMaPortalServlet extends HttpServlet { inMessage = WxMaMessage.fromEncryptedXml(request.getInputStream(), this.config, timestamp, nonce, msgSignature); } - final WxMaXmlOutMessage outMessage = this.messageRouter.route(inMessage); + final WxMaOutMessage outMessage = this.messageRouter.route(inMessage); if (outMessage != null) { - response.getWriter().write(outMessage.toEncryptedXml(this.config)); + if (isJson) { + response.getWriter().write(outMessage.toEncryptedJson(this.config)); + } else { + response.getWriter().write(outMessage.toEncryptedXml(this.config)); + } return; } response.getWriter().write("success"); diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessageTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessageTest.java new file mode 100644 index 000000000..09f3beaf2 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/message/WxMaJsonOutMessageTest.java @@ -0,0 +1,56 @@ +package cn.binarywang.wx.miniapp.message; + +import me.chanjar.weixin.common.api.WxConsts; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WxMaJsonOutMessageTest { + + @Test + public void testToJson() { + WxMaJsonOutMessage message = WxMaJsonOutMessage.builder() + .fromUserName("test_from_user") + .toUserName("test_to_user") + .msgType(WxConsts.XmlMsgType.TRANSFER_CUSTOMER_SERVICE) + .createTime(System.currentTimeMillis() / 1000) + .build(); + + String jsonResult = message.toJson(); + assertThat(jsonResult).isNotEmpty(); + assertThat(jsonResult).contains("test_from_user"); + assertThat(jsonResult).contains("test_to_user"); + assertThat(jsonResult).contains(WxConsts.XmlMsgType.TRANSFER_CUSTOMER_SERVICE); + + System.out.println("JSON Output:"); + System.out.println(jsonResult); + } + + @Test + public void testEmptyMessage() { + WxMaJsonOutMessage message = new WxMaJsonOutMessage(); + String jsonResult = message.toJson(); + assertThat(jsonResult).isNotEmpty(); + System.out.println("Empty message JSON:"); + System.out.println(jsonResult); + } + + @Test + public void testImplementsInterface() { + WxMaJsonOutMessage message = WxMaJsonOutMessage.builder() + .fromUserName("test_from_user") + .toUserName("test_to_user") + .msgType(WxConsts.XmlMsgType.TEXT) + .createTime(System.currentTimeMillis() / 1000) + .build(); + + // Test that it implements WxMaOutMessage interface + WxMaOutMessage outMessage = message; + assertThat(outMessage).isNotNull(); + + // Test both toJson and toXml methods (for JSON messages, both return JSON format) + assertThat(outMessage.toJson()).isNotEmpty(); + assertThat(outMessage.toXml()).isNotEmpty(); + assertThat(outMessage.toJson()).isEqualTo(outMessage.toXml()); + } +} \ No newline at end of file