基于web的在线聊天系统“爱讨论”设计与实现

枫之林100 2021-12-29 22:29:26

        聊天室在早期的网络环境中非常流行,网络上的用户可以实时接收和发送信息,相比于邮件的通信方式,极大地提高了时效性。可以这么说,实时聊天已经融入了我们的生活。公司开会、学校讲课、淘宝购物等等,都需要用到实时聊天。那么,如何从头实现一个实时聊天系统呢?

1、技术选择

        为了实现一个实时聊天系统,那么需要进行相应的技术方案选取。在前端方面,vue和react的选择是一个重点。vue越来越受市场的欢迎,其生态越来越完善,国内外大大小小的公司都有用vue做前端。考虑到vue上手快,轻量级,对新手友好等特点,最后选择了vue。在后端方面,则选择了Express+Node.js+MongoDB,因为其对静态服务提供的优越性能,实现轻量级的应用实为一个不错的选择。

2、设计方案

2.1、用例图

        该系统的角色只有用户。用户可以进行登录(登录前必须注册),也可以使用cookie免登录,这是登录的一个扩展用例。用户可以进行聊天,其主要用例为发送消息、接收消息、创建群聊。

 

2.2、类图

        系统中所包含的类有SystemMsg(系统消息类)、UserMsg(用户消息)、Group(群类)、User(用户类)。其中,SystemMsg和UserMsg实现了Msg接口,一个群组中,包含多个Msg信息。UserMsg类和Group类都对User具有依赖关系。

 2.3、时序图

       用户首先进行登录,登录后加入群聊,加入时,发送系统消息给聊天室”xxx加入聊天室”。用户每发送一条消息都需要经过socket服务器,socket服务器将其保存在数据库中,方便新加入群聊的用户查阅历史消息。用户在群聊中发送消息时,消息先经过socket服务器,然后socket服务器再把消息进行广播,这样所有在群聊内的用户都能收到消息。

 

3.1、前端页面的搭建

        要进行实时聊天,则需要进行用户登录(没有用户登录则无法辨别用户),首先需要搭建登录页。在搭建前端页面时,选择了蓝色基调,其页面设计大体如下。

 

 

        用户如果没有进行注册,则需要进行注册。

        注册完毕后,则可以进行登录。如果用户是第一次登录,则需要进行相应的信息完善,需要完善的有用户头像、昵称、个人简介等信息。

        完善个人信息后,便可以点击“加入爱讨论”按钮,进入群组大厅。如下图所示,目前的群组大厅有两个群,分别名为“lol"、”同学交流群“,右侧组件显示了相关的群聊信息,可以点击右边的进入讨论组来加入群聊。

        加入群聊后,便可以和群内所有成员开启聊天。下图展示了聊天室的基本情况,左侧可以看到当前在线的人员昵称,右侧则是聊天室的主体界面,用于展示信息。

 

3.2、后端服务的搭建

        该聊天室应用要使用需要进行用户登录,因此设计用户的Schema使用了全局唯一用于标识用户的uid、用户名uname、昵称name、头像header、个人介绍intro。其中,用户名是必选项。

        用户登录后,则可以进入群聊大厅,那么众多的群聊又是如何设计的呢?群聊设计了4个属性,群聊标题title、群聊描述、群聊类型type、群主用户名createuname。

     进入群聊后,如何进行消息的发送与接收呢?这个时候需要设计一个消息实体,每一条消息都有发送用户的标识from、消息来自哪个群聊msgfrom、消息目的是哪个群聊to、消息主体内容msg、消息类型msgtype、消息创建时间create_time等属性。有了这些属性,便可以实现用户进入群聊时,获取历史群聊记录,每个用户发送的群聊消息精准地被接收。

 

3.3、细节完善

3.3.1、24小时免登录

        群聊项目不必每次都登录,使用cookie机制可以让服务器保存每个用户地登录状态。这需要服务器在用户登录成功时,为其添加一个cookie,字段为_id,值为当前登录用户地uid。判断是否可以免登录地标准就是前端发送的请求中cookie中的_id是否为空,如果为空,则需要登录,如果非空,则需要登录。值得注意的是,该应用只设置了24小时免登录(maxAge设置为1000*24*60*60)。

 

