【IM开发教程】集成环信IM时如何下载历史消息记录并解析内容

发布于:2025-02-13 ⋅ 阅读:(9) ⋅ 点赞:(0)

在集成环信IM功能时,会涉及到需要备份消息到本地服务器这样的需求,此文章讲述了如何下载历史消息文件并逐条解析

1.环信提供了下载历史消息的接口,此接口按照1小时为单位,也就是每次下载历史消息记录,将会直接下载一个小时内的所有消息并存储为单个文件
2.直接下载下来的文件为压缩成gz格式的压缩文件

此文章展示了2种语言处理方式:JAVA,Python

一.java版本

1.需要集成1项:
fastjson

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.53</version>
</dependency>

2.代码如下


package org.jj.util;

import com.alibaba.fastjson.JSONObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.GZIPInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class MessageLogHelper {

    /**
     * restapi : ❌需要根据实际appkey确定是哪一个地址
     * appkey : ❌请填入你的appkey
     * app_token : ❌请填入你的APP TOKEN
     */

    static String restapi = "a1.easemob.com";
    static String appkey = "easemob-demo#support";
    static String orgName = appkey.split("#")[0];
    static String appName = appkey.split("#")[1];
    static String baseurl = "https://" + restapi + "/" + orgName + "/" + appName;
    static String app_token = "❎这里需要填入你的APP TOKEN";

    public static String fetchMessageLogFileURL(String time) {
        String urlString = baseurl + "/chatmessages/" + time;
        try {
            URL url = new URL(urlString); // 替换为你想访问的URL
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Authorization", "bearer " + app_token);
            // 检查响应码,例如 200 表示成功
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }

                in.close();
                // 打印结果
                System.out.println(response);
                JSONObject jo = JSONObject.parseObject(response.toString());
                return jo.getJSONArray("data").getJSONObject(0).getString("url");
            } else {
                System.out.println("GET request not worked");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }



    /**
     *
     * @Title: getInputStream
     * @Description: TODO 获取网络连接的InputStream
     * @return
     * @throws IOException
     * @CreateDate:2021 Nov 2 20:56:56
     */
    private static InputStream getInputStream(String urlString) throws IOException {
        InputStream inputStream=null;
        HttpURLConnection httpurlconn=null;
        try {
            URL url=new URL(urlString);
            if(url!=null) {
                httpurlconn=(HttpURLConnection) url.openConnection();
                //设置连接超时时间
                httpurlconn.setConnectTimeout(3000);
                //表示使用GET方式请求
                httpurlconn.setRequestMethod("GET");
                httpurlconn.setRequestProperty("Authorization", "authorization");
                int responsecode=httpurlconn.getResponseCode();
                if(responsecode==200) {
                    //从服务返回一个输入流
                    System.out.println("成功");
                    inputStream=httpurlconn.getInputStream();
                }else {
                    System.out.println("失败" + responsecode);
                }
            }
        }catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return inputStream;
    }
    /**
     * 将InputStream写入本地文件
     * @param destination 写入本地目录
     * @param input 输入流
     * @throws IOException
     */
    private static void writeToLocal(String destination, InputStream input)
            throws IOException {
        byte[] bytes = new byte[1024];
        FileOutputStream fileOut = new FileOutputStream(destination);

//       int index = 0;
        int length = 0;
        while ((length = input.read(bytes)) != -1) {
            fileOut.write(bytes, 0, length);
            fileOut.flush();
//         index ++;
        }
        fileOut.close();
        input.close();
    }

    //下载文件到本地
    public static void downloadFile(String urlString,String filePath) {
        InputStream inputStream = null;
        try {
            inputStream = getInputStream(urlString);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            writeToLocal(filePath,inputStream);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println();
    }

    //解压gzip文件
    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;
    }

    public static void test_parseMessages(String filePath) throws IOException {

        FileInputStream inputStream = new FileInputStream(filePath);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String str = null;
        long i = 0;
        while((str = bufferedReader.readLine()) != null){
            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
        inputStream.close();
        bufferedReader.close();
    }
    
    //运行测试
    public static void main(String[] args) {
        String time = "2024123011";
        String url = fetchMessageLogFileURL("2024123011");
        System.out.println(url);
        String g_path = "/Users/yj/Documents/讲解/消息记录导出并解析/java/" + time + ".gz";
        String f_path = "/Users/yj/Documents/讲解/消息记录导出并解析/java/" + time + ".txt";
        downloadFile(url, g_path);
        unGzipFile(g_path, f_path);
        try {
            test_parseMessages(f_path);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

二.python版本

1.需要集成1项

pip install requests
import json
import requests
import gzip

# ❌需要根据实际appkey确定是哪一个地址
restapi = 'a1.easemob.com'
# ❌请填入你的appkey
appkey = 'easemob-demo#support'
org = appkey.split('#')[0]
app = appkey.split('#')[1]
baseurl = f'https://{restapi}/{org}/{app}'
# ❌请填入你的APP TOKEN
app_token = '<⚠️APP TOKEN>'

#  示例 如果需要获取2024年12月30日10时到11时的消息记录,则填入: '2024123010'
def getMessageLogFileURL(time):
    url = f'{baseurl}/chatmessages/{time}'
    headers = {
        'Authorization': f'Bearer {app_token}',
        'Content-Type': 'application/json',
    }
    response = requests.get(url, headers=headers)
    json = response.json()
    print("response = " , json)
    url = json['data'][0]['url']
    print("url = " , url)
    return url

def downloadFile(url, filePath):
    response = requests.get(url, stream=True)  # 发送GET请求,stream参数指定以流的方式下载文件
    if response.status_code == 200:  # 检查响应状态码
        with open(filePath, 'wb') as f:  # 打开本地文件进行写入操作
            for chunk in response.iter_content(chunk_size=8192):  # 分块读取文件内容,每次读取1KB
                if chunk:  # 检查是否有数据块可读
                    f.write(chunk)  # 将数据块写入本地文件
                    f.flush()  # 刷新缓冲区,确保数据写入磁盘
        print('文件下载完成!')
    else:
        print('下载失败,状态码:', response.status_code)

def unzipFile(zipPath,unzipPath):
    g_file = gzip.GzipFile(zipPath)
    # 创建gzip对象
    with open(unzipPath, "wb+") as content:
        content.write(g_file.read())
    g_file.close()

def parseMessages(filePath):

    with open(filePath, 'r') as file:
        for line in file:
            # 处理每一行,例如打印
            # print(line.strip())  # strip()去除行尾换行符
            jsonObj = json.loads(line)
            print('================================')
            print(f"消息id [{jsonObj['msg_id']}]")
            print(f"消息from [{jsonObj['from']}]")
            print(f"消息to [{jsonObj['to']}]")
            print(f"消息timestamp [{jsonObj['timestamp']}]")
            print(f"消息chat_type [{jsonObj['chat_type']}]")
            print(f"消息content_type [{jsonObj['content_type']}]")
            print(f"消息内容payload [{jsonObj['payload']}]")


# ❌这里获取的是2024年12月30日11点的 消息记录文件
time = '2024123011'
fileURL = getMessageLogFileURL(time)
directory = '/Users/yj/Documents/讲解/消息记录导出并解析/python'
gzipPath = f'{directory}/{time}.gz'
filePath = f'{directory}/{time}.txt'
# 下载
downloadFile(fileURL, gzipPath)
# 解压
unzipFile(gzipPath,filePath)
# 解析
parseMessages(filePath)

三、关于 restapi appkey app_token 获取方式:

appkey

格式说明:参考:https://doc.easemob.com/document/server-side/enable_and_configure_IM.html#获取环信即时通讯-im-的信息

一 打开页面

https://console.easemob.com/app/applicationOverview/detail

在这里插入图片描述

根据此页面,我们可获取到三个字段

appkey、Client ID、ClientSecret

appkey是由 orgname和appname构成,用符号#衔接

“Client ID” 和 “ClientSecret” 仅在获取apptoken时会用到

二 打开页面

https://console.easemob.com/app/im-service/detail

在这里插入图片描述
可获得字段 Rest Api
a1.easemob.com
最终字段收集完成

获取apptoken

文档地址:
https://doc.easemob.com/document/server-side/easemob_app_token.html

# 数据如下
# 1. appkey
#    1168171101115760#dabaojian

# 2. Client ID
#    YXA6uUquUL6lEeeIi-vMCP7JJg

# 3. ClientSecret 
#    YXA6qb6yfKTMOhCdZibj9Q5Z9YNfzoA
# 4. restApi
#    a1.easemob.com
# 下面这段代码为shell脚本代码,可直接复制并放在命令行(终端)中执行,可得到apptoken

curl -X POST -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{
   "grant_type": "client_credentials",
   "client_id": "YXA6uUquUL6lEeeIi-vMCP7JJg",
   "client_secret": "YXA6qb6yfKTMOhCdZibj9Q5Z9YNfzoA",
   "ttl": 1024000
 }' 'https://a1.easemob.com/1168171101115760/dabaojian/token'


# ❌❌❌ 注意,以上所使用数据是一个测试appkey的数据,请使用自己的appkey和相关数据

结果如下
在这里插入图片描述

postman测试

在这里插入图片描述

apptoken使用示例如下:

示例所用接口:
获取单个用户详情,文档链接: https://doc.easemob.com/document/server-side/account_system.html#获取单个用户的详情
在这里插入图片描述

细节描述:
header中加入:

 "Authorization" : "Bearer YWMtNYtW0saVEe-nbnHeHt5XS1OaBn8hITJOq1PUZikodyC5Sq5QvqUR54iL68wI_skmAgMAAAGUFwSOzAAPoADMuiOI4HZ6xjlpgz7DOhyf9dRtSB8bqxy9_ZXbc4xb_Q"

这里需要格外注意的点:
1 key为 Authorization
2 value 有个前缀 Bearer,并且和 <access_token> 之间用一个空格衔接

相关文档: