社区用户之间的私信功能
这几天查了很多博客、文档,磕磕绊绊的总算完成了用户私信的功能,这份md记录了社区对私信功能的实现,,使用WebSocket与Jwt认证,将包括前端部分Vue、后端springBoot的代码。

具体实现
后端webSocket配置类
- 首先设置消息代理
1 |
|
- 重写
webSocket握手拦截器,主要功能是解析cookie中的jwt,然后将用户信息存入webSocketSession
1 | /**@Bean |
- 配置服务端连接点,添加握手拦截器
1 | //注册STOMP协议节点并映射url |
- 配置WebSocket传输器,主要目的是注册
DecoratorFactory装饰工厂,重写处理器WebSocketHandler中的方法。
1 |
|
- 配置类总体概况
1 | package cn.shirtiny.community.SHcommunity.Config; |
数据库表模型
消息历史记录
1 | package cn.shirtiny.community.SHcommunity.Model; |
单个消息
1 | package cn.shirtiny.community.SHcommunity.Model; |
后端控制器和服务层
/sendToUser处理用户之间的消息传输,并记录和存储
1 | //一对一聊天 message需要携带消息内容、接收者的id |
其中,chatMessageService的parseMessageToChatMessage()内容为:
1 |
|
createHistoryId()方法,生成该消息的消息记录Id,内容为:
1 |
|
这样由两个用户的id,可以唯一确定一条消息记录。
/allHistoryMessage查询某个用户的所有消息记录
1 | //查询某个用户的全部消息记录及其内容 |
返回结果如:

其中selectAllHistoryMessageByUid()方法处理两个用户之前的相对关系:
1 | //查询某个用户的全部消息记录及其内容 并设置targetUser的值 |
涉及到的mapper的selectAllChatHistoryByUid()方法为:
1 | //查询出单个用户的所有聊天记录 及其全部消息 |
前端Vue、Element
- 数据对象
1 | data: { |
- 两个计算属性
1 | computed: { |
- 主要方法
从url中获取要建立通信的用户id:
比如url : http://localhost:8881/messageCenter?uid=117603681930663529
1 | //从url获取用户id 然后返回url里的用户id |
连接socket
1 | //以jwt为认证标准,连接服务器 |
订阅频道
1 | //以当前js登录的用户,与当前激活的tabName为准,订阅频道 |
订阅回调函数,处理message
1 | /订阅消息的回调函数 |
发送消息
1 | sendMessage: function () { |
从通信列表中移除用户
1 | //移除tab |
更多内容…,可以在我Github上查看源码。
- mounted()
1 | mounted() { |
- watch监控
1 | watch: { |
- 结构

- 主要css
1 | /*注意下面三个div的 overflow:hidden 的作用是清除浮动 让外层div自适应内层div高度*/ |
离线状态处理
- 消息的收信人离线时,无法及时收到消息,所以消息模型需要增加一个字段,来标识已读状态。
1 | package cn.shirtiny.community.SHcommunity.Model; |
- 当客户端收到消息时,需要
message.ack()来通知服务端它已经接收了消息
1 | //订阅回调函数 |
通过ack的自定义header传递消息对象或消息id,以传达给服务器具体消息对象的信息。
- 当服务器通过
webSocketHandler在收到客户端回应的ack时,改变对应消息的已读状态。如果没有收到ack,则该消息保持默认的未读状态。我这里不管是否收到ack,消息都入库存储。若需求较大,也可以针对未读消息引入缓存或消息队列。
1 |
|
- 用户上线时,在导航条提示用户未读消息的计数,引导其前往消息中心

在消息中心可以直接显示全部消息,也可以选择将消息重新发送到相应频道。最后更新用户点击过的聊天记录消息的已读状态。
1 | //更新对应tab的消息记录的消息为已读状态 |
1 | watch: { |