diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java index afd6bfe7ba..091f3af3f5 100644 --- a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java @@ -1,8 +1,11 @@ package cn.iocoder.yudao.module.im.enums.conversation; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.Arrays; + /** * IM 会话类型枚举 * 参考 “会话类型” 文档 @@ -11,12 +14,14 @@ import lombok.Getter; */ @Getter @AllArgsConstructor -public enum ConversationTypeEnum { +public enum ConversationTypeEnum implements IntArrayValuable { SINGLE(1, "单聊"), GROUP(3, "群聊"), NOTIFICATION(4, "通知会话"); + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ConversationTypeEnum::getType).toArray(); + /** * 类型 */ @@ -27,6 +32,11 @@ public enum ConversationTypeEnum { */ private final String name; + @Override + public int[] array() { + return ARRAYS; + } + /** * 生成会话编号 * @param fromUserId 发送者编号 diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/InboxServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/InboxServiceImpl.java index 472d297fc8..20df49d017 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/InboxServiceImpl.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/InboxServiceImpl.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.im.dal.redis.inbox.InboxLockRedisDAO; import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceRedisDao; import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum; import cn.iocoder.yudao.module.im.service.groupmember.GroupMemberService; +import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi; import jakarta.annotation.Resource; import org.dromara.hutool.core.date.DateUnit; import org.springframework.stereotype.Service; @@ -38,7 +39,7 @@ public class InboxServiceImpl implements InboxService { @Resource private InboxLockRedisDAO inboxLockRedisDAO; // 收件箱的锁 Redis DAO @Resource - private WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器 + private WebSocketSenderApi webSocketSenderApi; @Resource private GroupMemberService groupMemberService; @@ -71,7 +72,7 @@ public class InboxServiceImpl implements InboxService { InboxSendMessageReqVO message = BeanUtils.toBean(inboxSaveMessage, InboxSendMessageReqVO.class); message.setSequence(userSequence); - webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message); + webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message); }); } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java index 4f837b0c53..0ca4748575 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java @@ -88,13 +88,15 @@ public class MessageServiceImpl implements MessageService { messageMapper.insert(messageDO); // 设置 InboxSaveMessageReqVO 对象 - inboxSaveMessageReqVO.setConversationType(message.getConversationType()); - inboxSaveMessageReqVO.setFromId(fromUserId); - inboxSaveMessageReqVO.setReceiverId(message.getReceiverId()); - inboxSaveMessageReqVO.setMessageId(messageDO.getId()); - inboxSaveMessageReqVO.setContentType(message.getContentType()); - inboxSaveMessageReqVO.setContent(message.getContent()); - inboxSaveMessageReqVO.setSendTime(messageDO.getSendTime()); + inboxSaveMessageReqVO.setConversationType(message.getConversationType()) + .setFromId(fromUserId) + .setReceiverId(message.getReceiverId()) + .setMessageId(messageDO.getId()) + .setContentType(message.getContentType()) + .setContent(message.getContent()) + .setSendTime(messageDO.getSendTime()) + .setSenderNickname(fromUser.getNickname()) + .setSenderAvatar(fromUser.getAvatar()); // 返回 SendMessageRespVO 对象 return new SendMessageRespVO(messageDO.getId(), messageDO.getSendTime()); diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java new file mode 100644 index 0000000000..21cbdbc27e --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.im.websocket; + +import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; +import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; +import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; +import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketSession; + +// TODO @hao:消息发送,使用 http 上行。因为在 cloud 框架下,我们比较难去 Listener。因为 im-server 不会自己启动 websocket 路径 + +/** + * WebSocket im + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class ImWebSocketMessageListener implements WebSocketMessageListener { + + public static final String IM_MESSAGE_RECEIVE = "im-message-receive"; + @Resource + private WebSocketSenderApi webSocketSenderApi; // WebSocket消息发送器 + + /** + * 处理WebSocket消息 + * + * @param session WebSocket会话 + * @param message 发送的IM消息 + */ + @Override + public void onMessage(WebSocketSession session, ImSendMessage message) { + Long fromUserId = WebSocketFrameworkUtils.getLoginUserId(session); // 获取登录用户ID + log.info(message.toString()); + } + + /** + * 获取类型 + * + * @return 类型 + */ + @Override + public String getType() { + return "im-message-send"; + } + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImReceiveMessage.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImReceiveMessage.java new file mode 100644 index 0000000000..87d8df592f --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImReceiveMessage.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.im.websocket.message; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 消息发送 receive") +@Data +public class ImReceiveMessage { + + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(ConversationTypeEnum.class) + private Integer conversationType; + + @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long fromId; // 根据 conversationType 区分 + + // TODO @hao:昵称和头像,也直接发给接收人好了; + + @Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454") + private Long messageId; + + @Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer contentType; // 参见 ImMessageTypeEnum 枚举 + + @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime sendTime; + + @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long sequence; + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImSendMessage.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImSendMessage.java new file mode 100644 index 0000000000..77e37a3cb5 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImSendMessage.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.im.websocket.message; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - IM 消息发送 send") +@Data +public class ImSendMessage { + + @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331") + private String clientMessageId; + + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(ConversationTypeEnum.class) + private Integer conversationType; + + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long receiverId; // 根据 conversationType 区分 + + @Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(MessageContentTypeEnum.class) + private Integer contentType; + + @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + +} \ No newline at end of file