环信服务端下载消息文件---菜鸟教程

前言

在服务端,下载消息文件是一个重要的功能。它允许您从服务器端获取并保存聊天消息、文件等数据,以便在本地进行进一步的处理和分析。本指南将指导您完成环信服务端下载消息文件的步骤。
环信服务端下载消息文件是指在环信服务端上,通过调用相应的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/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/316544.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Self-Attention

前置知识&#xff1a;RNN&#xff0c;Attention机制 在一般任务的Encoder-Decoder框架中&#xff0c;输入Source和输出Target内容是不一样的&#xff0c;比如对于英-中机器翻译来说&#xff0c;Source是英文句子&#xff0c;Target是对应的翻译出的中文句子&#xff0c;Attent…

【新特性演示】YOLOv8实现旋转对象检测

学习《OpenCV应用开发&#xff1a;入门、进阶与工程化实践》一书 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; YOLOv8旋转对象检测 YOLOv8框架在在支持分类、对象检测、实例分割、姿态评估的基础上更近一步&#xff0c;现已经支持旋转对象…

【微信小程序独立开发1】项目提出和框架搭建

前言&#xff1a;之前学习小程序开发时仿照别人的页面自己做了一个商城项目和小说项目&#xff0c;最近突发奇想&#xff0c;想从0开发一个关于《宠物日记》的小程序&#xff0c;需求和页面都由自己设计&#xff0c;将在这记录开发的全部流程和过程中遇到的难题等... 1、搭建小…

AI Table应用程序接口表的格式说明和作用

AI Table 首先全拼不是AI人工智能表&#xff0c;而是Application Interface Table应用程序接口表。此表按照AUTOSAR的格式规范去定义&#xff0c;并且使用此Excel 表格生成相应的应用软件组件Arxml文件。下面就让我们按照AUTOSAR_EXP_AIUserGuide.pdf文档官方解释描述文件去看看…

Camtasia2024屏幕录像和视频编辑软件

做网络教学视频&#xff0c;开发微课程&#xff0c;用得最多的就是录屏视频编辑&#xff0c;而在这类软件中我只推荐Camtasia Studio。随着Camtasia Studio的更新&#xff0c;其功能越来越完善&#xff0c;用户界面越来越友好&#xff0c;除了安装更加简单&#xff0c;汉化只需…

51-10 多模态论文串讲—ALBEF 论文精读

今天我们就来过一下多模态的串讲&#xff0c;其实之前&#xff0c;我们也讲了很多工作了&#xff0c;比如说CLIP&#xff0c;还有ViLT&#xff0c;以及CLIP的那么多后续工作。多模态学习在最近几年真的是异常的火爆&#xff0c;那除了普通的这种多模态学习&#xff0c;比如说视…

管桩生产管理系统 | 任务单自动计算了解一下!

库存、生产、运输科学化管理 采用自主研发的数智控制技术 对管桩生产登记、管桩配料 管桩混凝土分料生产过程进行管理 不仅能管生产 对于成品库存、管桩运输思伟都有 对应系统模块支持科学管理 系统提升管桩量产效率至少 30% 降低人工重复工作量 60% 给您 100% 畅快体验 …

【开源】基于JAVA的固始鹅块销售系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固始鹅块模块2.4 鹅块订单模块2.5 评论管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 鹅块类型表3.2.2 鹅块表3.2.3 鹅块订单表3.2.4 鹅块评论表 四、系统展示五、核心代码5.…

Ansible的切片特性与多机器选取

一、【概述】 本文介绍一下Ansible的多机器选取和切片特性&#xff0c;这个还是一个比较有用的技巧&#xff0c;可以快速选取仓库中我们需要的机器清单。 因为该特性可能与其他工具语法稍微有些不一样&#xff0c;时间长了会忘&#xff0c;值得记录一下 二、【具体说明】 1…

【Maven】005-基于 IDEA 进行 Maven 依赖管理

