1
0
mirror of synced 2026-03-24 05:28:47 +08:00

🎨 #3880 【企业微信】修复MemChangeList群成员变更ID解析为空字符串的问题

This commit is contained in:
Copilot
2026-02-28 16:55:43 +08:00
committed by GitHub
parent 5ff4114b6c
commit 3233384b17
3 changed files with 104 additions and 1 deletions

View File

@@ -0,0 +1,54 @@
package me.chanjar.weixin.common.util.xml;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
* 兼容两种格式的字符串列表转换器:
* <ul>
* <li>旧格式4.8.0之前):&lt;MemChangeList&gt;&lt;![CDATA[id1,id2]]&gt;&lt;/MemChangeList&gt;</li>
* <li>新格式4.8.0起):&lt;MemChangeList&gt;&lt;Item&gt;&lt;![CDATA[id1]]&gt;&lt;/Item&gt;&lt;/MemChangeList&gt;</li>
* </ul>
* 解析结果统一为逗号分隔的字符串。
*/
public class XStreamCDataListConverter implements Converter {
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
if (source != null) {
writer.setValue("<![CDATA[" + source + "]]>");
}
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
if (reader.hasMoreChildren()) {
// 新格式:含有 <Item> 子元素
StringBuilder sb = new StringBuilder();
while (reader.hasMoreChildren()) {
reader.moveDown();
String value = reader.getValue();
if (value != null && !value.isEmpty()) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(value);
}
reader.moveUp();
}
return sb.length() > 0 ? sb.toString() : null;
} else {
// 旧格式:直接 CDATA 文本
String value = reader.getValue();
return (value != null && !value.isEmpty()) ? value : null;
}
}
@Override
public boolean canConvert(Class type) {
return type == String.class;
}
}

View File

@@ -11,6 +11,7 @@ import me.chanjar.weixin.common.util.XmlUtils;
import me.chanjar.weixin.common.util.xml.IntegerArrayConverter;
import me.chanjar.weixin.common.util.xml.LongArrayConverter;
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
import me.chanjar.weixin.common.util.xml.XStreamCDataListConverter;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
@@ -156,7 +157,7 @@ public class WxCpXmlMessage implements Serializable {
private String memChangeCnt;
@XStreamAlias("MemChangeList")
@XStreamConverter(value = XStreamCDataConverter.class)
@XStreamConverter(value = XStreamCDataListConverter.class)
private String memChangeList;
@XStreamAlias("LastMemVer")

View File

@@ -570,5 +570,53 @@ public class WxCpXmlMessageTest {
assertEquals(wxMessage3.getUpdateDetail(), "change_name");
// 当XML中没有MemChangeList元素时字段应该为null而不是空字符串
assertThat(wxMessage3.getMemChangeList()).isNull();
// 测试企业微信4.8.0新格式MemChangeList使用<Item>子元素(加群场景)
String xmlNewFormatAddMember = "<xml>"
+ "<ToUserName><![CDATA[c2e112dad808119117371bbcd6]]></ToUserName>"
+ "<FromUserName><![CDATA[sys]]></FromUserName>"
+ "<CreateTime>9811170016713</CreateTime>"
+ "<MsgType><![CDATA[event]]></MsgType>"
+ "<Event><![CDATA[change_external_chat]]></Event>"
+ "<ChatId><![CDATA[wrxUBwDQAAa44T11Ziaed811rhUr8-3Igmug]]></ChatId>"
+ "<ChangeType><![CDATA[update]]></ChangeType>"
+ "<UpdateDetail><![CDATA[add_member]]></UpdateDetail>"
+ "<JoinScene>3</JoinScene>"
+ "<MemChangeCnt>1</MemChangeCnt>"
+ "<MemChangeList><Item><![CDATA[wmxUBwDQAAO-Hn5_wFJz4wvo5TxLFibw]]></Item></MemChangeList>"
+ "<LastMemVer><![CDATA[5807afd2ab75771d5e8ac623f534ac0b]]></LastMemVer>"
+ "<CurMemVer><![CDATA[ea36e8b6062b803cda0ee45e9418d637]]></CurMemVer>"
+ "</xml>";
WxCpXmlMessage wxMessage4 = WxCpXmlMessage.fromXml(xmlNewFormatAddMember);
assertEquals(wxMessage4.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CHAT);
assertEquals(wxMessage4.getChangeType(), "update");
assertEquals(wxMessage4.getUpdateDetail(), "add_member");
assertEquals(wxMessage4.getJoinScene(), "3");
assertEquals(wxMessage4.getMemChangeCnt(), "1");
// 新格式:<Item>子元素中的成员ID应被正确解析
assertEquals(wxMessage4.getMemChangeList(), "wmxUBwDQAAO-Hn5_wFJz4wvo5TxLFibw");
// 测试企业微信4.8.0新格式:多个<Item>子元素(多成员变更)
String xmlNewFormatMultiMember = "<xml>"
+ "<ToUserName><![CDATA[toUser]]></ToUserName>"
+ "<FromUserName><![CDATA[sys]]></FromUserName>"
+ "<CreateTime>1403610513</CreateTime>"
+ "<MsgType><![CDATA[event]]></MsgType>"
+ "<Event><![CDATA[change_external_chat]]></Event>"
+ "<ChangeType><![CDATA[update]]></ChangeType>"
+ "<ChatId><![CDATA[wrOgQhDgAAMYQiS5ol9G7gK9JVAAAA]]></ChatId>"
+ "<UpdateDetail><![CDATA[del_member]]></UpdateDetail>"
+ "<QuitScene>1</QuitScene>"
+ "<MemChangeCnt>2</MemChangeCnt>"
+ "<MemChangeList>"
+ "<Item><![CDATA[wmEJiCwAAA9KG2qlSq6rKwASSgAAAA]]></Item>"
+ "<Item><![CDATA[wmEJiCwAAA9KG2qlSq6rKwBBBBBBB]]></Item>"
+ "</MemChangeList>"
+ "</xml>";
WxCpXmlMessage wxMessage5 = WxCpXmlMessage.fromXml(xmlNewFormatMultiMember);
assertEquals(wxMessage5.getUpdateDetail(), "del_member");
assertEquals(wxMessage5.getMemChangeCnt(), "2");
// 多个<Item>元素应被解析为逗号分隔字符串
assertEquals(wxMessage5.getMemChangeList(), "wmEJiCwAAA9KG2qlSq6rKwASSgAAAA,wmEJiCwAAA9KG2qlSq6rKwBBBBBBB");
}
}