From 93017a5ae0cc629a42c59be43c0d11429855e4c0 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 21:38:13 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20#4011=20=E3=80=90=E4=BC=81=E4=B8=9A?= =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E3=80=91=E5=A2=9E=E5=8A=A0=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA=20API=20=E6=A8=A1=E5=BC=8F=20JSON?= =?UTF-8?q?=20=E5=9B=9E=E8=B0=83=E6=B6=88=E6=81=AF=E7=B1=BB=E5=92=8C?= =?UTF-8?q?=E7=9B=B8=E5=BA=94=E7=9A=84=E8=A7=A3=E6=9E=90=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weixin-java-cp/INTELLIGENT_ROBOT.md | 12 +- .../cp/api/WxCpIntelligentRobotService.java | 10 +- .../impl/WxCpIntelligentRobotServiceImpl.java | 7 +- .../WxCpIntelligentRobotMessage.java | 196 ++++++++++++++++++ .../WxCpIntelligentRobotServiceImplTest.java | 13 +- .../WxCpIntelligentRobotMessageTest.java | 76 +++++++ 6 files changed, 310 insertions(+), 4 deletions(-) create mode 100644 weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessage.java create mode 100644 weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessageTest.java diff --git a/weixin-java-cp/INTELLIGENT_ROBOT.md b/weixin-java-cp/INTELLIGENT_ROBOT.md index dcd90e1a1..18dd0c677 100644 --- a/weixin-java-cp/INTELLIGENT_ROBOT.md +++ b/weixin-java-cp/INTELLIGENT_ROBOT.md @@ -109,6 +109,16 @@ String fromUser = message.getFromUserName(); // 发送用户 // ... ``` +对于智能机器人 API 模式的 JSON 回调消息,可使用 `WxCpIntelligentRobotMessage` 解析: + +```java +WxCpIntelligentRobotMessage callbackMessage = + robotService.parseCallbackMessage(jsonBody); +String botId = callbackMessage.getAiBotId(); +String userId = callbackMessage.getFrom().getUserid(); +String msgType = callbackMessage.getMsgType(); +``` + ### 删除智能机器人 ```java @@ -146,4 +156,4 @@ robotService.deleteRobot(robotId); 1. 需要确保企业微信应用具有智能机器人相关权限 2. 智能机器人功能可能需要特定的企业微信版本支持 3. 会话ID可以用于保持对话的连续性,提升用户体验 -4. 机器人状态: 0表示停用,1表示启用 \ No newline at end of file +4. 机器人状态: 0表示停用,1表示启用 diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java index bc5f3f191..58f4373ce 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpIntelligentRobotService.java @@ -74,4 +74,12 @@ public interface WxCpIntelligentRobotService { */ WxCpIntelligentRobotSendMessageResponse sendMessage(WxCpIntelligentRobotSendMessageRequest request) throws WxErrorException; -} \ No newline at end of file + /** + * 解析智能机器人 API 模式回调消息. + * + * @param callbackMessageJson 回调消息JSON + * @return 解析后的回调消息对象 + */ + WxCpIntelligentRobotMessage parseCallbackMessage(String callbackMessageJson); + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImpl.java index 8a12fa4ff..aba1ee85c 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImpl.java @@ -67,4 +67,9 @@ public class WxCpIntelligentRobotServiceImpl implements WxCpIntelligentRobotServ return WxCpIntelligentRobotSendMessageResponse.fromJson(responseText); } -} \ No newline at end of file + @Override + public WxCpIntelligentRobotMessage parseCallbackMessage(String callbackMessageJson) { + return WxCpIntelligentRobotMessage.fromJson(callbackMessageJson); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessage.java new file mode 100644 index 000000000..d485b59d6 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessage.java @@ -0,0 +1,196 @@ +package me.chanjar.weixin.cp.bean.intelligentrobot; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 企业微信智能机器人回调消息. + * + *

官方文档: https://developer.work.weixin.qq.com/document/path/100719

