在线聊天室架构设计 在线聊天管理系统_在线聊天室架构设计

(一)

1 基于SpringBoot的websocket建立,建立websocket连接功能 创建websocket服务端类,添加一个自定义的解码器和一个编码器,用于解析java对象和前端传来的字符串,以及一个自定义的websocket配置类,通过这个配置类对websocket服务进行发布,创建一个控制器类,用于模拟服务器的响应,发送消息通知客户端.。
2 包和类的划分 在SpringBoot脚手架基础上做的包和类的划分。
3 前端在现有基础上对用户注册登录功能加以限制和完善 客户端使用md5对用户名、密码进行加密。一定程度上提高了了系统的安全性。
4 本地缓存localStorage的创建与加载 把实时聊天产生的庞大数据放在本地缓存中,来减小冗余的数据对系统的负载,并且能够在用户登录时及时显示出来。
5 数据库的设计 采用MySQL和navicat数据库,使用了DAO模式。表设计符合第三范式。

四、本人负责功能详解

  1. *基于SpringBoot的websocket建立,建立websocket连接功能
    在Tomcat 7以上的版本中含有一个自带的关于websocket的包,我们在建立连接时直接继承过来;或者使用Springboot内部自己集成的websocket类。
    使用ServerEndpoint这个注解可以使websocket类被SpringBoot加载进去。

在配置类config目录下的WebSocket.java文件中,有WebSocketConfig类,其中的注解Configuration即把此类放到一个配置环境变量的类中,因此在注解ServerEndpoint加载时就会生成一个新的Bean。
此时就可以等待接收前端发出的请求,来建立连接。

一旦建立websocket连接成功之后,执行onOpen方法,包括检查该用户是否有未读消息、给所有好友发送上线消息的功能。
然后依次编写连接关闭、当收到信息、发生错误、发送消息、发送单人一对一聊天消息、发送群聊天信息等功能。