3.3.2、分辨发送信息人

        一个群聊中存在许多用户,如果信息不加以分辨,则所有信息都排列在一起,难以分辨哪些信息是自己发送的,哪些信息是他人发送的。因此,前端可以设置展示信息时,对比其发送人的id和自己的id是否一致,如果一致,则把该条信息显示在右侧(表示该信息由自己发送)否则信息应显示在左侧。值得注意的时,采取这个机制,别人看到自己发送的信息永远在左侧。

 

3.3.3、加入、退出群聊提示

        这个细节在实现时,需要考虑到用户什么时候在线,用户什么时候离线。因此,在用户每次建立socket连接时,添加一条系统消息,这个系统消息仅用于表示xxx加入或退出群聊。进入群聊时机为建立socket连接,那么退出群聊呢?这里使用后端维护一个活跃列表,前端浏览器向后端每隔几秒发送一个心跳包,后端活跃列表每隔一定频率把列表中的栏目状态提升(0、1、2、3),接收到心跳包后状态置为0,一次没接收到心跳包则+1(设置2、3的目的是防止网络环境糟糕时延迟过大导致丢包)如果状态提升到3则表示socket已经断开,便把该用户从活跃列表中剔除,此时便可以向群聊中发送一条系统消息:”xxx离开群聊”。

 

4、源码剖析

4.1 用户注册与登录

       用户登录时,需要传送用户的用户名与密码,保存时,保存MD5加密后的密码。如果登录成功,则生成一个cookie,用于实现1天免登录的功能。

        用户注册时,首先判断用户名是否已经被注册,然后再判断两次密码是否一致,注意,这个两次密码是否一致的判断在前端也会进行。如果用户名没有被注册而且两次密码一致的情况下,便可以向数据库中新增一个文档,也就添加了一个用户。

 

4.2 建立socket连接

        在vue项目的main.js中,引入SocketIO、引入VueSocketIO、建立套接字连接(分别在下图中的红色框内)。

        前端组件中的Main组件中,有socket连接消息的相应动作(socket和vue的生命周期函数同级别),这些动作需要和服务端进行统一,比如sockets中的message、intoChatRoom,在后端的代码中需要使用同样的message、intoChatRoom字段标识,否则socket发送的消息将无法接收。

 

 

4.3 加入聊天室

       加入聊天室首先必须在用户已登录的状态下进行。用户在进入聊天大厅时,前端使用axios发送请求,获取当前的群聊列表groups,然后通过vue的双向绑定机制,动态渲染组件并展示。当用户选择了某个聊天室进行加入,则使用vue的路由,跳转到Main界面,即聊天主界面。值得注意的是,在跳转之前,使用cookie记住了当前的聊天室信息,这样就可以选择性接收服务端socket发出的信息(前端在接收群聊消息时,需要判断群聊消息是否为当前群聊中产生的,使用cookie可以进行消息过滤)。

        后端的socket连接监听到intoChatRoom事件后,立即执行解析,携带的参数有加入群聊的用户信息,目标群聊的群id。首先判断群聊是否存在,如果存在,则判断该用户是否已经加入群聊。如果该用户已经在群聊中,则不发送系统消息“xxx加入了群聊”,如果该用户不在群聊中,则系统发送消息”xxx加入了群聊”,并且向前端返回一个当前在群聊内的用户列表。如下图:1判断是否该用户已经加入群聊 2向群聊中发送系统消息并且返回新的群聊用户列表  3 群聊不存在时,表命用户新建了一个群聊

 

4.4 消息的发送与接收

       在前端,消息首先需要发送给服务器。因此,在用户向输入栏中输入发送的信息,然后回车发送时,应触发发送消息事件,执行向服务器发送消息的函数。

 

        前端向服务器发送消息后,后端进行消息的处理,这个消息需要保存在数据库中,避免后续用户加入群聊时消息丢失。

        服务端收到消息后,立即在socket中进行广播,所有与服务器建立连接的用户都会接收到消息,前端根据聊天室的id进行过滤,便能显示对应的群聊中的消息。此处设置了一个定时器,前端接收到消息后,延迟0.2S把消息加载到消息列表底部。

项目源码:https://gitee.com/ybf521/web-chat-room.git 

作者:NP504

...全文
426 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

566

社区成员

发帖
与我相关
我的任务
社区描述
软件工程教学新范式,强化专项技能训练+基于项目的学习PBL。Git仓库:https://gitee.com/mengning997/se
软件工程 高校
社区管理员
  • 码农孟宁
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