+ */ +@Data +public class WxCpIntelligentRobotMessage implements Serializable { + private static final long serialVersionUID = -1L; + + /** + * 本次回调的唯一性标志. + */ + @SerializedName("msgid") + private String msgId; + + /** + * 智能机器人id. + */ + @SerializedName("aibotid") + private String aiBotId; + + /** + * 会话id,仅群聊类型时返回. + */ + @SerializedName("chatid") + private String chatId; + + /** + * 会话类型,single/group. + */ + @SerializedName("chattype") + private String chatType; + + /** + * 消息发送者. + */ + @SerializedName("from") + private From from; + + /** + * 支持主动回复消息的临时url. + */ + @SerializedName("response_url") + private String responseUrl; + + /** + * 消息类型. + */ + @SerializedName("msgtype") + private String msgType; + + @SerializedName("text") + private Text text; + + @SerializedName("image") + private Image image; + + @SerializedName("mixed") + private Mixed mixed; + + @SerializedName("voice") + private Voice voice; + + @SerializedName("file") + private FileInfo file; + + @SerializedName("video") + private Video video; + + @SerializedName("quote") + private Quote quote; + + @SerializedName("stream") + private Stream stream; + + public static WxCpIntelligentRobotMessage fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpIntelligentRobotMessage.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + @Data + public static class From implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("userid") + private String userid; + } + + @Data + public static class Text implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("content") + private String content; + } + + @Data + public static class Image implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("url") + private String url; + } + + @Data + public static class Voice implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("content") + private String content; + } + + @Data + public static class FileInfo implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("url") + private String url; + } + + @Data + public static class Video implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("url") + private String url; + } + + @Data + public static class Stream implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("id") + private String id; + } + + @Data + public static class Mixed implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("msg_item") + private List msgItem; + } + + @Data + public static class MixedItem implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("msgtype") + private String msgType; + + @SerializedName("text") + private Text text; + + @SerializedName("image") + private Image image; + } + + @Data + public static class Quote implements Serializable { + private static final long serialVersionUID = -1L; + + @SerializedName("msgtype") + private String msgType; + + @SerializedName("text") + private Text text; + + @SerializedName("image") + private Image image; + + @SerializedName("mixed") + private Mixed mixed; + + @SerializedName("voice") + private Voice voice; + + @SerializedName("file") + private FileInfo file; + + @SerializedName("video") + private Video video; + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java index 85104ee73..843bf6aac 100644 --- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpIntelligentRobotServiceImplTest.java @@ -119,4 +119,15 @@ public class WxCpIntelligentRobotServiceImplTest { assert response.getSessionId().equals("session123"); assert response.getErrcode() == 0; } -} \ No newline at end of file + + @Test + public void testParseCallbackMessage() { + String callbackJson = "{\"msgid\":\"msg_1\",\"aibotid\":\"bot_1\",\"chattype\":\"single\"," + + "\"from\":{\"userid\":\"user_1\"},\"msgtype\":\"text\",\"text\":{\"content\":\"hello\"}}"; + WxCpIntelligentRobotMessage message = this.wxCpService.getIntelligentRobotService().parseCallbackMessage(callbackJson); + assert message.getMsgId().equals("msg_1"); + assert message.getAiBotId().equals("bot_1"); + assert message.getFrom().getUserid().equals("user_1"); + assert message.getText().getContent().equals("hello"); + } +} diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessageTest.java new file mode 100644 index 000000000..f8f8791d0 --- /dev/null +++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/intelligentrobot/WxCpIntelligentRobotMessageTest.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.cp.bean.intelligentrobot; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +/** + * 智能机器人回调消息测试. + */ +public class WxCpIntelligentRobotMessageTest { + + @Test + public void testFromJsonWithTextMessage() { + String json = "{" + + "\"msgid\":\"msg_1\"," + + "\"aibotid\":\"bot_1\"," + + "\"chatid\":\"chat_1\"," + + "\"chattype\":\"group\"," + + "\"from\":{\"userid\":\"zhangsan\"}," + + "\"response_url\":\"https://example.com/reply\"," + + "\"msgtype\":\"text\"," + + "\"text\":{\"content\":\"@robot hello\"}" + + "}"; + + WxCpIntelligentRobotMessage message = WxCpIntelligentRobotMessage.fromJson(json); + assertEquals(message.getMsgId(), "msg_1"); + assertEquals(message.getAiBotId(), "bot_1"); + assertEquals(message.getChatId(), "chat_1"); + assertEquals(message.getChatType(), "group"); + assertNotNull(message.getFrom()); + assertEquals(message.getFrom().getUserid(), "zhangsan"); + assertEquals(message.getResponseUrl(), "https://example.com/reply"); + assertEquals(message.getMsgType(), "text"); + assertNotNull(message.getText()); + assertEquals(message.getText().getContent(), "@robot hello"); + assertNull(message.getMixed()); + assertNull(message.getStream()); + } + + @Test + public void testFromJsonWithMixedAndQuote() { + String json = "{" + + "\"msgid\":\"msg_2\"," + + "\"aibotid\":\"bot_2\"," + + "\"chattype\":\"single\"," + + "\"from\":{\"userid\":\"lisi\"}," + + "\"msgtype\":\"mixed\"," + + "\"mixed\":{\"msg_item\":[" + + "{\"msgtype\":\"text\",\"text\":{\"content\":\"hello\"}}," + + "{\"msgtype\":\"image\",\"image\":{\"url\":\"https://example.com/1.png\"}}" + + "]}," + + "\"quote\":{\"msgtype\":\"text\",\"text\":{\"content\":\"quoted\"}}" + + "}"; + + WxCpIntelligentRobotMessage message = WxCpIntelligentRobotMessage.fromJson(json); + assertEquals(message.getMsgType(), "mixed"); + assertNotNull(message.getMixed()); + assertNotNull(message.getMixed().getMsgItem()); + assertEquals(message.getMixed().getMsgItem().size(), 2); + assertEquals(message.getMixed().getMsgItem().get(0).getMsgType(), "text"); + assertEquals(message.getMixed().getMsgItem().get(0).getText().getContent(), "hello"); + assertEquals(message.getMixed().getMsgItem().get(1).getMsgType(), "image"); + assertEquals(message.getMixed().getMsgItem().get(1).getImage().getUrl(), "https://example.com/1.png"); + assertNotNull(message.getQuote()); + assertEquals(message.getQuote().getMsgType(), "text"); + assertEquals(message.getQuote().getText().getContent(), "quoted"); + + String serialized = message.toJson(); + WxCpIntelligentRobotMessage deserialized = WxCpIntelligentRobotMessage.fromJson(serialized); + assertEquals(deserialized.getAiBotId(), "bot_2"); + assertEquals(deserialized.getFrom().getUserid(), "lisi"); + assertEquals(deserialized.getMixed().getMsgItem().size(), 2); + } +}