环信服务端下载消息文件---菜鸟教程
前言
在服务端,下载消息文件是一个重要的功能。它允许您从服务器端获取并保存聊天消息、文件等数据,以便在本地进行进一步的处理和分析。本指南将指导您完成环信服务端下载消息文件的步骤。
环信服务端下载消息文件是指在环信服务端上,通过调用相应的API接口,从服务器端下载聊天消息、文件等数据的过程。因环信服务端保存的消息漫游是有时间限制,有用户需要漫游全部的消息或者自己服务端做所有消息记录的备份。可以从环信服务端下载消息文件来进行解压,读取消息文件内容进行存储到自己的服务端。
前提条件
- 已在环信即时通讯控制台 开通配置环信即时通讯 IM 服务。
注册环信即时通讯IM - 了解环信 IM REST API 的调用频率限制
- 环信接口文档介绍:
一、下载消息文件
以下将介绍如何通过环信接口获取到的URL来进行下载文件,解压文件,读取文件。
注:
time参数: 历史消息记录查询的起始时间。UTC 时间,使用 ISO8601 标准,格式为 yyyyMMddHH。例如 time 为 2018112717,则表示查询 2018 年 11 月 27 日 17 时至 2018 年 11 月 27 日 18 时期间的历史消息。若海外集群为 UTC 时区,需要根据自己所在的时区进行时间转换。
上图是环信官方文档中给出的获取历史消息记录响应示例。从示例中可以看出我们请求以后可以得到一个URL,这个URL为消息文件的下载URL。
1、下载消息文件环信rest 接口请求代码如下:
String url = "https://{{RestApi}}/{{org_name}}/{{app_name}}/chatmessages/2023122010";
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type","application/json");
headers.add("Authorization","Bearer Authorization");
Map<String, String> body = new HashMap<>();
HttpEntity<Map<String, String>> entity = new HttpEntity<>(body, headers);
ResponseEntity<Map> response;
try {response = restTemplate.exchange(url, HttpMethod.GET, entity, Map.class);System.out.print("消息文件下载成功---"+response.toString());
} catch (Exception e) {System.out.print("消息文件下载失败---"+e.toString());
}
2、消息文件下载,通过请求环信下载历史消息文件接口获取到的URL 进行下载。
示例代码:
String url = "";
String targetUrl = "";
download(url,targetUrl);
/**
* 根据url下载文件,保存到filepath中
*
* @param url 文件的url
* @param diskUrl 本地存储路径
* @return
*/
public static String download(String url, String diskUrl) {String filepath = "";String filename = "";try {HttpClient client = HttpClients.createDefault();HttpGet httpget = new HttpGet(url);// 加入Referer,防止防盗链 httpget.setHeader("Referer", url);HttpResponse response = client.execute(httpget);HttpEntity entity = response.getEntity();InputStream is = entity.getContent();if (StringUtils.isBlank(filepath)){Map<String,String> map = getFilePath(response,url,diskUrl);filepath = map.get("filepath");filename = map.get("filename");}File file = new File(filepath);file.getParentFile().mkdirs();FileOutputStream fileout = new FileOutputStream(file);byte[] buffer = new byte[cache];int ch = 0;while ((ch = is.read(buffer)) != -1) {fileout.write(buffer, 0, ch);}is.close();fileout.flush();fileout.close();} catch (Exception e) {e.printStackTrace();}return filename;
}/**
* 获取response要下载的文件的默认路径
** @param response* @return */public static Map<String,String> getFilePath(HttpResponse response, String url, String diskUrl) {Map<String,String> map = new HashMap<>();String filepath = diskUrl;String filename = getFileName(response, url);String contentType = response.getEntity().getContentType().getValue();if(StringUtils.isNotEmpty(contentType)){// 获取后缀 String regEx = ".+(.+)$";Pattern p = Pattern.compile(regEx);Matcher m = p.matcher(filename);if (!m.find()) {// 如果正则匹配后没有后缀,则需要通过response中的ContentType的值进行匹配 filename = filename +".gz";}else{if(filename.length()>20){filename = getRandomFileName() + ".gz";}}}if (filename != null) {filepath += filename;} else {filepath += getRandomFileName();}map.put("filename", filename);map.put("filepath", filepath);return map;
}/*** 获取response header中Content-Disposition中的filename值* @param response * @param url* @return*/public static String getFileName(HttpResponse response,String url) {Header contentHeader = response.getFirstHeader("Content-Disposition");String filename = null;if (contentHeader != null) {// 如果contentHeader存在 HeaderElement[] values = contentHeader.getElements();if (values.length == 1) {NameValuePair param = values[0].getParameterByName("filename");if (param != null) {try {filename = param.getValue();} catch (Exception e) {e.printStackTrace();}}}}else{// 正则匹配后缀 filename = getSuffix(url);}return filename;
}/**
* 获取随机文件名
*
* @return
*/
public static String getRandomFileName() {return String.valueOf(System.currentTimeMillis());
}/**
* 获取文件名后缀
* @param url
* @return
*/
public static String getSuffix(String url) {// 正则表达式“.+/(.+)$”的含义就是:被匹配的字符串以任意字符序列开始,后边紧跟着字符“/”, // 最后以任意字符序列结尾,“()”代表分组操作,这里就是把文件名做为分组,匹配完毕我们就可以通过Matcher // 类的group方法取到我们所定义的分组了。需要注意的这里的分组的索引值是从1开始的,所以取第一个分组的方法是m.group(1)而不是m.group(0)。 String regEx = ".+/(.+)$";Pattern p = Pattern.compile(regEx);Matcher m = p.matcher(url);if (!m.find()) {// 格式错误,则随机生成个文件名 return String.valueOf(System.currentTimeMillis());}return m.group(1);}
- url为第一步中从环信下载历史消息文件接口中请求返回的url(消息文件下载地址)
- targetUrl 为下载的本地存储路径
下载以后从对应的路径下就可以看到所下载的文件。
3、消息文件解压,下载完的文件是以.gz结尾的压缩文件,需要对压缩文件进行解压
public static void unGzipFile(String gzFilePath,String directoryPath) {String ouputfile = "";try {//建立gzip压缩文件输入流 FileInputStream fin = new FileInputStream(gzFilePath);//建立gzip解压工作流 GZIPInputStream gzin = new GZIPInputStream(fin);//建立解压文件输出流// ouputfile = sourcedir.substring(0,sourcedir.lastIndexOf('.'));// ouputfile = ouputfile.substring(0,ouputfile.lastIndexOf('.')); FileOutputStream fout = new FileOutputStream(directoryPath);int num;byte[] buf=new byte[1024];while ((num = gzin.read(buf,0,buf.length)) != -1) {fout.write(buf,0,num);}gzin.close();fout.close();fin.close();} catch (Exception ex){System.err.println(ex.toString());}return;}
gzFilePath:压缩文件路径
directoryPath:加压到的文件目录路径
解压后的文件如下图所示:
4、文件读取,将解压后的文件读取出来
FileInputStream inputStream = null;
try {inputStream = new FileInputStream("/Users/liupeng/Downloads/download/1234567890");BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String str = null;long i = 0;while(true){try {if (!((str = bufferedReader.readLine()) != null)) break;} catch (IOException e) {e.printStackTrace();}JSONObject jo = JSONObject.parseObject(str);System.out.println("==========================================" + i);System.out.println("消息id:" + jo.get("msg_id"));System.out.println("发送id:" + jo.get("from"));System.out.println("接收id:" + jo.get("to"));System.out.println("服务器时间戳:" + jo.get("timestamp"));System.out.println("会话类型:" + jo.get("chat_type"));System.out.println("消息扩展:" + jo.getJSONObject("payload").get("ext"));System.out.println("消息体:" + jo.getJSONObject("payload").getJSONArray("bodies").get(0));i ++;if (i > 100) break;}//close try {inputStream.close();bufferedReader.close();} catch (IOException e) {e.printStackTrace();}} catch (FileNotFoundException e) {e.printStackTrace();
}
解析完以后日志打印如下:
至此,解析完以后可以将解析的数据进行存储。
相关文档:
注册环信即时通讯IM:https://console.easemob.com/user/register
环信IM集成文档:https://docs-im-beta.easemob.com/document/ios/quickstart.html
IMGeek社区支持:https://www.imgeek.net/
相关文章:
环信服务端下载消息文件---菜鸟教程
前言 在服务端,下载消息文件是一个重要的功能。它允许您从服务器端获取并保存聊天消息、文件等数据,以便在本地进行进一步的处理和分析。本指南将指导您完成环信服务端下载消息文件的步骤。 环信服务端下载消息文件是指在环信服务端上,通过调…...
创建型模式 | 建造者模式
一、建造者模式 1、原理 建造者模式又叫生成器模式,是一种对象的构建模式。它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。创建者模式是一步一步创建一个复杂的对象…...
MVC设计模式
在当今的软件开发领域,MVC(Model-View-Controller)设计模式已经成为了一种广泛使用的架构模式。它为应用程序提供了一种结构化的方法,将数据、用户界面和业务逻辑分开,从而使得应用程序更易于维护、扩展和重用。 一、…...
WSL (2103) ERROR: CreateProcessEntryCommon:493: chdir 错误解决
[TOC](WSL (2103) ERROR: CreateProcessEntryCommon:493: chdir 错误解决) 1. 错误信息 <3>WSL (2103) ERROR: CreateProcessEntryCommon:493: chdir(/mnt/d/Program Files/PowerShell/7) failed 52. 解决方法 wsl --shutdownwslrefer: https://github.com/microsoft/…...
【二、自动化测试】为什么要做自动化测试?哪种项目适合做自动化?
自动化测试是一种软件测试方法,通过编写和使用自动化脚本和工具,以自动执行测试用例并生成结果。 自动化旨在替代手动测试过程,提高测试效率和准确性。 自动化测试可以覆盖多种测试类型,包括功能测试、性能测试、安全测试等&…...
用ChatGPT来造一个ChatGPT:计算机领域智能问答系统实践(2)
在PHP语言中,你可以使用MySQL数据库来存储知识库,并使用PHP来实现系统的逻辑。以下是一个简单的示例: 创建数据库表: 首先,创建一个名为 computer_knowledge 的表来存储计算机知识。可以使用以下SQL语句:…...
Ubuntu开机自动挂载硬盘
前言: 因为我的电脑是WIN10 Ubuntu18.04双系统,且两个系统都装在C盘上,而D盘作为数据和代码存储盘,经常会开机就被访问,例如上一次关机前用VS Code访问D盘代码,然后下一次开机的时候打开VSCode发现打不开…...
vue3基础:单文件组件介绍
介绍 Vue 的单文件组件 (即 *.vue 文件,简称 SFC,全称是single file component) 是一种特殊的文件格式,使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中。下面是一个单文件组件的示例: <script> export def…...
OCR字符识别:开始批量识别身份证信息
身份证信息批量识别OCR是一项解决方案,它能够将身份证照片打包成zip格式或通过URL地址进行提交,并能够识别照片中的文本信息。最终,用户可以将识别结果生成为excel文件进行下载。 API接口功能: 1. 批量识别:支持将多…...
php多小区智慧物业管理系统源码带文字安装教程
多小区智慧物业管理系统源码带文字安装教程 运行环境 服务器宝塔面板 PHP 7.0 Mysql 5.5及以上版本 Linux Centos7以上 统计分析以小区为单位,统计如下数据:小区总栋数、小区总户数、小区总人数、 小区租户数量、小区每月收费金额统计、小区车位统计、小…...
解决虚拟机的网络图标不见之问题
在WIN11中,启动虚拟机后,发现网络图标不见了,见下图: 1、打开虚拟机终端 输入“sudo server network-manager stop”,停止网络管理器 输入“cd /回车” , 切换到根目录 输入“cd var回车” ,…...
【Spring类路径Bean定义信息扫描】
Spring类路径Bean定义信息扫描 1. ClassPathBeanDefinitionScanner作用2. 类声明3. 属性4. 构造器5. 扫描方法6. 真正扫描方法7. postProcessBeanDefinition8. 注册bean定义 1. ClassPathBeanDefinitionScanner作用 扫描类路径下的类注册为bean定义。2. 类声明 public class …...
Ubuntu上安装VMware+win11系统手册
Ubuntu安装vmware 下载: Linux 版下载地址:https://www.vmware.com/go/getworkstation-linux 安装: sudo chmod x VMware-Workstation-Full-17.5.0-22583795.x86_64.bundle 执行安装命令: sudo ./VMware-Workstation-Full-17.5.0…...
2024年1月12日:清爽无糖rio留下唇齿之间的香甜
友利奈绪的时间管理 2024年1月12日08:02:28进行java程序设计的上课准备 2024年1月12日08:02:44知道java的题目有18道 2024年1月12日08:43:07随机数去重比较 2024年1月12日08:54:03C语言题目最小公倍数 2024年1月12日08:58:37C语言题目二维数组变一维数组 2024年1月12日10…...
群晖Synology Drive同步文件时过滤指定文件夹“dist“, “node_modules“
群晖Synology Drive同步文件时过滤指定文件夹"dist", “node_modules” mac用户 安装Synology Drive创建同步任务修改Synology Drive配置 打开/Users/[用户名]/Library/Application Support/SynologyDrive/data/session/[同步任务序号,第一个同步任务就…...
小程序中滚动字幕
需求:在录像时需要在屏幕上提示字幕,整体匀速向上滚动 html部分: <view class"subtitles_main"><view style"font-size:34rpx;color: #fff;line-height: 60rpx;" animation"{{animation}}">人生的…...
MySQL中约束是什么?
🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页:小小恶斯法克的博客 🎈该系列文章专栏:重拾MySQL 🍹文章作者技术和水平很有限,如果文中出现错误&am…...
若依在表格中如何将字典的键值转为中文
文章目录 一、需求:二、问题解决步骤1、给需要转换的列绑定formatter属性2、获取字典项3、编写formatter属性绑定的方法 一、需求: 后端有时候返回的是字典的键值,在前端展示时需要转成中文值 后端返回的是dictValue,现在要转换…...
用笨办法-刻意练习来提高自己的编程能力
尝试了很多学习方法,企图快速提高编程能力,但最终发现,唯有老老实实刻意练习1,在辛苦与时间积累下,逐渐提升能力,才是最有效的方式。 将自己的笨办法总结了一下,主要包含7个步骤: …...
FineBI报表页面大屏小屏自适应显示问题
大屏正常显示 显示正常 小屏BI自适应显示 存在遮挡字体情况 小屏浏览器缩放显示 等比缩放后显示正常...
NAND Separate Command Address (SCA) 接口命令解读
CA output packet和CA input packet是Separate Command Address (SCA) NAND接口协议中用于命令和地址传输的关键数据结构。 CA Input Packet: 在SCA接口中,输入到NAND器件的命令和地址信息被组织成并行至串行转换的CA(Command and Address)输…...
Git的简单使用说明
Git入门教程 git的最主要的作用:版本控制,协助开发 一.版本控制分类 1.本地版本控制 2.集中版本控制 所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不…...
少儿编程 2023年12月电子学会图形化编程等级考试Scratch二级真题解析(判断题)
2023年12月scratch编程等级考试二级真题 判断题(共10题,每题2分,共20分) 26、声音Medieval1的长度是9.68秒,运行下列程序1或程序2都能实现,播放声音2秒后,声音停止角色移动100步 答案:对 考点分析:考查积木综合使用,重点考查声音积木的使用 程序1中用的是等待播完…...
前端面试 -- vue系列
Vue系列 1. vue理解:2. SPA(单页面应用理解)3. vue实例挂载的过程4. v-for和v-if优先级5. SPA首屏加载速度慢的原因和解决办法6. Vue中给对象添加新属性界面不刷新(直接给对象添加属性)7. vue组件之间的通信方式有哪些…...
open3d相关操作总结
open3d其实有很多交互式命令,在运行程序打开了open3d渲染的窗口后,鼠标点击窗口,按H就会弹出,交互命令的帮助,如下图所示: 其中比较常用的有: Q :退出当前窗口 H:打印帮…...
HTTP数据请求
文章目录 1 概述2 什么是HTTP3 如何发起HTTP请求4 参考链接 1 概述 日常生活中我们使用应用程序看新闻、发送消息等,都需要连接到互联网,从服务端获取数据。例如,新闻应用可以从新闻服务器中获取最新的热点新闻,从而给用户打造更…...
孩子兄弟结构体【】
#include <stdio.h> typedef int TElemType; typedef struct CSTNode {TElemType data;struct CSTNode* firstChild;struct CSTNode* nextSibling; }CSTNode,*CSTree;...
SSM-SpringMVC+Spring+Mybatis
创建项目 创建好 项目后, 项目目录分析 数据库设计 我们采用员工表 Employee 与 部门表 Department 部门表 表设计--- 员工表 --表设计 因为有文件上传操作,因此 建立 info表 (其中 员工只能隶属一个部门,因此 两张表之间 有外键关系) java 代码 设计 数据库建立完毕后,需要…...
系统存储架构升级分享 | 京东云技术团队
一、业务背景 系统业务功能:系统内部进行数据处理及整合, 对外部系统提供结果数据的初始化(写)及查询数据结果服务。 系统网络架构: 部署架构对切量上线的影响 - 内部管理系统上线对其他系统的读业务无影响分布式缓存可进行单独扩容, 与存储及查询功能升级无关通过…...
OpenCV-22高斯滤波
一、高斯函数的基础 要理解高斯滤波首先要直到什么是高斯函数,高斯函数是符合高斯分布的(也叫正态分布)的数据的概率密度函数。 高斯函数的特点是以x轴某一点(这一点称为均值)为对称轴,越靠近中心数据发生…...
中核集团八大子公司/合肥百度网站排名优化
题库来源:安全生产模拟考试一点通公众号小程序 2021年西式面点师(初级)考试APP及西式面点师(初级)模拟考试题,包含西式面点师(初级)考试APP答案和解析及西式面点师(初级…...
美工做任务网站/优质外链平台
此处举例说明WaterMark可能更容易理解,以EventTimeTumblingWindow为例: 如果设置窗口时间大小是10秒,窗口的边界可以是10000-19999; WaterMark延迟2秒,那么当EventTime为21999的数据来到时,会触发计算Eve…...
用ftp改网站电话怎么内页底部的没有变/品牌推广与传播
作者崇尚简约、见解独到、看法新颖、内容有点另类,却总让我产生共鸣,从中受到不少启发,看起来真是过瘾。原来书还可以这样写。有些可能不知不觉加上了我自己的观点,同一句话不同的人有不同的理解,可能会出现断章取义的…...
网站怎么做语言切换/关键词是指什么
C#中 const 和 readonly 的区别 来源 https://www.cnblogs.com/gsk99/archive/2008/10/10/1308299.html http://dev.csdn.net/develop/article/82/82998.shtm const 和 readonly 的区别,总是不太清楚,于是查了查资料。 const 的概念就是一个包含不能修改…...
自己服务器可以做网站/近期的重大新闻
RPA10.0该如何用,今天艺赛旗的工程师就手把手教您做一个**本教程只针对有并能够使用金蝶 Kis 应用的人员使用,艺赛旗设计器 10.0 版本及以上;第一步:开发流程中所需字段, 变量说明第二步:新建全局变量,运行…...
做网站去哪找/新东方教育培训机构
在一个项目中使用到一个问卷调查,在用户完成之后,需要统计所有题目中哪一个选项被选中次数最多。 我的实现方法是将所有题目选中的选项拼接为一个字符串,如:ABCADAA 在分析被选中次数的时候最初是将字符串变为字符数组,…...