【Maven】005-基于 IDEA 进行 Maven 依赖管理 文章目录 【Maven】005-基于 IDEA 进行 Maven 依赖管理一、Maven 依赖管理二、GAVP 再说明三、Maven 工程依赖管理配置1、依赖配置2、版本统一声明和使用3、依赖范围说明4、Maven工程依赖下载失败错误解决&#xff08;重点&#xf…

行为驱动测试 python + behave

行为驱动&#xff0c;Behave-Driven Development&#xff0c;简称BDD。在行为驱动中运用结构化的自然语言描述场景测试&#xff0c;然后将这些结构化的自然语言转化为可执行的测试脚本或者其他形式。BDD的一种优势是&#xff0c;它建立了一种通用语言&#xff0c;而这种语言可以…

【Java SE语法篇】5.方法

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ 文章目录 0. 前言1. 方法的概念和使用1.1 什么是方法1.2 方法…

Android开发基础(二)

Android开发基础&#xff08;二&#xff09; 上篇主要描述了Android系统架构&#xff0c;代码是通过Java表示的&#xff1b; 本篇将从介绍Android组件去理解Android开发&#xff0c;代码将对Java和Kotlin进行对比。 Android组件 Android应用程序由一些零散的有联系的组件组成…

SQL Server的彻底卸载的方式

这篇文章主要介绍了SQL Server的彻底卸载的方式&#xff0c;具有很好的参考价值&#xff0c;希望对大家有所帮助。如有错误或未考虑完全的地方&#xff0c;望不吝赐教 SQL Server的彻底卸载与再次安装 可能大家已经有深刻体会&#xff0c;SQL Server的卸载十分繁琐。最让人头…

时间序列数据库选型: influxdb; netdiscover列出docker实例们的ip,docker管理工具lazydocker、scope

influxdb influxdb: 有收费版本、有开源版本 influxdb 安装、启动(docker) docker run -itd --name influxdb-dev -p 8086:8086 influxdb #influxdb的web客户端(端口8003)被去掉了 #8006是web-service端口#docker exec -it influxdb-dev bashinfluxdb 自带web界面 从后面的…

3年测试经验,用例设计竟然不知道状态迁移法?

3年测试经验&#xff0c;用例设计竟然不知道状态迁移法&#xff1f; 1、概念 状态迁移法主要关注在测试状态转移的正确性上面。对于一个有限状态机&#xff0c;通过测试验证其在给定的条件内是否能够产生需要的状态变化&#xff0c;有没有不可达的状态和非法的状态&#xff0c…

如何在 Windows 10、11 上恢复删除、未保存或覆盖的 Excel 文件?

我们中的大多数人可能都经历过其中一种情况——关闭电源时未保存 Excel 文件或误点击“不要保存”&#xff0c;不小心删除了重要的 Excel 文件&#xff0c;或覆盖了 Excel 文件而未保存原始副本。在遇到这些情况时&#xff0c;我们都会为没有采取适当的措施而感到内疚&#xff…

单片机原理及应用:定时器/计数器综合应用

本文是《单片机原理及应用》专栏中的最后一篇文章&#xff0c;笔者以编译器的安装配置——51单片机简介——LED和数码管外设——开关和按键控制功能切换——外部中断系统——定时器与计数器为知识大纲&#xff0c;介绍了C语言编程控制51单片机的入门教程。作为收尾&#xff0c;…

SQL性能分析-整理

昨日对MySQL的索引整理了一份小文档&#xff0c;对结构/分类/语法等做了一个小总结&#xff0c;具体文章可点击&#xff1a;MySQL-索引回顾&#xff0c;索引知识固然很重要&#xff0c;但引入运用到实际工作中更重要。 参考之前的文章&#xff1a;SQL优化总结以及参考百度/CSDN…

java方法的定义和使用

方法 今日目标&#xff1a; 能够知道方法的好处 能够根据两个明确分析方法的参数和返回值 能够编写方法完成授课案例&#xff0c;并在主方法中完成方法的调用 能够知道方法重载及其特点 1&#xff1a;方法的定义和使用 1.1 方法概述 方法(method)&#xff1a;就是完成特…