当登录成功进入聊天系统主界面时,系统执行
在目录src/main/resources/static/home/js/websocket.js下
建立websocket连接的方法buildWebSocket(userid),参数为userid,用来区分是哪一个用户建立的连接(因为每建立一个websocket连接就会new一个对象,所以需要传递参数来区分)。
然后向服务器后台发送请求,用来建立websocket连接:
ws = new WebSocket(“ws://”+window.location.host+“/webSocket/”+userid);
括号中内容为此次请求的地址,与weboscket.java中注解的地址一致

将console和在线聊天系统页面都刷新一下,可以看到建立了一个websocket连接,后台则调用了onOpen方法,输出显示(“成功建立连接,用户ID = 【” + userid + “】,当前在线用户数:” + onlineCount)这句话。

  1. *前端在现有基础上对用户注册登录功能加以限制和完善
    使用专门的接口8081来实现系统

登录与注册界面相应的网址与eclipse中方法存在的位置相对应:
以登录界面和注册界面为例:
① 登录界面:网址http://localhost:8081/home/index/login
对应方法的位置:controller/home/HomeIndexController

② 注册界面:网址http://localhost:8081/home/index/register
对应方法位置:controller/home/HomeIndexController

所有页面相关代码都在模板templates 下
(src/main/resources/templates)
所以在此目录下可以找到上述index和register对应网页的代码。

点击注册按钮之后,执行“提交注册表单”程序,然后是“提交登录表单”,登录成功后,表示用户已存在。

这里用自定义注解包来判断用在注册账号时是否符合要求。
比如,注册时检查用户名是否重复、要求该字段是必填字段、String类型则检查其长度、数字类型则规定是否检查最大最小值;以及登录时检查密码是否正确,检查状态是否正常,若登陆成功则修改状态为在线等功能的实现等。
3. *数据库的设计
共设计了13张表,每张表都与entity中的一个实体类相对应。

(1) account

(2) account_group

(3) account_group_member

(4) database_bak

(5) friend

(6) friend_request

(7) menu

(8) msg_log

(9) operater_log

(10) order_auth

(11) role

(12) role_authorities

(13) uesr

  1. 包和类的划分

(1) annotion为自定义注解包:用来验证自定义实体,可以加到实体类(例如Role类)上去
(2) bean类:基于entity的实体,entity实体直接对应数据库中的一张表,而bean实体直接展现给用户,相当于把entity实体做了一个向上的转义(修改)。用于修改一些敏感信息,比如手机号在展示给用户时中间4位数字要改成*号,此时就需要把数据库中的信息转义后显示给用户
①CodeMsg:错误码统一处理类,所有的错误码统一定义在这里,包括通用错误码定义(例如处理成功消息码和非法数据错误码)和后台管理错误码(例如用户管理类错误、登录类错误等)。
②MsgVo:消息后台管理展示类,做实体的转义。内容包括发送者、接收者和相关消息记录等。
③PageBean:分页信息封装类。
④Result:提交统一返回结果类。
⑤WebSocketMsg:封装前段消息体。
(3)config:做配置的类
①admin:后台的配置类,用来配置拦截器,拦截除标明的类之外所有的请求,即把所有请求拦截,再把相应请求(constant中)放掉
②home:前台的配置类,用来配置拦截器。
③AppConfig:整个项目一启动时的配置文件,即刚启动时就执行其中的方法。
④SiteConfig:整个网站的配置文件,通过@Value注解方法直接把配置文件里的site.properties值加载到此类中。
⑤WebSocketConfig:做WebSocket的配置,在SpringBoot中做WebSocket需要做这样的配置。其中@Configuration:SpringBoot启动时会把Bean类加载进去。
(4)constant:存放常量
①RuntimeConstant:放置系统运行时的常量。
②SessionConstant:关于session的所有常量统一存放类。
(5)controller:控制器。MVC(Model-View-Controller模型-视图-控制器)模式:用户的请求直接进入controller里,controller再把请求根据自己的功能判断交给哪一个模型去处理,处理完再返回到相应的视图上。
①admin:后台管理控制器
i. AccountController:后台用户管理控制器
ii. DatabaseBakController:数据库备份管理控制器
iii. GroupController:后台群组管理控制器
iv. MenuController:后台菜单管理控制器
v. MsgController:后台消息管理控制器
vi. RoleController:后台角色管理控制器
vii. SystemController:系统控制器
viii. UserController:后台用户管理控制器
②common:前后台管理共用控制器
i. CpachaController:系统验证码公用控制器
ii. DownloadController:下载控制器统一管理类
iii. PhotoController:图片统一查看控制器
iv. UploadController:公用的上传类
③home:前台用户控制器:主界面、登陆注册等
i. HomeAccountController:前台首页控制器(用户中心、好友列表、查看群信息、会话列表页面、批量发送好友验证等)
ii. HomeIndexController:前台首页控制器(登录页面、退出登录、注册页面、提交注册表单、登录表单提交)
(6)dao:直接作用于数据库的类
(7)entity:其中每一个实体对应数据库中的一个表,表名为Table(name=’’xxx’’),可以通过这个名字找到打开数据中的表。
①admin:后端实体类。
i. DatabaseBak:数据库备份记录实体类,存放备份的文件名、文件路径。
ii. Menu:后台菜单实体类,包含菜单名称、菜单父分类、菜单URL、菜单图标icon、菜单顺序等)
iii. OperaterLog:后台操作日志记录表,包含操作者和操作内容。
iv. OrderAuth:订单验证日志记录表,包含手机号、记录编号等。
v. Role:后台角色实体类,包含角色状态(是否被冻结)、角色名称、角色对应权限列表、角色备注等。
vi. User:后台用户实体类,包含用户所属角色、用户名、登录密码、用户状态、用户头像、性别、手机号、邮箱等。
②common:前后端共用实体类。
i. Account:前台用户实体类
ii. AccountGroup:用户群实体类,包含群主、群名称、群头像、群公告、群最大最小人数等。
iii. AccountGroupMember:群成员实体类,包含所属群、用户、消息状态、群昵称等。
iv. BaseEntity:基础实体公共属性,包含唯一ID、创建时间、更新时间。
v. Friend:好友实体类。
vi. MsgContent:消息内容实体类,包含发送者ID、接收者ID、聊天类型、消息类型、消息内容、消息附加字段、附件地址、附件大小等。
vii. MsgLog:消息记录实体类。
(8)interceptor:拦截器
①admin:后台拦截器,有两个。
i. 权限统一管理拦截器:做入口处的配置,项目启动时要拦截哪些请求,拦截时要执行哪些类
ii. 登录拦截器:用于查询是否登录,未登录时有些操作无法进行(必须在登录之后才能进行的操作在constant常量中进行定义)
②home:前段拦截器。
i. HomeGlobalInterceptor:前台全局拦截器。
ii. HomeLoginInterceptor:前台登录拦截器,用户还未登录或者会话页面失效,重定向到登录页面。
(9)listener:绘画监听事件,用户第一次打开系统和退出系统时创建一个session。session一般用来统计当前在线人数。
(10)schedule:定时执行任务。
(11) server.home:用于发送和接收消息的类WebSocket。
(12)service:基于controller和dao作用的类,是一个中间态。controller根据自己的业务逻辑把任务派给service,再由service调用dao进行具体的数据库的操作。
①admin:后台管理控制器
i. DatabaseBak:分页查找数据库备份记录、添加或修改数据库备份记录、通过ID查询删除等、备份还原数据库等。
ii. Menu:后台菜单操作,包含菜单添加/编辑、获取所有的菜单列表、根据id查询菜单、删除一条记录。
iii. OperaterLog:后台操作类,数据库操作service,包含添加/修改操作日志,当id不为空时,修改,id为空时自动新增一条记录、获取指定条数的操作日志列表、根据id查询单条数据、返回所有的记录等。
iv. OrderAuth:后台操作类 数据库操作service,获取一条记录。
v. Role:后台角色操作service,角色添加/编辑、获取所有的角色列表、分页按角色名称搜索角色列表、分页按角色名称搜索角色列表、删除一条记录。
vi. User:用户管理service,根据用户id查询、按照用户名查找用户、用户添加/编辑操作、分页查询用户列表、判断用户名是否存在,添加和编辑均可判断、按照用户id删除、返回用户总数。
② common:前后台管理共用控制器
i. AccountGroupMember:新增或编辑群、获取群成员、获取某个用户参与的所有群、根据群和用户id查询等。
ii. AccountGroupService:获取我创建的所有群列表、分页查询群组列表、根据ID查询、删除、返回总数等。
iii. AccountService:用户管理service,根据用户id查询、按照用户名查找用户、用户添加/编辑操作等。
iv. FriendService:好友service,更新或新增、根据ID查找删除、获取我的好友列表等。
v. MsgContentService:消息内容管理service,根据id查询、添加/编辑操作、获取消息列表等。
vi. MsgLogService:消息记录管理service,获取指定用户的指定状态消息,根据消息内容查询关联记录,返回总数。

