IM系统中聊天记录模块的设计与实现
看到很多开发IM系统的朋友都想实现聊天记录存储和查询这一不可或缺的功能,这里我就把自己前段时间为傲瑞通(OrayTalk)开发聊天记录模块的经验分享出来,供需要的朋友参考下。
一.总体设计
1.存储位置
从一开始我们就打算在服务端和客户端本地同时存储聊天记录,而且,在客户端查看聊天记录时,可以选择是从本地加载、还是从服务器加载。这样做的好处有两个:
(1)从本地加载聊天记录速度非常快。
(2)当更换了登录的机器,在任何地方任何时刻都可以从服务器加载完整的聊天记录,记录永远不会丢失。
2.存储方案
(1)在服务端存储聊天记录当然使用我们主流的数据库SqlServer或Mysql等。
(2)在客户端,我们开始选择的是使用序列化技术,但是,考虑到当聊天记录数据量庞大时,序列化方案就不够灵活了,而且性能也跟不上。所以,最后决定使用轻量级的数据库Sqlite。
3.ORM框架
DataRabbit的最新版本增加了对Sqlite的支持,并且对不同数据库的操作API是完全一致的,所以我们使用DataRabbit写了一个小组件来完成聊天记录的存储与查询等数据库访问操作。而无论是客户端还是服务端的聊天记录存储相关的工作,都交给这个组件来完成。
二.具体实现
1.ChatMessageRecord类
一条聊天记录基本上包含了以下几个内容:发送人、接收人、内容、时间等。并且,我们想将两人聊天及群聊天抽象成同一个模型,于是,聊天记录的Entity类ChatMessageRecord设计成如下模样:
public class ChatMessageRecord
{
#region AutoID
private long autoID = ;
/// <summary>
/// 自增ID,编号。
/// </summary>
public long AutoID
{
get { return autoID; }
set { autoID = value; }
}
#endregion #region SpeakerID
private string speakerID = "";
/// <summary>
/// 发言人的ID。
/// </summary>
public string SpeakerID
{
get { return speakerID; }
set { speakerID = value; }
}
#endregion #region AudienceID
private string audienceID = "";
/// <summary>
/// 听众ID,可以为GroupID。
/// </summary>
public string AudienceID
{
get { return audienceID; }
set { audienceID = value; }
}
#endregion #region OccureTime
private DateTime occureTime = DateTime.Now;
/// <summary>
/// 聊天记录发生的时间。
/// </summary>
public DateTime OccureTime
{
get { return occureTime; }
set { occureTime = value; }
}
#endregion #region ContentRtf
private string contentRtf = "";
/// <summary>
/// 聊天的内容。
/// </summary>
public string ContentRtf
{
get { return contentRtf; }
set { contentRtf = value; }
}
#endregion #region IsGroupChat
private bool isGroupChat = false;
/// <summary>
/// 是否为群聊记录。
/// </summary>
public bool IsGroupChat
{
get { return isGroupChat; }
set { isGroupChat = value; }
}
#endregion
}
在ChatMessageRecord的定义中,聊天内容字段被设计为string类型,这是因为在OrayTalk中,聊天内容是富文本RTF格式的。如果需要,可以更改为byte[]类型,这样通过自定义的序列化操作就可以承载更复杂的聊天格式。
最后一个字段IsGroupChat表明当前记录是否为群聊记录,如果是群聊记录,那么,AudienceID就不是好友的ID了,而是目标群组的ID。
最后请注意:ChatMessageRecord实体与数据库中的ChatMessageRecord表是完全映射的关系,这才使得DataRabbit的ORM数据访问成为可能。
2.ChatRecordPage类
当我们请求聊天记录时,由于记录数量可能非常庞大,所以,采用分页是不可避免的。我们用ChatRecordPage来封装查询返回的一页聊天记录:
根据ChatRecordPage中的TotalCount字段,查询者可以知道符合条件的记录数是多少,如此,就可以知道总共有多少页。
3.IChatRecordPersister接口
无论是客户端还是服务端存储与查询聊天记录,我们都使用同一个接口IChatRecordPersister来进行抽象:
public interface IChatRecordPersister
{
/// <summary>
/// 插入一条聊天记录(包括群聊天记录)。
/// </summary>
void InsertChatMessageRecord(ChatMessageRecord record); /// <summary>
/// 获取一页与好友的聊天记录。
/// </summary>
/// <param name="timeScope">日期范围</param>
/// <param name="myID">自己的UserID</param>
/// <param name="friendID">好友的ID</param>
/// <param name="pageSize">页大小</param>
/// <param name="pageIndex">页索引</param>
/// <returns>聊天记录页</returns>
ChatRecordPage GetChatRecordPage(DateTimeScope timeScope, string myID, string friendID, int pageSize, int pageIndex); /// <summary>
/// 获取一页群聊天记录。
/// </summary>
/// <param name="timeScope">日期范围</param>
/// <param name="groupID">群ID</param>
/// <param name="pageSize">页大小</param>
/// <param name="pageIndex">页索引</param>
/// <returns>聊天记录页</returns>
ChatRecordPage GetGroupChatRecordPage(DateTimeScope timeScope, string groupID, int pageSize, int pageIndex);
}
(1)插入游戏记录时,与好友聊天记录以及群聊天记录使用同一个InsertChatMessageRecord方法即可,只是在构造ChatMessageRecord对象时,字段的赋值有所区别。
(2)使用DataRabbit实现该接口时(如ChatRecordPersister类),通过属性DataBaseType来控制访问的是否为Sqlite数据库。然后在服务端使用ChatRecordPersister存取聊天记录时,就将DataBaseType设置为SqlServer;客户端则设置为Sqlite。
三.可能的Remoting的接口
当我们从服务器加载聊天记录时,可以考虑使用Remoting技术来实现,如果是这样,只需要在服务端把IChatRecordPersister接口暴露为Remoting服务,然后客户端使用这一Remoting服务进行聊天记录查询。这样一来,客户端在切换从本地加载和从服务器加载时,只需要切换IChatRecordPersister为本地ChatRecordPersister对象的引用或remoting远程引用即可。整个的代码实现将会非常简洁一致。
到这里,关于聊天记录模块的设计与实现就介绍得差不多了,依照这样的思路,大家在自己的IM系统中增加聊天记录的功能应该是很简单的了。最后,上一张OrayTalk客户端查询聊天记录界面的截图:
就到这里了,还有疑问的朋友,请给我留言,我会及时回复的。
IM系统中聊天记录模块的设计与实现的更多相关文章
- MEF插件系统中通信机制的设计和实现
MEF插件系统中通信机制的设计和实现 1.背景 一般的WinForm中通过C#自带的Event机制便能很好的实现事件的注册和分发,但是,在插件系统中却不能这么简单的直接用已有的类来完成.一个插件本不包 ...
- Java生鲜电商平台-生鲜系统中微服务架构设计与分析实战
Java生鲜电商平台-生鲜系统中微服务架构设计与分析实战 说明: Java生鲜系统中微服务的拆分应该如何架构设计与分析呢?以下是我的实战中的设计与经验分析. 目录 1. 微服务简介2. 当前现状3. ...
- (3)MEF插件系统中通信机制的设计和实现
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 一般的WinForm中通过C#自带的Event机制便能很好的实 ...
- [Hyperledger] Fabric系统中 peer模块的 gossip服务详解
最近一直在看fabric系统中的核心模块之一——peer模块.在看peer的配置文件core.yaml的信息时,对其中的gossip配置选项很感兴趣.看了一上午,还是不能明白这个选项到底什么意思呢?表 ...
- MySQL-THINKPHP 商城系统一 商品模块的设计
在此之前,先了解下关于SPU及SKU的知识 SPU是商品信息聚合的最小单位,是一组可复用.易检索的标准化信息的集合,该集合描述了一个产品的特性.通俗点讲,属性值.特性相同的商品就可以称为一个SPU. ...
- 跟我一起学extjs5(13--运行菜单命令在tabPanel中显示模块)
跟我一起学extjs5(13--运行菜单命令在tabPanel中显示模块) 上面设计好了一个模块的主界面,以下通过菜单命令的运行来把这个模块增加到主界面其中. 在MainModule. ...
- 电商系统中的商品模型的分析与设计—续
前言 在<电商系统中的商品模型的分析与设计>中,对电商系统商品模型有一个粗浅的描述,后来有博友对货品和商品的区别以及属性有一些疑问.我也对此做一些研究,再次简单的对商品模型做一个介 ...
- 系统中异常公共处理模块 in spring boot
最近在用spring boot 做微服务,所以对于异常信息的 [友好展示]有要求,我设计了两点: 一. 在业务逻辑代码中,异常的抛出 我做了限定,一般只会是三种: 1. OmcException // ...
- Java开源生鲜电商平台-财务系统模块的设计与架构(源码可下载)
Java开源生鲜电商平台-财务系统模块的设计与架构(源码可下载) 前言:任何一个平台也好,系统也好,挣钱养活团队这个是无可厚非的,那么对于一个生鲜B2B平台盈利模式( 查看:http://www.cn ...
随机推荐
- mysql将一张表中多条记录按联系整合成一条
现有表如下:id time is_login 3 2012-07-03 11:20:20 13 2012-07-03 11:25:20 04 2012-07-03 12:30:20 14 2012-0 ...
- PMI列子1
遍历得到PMI中,是注释类型的,你可以参考一下.int num_text, thetype, thesubtype;tag_t draft_aid_tag = NULL_TAG;UF_UI_open ...
- Laravel 学习笔记 —— 神奇的服务容器 [转]
容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器.一个容器能够装什么,全部取决于你对该容器的定义.当然,有这样一种容器,它存放的不是文本.数值,而是对象.对象的描述(类.接口)或 ...
- react-router配合webpack实现按需加载
很久没有写博客了.一直感觉没有什么要写的,但是这个东西确实有必要的.使用react开发,不可能一直打包到一个文件.小项目肯定没有问题,但是变大一旦到几兆,这个问题就很严重.现在又Commonjs,AM ...
- c# 调用 matlab
如果本机没有安装Matlab 需要安装一个叫 MCRInstaller 的东西 运行环境 如果安装后 需要把D:\MATLAB\R2013a\bin\win64; 写入环境变量 (路径根据实际情况改 ...
- codeIgniter怎么实现对input type=text对话框blur事件的监听以及传值?
如题,这个问题怎么解决? 用JS和前端框架习惯了,现在学后端框架,感觉各种坑...
- 使用zabbix邮件发送报表
简介 首先我们来看下图片的url (右击screens中随便一张图片,选复制图片地址) http://zabbix.xxx.com/chart2.php?graphid=524&screeni ...
- Web系统大规模并发——电商秒杀与抢购 【转】
电商的秒杀和抢购,对我们来说,都不是一个陌生的东西.然而,从技术的角度来说,这对于Web系统是一个巨大的考验.当一个Web系统,在一秒钟内收到数以万计甚至更多请求时,系统的优化和稳定至关重要.这次我们 ...
- 图片浏览(CATransition)转场动画
Main.storyboard ViewController.m // // ViewController.m // 8A04.图片浏览(转场动画) // // Created by huan ...
- 微信小程序 wx.uploadFile在安卓手机上面the same task is working问题解决
微信小程序上传图片的时候,如果是多图片上传,一般都是直接用一个循环进行wx.uploadFile 这个在电脑上面测试与苹果手机上面都不会有什么问题 但当用安卓测试的时候,你会发现小程序会提示一个the ...