mirror of
https://gitee.com/yudaocode/yudao-boot-mini.git
synced 2026-10-06 06:12:58 +08:00
✨ feat(im):实现 1209 FRIEND_INFO_UPDATED 推送(system 发 AdminUserProfileUpdateMessage,IM Consumer 监听后批量推好友多端)
This commit is contained in:
+1
-1
@@ -80,7 +80,7 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> {
|
||||
* 对应 OpenIM:FriendInfoUpdatedNotification 1209
|
||||
* 对应自己的类:FriendInfoUpdatedNotification
|
||||
* 场景:B 改了昵称 / 头像后,推给 B 的所有好友
|
||||
* TODO @AI:未实现;待 system 模块改昵称 / 头像时回调 IM 模块批量推此事件,前端 dispatcher 已就绪
|
||||
* 触发:system 模块发 AdminUserProfileUpdateMessage,IM 消费者 AdminUserProfileUpdateConsumer 批量推此通知
|
||||
*/
|
||||
FRIEND_INFO_UPDATED(1209, "好友资料变更", false, false),
|
||||
/**
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
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;
|
||||
import cn.iocoder.yudao.module.im.service.websocket.ImWebSocketService;
|
||||
import cn.iocoder.yudao.module.im.service.websocket.dto.ImPrivateMessageDTO;
|
||||
import cn.iocoder.yudao.module.im.service.websocket.dto.notification.friend.FriendInfoUpdatedNotification;
|
||||
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 java.util.List;
|
||||
|
||||
/**
|
||||
* 监听 system 模块的 {@link AdminUserProfileUpdateMessage} 消息,向「资料被改的人」的所有好友推送 FRIEND_INFO_UPDATED 通知
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AdminUserProfileUpdateConsumer {
|
||||
|
||||
@Resource
|
||||
private ImFriendService friendService;
|
||||
@Resource
|
||||
private ImWebSocketService websocketService;
|
||||
|
||||
@EventListener
|
||||
@Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
|
||||
public void onMessage(AdminUserProfileUpdateMessage message) {
|
||||
Long userId = message.getUserId();
|
||||
// 1. 找当前用户的所有有效好友(DISABLE 已删的不推)
|
||||
List<ImFriendDO> friends = friendService.getFriendList(userId);
|
||||
if (friends.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 给每个好友的多端推 FRIEND_INFO_UPDATED;payload 里 operatorUserId / friendUserId 都是「资料被改的人」
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.im.service.websocket.dto.notification.friend;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
// TODO @AI:1209 暂未实现;好友信息在 system 模块,需要 system 改昵称 / 头像后发 ApplicationEvent,IM 模块监听后回调发送此通知
|
||||
/**
|
||||
* 好友资料变更通知(对端改了昵称 / 头像)
|
||||
* <p>
|
||||
* 推送给资料被改的人的所有好友;前端清缓存 + 重拉资料
|
||||
* 由 AdminUserProfileUpdateConsumer 监听 system 模块的 AdminUserProfileUpdateMessage 后,批量推送给资料被改的人的所有好友;
|
||||
* 前端 dispatcher 收到后调 loadFriendInfo 重拉资料
|
||||
* <p>
|
||||
* 此处 friendUserId 表示「资料被更新的那个人」(即对端),与 operatorUserId 一致
|
||||
*/
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.system.api.message.user;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 管理员用户资料(昵称 / 头像)变更消息
|
||||
* <p>
|
||||
* 仅当 nickname 或 avatar 真的发生变化时才发送;订阅方据此做下游分发,
|
||||
* 例如 IM 模块向该用户的所有好友推送 FRIEND_INFO_UPDATED 通知
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class AdminUserProfileUpdateMessage {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
/**
|
||||
* 变更后的昵称(无变更时为 null)
|
||||
*/
|
||||
private String nickname;
|
||||
/**
|
||||
* 变更后的头像(无变更时为 null)
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.system.mq.producer.user;
|
||||
|
||||
import cn.iocoder.yudao.module.system.api.message.user.AdminUserProfileUpdateMessage;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 管理员用户 Producer
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AdminUserProducer {
|
||||
|
||||
@Resource
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* 发送 {@link AdminUserProfileUpdateMessage} 消息
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param nickname 变更后的昵称(无变更传 null)
|
||||
* @param avatar 变更后的头像(无变更传 null)
|
||||
*/
|
||||
public void sendUserProfileUpdateMessage(Long userId, String nickname, String avatar) {
|
||||
applicationContext.publishEvent(new AdminUserProfileUpdateMessage()
|
||||
.setUserId(userId).setNickname(nickname).setAvatar(avatar));
|
||||
}
|
||||
|
||||
}
|
||||
+27
-3
@@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.user.AdminUserProducer;
|
||||
import cn.iocoder.yudao.module.system.service.dept.DeptService;
|
||||
import cn.iocoder.yudao.module.system.service.dept.PostService;
|
||||
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
|
||||
@@ -88,6 +89,9 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
@Resource
|
||||
private ConfigApi configApi;
|
||||
|
||||
@Resource
|
||||
private AdminUserProducer adminUserProducer;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}",
|
||||
@@ -158,6 +162,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
userMapper.updateById(updateObj);
|
||||
// 2.2 更新岗位
|
||||
updateUserPost(updateReqVO, updateObj);
|
||||
// 2.3 昵称 / 头像变化时,发送消息供下游订阅(如 IM 模块推 FRIEND_INFO_UPDATED)
|
||||
publishUserProfileUpdatedIfChanged(oldUser, updateReqVO.getNickname(), updateReqVO.getAvatar());
|
||||
|
||||
// 3. 记录操作日志上下文
|
||||
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldUser, UserSaveReqVO.class));
|
||||
@@ -188,12 +194,30 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
|
||||
@Override
|
||||
public void updateUserProfile(Long id, UserProfileUpdateReqVO reqVO) {
|
||||
// 校验正确性
|
||||
validateUserExists(id);
|
||||
// 1. 校验正确性
|
||||
AdminUserDO oldUser = validateUserExists(id);
|
||||
validateEmailUnique(id, reqVO.getEmail());
|
||||
validateMobileUnique(id, reqVO.getMobile());
|
||||
// 执行更新
|
||||
|
||||
// 2. 执行更新
|
||||
userMapper.updateById(BeanUtils.toBean(reqVO, AdminUserDO.class).setId(id));
|
||||
|
||||
// 3. 昵称 / 头像变化时,发送消息供下游订阅(如 IM 模块推 FRIEND_INFO_UPDATED)
|
||||
publishUserProfileUpdatedIfChanged(oldUser, reqVO.getNickname(), reqVO.getAvatar());
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅当 nickname 或 avatar 跟旧值不一致时,发送 AdminUserProfileUpdateMessage
|
||||
*/
|
||||
private void publishUserProfileUpdatedIfChanged(AdminUserDO oldUser, String newNickname, String newAvatar) {
|
||||
boolean nicknameChanged = newNickname != null && !ObjUtil.equal(oldUser.getNickname(), newNickname);
|
||||
boolean avatarChanged = newAvatar != null && !ObjUtil.equal(oldUser.getAvatar(), newAvatar);
|
||||
if (!nicknameChanged && !avatarChanged) {
|
||||
return;
|
||||
}
|
||||
adminUserProducer.sendUserProfileUpdateMessage(oldUser.getId(),
|
||||
nicknameChanged ? newNickname : null,
|
||||
avatarChanged ? newAvatar : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user