③ home:前台用户控制器

(13)util:实用工具类,把共用的方法进行封装在此类中,使用时可以直接调用这些方法,实现了“一处定义,处处调用”的功能,可以使代码结构更加紧凑,内容更加精炼。
①CpachaUtil:验证码生成器
②DESUtil:加密工具类
③ HttpUtil:https请求
④ MenuUtil:菜单工具类
⑤ SessionUtil:session统一操作工具类
⑥ StringUtil:项目通用工具类
⑦ValidateEntityUtil:验证实体工具类
(14)App.java:项目入口启动文件

  1. 本地缓存localStorage的创建与加载
    首先阐述设计本地缓存的原因:对于实时聊天,不管是几个字、一个图片、一个文件,都算做一条消息,因此会产生庞大的聊天数据,如果用数据库实时加载,对系统的负载太大,且运行速度慢,所以我选择将实时聊天记录存放在本地缓存中,用户未登录时就暂存在服务器中,登录时显示给用户;在线时的即时聊天记录也保存在本地缓存和服务器中。
    本地缓存使用localstorage,方便存放一些格式化的对象,并且存储空间较大。

在目录src/main/resources/static/home/js/chat.js下
用户上线后,弹出提示“会话列表从本地加载成功”
调用方法getALLChatTapInfoFromLocal()用于从本地中获取所有会话信息:从localstorage中获取变量,getItem表示名字(其中user_id用来区分在一个浏览器中登录的多个用户的属于不同用户的消息),把从localstorage中获得的变量赋值给allChatTapInfo,如果值为空,则说明此用户为新注册的用户,没有聊天记录,则赋值一个空对象;如果不为空,则说明此用户不是新用户,则调用JSON.parse()方法把变量转换为JSON对象,再返回消息。

