先看效果图吧:
私信列表
私信详情
从图片上可以看出来,我们要做的事情大概有这些:
1)私信列表:
- 查询当前用户的会话列表,且每个会话只显示一条最新的私信
- 查询某个会话的私信数量
- 支持分页显示
- 显示未读消息数量
- 显示与某个用户对话的未读消息数量
- 显示所有对话的未读消息消息
2)私信详情:
- 查询某个会话所包含的私信
- 支持分页显示
- 访问私信详情时,将显示的私信设为已读状态
OK,先回顾下私信表的结构:
- id:私信/系统通知的唯一标识
- from_id:私信/系统通知的发送方 id
- to_id:私信/系统通知的接收方 id
- conversation_id:标识两个用户之间的对话。比如用户 id 112 给 113 发消息,或者 113 给 112 发消息,我们规定这两个会话的
conservation_id
都是112_113
。这样,通过这个字段我们就能迅速查出 112 和 113 之间的私信往来。当然,这个字段是冗余的,我们可以通过 from_id 和 to_id 推演出来,但是有了这个字段方便后面的查询等操作 - content:私信/系统通知的内容
- status:私信/系统通知的状态(这个字段就是我们实现未读消息的关键)
- 0 - 未读(默认)
- 1 - 已读
- 2 - 删除(暂未使用)
- create_time:私信/系统通知的发送时间
需要注意的是:这张表不仅存储用户之间的私信,也存储系统通知,不同的是,系统通知的 from_id
特定为 1,而这个 id 为 1 的用户是我们手动内置进去的。
Dao 层
根据上述罗列的大致需要做的事情,我们来定义下 Dao 层的操作。
分页查询这里就不再说了,直接复用我们封装好的模型即可,不明白的小伙伴可以看这里 Echo 的帖子列表与分页是怎么做的,需要注意的是,分页查询需要获得该用户的所有会话数量(该方法是 selectConversationCount
,与接下来介绍的 selectConversations
差不多,这里),从而计算页数。
首先,对于私信列表页:
1)询问当前用户的会话列表,针对每个会话只返回一条最新的私信:selectConversations
对于当前用户来说,它的会话列表中,不仅包含别人发给他的,也包含他发给别人的,所以在查询的时候,只要这条私信的 from_id 或者 to_id 的其中一个字段与该用户的 id 相同,那么就认为这条私信属于该用户。
至于这条私信需不需要显示在会话列表中呢?
我们说了,针对每个会话只返回一条最新的私信。这个也好办,首先按照 conversion_id 也就是会话 id 进行分组归类,查到这个分组所拥有的所有私信后,私信记录 id 最大的那条就是这个分组会话中最新的私信。
看代码,不难理解:
2)查询某个会话的私信数量:selectLetterCount
这个简单,直接按照 conversation_id 查就行。
3)显示该用户的未读消息数量,这个功能包含两点:显示与某个用户对话的未读消息数量;显示所有对话的未读消息消息。
轻车熟路,使用动态 SQL,一个方法搞定:selectLetterUnreadCount
如果传入的参数 conversationId == null,就查询该用户所有会话的未读私信数量;如果传入的 conversationId != null,则查询这个会话的未读私信数量。
另外,未读消息即状态 status = 0。既然是未读消息,那肯定是别人发给我的对吧,我发给别人的消息谈何未读呢?所以这里需要指定 to_id 等于该用户的 id。
再来看私信详细页需要做的事情:
1)查询某个会话所包含的私信:selectLetters
和查询某个会话的私信数量 selectLetterCount
方法差不多,没啥难度,直接按照 conversation_id 查就行。
2)访问私信详情时,将显示的私信设为已读状态
具体的业务逻辑我们下文会讲,这里只解释下 Dao 层批量修改私信状态的操作:updateStatus
表现层
前端部分我就不写了,直接获取后台存入 Model 中的值就行。
首先,对于私信列表:getLetterList
这段代码大部分没啥好说的,需要注意的是查询未读消息数量这块,各位应该注意到在我们的界面顶部也会显示一个未读消息数量,这个数量是未读私信的数量和未读系统通知数量(后续文章会写)的总和,这个怎么做呢?怎么把未读私信的数量和未读系统通知数量实时的传过来呢?
没错,拦截器。
这样,前端读取 allUnreadCount 这个属性就行了。
再来看私信详情:getLetterDetail
这里需要注意的就是上图粉红色框中的代码。
可能有些小伙伴会疑惑私信目标 target 是干啥的,这个不难理解,看下图:
这里需要做个简单的判断,上文说过, conservation_id
的生成是需要遵守一个规则的,比如用户 id 112 给 113 发消息,或者 113 给 112 发消息,我们规定这两个会话的 conservation_id
都是 112_113
。也就是说 id 按照从小到大排的。
那如果当前登录用户是 112,这个会话里显示的私信目标就应该是用户 113;如果当前登录用户是 113,那这个会话里显示的私信目标就应该是用户 112。具体判断代码看这里:
OK,再来看如何将私信列表中的未读消息改为已读。
具体流程是这样的:进入私信详情页后,先从当前页的私信列表 letterList
中获取当前登录用户未读私信的 id,然后批量的将这些 id 对应的私信状态设置为已读。
这里多提一嘴,防止有小伙伴懵逼,我们的私信列表 letterList
是按照分页查询的,每次进入新的一页,letterList
就会发生新的变化。所以你看到的效果就是这样的:
当你点开一个会话后,你会先进入第一页,然后第一页消息列表中的所有未读消息的状态都会被设置为已读;你进入第二页,于是第二页消息列表中的所有未读消息的状态都会被设置为已读......
至于如何获取当前登录用户未读私信的 id,没啥好说的,这里直接贴个图吧: