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