把消息存入本地缓存:
和加载会话消息列表时一样,首先将变量从localstorage中加载出来,然后调用update方法,往JSON对象中加一个键值进去,再调用setItem方法存入localstorage中,就可以把新产生的聊天记录和原来的记录一并存入本地缓存中。

这样,就完成了本地缓存localStorage的创建与加载功能的实现。

(二)

沈阳化工大学

Java语言实践
课程设计

专 业 信息与计算科学 班 级 信息1901
姓 名 高敏 学 号 1916030124
成 绩 指导老师 李玉红

2021年6 月 13 日
一、项目简介
功能描述:能够实现私聊,群聊,编辑个人信息,编辑群信息,发送文字、图片、文件消息功能的在线聊天系统

个人负责任务:个人负责的内容是基于SpringBoot的websocket建立、建立websocket连接功能,前端在现有基础上对用户注册登录功能加以限制和完善,本地缓存localStorage的创建与加载,以及数据库表的设计。

团队博客链接:

个人博客链接:

二、功能架构图
个人负责的内容是基于SpringBoot的websocket建立、建立websocket连接功能,前端在现有基础上对用户注册登录功能加以限制和完善,本地缓存localStorage的创建与加载,以及数据库表的设计。

三、个人任务简述
序号 完成功能与任务 描述
1 基于SpringBoot的websocket建立,建立websocket连接功能 创建websocket服务端类,添加一个自定义的解码器和一个编码器,用于解析java对象和前端传来的字符串,以及一个自定义的websocket配置类,通过这个配置类对websocket服务进行发布,创建一个控制器类,用于模拟服务器的响应,发送消息通知客户端.。
2 包和类的划分 在SpringBoot脚手架基础上做的包和类的划分。
3 前端在现有基础上对用户注册登录功能加以限制和完善 客户端使用md5对用户名、密码进行加密。一定程度上提高了了系统的安全性。
4 本地缓存localStorage的创建与加载 把实时聊天产生的庞大数据放在本地缓存中,来减小冗余的数据对系统的负载,并且能够在用户登录时及时显示出来。
5 数据库的设计 采用MySQL和navicat数据库,使用了DAO模式。表设计符合第三范式。

四、本人负责功能详解

  1. *基于SpringBoot的websocket建立,建立websocket连接功能
    在Tomcat 7以上的版本中含有一个自带的关于websocket的包,我们在建立连接时直接继承过来;或者使用Springboot内部自己集成的websocket类。
    使用ServerEndpoint这个注解可以使websocket类被SpringBoot加载进去。

在配置类config目录下的WebSocket.java文件中,有WebSocketConfig类,其中的注解Configuration即把此类放到一个配置环境变量的类中,因此在注解ServerEndpoint加载时就会生成一个新的Bean。
此时就可以等待接收前端发出的请求,来建立连接。

一旦建立websocket连接成功之后,执行onOpen方法,包括检查该用户是否有未读消息、给所有好友发送上线消息的功能。
然后依次编写连接关闭、当收到信息、发生错误、发送消息、发送单人一对一聊天消息、发送群聊天信息等功能。

