Commit dc7be585063ca833ff3b6fb07b68fde2ecc0146b
1 parent
d6d90b2b
✨ feat(im): 优化 pullPrivateMessageList 接口的实现
Showing
5 changed files
with
29 additions
and
19 deletions
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<ImPrivateMessageDO> | @@ -24,18 +25,15 @@ public interface ImPrivateMessageMapper extends BaseMapperX<ImPrivateMessageDO> | ||
| 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"); |