Skip to content

Commit fe49e5a

Browse files
authored
🎨 #2773【企业微信】优化会话存档,增加会话存档的多企业支持
1 parent 53d3321 commit fe49e5a

File tree

7 files changed

+91
-28
lines changed

7 files changed

+91
-28
lines changed

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMsgAuditService.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,24 @@ public interface WxCpMsgAuditService {
3333
/**
3434
* 获取解密的聊天数据Model
3535
*
36+
* @param sdk getChatDatas()获取到的sdk
3637
* @param chatData getChatDatas()获取到的聊天数据
3738
* @param pkcs1 使用什么方式进行解密,1代表使用PKCS1进行解密,2代表PKCS8进行解密 ...
3839
* @return 解密后的聊天数据
3940
* @throws Exception
4041
*/
41-
WxCpChatModel getDecryptData(@NonNull WxCpChatDatas.WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception;
42+
WxCpChatModel getDecryptData(@NonNull long sdk, @NonNull WxCpChatDatas.WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception;
4243

4344
/**
4445
* 获取解密的聊天数据明文
4546
*
47+
* @param sdk getChatDatas()获取到的sdk
4648
* @param chatData getChatDatas()获取到的聊天数据
4749
* @param pkcs1 使用什么方式进行解密,1代表使用PKCS1进行解密,2代表PKCS8进行解密 ...
4850
* @return 解密后的明文
4951
* @throws Exception
5052
*/
51-
String getChatPlainText(@NonNull WxCpChatDatas.WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception;
53+
String getChatPlainText(@NonNull long sdk, @NonNull WxCpChatDatas.WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception;
5254

5355
/**
5456
* 获取媒体文件
@@ -58,14 +60,15 @@ public interface WxCpMsgAuditService {
5860
* 根据上面返回的文件类型,拼接好存放文件的绝对路径即可。此时绝对路径写入文件流,来达到获取媒体文件的目的。
5961
* 详情可以看官方文档,亦可阅读此接口源码。
6062
*
63+
* @param sdk getChatDatas()获取到的sdk,注意,每次获取的sdk会不一样
6164
* @param sdkfileid 消息体内容中的sdkfileid信息
6265
* @param proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081,如果没有传null
6366
* @param passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123,如果没有传null
6467
* @param timeout 超时时间,分片数据需累加到文件存储。单次最大返回512K字节,如果文件比较大,自行设置长一点,比如timeout=10000
6568
* @param targetFilePath 目标文件绝对路径+实际文件名,比如:/usr/local/file/20220114/474f866b39d10718810d55262af82662.gif
6669
* @throws WxErrorException
6770
*/
68-
void getMediaFile(@NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException;
71+
void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException;
6972

7073
/**
7174
* 获取会话内容存档开启成员列表

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,19 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S
7676
osLib.addAll(fileLib);
7777

7878
Finance.loadingLibraries(osLib, prefixPath);
79-
long sdk = Finance.SingletonSDK();
79+
long sdk = Finance.NewSdk();
8080

8181
long ret = Finance.Init(sdk, cpService.getWxCpConfigStorage().getCorpId(), cpService.getWxCpConfigStorage().getCorpSecret());
8282
if (ret != 0) {
83-
Finance.DestroySingletonSDK(sdk);
83+
Finance.DestroySdk(sdk);
8484
throw new WxErrorException("init sdk err ret " + ret);
8585
}
8686

8787
long slice = Finance.NewSlice();
8888
ret = Finance.GetChatData(sdk, seq, limit, proxy, passwd, timeout, slice);
8989
if (ret != 0) {
9090
Finance.FreeSlice(slice);
91-
Finance.DestroySingletonSDK(sdk);
91+
Finance.DestroySdk(sdk);
9292
throw new WxErrorException("getchatdata err ret " + ret);
9393
}
9494

@@ -97,20 +97,21 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S
9797
Finance.FreeSlice(slice);
9898
WxCpChatDatas chatDatas = WxCpChatDatas.fromJson(content);
9999
if (chatDatas.getErrCode().intValue() != 0) {
100-
Finance.DestroySingletonSDK(sdk);
100+
Finance.DestroySdk(sdk);
101101
throw new WxErrorException(chatDatas.toJson());
102102
}
103103

104+
chatDatas.setSdk(sdk);
104105
return chatDatas;
105106
}
106107

107108
@Override
108-
public WxCpChatModel getDecryptData(@NonNull WxCpChatDatas.WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception {
109-
String plainText = this.decryptChatData(chatData, pkcs1);
109+
public WxCpChatModel getDecryptData(@NonNull long sdk, @NonNull WxCpChatDatas.WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception {
110+
String plainText = this.decryptChatData(sdk, chatData, pkcs1);
110111
return WxCpChatModel.fromJson(plainText);
111112
}
112113

113-
public String decryptChatData(WxCpChatDatas.WxCpChatData chatData, Integer pkcs1) throws Exception {
114+
public String decryptChatData(long sdk, WxCpChatDatas.WxCpChatData chatData, Integer pkcs1) throws Exception {
114115
/**
115116
* 企业获取的会话内容,使用企业自行配置的消息加密公钥进行加密,企业可用自行保存的私钥解开会话内容数据。
116117
* msgAuditPriKey 会话存档私钥不能为空
@@ -124,7 +125,6 @@ public String decryptChatData(WxCpChatDatas.WxCpChatData chatData, Integer pkcs1
124125
/**
125126
* 每次使用DecryptData解密会话存档前需要调用NewSlice获取一个slice,在使用完slice中数据后,还需要调用FreeSlice释放。
126127
*/
127-
long sdk = Finance.SingletonSDK();
128128
long msg = Finance.NewSlice();
129129

130130
/**
@@ -135,7 +135,7 @@ public String decryptChatData(WxCpChatDatas.WxCpChatData chatData, Integer pkcs1
135135
int ret = Finance.DecryptData(sdk, decryptByPriKey, chatData.getEncryptChatMsg(), msg);
136136
if (ret != 0) {
137137
Finance.FreeSlice(msg);
138-
Finance.DestroySingletonSDK(sdk);
138+
Finance.DestroySdk(sdk);
139139
throw new WxErrorException("msg err ret " + ret);
140140
}
141141

@@ -148,12 +148,12 @@ public String decryptChatData(WxCpChatDatas.WxCpChatData chatData, Integer pkcs1
148148
}
149149

150150
@Override
151-
public String getChatPlainText(WxCpChatDatas.@NonNull WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception {
152-
return this.decryptChatData(chatData, pkcs1);
151+
public String getChatPlainText(@NonNull long sdk, WxCpChatDatas.@NonNull WxCpChatData chatData, @NonNull Integer pkcs1) throws Exception {
152+
return this.decryptChatData(sdk, chatData, pkcs1);
153153
}
154154

155155
@Override
156-
public void getMediaFile(@NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException {
156+
public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull String targetFilePath) throws WxErrorException {
157157
/**
158158
* 1、媒体文件每次拉取的最大size为512k,因此超过512k的文件需要分片拉取。
159159
* 2、若该文件未拉取完整,sdk的IsMediaDataFinish接口会返回0,同时通过GetOutIndexBuf接口返回下次拉取需要传入GetMediaData的indexbuf。
@@ -166,13 +166,13 @@ public void getMediaFile(@NonNull String sdkfileid, String proxy, String passwd,
166166

167167
String indexbuf = "";
168168
int ret, data_len = 0;
169+
log.debug("正在分片拉取媒体文件 sdkFileId为{}", sdkfileid);
169170
while (true) {
170171
long mediaData = Finance.NewMediaData();
171-
long sdk = Finance.SingletonSDK();
172172
ret = Finance.GetMediaData(sdk, indexbuf, sdkfileid, proxy, passwd, timeout, mediaData);
173173
if (ret != 0) {
174174
Finance.FreeMediaData(mediaData);
175-
Finance.DestroySingletonSDK(sdk);
175+
Finance.DestroySdk(sdk);
176176
throw new WxErrorException("getmediadata err ret " + ret);
177177
}
178178

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,20 @@ public class WxCpXmlMessage implements Serializable {
434434
* 1. 群发的结果.
435435
* 2. 通讯录变更事件
436436
* 激活状态:1=已激活 2=已禁用 4=未激活 已激活代表已激活企业微信或已关注微工作台(原企业号).
437+
* 3. 直播回调事件
438+
* 直播状态 ,0:预约中,1:直播中,2:已结束,4:已取消 (已过期状态目前没有回调)
437439
*/
438440
@XStreamAlias("Status")
439441
@XStreamConverter(value = XStreamCDataConverter.class)
440442
private String status;
441443

444+
/**
445+
* 直播ID
446+
*/
447+
@XStreamAlias("LivingId")
448+
@XStreamConverter(value = XStreamCDataConverter.class)
449+
private String livingId;
450+
442451
/**
443452
* group_id下粉丝数;或者openid_list中的粉丝数.
444453
*/

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatDatas.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
/**
1313
* 聊天记录数据内容.
1414
*
15-
* @author Wang_Wong
15+
* @author <a href="https://github.com/0katekate0">Wang_Wong</a>
16+
* @date 2022-01-17
1617
*/
1718
@Data
1819
public class WxCpChatDatas implements Serializable {
@@ -24,6 +25,9 @@ public class WxCpChatDatas implements Serializable {
2425
@SerializedName("errmsg")
2526
private String errMsg;
2627

28+
@SerializedName("sdk")
29+
private long sdk;
30+
2731
@SerializedName("chatdata")
2832
private List<WxCpChatData> chatData;
2933

weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/crypto/WxCpCryptUtil.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package me.chanjar.weixin.cp.util.crypto;
22

3-
import com.google.common.io.BaseEncoding;
43
import me.chanjar.weixin.common.error.WxErrorException;
54
import me.chanjar.weixin.common.util.crypto.WxCryptUtil;
65
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
@@ -61,7 +60,7 @@ public static String decryptPriKey(String encryptRandomKey, String msgAuditPriKe
6160
* @throws Exception
6261
*/
6362
public static String decryptPriKeyByPKCS8(String encryptRandomKey, String msgAuditPriKey) throws Exception {
64-
String privateKey = msgAuditPriKey.replaceAll("\\n", "")
63+
String privateKey = msgAuditPriKey.replaceAll("(\r\n|\r|\n|\n\r)", "")
6564
.replace("-----BEGIN PRIVATE KEY-----", "")
6665
.replace("-----END PRIVATE KEY-----", "")
6766
.replaceAll(" ", "");
@@ -87,7 +86,7 @@ public static String decryptPriKeyByPKCS8(String encryptRandomKey, String msgAud
8786
* @throws Exception
8887
*/
8988
public static String decryptPriKeyByPKCS1(String encryptRandomKey, String msgAuditPriKey) throws Exception {
90-
String privateKey = msgAuditPriKey.replaceAll("\\n", "")
89+
String privateKey = msgAuditPriKey.replaceAll("(\r\n|\r|\n|\n\r)", "")
9190
.replace("-----BEGIN RSA PRIVATE KEY-----", "")
9291
.replace("-----END RSA PRIVATE KEY-----", "")
9392
.replaceAll(" ", "");

weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpLivingTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
import lombok.extern.slf4j.Slf4j;
44
import lombok.val;
55
import me.chanjar.weixin.common.error.WxErrorException;
6+
import me.chanjar.weixin.common.util.XmlUtils;
67
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
78
import me.chanjar.weixin.cp.bean.living.*;
9+
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
810
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
911
import me.chanjar.weixin.cp.demo.WxCpDemoInMemoryConfigStorage;
12+
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
1013
import org.eclipse.jetty.util.ajax.JSON;
1114
import org.testng.annotations.Test;
1215

@@ -18,7 +21,8 @@
1821
* 企业微信直播测试类.
1922
* 官方文档:https://open.work.weixin.qq.com/api/doc/90000/90135/93632
2023
*
21-
* @author Wang_Wong
24+
* @author <a href="https://github.com/0katekate0">Wang_Wong</a>
25+
* @date 2021-12-23
2226
*/
2327
@Slf4j
2428
public class WxCpLivingTest {
@@ -36,6 +40,31 @@ public void test() throws WxErrorException {
3640
wxCpService = new WxCpServiceImpl();
3741
wxCpService.setWxCpConfigStorage(config);
3842

43+
44+
/**
45+
* 直播回调事件
46+
* 一场完整的直播,会经历 预约直播/开始直播/结束直播 等一系列状态变更。
47+
* 为了让企业实时获取直播的动态,当直播状态变更后,企业微信会将该变更推送到开发者配置的回调URL。
48+
* 只有通过接口创建的预约/立即直播才会回调。
49+
*
50+
* 请注意,只有用企业微信api创建的直播才能收到回调,且调用创建直播接口的应用,要配置好回调url。
51+
*/
52+
String livingXml = "<xml>\n" +
53+
" <ToUserName><![CDATA[toUser]]></ToUserName>\n" +
54+
" <FromUserName><![CDATA[fromUser]]></FromUserName> \n" +
55+
" <CreateTime>1348831860</CreateTime>\n" +
56+
" <MsgType><![CDATA[event]]></MsgType>\n" +
57+
" <Event><![CDATA[living_status_change]]></Event>\n" +
58+
" <LivingId><![CDATA[LivingId]]></LivingId>\n" +
59+
" <Status>1</Status>\n" +
60+
" <AgentID>1</AgentID>\n" +
61+
"</xml>";
62+
63+
final WxCpXmlMessage livingXmlMsg = XStreamTransformer.fromXml(WxCpXmlMessage.class, livingXml);
64+
livingXmlMsg.setAllFieldsMap(XmlUtils.xml2Map(livingXml));
65+
log.info("livingXmlMsg:{}", JSON.toString(livingXmlMsg));
66+
67+
3968
/**
4069
* 测试创建直播
4170
*/

weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpMsgAuditTest.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package me.chanjar.weixin.cp.api;
22

33
import com.google.common.collect.Lists;
4+
import com.tencent.wework.Finance;
45
import lombok.extern.slf4j.Slf4j;
56
import me.chanjar.weixin.common.util.XmlUtils;
67
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
@@ -114,7 +115,23 @@ public void test() throws Exception {
114115
* <msgAuditLibPath>D:/WorkSpace/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,libWeWorkFinanceSdk_Java.so</msgAuditLibPath>
115116
* Linux:
116117
* <msgAuditLibPath>/www/osfile/work_msg_storage/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll,libWeWorkFinanceSdk_Java.so</msgAuditLibPath>
117-
*/
118+
*
119+
*
120+
* yml配置(支持多个corpId):
121+
* wx:
122+
* cp:
123+
* appConfigs:
124+
* - agentId: 10001 #客户联系
125+
* corpId: xxxxxxxxxxx
126+
* secret: T5fTj1n-sBAT4rKNW5c9IYNfPdXZxxxxxxxxxxx
127+
* token: 2bSNqTcLtxxxxxxxxxxx
128+
* aesKey: AXazu2Xyw44SNY1x8go2phn9p9B2xxxxxxxxxxx
129+
* - agentId: 10002 #会话内容存档
130+
* corpId: xxxxxxxxxxx
131+
* secret: xIpum7Yt4NMXcyxdzcQ2l_46BG4Qxxxxxxxxxxx
132+
* token:
133+
* aesKey:
134+
* /
118135
119136
/**
120137
* 建议放到redis,本次请求获取消息记录开始的seq值。首次访问填写0,非首次使用上次企业微信返回的最大seq。允许从任意seq重入拉取。
@@ -145,13 +162,13 @@ public void test() throws Exception {
145162
// Integer publickeyVer = chatData.getPublickeyVer();
146163

147164
// 获取明文数据
148-
final String chatPlainText = cpService.getMsgAuditService().getChatPlainText(chatData, 2);
165+
final String chatPlainText = cpService.getMsgAuditService().getChatPlainText(chatDatas.getSdk(), chatData, 2);
149166
final WxCpChatModel wxCpChatModel = WxCpChatModel.fromJson(chatPlainText);
150167
log.info("明文数据为:{}", wxCpChatModel.toJson());
151168

152169
// 获取消息数据
153170
// https://developer.work.weixin.qq.com/document/path/91774
154-
final WxCpChatModel decryptData = cpService.getMsgAuditService().getDecryptData(chatData, 2);
171+
final WxCpChatModel decryptData = cpService.getMsgAuditService().getDecryptData(chatDatas.getSdk(), chatData, 2);
155172
log.info("获取消息数据为:{}", decryptData.toJson());
156173

157174
/**
@@ -239,13 +256,15 @@ public void test() throws Exception {
239256
* 3、比如可以上传到阿里云oss或者腾讯云cos
240257
*/
241258
String targetPath = path + md5Sum + suffix;
242-
cpService.getMsgAuditService().getMediaFile(sdkFileId, null, null, 1000L, targetPath);
259+
cpService.getMsgAuditService().getMediaFile(chatDatas.getSdk(), sdkFileId, null, null, 1000L, targetPath);
243260

244261
}
245-
246262
}
247-
248263
}
264+
// 注意:
265+
// 当此批次数据拉取完毕后,可以释放此次sdk
266+
log.info("释放sdk {}", chatDatas.getSdk());
267+
Finance.DestroySdk(chatDatas.getSdk());
249268

250269
}
251270

0 commit comments

Comments
 (0)