当登录成功进入聊天系统主界面时,系统执行
在目录src/main/resources/static/home/js/websocket.js下
建立websocket连接的方法buildWebSocket(userid),参数为userid,用来区分是哪一个用户建立的连接(因为每建立一个websocket连接就会new一个对象,所以需要传递参数来区分)。
然后向服务器后台发送请求,用来建立websocket连接:
ws = new WebSocket(“ws://”+window.location.host+“/webSocket/”+userid);
括号中内容为此次请求的地址,与weboscket.java中注解的地址一致

将console和在线聊天系统页面都刷新一下,可以看到建立了一个websocket连接,后台则调用了onOpen方法,输出显示(“成功建立连接,用户ID = 【” + userid + “】,当前在线用户数:” + onlineCount)这句话。

  1. *前端在现有基础上对用户注册登录功能加以限制和完善
    使用专门的接口8081来实现系统

登录与注册界面相应的网址与eclipse中方法存在的位置相对应:
以登录界面和注册界面为例:
① 登录界面:网址http://localhost:8081/home/index/login
对应方法的位置:controller/home/HomeIndexController

② 注册界面:网址http://localhost:8081/home/index/register
对应方法位置:controller/home/HomeIndexController

所有页面相关代码都在模板templates 下
(src/main/resources/templates)
所以在此目录下可以找到上述index和register对应网页的代码。

点击注册按钮之后,执行“提交注册表单”程序,然后是“提交登录表单”,登录成功后,表示用户已存在。

这里用自定义注解包来判断用在注册账号时是否符合要求。
比如,注册时检查用户名是否重复、要求该字段是必填字段、String类型则检查其长度、数字类型则规定是否检查最大最小值;以及登录时检查密码是否正确,检查状态是否正常,若登陆成功则修改状态为在线等功能的实现等。
3. *数据库的设计
共设计了13张表,每张表都与entity中的一个实体类相对应。

(1) account

(2) account_group

(3) account_group_member

(4) database_bak

(5) friend

(6) friend_request

(7) menu

(8) msg_log

(9) operater_log

(10) order_auth

(11) role

(12) role_authorities

(13) uesr

  1. 包和类的划分

(1) annotion为自定义注解包:用来验证自定义实体,可以加到实体类(例如Role类)上去
(2) bean类:基于entity的实体,entity实体直接对应数据库中的一张表,而bean实体直接展现给用户,相当于把entity实体做了一个向上的转义(修改)。用于修改一些敏感信息,比如手机号在展示给用户时中间4位数字要改成*号,此时就需要把数据库中的信息转义后显示给用户
①CodeMsg:错误码统一处理类,所有的错误码统一定义在这里,包括通用错误码定义(例如处理成功消息码和非法数据错误码)和后台管理错误码(例如用户管理类错误、登录类错误等)。
②MsgVo:消息后台管理展示类,做实体的转义。内容包括发送者、接收者和相关消息记录等。
③PageBean:分页信息封装类。
④Result:提交统一返回结果类。
⑤WebSocketMsg:封装前段消息体。
(3)config:做配置的类
①admin:后台的配置类,用来配置拦截器,拦截除标明的类之外所有的请求,即把所有请求拦截,再把相应请求(constant中)放掉
②home:前台的配置类,用来配置拦截器。
③AppConfig:整个项目一启动时的配置文件,即刚启动时就执行其中的方法。
④SiteConfig:整个网站的配置文件,通过@Value注解方法直接把配置文件里的site.properties值加载到此类中。
⑤WebSocketConfig:做WebSocket的配置,在SpringBoot中做WebSocket需要做这样的配置。其中@Configuration:SpringBoot启动时会把Bean类加载进去。
(4)constant:存放常量
①RuntimeConstant:放置系统运行时的常量。
②SessionConstant:关于session的所有常量统一存放类。
(5)controller:控制器。MVC(Model-View-Controller模型-视图-控制器)模式:用户的请求直接进入controller里,controller再把请求根据自己的功能判断交给哪一个模型去处理,处理完再返回到相应的视图上。
①admin:后台管理控制器
i. AccountController:后台用户管理控制器
ii. DatabaseBakController:数据库备份管理控制器
iii. GroupController:后台群组管理控制器
iv. MenuController:后台菜单管理控制器
v. MsgController:后台消息管理控制器
vi. RoleController:后台角色管理控制器
vii. SystemController:系统控制器
viii. UserController:后台用户管理控制器
②common:前后台管理共用控制器
i. CpachaController:系统验证码公用控制器
ii. DownloadController:下载控制器统一管理类
iii. PhotoController:图片统一查看控制器
iv. UploadController:公用的上传类
③home:前台用户控制器:主界面、登陆注册等
i. HomeAccountController:前台首页控制器(用户中心、好友列表、查看群信息、会话列表页面、批量发送好友验证等)
ii. HomeIndexController:前台首页控制器(登录页面、退出登录、注册页面、提交注册表单、登录表单提交)
(6)dao:直接作用于数据库的类
(7)entity:其中每一个实体对应数据库中的一个表,表名为Table(name=’’xxx’’),可以通过这个名字找到打开数据中的表。
①admin:后端实体类。
i. DatabaseBak:数据库备份记录实体类,存放备份的文件名、文件路径。
ii. Menu:后台菜单实体类,包含菜单名称、菜单父分类、菜单URL、菜单图标icon、菜单顺序等)
iii. OperaterLog:后台操作日志记录表,包含操作者和操作内容。
iv. OrderAuth:订单验证日志记录表,包含手机号、记录编号等。
v. Role:后台角色实体类,包含角色状态(是否被冻结)、角色名称、角色对应权限列表、角色备注等。
vi. User:后台用户实体类,包含用户所属角色、用户名、登录密码、用户状态、用户头像、性别、手机号、邮箱等。
②common:前后端共用实体类。
i. Account:前台用户实体类
ii. AccountGroup:用户群实体类,包含群主、群名称、群头像、群公告、群最大最小人数等。
iii. AccountGroupMember:群成员实体类,包含所属群、用户、消息状态、群昵称等。
iv. BaseEntity:基础实体公共属性,包含唯一ID、创建时间、更新时间。
v. Friend:好友实体类。
vi. MsgContent:消息内容实体类,包含发送者ID、接收者ID、聊天类型、消息类型、消息内容、消息附加字段、附件地址、附件大小等。
vii. MsgLog:消息记录实体类。
(8)interceptor:拦截器
①admin:后台拦截器,有两个。
i. 权限统一管理拦截器:做入口处的配置,项目启动时要拦截哪些请求,拦截时要执行哪些类
ii. 登录拦截器:用于查询是否登录,未登录时有些操作无法进行(必须在登录之后才能进行的操作在constant常量中进行定义)
②home:前段拦截器。
i. HomeGlobalInterceptor:前台全局拦截器。
ii. HomeLoginInterceptor:前台登录拦截器,用户还未登录或者会话页面失效,重定向到登录页面。
(9)listener:绘画监听事件,用户第一次打开系统和退出系统时创建一个session。session一般用来统计当前在线人数。
(10)schedule:定时执行任务。
(11) server.home:用于发送和接收消息的类WebSocket。
(12)service:基于controller和dao作用的类,是一个中间态。controller根据自己的业务逻辑把任务派给service,再由service调用dao进行具体的数据库的操作。
①admin:后台管理控制器
i. DatabaseBak:分页查找数据库备份记录、添加或修改数据库备份记录、通过ID查询删除等、备份还原数据库等。
ii. Menu:后台菜单操作,包含菜单添加/编辑、获取所有的菜单列表、根据id查询菜单、删除一条记录。
iii. OperaterLog:后台操作类,数据库操作service,包含添加/修改操作日志,当id不为空时,修改,id为空时自动新增一条记录、获取指定条数的操作日志列表、根据id查询单条数据、返回所有的记录等。
iv. OrderAuth:后台操作类 数据库操作service,获取一条记录。
v. Role:后台角色操作service,角色添加/编辑、获取所有的角色列表、分页按角色名称搜索角色列表、分页按角色名称搜索角色列表、删除一条记录。
vi. User:用户管理service,根据用户id查询、按照用户名查找用户、用户添加/编辑操作、分页查询用户列表、判断用户名是否存在,添加和编辑均可判断、按照用户id删除、返回用户总数。
② common:前后台管理共用控制器
i. AccountGroupMember:新增或编辑群、获取群成员、获取某个用户参与的所有群、根据群和用户id查询等。
ii. AccountGroupService:获取我创建的所有群列表、分页查询群组列表、根据ID查询、删除、返回总数等。
iii. AccountService:用户管理service,根据用户id查询、按照用户名查找用户、用户添加/编辑操作等。
iv. FriendService:好友service,更新或新增、根据ID查找删除、获取我的好友列表等。
v. MsgContentService:消息内容管理service,根据id查询、添加/编辑操作、获取消息列表等。
vi. MsgLogService:消息记录管理service,获取指定用户的指定状态消息,根据消息内容查询关联记录,返回总数。

