知方号

知方号

企业微信会话存档<企业微信文件保存地址>

企业微信会话存档

需求:

获取聊天记录里产生的文件,下载并保存,存储到文件服务器(用oss表示)中

过程:

看起来很简单,直接干;

初步思路:

请求企业微信文件下载接口,先下载到本地从本地读取文件,上传到oss

看起来并没什么问题,直接干!

踩坑1

既然是从企业微信接口下载的,那就先看看企业微信的开发文档吧

纳尼,这些参数是什么???

好吧,获取这些参数的方式请参考《企业微信会话存档-如何高性能存储海量聊天记录》,这里就不深究了:获取聊天记录,消息类型有很多,如果消息包含文件类型,那就会包含以上字段;

因为涉及其他业务,一条消息可能需要多次处理,所以处理消息的方式使用事件广播的方式,这里只需要监听消息事件就可以了。

通过API文档了解到,媒体消息是需要进行分片拉取的,每个分片大小最大为512kb;

实际的代码太长了,为方便理解使用伪代码表示,如下(文中所有的代码均为伪代码)

// 0. 记录文件信息表inert(fileInfo);// 1. 初始化sdk;验证秘钥并解密sdk = init();// 2. 创建文件file = createFile();byte[] b = new byte[0];// 3. 拉取消息indexBuf = "";while(true) { // 3.1 获取数据 result = getMediaData(indexBuf); // 3.2 将数据保存 // 企微返回的就是byte数组 byte[] b1 = result.data; b = b.length == 0 ? b1 : ArrayUtil.addAll(b, b1); // 3.3 判断文件是否下载完成;1表示下载完成 if (1 == isFinish) { break; } else { // 记录 indexBuf,即文件下载到哪里了,下次请求带上该参数 indexBuf = result.indexBuf; }}// 4. 保存到文件file.write(b);// 5. 上传到ossossService.upload(file);// 6. 删除文件del(file);

写到这里,完成了,上线上线

踩坑2,3,4,5,6…

一个一个写太慢了,篇幅长而无用也是浪费读者时间,这里一并列举:

项目跑的时候,同事发了个win11的系统镜像;哎,系统怎么停了,服务器内存怎么满了?一个一个下载文件,太慢了,改成多线程吧;使用线程池,最大开了8个线程,等待队列开了20个;项目重启,刚才的文件呢,怎么丢了一部分?oss的服务怎么突然停了,那我的项目怎么跑?纳尼,不用oss了,换成s3服务器了?因为oss在升级,过段时间再换回来?内心…怎么客户发送了个文件,消息记录有这条消息,但是文件没法下载呢,也没个提示?大文件就算了,我就发了个不到1M的文件,就算有延迟,也不应该等了几个小时还没下载完吧?为什么有的文件没有传到oss呢,没传到oss的会丢失吗?文件太多了,能不能优化一下,节省一些带宽?客户:为什么,为什么,为什么…能不能这样处理…想要个这样的效果… 修复ing

剖析原始代码的问题:

使用byte[] 数组接收数据,但是所有的数据都是存储在内存中的,文件过大会把内存占满因为是请求的企业微信,外网通信,难免会因为网络等原因导致请求失败,如果中途请求失败,文件会丢失文件下载完成之后,直接上传oss,若上传失败,文件又会丢失

逐个针对单个问题简单说一下解决思路(单个看起来有点儿乱,可直接看完整解决方案):

byte[] 更换为 FileOutputStream;每次while循环里都直接写入并flush();while完成后关闭流;可解决大文件读取在内存中,导致内存不足的问题等待队列改为0;文件记录存入redis;重启项目不会丢失数据记录文件id和状态,使用定时任务去重试上传oss抽象一个文件上传第三方服务器的接口,把使用第三方服务的类型放进配置中心,修改配置中心即可更换上传方式将文件下载的状态也记录起来,同步到页面展示有可能刚好几个线程全是下载的大文件,都很耗时;将大文件小文件分开下载重复多次上传,一直失败,就永久保存,提供文件访问接口使用md5校验文件内容是否一致,如果相同就不重复下载和上传 完整解决方案

经过不断的踩坑,不断的修复,终于得到了一个较为完善的解决方案;

处理流程中,文件有多种状态,为保证文件不丢失,将文件状态记录到表中;各状态分别是:

/** * -1 初始化值;监听到消息就记录值 */Integer INIT = -1;/** * 0-微信下载中 */Integer DOWNLOADING = 0;/** * 1-微信下载失败 */Integer WECHAT_ERROR = 1;/** * 2-文件存储失败 */Integer SAVE_ERROR = 2;/** * 6-文件无需下载 */Integer NOT_NEED_DOWNLOAD = 6;/** * 7-文件存储成功 */Integer SUCCESS = 7;/** * 8-文件转存oss失败 */Integer OSS_ERROR = 8;/** * 9-文件转存oss成功 */Integer OSS_SUCCESS = 9;

程序的执行流程,纯文字看起来太迷糊了,来张图看吧

总结

总结就是上图

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。

上一篇 没有了

下一篇没有了