Commit dc7be585063ca833ff3b6fb07b68fde2ecc0146b

Authored by YunaiV
1 parent d6d90b2b

✨ feat(im): 优化 pullPrivateMessageList 接口的实现

yudao-module-im/yudao-module-im-biz/pom.xml
@@ -23,6 +23,11 @@ @@ -23,6 +23,11 @@
23 <artifactId>yudao-module-im-api</artifactId> 23 <artifactId>yudao-module-im-api</artifactId>
24 <version>${revision}</version> 24 <version>${revision}</version>
25 </dependency> 25 </dependency>
  26 + <dependency>
  27 + <groupId>cn.iocoder.boot</groupId>
  28 + <artifactId>yudao-module-system</artifactId>
  29 + <version>${revision}</version>
  30 + </dependency>
26 31
27 <!-- Web 相关 --> 32 <!-- Web 相关 -->
28 <dependency> 33 <dependency>
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImPrivateMessageController.java
@@ -43,9 +43,9 @@ public class ImPrivateMessageController { @@ -43,9 +43,9 @@ public class ImPrivateMessageController {
43 @Operation(summary = "拉取私聊消息(增量)") 43 @Operation(summary = "拉取私聊消息(增量)")
44 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0") 44 @Parameter(name = "minId", description = "最小消息 id", required = true, example = "0")
45 @Parameter(name = "size", description = "拉取数量", required = true, example = "100") 45 @Parameter(name = "size", description = "拉取数量", required = true, example = "100")
46 - public CommonResult<List<ImPrivateMessageRespVO>> pullPrivateMessages(@RequestParam("minId") Long minId,  
47 - @RequestParam("size") Integer size) {  
48 - List<ImPrivateMessageDO> messages = privateMessageService.pullPrivateMessages(getLoginUserId(), minId, size); 46 + public CommonResult<List<ImPrivateMessageRespVO>> pullPrivateMessageList(@RequestParam("minId") Long minId,
  47 + @RequestParam("size") Integer size) {
  48 + List<ImPrivateMessageDO> messages = privateMessageService.pullPrivateMessageList(getLoginUserId(), minId, size);
49 return success(BeanUtils.toBean(messages, ImPrivateMessageRespVO.class)); 49 return success(BeanUtils.toBean(messages, ImPrivateMessageRespVO.class));
50 } 50 }
51 51
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImPrivateMessageMapper.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.im.dal.mysql.message; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.im.dal.mysql.message;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
5 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO; 6 import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO;
6 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
7 8
@@ -24,18 +25,15 @@ public interface ImPrivateMessageMapper extends BaseMapperX&lt;ImPrivateMessageDO&gt; @@ -24,18 +25,15 @@ public interface ImPrivateMessageMapper extends BaseMapperX&lt;ImPrivateMessageDO&gt;
24 * @return 消息列表 25 * @return 消息列表
25 */ 26 */
26 default List<ImPrivateMessageDO> selectListByMinId(Long userId, Long minId, Integer size) { 27 default List<ImPrivateMessageDO> selectListByMinId(Long userId, Long minId, Integer size) {
27 - return selectList(new LambdaQueryWrapperX<ImPrivateMessageDO>()  
28 - .and(w -> w.eq(ImPrivateMessageDO::getSenderId, userId)  
29 - .or()  
30 - .eq(ImPrivateMessageDO::getReceiverId, userId))  
31 - .gt(ImPrivateMessageDO::getId, minId)  
32 - .orderByAsc(ImPrivateMessageDO::getId)  
33 - .last("LIMIT " + size)); 28 + QueryWrapperX<ImPrivateMessageDO> wrapper = new QueryWrapperX<>();
  29 + wrapper.and(w -> w.eq("sender_id", userId)
  30 + .or().eq("receiver_id", userId))
  31 + .gt("id", minId)
  32 + .orderByAsc("id");
  33 + wrapper.limitN(size);
  34 + return selectList(wrapper);
34 } 35 }
35 36
36 - /**  
37 - * 根据 senderId 和 clientMessageId 查询(幂等校验)  
38 - */  
39 default ImPrivateMessageDO selectBySenderIdAndClientMessageId(Long senderId, String clientMessageId) { 37 default ImPrivateMessageDO selectBySenderIdAndClientMessageId(Long senderId, String clientMessageId) {
40 return selectOne(new LambdaQueryWrapperX<ImPrivateMessageDO>() 38 return selectOne(new LambdaQueryWrapperX<ImPrivateMessageDO>()
41 .eq(ImPrivateMessageDO::getSenderId, senderId) 39 .eq(ImPrivateMessageDO::getSenderId, senderId)
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageService.java
@@ -29,7 +29,7 @@ public interface ImPrivateMessageService { @@ -29,7 +29,7 @@ public interface ImPrivateMessageService {
29 * @param size 拉取数量 29 * @param size 拉取数量
30 * @return 消息列表 30 * @return 消息列表
31 */ 31 */
32 - List<ImPrivateMessageDO> pullPrivateMessages(Long userId, Long minId, Integer size); 32 + List<ImPrivateMessageDO> pullPrivateMessageList(Long userId, Long minId, Integer size);
33 33
34 /** 34 /**
35 * 标记私聊消息已读 35 * 标记私聊消息已读
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImpl.java
@@ -81,29 +81,36 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService { @@ -81,29 +81,36 @@ public class ImPrivateMessageServiceImpl implements ImPrivateMessageService {
81 } 81 }
82 82
83 @Override 83 @Override
84 - public List<ImPrivateMessageDO> pullPrivateMessages(Long userId, Long minId, Integer size) { 84 + public List<ImPrivateMessageDO> pullPrivateMessageList(Long userId, Long minId, Integer size) {
85 if (size > MAX_PULL_SIZE) { 85 if (size > MAX_PULL_SIZE) {
86 throw exception(MESSAGE_PULL_SIZE_EXCEEDED); 86 throw exception(MESSAGE_PULL_SIZE_EXCEEDED);
87 } 87 }
88 - return privateMessageMapper.selectListByMinId(userId, minId, size); 88 + List<ImPrivateMessageDO> messages = privateMessageMapper.selectListByMinId(userId, minId, size);
  89 + log.info("[pullPrivateMessageList][userId({}) minId({}) size({}) result({})]",
  90 + userId, minId, size, messages.size());
  91 + return messages;
89 } 92 }
90 93
91 - // DONE @芋艿:已 review,逻辑正确 94 + // TODO @AI:应该是将 friendId 改成 receiverId,毕竟消息是发给对方的
92 @Override 95 @Override
93 public void readPrivateMessages(Long userId, Long friendId) { 96 public void readPrivateMessages(Long userId, Long friendId) {
94 // 1. 批量更新消息状态为已读 97 // 1. 批量更新消息状态为已读
  98 + // TODO @AI:先查询;然后在 update;避免锁的问题;
  99 + // TODO @AI:注意,update 的时候,也要 id in、status =,最后 updateObj 传入;避免并发问题;
95 int updated = privateMessageMapper.updateStatusToRead(userId, friendId); 100 int updated = privateMessageMapper.updateStatusToRead(userId, friendId);
96 if (updated == 0) { 101 if (updated == 0) {
97 return; // 没有需要更新的消息 102 return; // 没有需要更新的消息
98 } 103 }
99 - // 2. 发送 READ 事件给自己的其他终端(多端同步) 104 +
  105 + // TODO @AI:继续 async !
  106 + // 2.1 发送 READ 事件给自己的其他终端(多端同步)
100 ImMessageReadMessage readMessage = new ImMessageReadMessage() 107 ImMessageReadMessage readMessage = new ImMessageReadMessage()
101 .setFriendId(friendId.toString()) 108 .setFriendId(friendId.toString())
102 .setMessageScene("private"); 109 .setMessageScene("private");
103 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, 110 webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId,
104 ImMessageReadMessage.TYPE, readMessage); 111 ImMessageReadMessage.TYPE, readMessage);
105 112
106 - // 3. 发送 RECEIPT 事件给对方(已读回执) 113 + // 2.2 发送 RECEIPT 事件给对方(已读回执)
107 ImMessageReceiptMessage receiptMessage = new ImMessageReceiptMessage() 114 ImMessageReceiptMessage receiptMessage = new ImMessageReceiptMessage()
108 .setUserId(userId.toString()) 115 .setUserId(userId.toString())
109 .setMessageScene("private"); 116 .setMessageScene("private");