③ home:前台用户控制器

(13)util:实用工具类,把共用的方法进行封装在此类中,使用时可以直接调用这些方法,实现了“一处定义,处处调用”的功能,可以使代码结构更加紧凑,内容更加精炼。
①CpachaUtil:验证码生成器
②DESUtil:加密工具类
③ HttpUtil:https请求
④ MenuUtil:菜单工具类
⑤ SessionUtil:session统一操作工具类
⑥ StringUtil:项目通用工具类
⑦ValidateEntityUtil:验证实体工具类
(14)App.java:项目入口启动文件

  1. 本地缓存localStorage的创建与加载
    首先阐述设计本地缓存的原因:对于实时聊天,不管是几个字、一个图片、一个文件,都算做一条消息,因此会产生庞大的聊天数据,如果用数据库实时加载,对系统的负载太大,且运行速度慢,所以我选择将实时聊天记录存放在本地缓存中,用户未登录时就暂存在服务器中,登录时显示给用户;在线时的即时聊天记录也保存在本地缓存和服务器中。
    本地缓存使用localstorage,方便存放一些格式化的对象,并且存储空间较大。

在目录src/main/resources/static/home/js/chat.js下
用户上线后,弹出提示“会话列表从本地加载成功”
调用方法getALLChatTapInfoFromLocal()用于从本地中获取所有会话信息:从localstorage中获取变量,getItem表示名字(其中user_id用来区分在一个浏览器中登录的多个用户的属于不同用户的消息),把从localstorage中获得的变量赋值给allChatTapInfo,如果值为空,则说明此用户为新注册的用户,没有聊天记录,则赋值一个空对象;如果不为空,则说明此用户不是新用户,则调用JSON.parse()方法把变量转换为JSON对象,再返回消息。

