Commit ee01a16f8b358e4b7149822fd1bcb1fdbfc4d433
1 parent
eb2d3c39
🐛 fix(im):好友模块 codex 评审修复——1209 改 @TransactionalEventListener(AFTER_COMMIT) 避免幽灵…
…通知、Consumer 过滤下推 SQL、申请表索引带 id 后缀覆盖游标排序、limit 加 @Max(200) 上限
Showing
4 changed files
with
20 additions
and
13 deletions
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; | @@ -16,6 +16,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 16 | import io.swagger.v3.oas.annotations.tags.Tag; | 16 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 17 | import jakarta.annotation.Resource; | 17 | import jakarta.annotation.Resource; |
| 18 | import jakarta.validation.Valid; | 18 | import jakarta.validation.Valid; |
| 19 | +import jakarta.validation.constraints.Max; | ||
| 19 | import jakarta.validation.constraints.Min; | 20 | import jakarta.validation.constraints.Min; |
| 20 | import jakarta.validation.constraints.NotNull; | 21 | import jakarta.validation.constraints.NotNull; |
| 21 | import jakarta.validation.constraints.Size; | 22 | import jakarta.validation.constraints.Size; |
| @@ -81,7 +82,8 @@ public class ImFriendRequestController { | @@ -81,7 +82,8 @@ public class ImFriendRequestController { | ||
| 81 | public CommonResult<List<ImFriendRequestRespVO>> getMyFriendRequestList( | 82 | public CommonResult<List<ImFriendRequestRespVO>> getMyFriendRequestList( |
| 82 | @Parameter(description = "当前列表最旧记录的 id;首页不传") | 83 | @Parameter(description = "当前列表最旧记录的 id;首页不传") |
| 83 | @RequestParam(value = "lastRequestId", required = false) Long lastRequestId, | 84 | @RequestParam(value = "lastRequestId", required = false) Long lastRequestId, |
| 84 | - @Parameter(description = "单次拉取条数", required = true) @RequestParam("limit") @Min(1) Integer limit) { | 85 | + @Parameter(description = "单次拉取条数", required = true) |
| 86 | + @RequestParam("limit") @Min(1) @Max(200) Integer limit) { | ||
| 85 | List<ImFriendRequestDO> list = friendRequestService.getMyFriendRequestList(getLoginUserId(), lastRequestId, limit); | 87 | List<ImFriendRequestDO> list = friendRequestService.getMyFriendRequestList(getLoginUserId(), lastRequestId, limit); |
| 86 | return success(buildList(list)); | 88 | return success(buildList(list)); |
| 87 | } | 89 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/mq/consumer/friend/AdminUserProfileUpdateConsumer.java
| 1 | package cn.iocoder.yudao.module.im.mq.consumer.friend; | 1 | package cn.iocoder.yudao.module.im.mq.consumer.friend; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; | 3 | import cn.iocoder.yudao.module.im.dal.dataobject.friend.ImFriendDO; |
| 5 | import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; | 4 | import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; |
| 6 | import cn.iocoder.yudao.module.im.service.friend.ImFriendService; | 5 | 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 | @@ -10,9 +9,10 @@ import cn.iocoder.yudao.module.im.service.websocket.dto.notification.friend.Frie | ||
| 10 | import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage; | 9 | import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage; |
| 11 | import jakarta.annotation.Resource; | 10 | import jakarta.annotation.Resource; |
| 12 | import lombok.extern.slf4j.Slf4j; | 11 | import lombok.extern.slf4j.Slf4j; |
| 13 | -import org.springframework.context.event.EventListener; | ||
| 14 | import org.springframework.scheduling.annotation.Async; | 12 | import org.springframework.scheduling.annotation.Async; |
| 15 | import org.springframework.stereotype.Component; | 13 | import org.springframework.stereotype.Component; |
| 14 | +import org.springframework.transaction.event.TransactionPhase; | ||
| 15 | +import org.springframework.transaction.event.TransactionalEventListener; | ||
| 16 | 16 | ||
| 17 | import java.util.List; | 17 | import java.util.List; |
| 18 | 18 | ||
| @@ -30,30 +30,25 @@ public class AdminUserProfileUpdateConsumer { | @@ -30,30 +30,25 @@ public class AdminUserProfileUpdateConsumer { | ||
| 30 | @Resource | 30 | @Resource |
| 31 | private ImWebSocketService websocketService; | 31 | private ImWebSocketService websocketService; |
| 32 | 32 | ||
| 33 | - @EventListener | ||
| 34 | - @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步 | 33 | + @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, fallbackExecution = true) |
| 34 | + @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步;事务提交后触发,避免回滚误推幽灵通知 / Consumer 抢在 commit 前读旧值 | ||
| 35 | public void onMessage(AdminUserProfileUpdateMessage message) { | 35 | public void onMessage(AdminUserProfileUpdateMessage message) { |
| 36 | log.info("[onMessage][消息内容({})]", message); | 36 | log.info("[onMessage][消息内容({})]", message); |
| 37 | Long userId = message.getUserId(); | 37 | Long userId = message.getUserId(); |
| 38 | - // 1. 找当前用户的所有有效好友(DISABLE 已删的不推) | ||
| 39 | - List<ImFriendDO> friends = friendService.getFriendList(userId); | 38 | + // 1. SQL 层过滤 ENABLE 好友 |
| 39 | + List<ImFriendDO> friends = friendService.getEnableFriendList(userId); | ||
| 40 | if (friends.isEmpty()) { | 40 | if (friends.isEmpty()) { |
| 41 | return; | 41 | return; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | // 2. 给每个好友的多端推 FRIEND_INFO_UPDATED;payload 里 operatorUserId / friendUserId 都是「资料被改的人」 | 44 | // 2. 给每个好友的多端推 FRIEND_INFO_UPDATED;payload 里 operatorUserId / friendUserId 都是「资料被改的人」 |
| 45 | - int notifyCount = 0; | ||
| 46 | for (ImFriendDO friend : friends) { | 45 | for (ImFriendDO friend : friends) { |
| 47 | - if (CommonStatusEnum.isDisable(friend.getStatus())) { | ||
| 48 | - continue; | ||
| 49 | - } | ||
| 50 | FriendInfoUpdatedNotification payload = (FriendInfoUpdatedNotification) new FriendInfoUpdatedNotification() | 46 | FriendInfoUpdatedNotification payload = (FriendInfoUpdatedNotification) new FriendInfoUpdatedNotification() |
| 51 | .setOperatorUserId(userId).setFriendUserId(userId); | 47 | .setOperatorUserId(userId).setFriendUserId(userId); |
| 52 | websocketService.sendPrivateMessageAsync(friend.getFriendUserId(), ImPrivateMessageDTO.ofFriendNotification( | 48 | websocketService.sendPrivateMessageAsync(friend.getFriendUserId(), ImPrivateMessageDTO.ofFriendNotification( |
| 53 | ImMessageTypeEnum.FRIEND_INFO_UPDATED.getType(), userId, friend.getFriendUserId(), payload)); | 49 | ImMessageTypeEnum.FRIEND_INFO_UPDATED.getType(), userId, friend.getFriendUserId(), payload)); |
| 54 | - notifyCount++; | ||
| 55 | } | 50 | } |
| 56 | - log.info("[onMessage][userId({}) 推送 FRIEND_INFO_UPDATED 给 {} 位好友]", userId, notifyCount); | 51 | + log.info("[onMessage][userId({}) 推送 FRIEND_INFO_UPDATED 给 {} 位好友]", userId, friends.size()); |
| 57 | } | 52 | } |
| 58 | 53 | ||
| 59 | } | 54 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendService.java
| @@ -33,6 +33,11 @@ public interface ImFriendService { | @@ -33,6 +33,11 @@ public interface ImFriendService { | ||
| 33 | List<ImFriendDO> getFriendList(Long userId); | 33 | List<ImFriendDO> getFriendList(Long userId); |
| 34 | 34 | ||
| 35 | /** | 35 | /** |
| 36 | + * 获得当前用户的有效好友列表(仅 ENABLE 状态) | ||
| 37 | + */ | ||
| 38 | + List<ImFriendDO> getEnableFriendList(Long userId); | ||
| 39 | + | ||
| 40 | + /** | ||
| 36 | * 获得当前用户与指定用户之间的有效好友列表(仅 ENABLE 状态) | 41 | * 获得当前用户与指定用户之间的有效好友列表(仅 ENABLE 状态) |
| 37 | */ | 42 | */ |
| 38 | List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds); | 43 | List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds); |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
| @@ -76,6 +76,11 @@ public class ImFriendServiceImpl implements ImFriendService { | @@ -76,6 +76,11 @@ public class ImFriendServiceImpl implements ImFriendService { | ||
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | @Override | 78 | @Override |
| 79 | + public List<ImFriendDO> getEnableFriendList(Long userId) { | ||
| 80 | + return friendMapper.selectListByUserIdAndStatus(userId, CommonStatusEnum.ENABLE.getStatus()); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Override | ||
| 79 | public List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds) { | 84 | public List<ImFriendDO> getActiveFriendList(Long userId, Collection<Long> friendUserIds) { |
| 80 | return friendMapper.selectListByUserIdAndFriendUserIdsAndStatus(userId, friendUserIds, | 85 | return friendMapper.selectListByUserIdAndFriendUserIdsAndStatus(userId, friendUserIds, |
| 81 | CommonStatusEnum.ENABLE.getStatus()); | 86 | CommonStatusEnum.ENABLE.getStatus()); |