🎨 #2858 【企业微信】优化会话存档获取媒体数据的接口

This commit is contained in:
Alixhan 2022-10-30 14:23:08 +08:00 committed by GitHub
parent edb098500d
commit 30264bfaae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 15 deletions

View File

@ -5,6 +5,7 @@ import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.msgaudit.*;
import java.util.List;
import java.util.function.Consumer;
/**
* 会话内容存档接口.
@ -72,6 +73,22 @@ public interface WxCpMsgAuditService {
void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout,
@NonNull String targetFilePath) throws WxErrorException;
/**
* 获取媒体文件 传入一个lambdaeach所有的数据分片byte[]更加灵活
* 针对图片文件等媒体数据提供sdk接口拉取数据内容
* 详情可以看官方文档亦可阅读此接口源码
*
* @param sdk getChatDatas()获取到的sdk注意每次获取的sdk会不一样
* @param sdkfileid 消息体内容中的sdkfileid信息
* @param proxy 使用代理的请求需要传入代理的链接socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081如果没有传null
* @param passwd 代理账号密码需要传入代理的账号密码 user_name:passwd_123如果没有传null
* @param timeout 超时时间分片数据需累加到文件存储单次最大返回512K字节如果文件比较大自行设置长一点比如timeout=10000
* @param action 传入一个lambdaeach所有的数据分片
* @throws WxErrorException the wx error exception
*/
void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout,
@NonNull Consumer<byte[]> action) throws WxErrorException;
/**
* 获取会话内容存档开启成员列表
* 企业可通过此接口获取企业开启会话内容存档的成员列表

View File

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.MsgAudit.*;
@ -80,10 +81,10 @@ public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService {
long sdk = Finance.NewSdk();
//因为会话存档单独有个secret,优先使用会话存档的secret
String msgAuditSecret = cpService.getWxCpConfigStorage().getMsgAuditSecret();
if(StringUtils.isEmpty(msgAuditSecret)) {
if (StringUtils.isEmpty(msgAuditSecret)) {
msgAuditSecret = cpService.getWxCpConfigStorage().getCorpSecret();
}
long ret = Finance.Init(sdk, cpService.getWxCpConfigStorage().getCorpId(),msgAuditSecret);
long ret = Finance.Init(sdk, cpService.getWxCpConfigStorage().getCorpId(), msgAuditSecret);
if (ret != 0) {
Finance.DestroySdk(sdk);
throw new WxErrorException("init sdk err ret " + ret);
@ -181,7 +182,26 @@ public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService {
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
this.getMediaFile(sdk, sdkfileid, proxy, passwd, timeout, i -> {
try {
// 大于512k的文件会分片拉取此处需要使用追加写避免后面的分片覆盖之前的数据
FileOutputStream outputStream = new FileOutputStream(targetFile, true);
outputStream.write(i);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
});
}
@Override
public void getMediaFile(@NonNull long sdk, @NonNull String sdkfileid, String proxy, String passwd, @NonNull long timeout, @NonNull Consumer<byte[]> action) throws WxErrorException {
/**
* 1媒体文件每次拉取的最大size为512k因此超过512k的文件需要分片拉取
* 2若该文件未拉取完整sdk的IsMediaDataFinish接口会返回0同时通过GetOutIndexBuf接口返回下次拉取需要传入GetMediaData的indexbuf
* 3indexbuf一般格式如右侧所示Range:bytes=524288-1048575:表示这次拉取的是从524288到1048575的分片单个文件首次拉取填写的indexbuf
* 为空字符串拉取后续分片时直接填入上次返回的indexbuf即可
*/
String indexbuf = "";
int ret, data_len = 0;
log.debug("正在分片拉取媒体文件 sdkFileId为{}", sdkfileid);
@ -200,9 +220,7 @@ public class WxCpMsgAuditServiceImpl implements WxCpMsgAuditService {
try {
// 大于512k的文件会分片拉取此处需要使用追加写避免后面的分片覆盖之前的数据
FileOutputStream outputStream = new FileOutputStream(new File(targetFilePath), true);
outputStream.write(Finance.GetData(mediaData));
outputStream.close();
action.accept(Finance.GetData(mediaData));
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -12,8 +12,11 @@ import me.chanjar.weixin.cp.constant.WxCpConsts;
import me.chanjar.weixin.cp.demo.WxCpDemoInMemoryConfigStorage;
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
import org.eclipse.jetty.util.ajax.JSON;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
@ -39,17 +42,21 @@ public class WxCpMsgAuditTest {
*/
// com.binarywang.spring.starter.wxjava.cp.config.WxCpServiceAutoConfiguration
// WxCpServiceImpl.getAccessToken()
@BeforeTest
private void initCpservice() {
if(cpService == null) {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml");
WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(inputStream);
config.setMsgAuditLibPath("/E:/IDEA_WORKSPACE/saisc/crs-member-java/target/classes/wework/libcrypto-1_1-x64.dll,libssl-1_1-x64.dll,libcurl-x64.dll,WeWorkFinanceSdk.dll");
wxCpConfigStorage = config;
cpService = new WxCpServiceImpl();
cpService.setWxCpConfigStorage(config);
}
}
@Test
public void test() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml");
WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(inputStream);
wxCpConfigStorage = config;
cpService = new WxCpServiceImpl();
cpService.setWxCpConfigStorage(config);
/**
* 客户同意进行聊天内容存档事件回调
* 配置了客户联系功能的成员添加外部联系人同意进行聊天内容存档时回调该事件
@ -644,9 +651,109 @@ public class WxCpMsgAuditTest {
* https://www.jianshu.com/p/dde171887d63
*/
String getUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s";
String data = cpService.get(String.format(getUrl, config.getCorpId(), config.getCorpSecret()), null);
String data = cpService.get(String.format(getUrl, wxCpConfigStorage.getCorpId(), wxCpConfigStorage.getCorpSecret()), null);
}
@Test
public void testGetMediaFile() throws Exception {
WxCpMsgAuditService msgAuditService = cpService.getMsgAuditService();
WxCpChatDatas chatDatas = msgAuditService.getChatDatas(0L, 100L, null, null, 10);
for (WxCpChatDatas.WxCpChatData chatDatum : chatDatas.getChatData()) {
WxCpChatModel decryptData = msgAuditService.getDecryptData(chatDatas.getSdk(), chatDatum, 2);
// 文件后缀
String suffix = "";
// 文件名md5
String md5Sum = "";
// sdkFileId
String sdkFileId = "";
String msgType = decryptData.getMsgType();
if(msgType == null ) msgType = "";
switch (msgType) {
case "image":
suffix = ".jpg";
md5Sum = decryptData.getImage().getMd5Sum();
sdkFileId = decryptData.getImage().getSdkFileId();
break;
case "voice":
suffix = ".amr";
md5Sum = decryptData.getVoice().getMd5Sum();
sdkFileId = decryptData.getVoice().getSdkFileId();
break;
case "video":
suffix = ".mp4";
md5Sum = decryptData.getVideo().getMd5Sum();
sdkFileId = decryptData.getVideo().getSdkFileId();
break;
case "emotion":
md5Sum = decryptData.getEmotion().getMd5Sum();
sdkFileId = decryptData.getEmotion().getSdkFileId();
int type = decryptData.getEmotion().getType();
switch (type) {
case 1:
suffix = ".gif";
break;
case 2:
suffix = ".png";
break;
default:
return;
}
break;
case "file":
md5Sum = decryptData.getFile().getMd5Sum();
suffix = "." + decryptData.getFile().getFileExt();
sdkFileId = decryptData.getFile().getSdkFileId();
break;
// 音频存档消息
case "meeting_voice_call":
md5Sum = decryptData.getVoiceId();
sdkFileId = decryptData.getMeetingVoiceCall().getSdkFileId();
for (WxCpChatModel.MeetingVoiceCall.DemoFileData demofiledata :
decryptData.getMeetingVoiceCall().getDemoFileData()) {
String demoFileDataFileName = demofiledata.getFileName();
suffix = demoFileDataFileName.substring(demoFileDataFileName.lastIndexOf(".") + 1);
}
break;
// 音频共享文档消息
case "voip_doc_share":
md5Sum = decryptData.getVoipId();
WxCpFileItem docShare = decryptData.getVoipDocShare();
String fileName = docShare.getFileName();
suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
break;
default:
continue;
}
/**
* 拉取媒体文件
*
* 传入一个each函数用于遍历每个分片的数据
*/
String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
String targetPath = path + "testfile/" + md5Sum + suffix;
File file = new File(targetPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}else{
file.delete();
}
cpService.getMsgAuditService().getMediaFile(chatDatas.getSdk(), sdkFileId, null, null, 1000L, data -> {
try {
// 大于512k的文件会分片拉取此处需要使用追加写避免后面的分片覆盖之前的数据
FileOutputStream outputStream = new FileOutputStream(targetPath, true);
outputStream.write(data);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
});
}
Finance.DestroySdk(chatDatas.getSdk());
}
}

View File

@ -12,6 +12,7 @@
<oauth2redirectUri>网页授权获取用户信息回调地址</oauth2redirectUri>
<webhookKey>webhook链接地址的key值</webhookKey>
<!-- 企业微信会话存档私钥windows以及linux环境sdk路径 -->
<msgAuditSecret>会话存档的secret</msgAuditSecret>
<msgAuditPriKey>-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCTfm5cxqfglfOV7b/Z7OtTZZoZpk2EPTvVhn/ngsfKR899xRdR
25s4h8HkK0XhxqYdOGoAdG3Gms+DvCSY/vu3UtImf0eZSNXpKZJBUnvUVjX4ivnr