把消息存入本地缓存:
和加载会话消息列表时一样,首先将变量从localstorage中加载出来,然后调用update方法,往JSON对象中加一个键值进去,再调用setItem方法存入localstorage中,就可以把新产生的聊天记录和原来的记录一并存入本地缓存中。

这样,就完成了本地缓存localStorage的创建与加载功能的实现。

(二)

  1. *发送消息(server.home/WebSocket.java)
    (1)Websocket连接建立后,接收一个String类型的消息message,进入到onMessage方法体,调用JSONObject.parseObject()方法把message转换成websocket类的一个对象,输出消息内容,在调用发送消息的方法sendMsg()。

(2)方法sendMsg():首先判断是单人聊天还是群聊天,如果都不是,则为通知好友事件。

①如果是单人聊天,则调用sendSingleMsg()方法。
sendSingleMsg():从客户端获取接收方的ID(getToId()方法),从getFromId拿到friend好友后,检查好友是否存在,判断与好友的状态——删除、拉黑、正常。
若为删除状态:弹出提示"你还不是对方的好友,请先加好友!“,添加好友后发送消息。
若为拉黑状态,弹出提示"你已被对方拉黑,无法发送消息!”,又把消息返回给发送方。
若为正常状态,用成员变量extAttr将成员的头像和昵称放在附加字段中一并发送给接收方。
其中,设置通知信息不需要保存到数据库,消息保存到数据库。
②如果是单人聊天,则调用sendGroupMsg ()方法。
sendGroupMsg():首先根据群ID获取群成员信息。
如果群成员列表为空,则表示该群已解散,把消息返回给发送方。
如果群成员为空,则表示当前用户已被群主移出该群,消息无法成功发送,把消息返回给发送方。
如果群状态正常且群成员在线,用成员变量extAttr将发送消息成员的头像和昵称放在附加字段中,并且遍历群成员、排除自己外,发送消息,设置将消息保存到数据库中。
③如果是通知好友事件:添加好友后好友列表刷新等事件,则调用方法refreshFriendList()来刷新好友列表。
(3)调用WebSocketMsg类中的sendText方法发送消息,消息类型分为单人聊天消息、群消息、时间消息、文本消息、图片消息、文件消息、上线消息、下线消息。

  1. *接收消息(src/main/resources/static/home/js/websocket.js)
    (1)首先打开一个web socket,new一个websocket的对象ws,并且成功建立连接。Web Socket 已连接上,使用 send() 方法发送数据。
    (2)接收到信息,存放到onmessage中,转换为JSON格式对象,接收方收到新消息提示,并且在会话页上显示最后一条信息,根据接收到的消息类型receivedMsg.chatType判断是单人聊天消息还是群聊消息,然后分别调用不同的方法。

