• IM设计与实现的系统模块的聊天记录


      到非常多开发IM系统的朋友都想实现聊天记录存储和查询这一不可或缺的功能,这里我就把自己前段时间为傲瑞通(OrayTalk)开发聊天记录模块的经验分享出来,供须要的朋友參考下。

    一.整体设计

    1.存储位置  

    从一開始我们就打算在服务端和client本地同一时候存储聊天记录。并且,在client查看聊天记录时。能够选择是从本地载入、还是从server载入。这样做的优点有两个:

    (1)从本地载入聊天记录速度很快。

    (2)当更换了登录的机器,在不论什么地方不论什么时刻都能够从server载入完整的聊天记录,记录永远不会丢失。

    2.存储方案

    (1)在服务端存储聊天记录当然使用我们主流的数据库SqlServer或Mysql等。

    (2)在client,我们開始选择的是使用序列化技术。可是。考虑到当聊天记录数据量庞大时,序列化方案就不够灵活了。并且性能也跟不上。所以,最后决定使用轻量级的数据库Sqlite。

    3.ORM框架

      DataRabbit的最新版本号添加了对Sqlite的支持,而且对不同数据库的操作API是全然一致的。所以我们使用DataRabbit写了一个小组件来完毕聊天记录的存储与查询等数据库訪问操作。

    而不管是client还是服务端的聊天记录存储相关的工作,都交给这个组件来完毕。 

    二.详细实现

    1.ChatMessageRecord类

      一条聊天记录基本上包括了下面几个内容:发送人、接收人、内容、时间等。

    而且,我们想将两人聊天及群聊天抽象成同一个模型,于是,聊天记录的Entity类ChatMessageRecord设计成例如以下模样:

        public class ChatMessageRecord
        {     
            #region AutoID
            private long autoID = 0;
            /// <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接口

      不管是client还是服务端存储与查询聊天记录。我们都使用同一个接口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;client则设置为Sqlite。 

    三.可能的Remoting的接口

      当我们从server载入聊天记录时,能够考虑使用Remoting技术来实现,假设是这样,仅仅须要在服务端把IChatRecordPersister接口暴露为Remoting服务。然后client使用这一Remoting服务进行聊天记录查询。这样一来,client在切换从本地载入和从server载入时。仅仅须要切换IChatRecordPersister为本地ChatRecordPersister对象的引用或remoting远程引用就可以。

    整个的代码实现将会很简洁一致。

      到这里,关于聊天记录模块的设计与实现就介绍得差点儿相同了,按照这种思路,大家在自己的IM系统中添加聊天记录的功能应该是非常easy的了。

    最后。上一张OrayTalkclient查询聊天记录界面的截图:

          

     就到这里了。还有疑问的朋友。请给我留言,我会及时回复的。

     

    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    Net设计模式实例之简单工厂模式(Simple Factory Pattern)
    Net设计模式实例系列文章总结
    2019年工作总结
    在Asp.Net Core中集成Kafka(中)
    如何将生产环境的服务Docker镜像拉取到本地进行调试
    记一次EFCore类型转换错误及解决方案
    Asp.Net Core中创建多DbContext并迁移到数据库
    ABP中的AutoMapper
    EFCore中的导航属性
    Asp.Net Core 调用第三方Open API查询物流数据
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4864646.html
Copyright © 2020-2023  润新知