From ee01a16f8b358e4b7149822fd1bcb1fdbfc4d433 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 4 May 2026 23:06:04 +0800 Subject: [PATCH] 🐛 fix(im):好友模块 codex 评审修复——1209 改 @TransactionalEventListener(AFTER_COMMIT) 避免幽灵通知、Consumer 过滤下推 SQL、申请表索引带 id 后缀覆盖游标排序、limit 加 @Max(200) 上限 --- yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java | 4 +++- yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java | 19 +++++++------------ yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java | 5 +++++ yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java | 5 +++++ 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java index 5a2bfb3..23e84bd 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java @@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -81,7 +82,8 @@ public class ImFriendRequestController { public CommonResult> getMyFriendRequestList( @Parameter(description = "当前列表最旧记录的 id;首页不传") @RequestParam(value = "lastRequestId", required = false) Long lastRequestId, - @Parameter(description = "单次拉取条数", required = true) @RequestParam("limit") @Min(1) Integer limit) { + @Parameter(description = "单次拉取条数", required = true) + @RequestParam("limit") @Min(1) @Max(200) Integer limit) { List list = friendRequestService.getMyFriendRequestList(getLoginUserId(), lastRequestId, limit); return success(buildList(list)); } diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java index 528b99b..9d4e5f5 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.im.mq.consumer.friend; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; import cn.iocoder.yudao.module.im.service.friend.ImFriendService; @@ -10,9 +9,10 @@ import cn.iocoder.yudao.module.im.service.websocket.dto.notification.friend.Frie import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; import java.util.List; @@ -30,30 +30,25 @@ public class AdminUserProfileUpdateConsumer { @Resource private ImWebSocketService websocketService; - @EventListener - @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true) + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步;事务提交后触发,避免回滚误推幽灵通知 / Consumer 抢在 commit 前读旧值 public void onMessage(AdminUserProfileUpdateMessage message) { log.info("[onMessage][消息内容({})]", message); Long userId = message.getUserId(); - // 1. 找当前用户的所有有效好友(DISABLE 已删的不推) - List friends = friendService.getFriendList(userId); + // 1. SQL 层过滤 ENABLE 好友 + List friends = friendService.getEnableFriendList(userId); if (friends.isEmpty()) { return; } // 2. 给每个好友的多端推 FRIEND_INFO_UPDATED;payload 里 operatorUserId / friendUserId 都是「资料被改的人」 - int notifyCount = 0; for (ImFriendDO friend : friends) { - if (CommonStatusEnum.isDisable(friend.getStatus())) { - continue; - } FriendInfoUpdatedNotification payload = (FriendInfoUpdatedNotification) new FriendInfoUpdatedNotification() .setOperatorUserId(userId).setFriendUserId(userId); websocketService.sendPrivateMessageAsync(friend.getFriendUserId(), ImPrivateMessageDTO.ofFriendNotification( ImMessageTypeEnum.FRIEND_INFO_UPDATED.getType(), userId, friend.getFriendUserId(), payload)); - notifyCount++; } - log.info("[onMessage][userId({}) 推送 FRIEND_INFO_UPDATED 给 {} 位好友]", userId, notifyCount); + log.info("[onMessage][userId({}) 推送 FRIEND_INFO_UPDATED 给 {} 位好友]", userId, friends.size()); } } diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java index 97af9d8..db9b26e 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java @@ -33,6 +33,11 @@ public interface ImFriendService { List getFriendList(Long userId); /** + * 获得当前用户的有效好友列表(仅 ENABLE 状态) + */ + List getEnableFriendList(Long userId); + + /** * 获得当前用户与指定用户之间的有效好友列表(仅 ENABLE 状态) */ List getActiveFriendList(Long userId, Collection friendUserIds); diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java index 8a4852c..1b83566 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java @@ -76,6 +76,11 @@ public class ImFriendServiceImpl implements ImFriendService { } @Override + public List getEnableFriendList(Long userId) { + return friendMapper.selectListByUserIdAndStatus(userId, CommonStatusEnum.ENABLE.getStatus()); + } + + @Override public List getActiveFriendList(Long userId, Collection friendUserIds) { return friendMapper.selectListByUserIdAndFriendUserIdsAndStatus(userId, friendUserIds, CommonStatusEnum.ENABLE.getStatus()); -- libgit2 0.21.4