结果截图:

  1. *消息的封装
    (1)封装方法:把字符串String类型的消息封装成JSON格式的对象,JSON格式对象可解析,相比String可以实现快速编写。
    (2)entity/common/MsgLog.java存放消息记录:消息所属用户account、消息实体(具体内容)msgContent、消息状态status。

(3)entity/common/MsgLogContent.java存放消息内容实体:接收者ID toId、发送者ID fromId、聊天类型chatType、消息类型msgType、消息内容msg、消息附加字段extAttr、附件地址attachUrl、附件大小attachSize。

其中,消息附加字段为消息内容之外的信息,比如发送者头像、发送时间等,在消息发送时一并发送给接收方;附件地址及附件大小在消息内容为文本消息是为空。
  1. 发送图片、文件消息
    发送方上传图片或文件的地址到服务器中,再由服务器将字符串类型的地址发送给客户端(本质上仍为发送文本消息),有了图片和文件的地址,接收方就可以通过地址查看传输的图片和文件了。

(三)

    1. 通讯录好友模型设计
     private static final int FRIEND_STATUS_ENABLE=1;//正常
     private static final int FRIEND_STATUS_BLOCK=-1;//拉黑
     private static final int FRIEND_MSG_STATUS_ENABLE=1;//正常提醒
     private static final int FRIEND_MSG_STATUS_MUTE=0;//消息免打扰
     private Account account;//所属用户
     private Account friendAccount;//好友用户
     private int status=FRIEND_STATUS_ENABLE;//默认正常
     private int msgStatus=FRIEND_MSG_STATUS_ENABLE;//默认正常
     private String remark;//备注当用户A删除好友用户B时,B不出现在A的好友列表里,但A仍出现在B的好友列表
     2.添加好友、创建群功能
     public static final int GROUP_MIN_PEOPLE=2;//创建群聊最小人数
     public static final int GROUP_MAX_PEOPLE=65535;//创建群聊最大人数
     private Account admin;//群主
     private String name;//群名称
     private String picture;//群封面图片
     private String info;//群介绍
     private String notice;//群公告
     private int minPeople=GROUP_MIN_PEOPLE;//当前群聊时最小人数
     private int maxPeople=GROUP_MAX_PEOPLE;//当前群聊时最大人数
     Private int curPeople=0;//当前群人数
     public static final int FRIEND_MSG_STATUS_ENABLE=1;//正常提醒
     public static final int FRIEND_MSG_STATUS_MUTE=0;//消息免打扰
     private AccountGroup accountGroup;//所属群
     private Account member;//用户
     private int msgStatus=FRIEND_MSG_STATUS_ENABLE;//默认正常
     private String nickname;//群昵称3. 上线后加载离线消息功能