diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java index cfe63d8..4938097 100644 --- a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java @@ -1,5 +1,5 @@ /** * @author anhaohao - * @date 2024/3/9 下午8:59 TODO @hao:没有 @date 这个,应该是 @since 哈 + * @since 2024/3/9 下午8:59 */ package cn.iocoder.yudao.module.im.api; \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java index c56f5da..3232338 100644 --- a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/ErrorCodeConstants.java @@ -17,6 +17,7 @@ public interface ErrorCodeConstants { // ========== 消息 (1-040-300-000) ========== ErrorCode MESSAGE_NOT_EXISTS = new ErrorCode(1_040_300_000, "消息不存在"); + ErrorCode MESSAGE_RECEIVER_NOT_EXISTS = new ErrorCode(1_040_300_001, "接收人不存在"); // ========== 群 (1-040-400-000) ========== ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_040_400_000, "群不存在"); diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ImConversationTypeEnum.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java index bef578a..afd6bfe 100644 --- a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ImConversationTypeEnum.java +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java @@ -4,26 +4,43 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * IM 会话的类型枚举 + * IM 会话类型枚举 + * 参考 “会话类型” 文档 * - * @author 芋道源码 + * @author anhaohao */ @Getter @AllArgsConstructor -public enum ImConversationTypeEnum { +public enum ConversationTypeEnum { - // TODO @hao:单聊,我们使用 SINGLE,主要 private 这个单词在 java 里太特殊了; - PRIVATE(1, "单聊"), - GROUP(2, "群聊"), - NOTICE(4, "通知会话"); + SINGLE(1, "单聊"), + GROUP(3, "群聊"), + NOTIFICATION(4, "通知会话"); /** * 类型 */ private final Integer type; + /** * 名字 */ private final String name; + /** + * 生成会话编号 + * @param fromUserId 发送者编号 + * @param receiverId 接收者编号 + * @param conversationType 会话类型 + * @return 会话编号 + */ + public static String generateConversationNo(Long fromUserId, Long receiverId, Integer conversationType) { + if (conversationType.equals(ConversationTypeEnum.SINGLE.getType())) { + return "s_" + fromUserId + "_" + receiverId; + } else if (conversationType.equals(ConversationTypeEnum.GROUP.getType())) { + return "g_" + receiverId; + } + return null; + } + } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java deleted file mode 100644 index 984f62b..0000000 --- a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.yudao.module.im.enums.message; - -import cn.iocoder.yudao.framework.common.core.IntArrayValuable; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.util.Arrays; - -// TODO @hao:类型保持和 openim 一致 -/** - * IM 消息的类型枚举 - *

- * 参考 “消息类型” 文档 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum ImMessageTypeEnum implements IntArrayValuable { - - TEXT(1, "文本"), // 消息内容为普通文本 - IMAGE(2, "图片"), // 消息内容为图片 URL 地址、尺寸、图片大小等信息 - AUDIO(3, "语音"), // 消息内容为语音文件的 URL 地址、时长、大小、格式等信息 - VIDEO(4, "视频"), // 消息内容为视频文件的 URL 地址、时长、大小、格式等信息 - FILE(5, "文件"), // 消息内容为文件的 URL 地址、大小、格式等信息 - LOCATION(6, "地理位置"), // 消息内容为地理位置标题、经度、纬度信息 - // TODO @芋艿:下面两种,貌似企业微信设计的更好:https://developer.work.weixin.qq.com/document/path/90240 - TIP(7, "提示"), // 又叫做 Tip 消息,没有推送和通知栏提醒,主要用于会话内的通知提醒,例如进入会话时出现的欢迎消息,或是会话过程中命中敏感词后的提示消息等场景 - NOTIFICATION(8, "通知"), // 主要用于群组、聊天室和超大群的事件通知,由服务端下发,客户端无法发送事件通知消息。通知类消息有在线、离线、漫游机制;没有通知栏提醒 - ; - - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageTypeEnum::getType).toArray(); - /** - * 类型 - */ - private final Integer type; - /** - * 名字 - */ - private final String name; - - @Override - public int[] array() { - return ARRAYS; - } - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageContentTypeEnum.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageContentTypeEnum.java new file mode 100644 index 0000000..580ed21 --- /dev/null +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageContentTypeEnum.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.im.enums.message; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + + +/** + * IM 消息的类型枚举 + *

+ * 参考 “消息类型” 文档 + * + * @author anhaohao + */ +@Getter +@AllArgsConstructor +public enum MessageContentTypeEnum implements IntArrayValuable { + + TEXT(101, "文本消息"), + PICTURE(102, "图片消息"), + VOICE(103, "语音消息"), + VIDEO(104, "视频消息"), + FILE(105, "文件消息"), + AT_TEXT(106, "@消息"), + MERGE(107, "合并消息"), + CARD(108, "名片消息"), + LOCATION(109, "位置消息"), + CUSTOM(110, "自定义消息"), + REVOKE_RECEIPT(111, "撤回消息回执"), + C2C_RECEIPT(112, "单聊消息回执"), + TYPING(113, "输入状态"), + QUOTE(114, "引用消息"), + FACE(115, "表情消息"), + ADVANCED_REVOKE(118, "高级撤回消息"), + //好友通知 1200-1299 + FRIEND_ADDED(1201, "双方成为好友通知"), + //系统通知 1400 + OA_NOTIFICATION(1400, "系统通知"), + //群相关 1500-1599 + GROUP_CREATED(1501, "群创建通知"), + GROUP_INFO_CHANGED(1502, "群信息改变通知"), + MEMBER_QUIT(1504, "群成员退出通知"), + GROUP_OWNER_CHANGED(1507, "群主更换通知"), + MEMBER_KICKED(1508, "群成员被踢通知"), + MEMBER_INVITED(1509, "邀请群成员通知"), + MEMBER_ENTER(1510, "群成员进群通知"), + GROUP_DISMISSED(1511, "解散群通知"), + GROUP_MEMBER_MUTED(1512, "群成员禁言通知"), + GROUP_MEMBER_CANCEL_MUTED(1513, "取消群成员禁言通知"), + GROUP_MUTED(1514, "群禁言通知"), + GROUP_CANCEL_MUTED(1515, "取消群禁言通知"), + GROUP_ANNOUNCEMENT_UPDATED(1519, "群公告改变通知"), + GROUP_NAME_UPDATED(1520, "群名称改变通知"), + + BURN_CHANGE(1701, "阅后即焚开启或关闭通知"), + REVOKE(2101, "撤回消息通知");; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageContentTypeEnum::getType).toArray(); + + /** + * 类型 + */ + private final Integer type; + + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageSourceEnum.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageSourceEnum.java new file mode 100644 index 0000000..3b04c97 --- /dev/null +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageSourceEnum.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.im.enums.message; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IM 消息的消息来源 100-用户发送;200-系统发送(一般是通知);不能为空 + */ +@RequiredArgsConstructor +@Getter +public enum MessageSourceEnum implements IntArrayValuable { + + USER_SEND(100, "用户发送"), + SYSTEM_SEND(200, "系统发送"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageSourceEnum::getStatus).toArray(); + + /** + * 状态 + */ + private final Integer status; + + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageStatusEnum.java index d2ce4e4..389d9fd 100644 --- a/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java +++ b/yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageStatusEnum.java @@ -6,21 +6,27 @@ import lombok.RequiredArgsConstructor; import java.util.Arrays; -// TODO @hao:注释哈; +/** + * IM 消息的状态枚举 + */ @RequiredArgsConstructor @Getter -public enum ImMessageStatusEnum implements IntArrayValuable { +public enum MessageStatusEnum implements IntArrayValuable { SENDING(1, "发送中"), - SUCCESS(2, "发送成功"), - FAILURE(3, "发送失败"), - DELETED(4, "已删除"), - RECALL(5, "已撤回"); - - // TODO @hao:静态变量,和普通变量,最好空一行; - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageStatusEnum::getStatus).toArray(); - // TODO @hao:注释哈; + SUCCEED(2, "发送成功"), + FAILED(3, "发送失败"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageStatusEnum::getStatus).toArray(); + + /** + * 状态 + */ private final Integer status; + + /** + * 名字 + */ private final String name; @Override diff --git a/yudao-module-im/yudao-module-im-biz/pom.xml b/yudao-module-im/yudao-module-im-biz/pom.xml index a6d1bff..058c10a 100644 --- a/yudao-module-im/yudao-module-im-biz/pom.xml +++ b/yudao-module-im/yudao-module-im-biz/pom.xml @@ -5,19 +5,19 @@ yudao-module-im cn.iocoder.boot - ${revision} + ${revision} 4.0.0 - jar + jar yudao-module-im-biz - ${project.artifactId} - + ${project.artifactId} + im 模块,主要实现 im 模块的业务逻辑。 - + cn.iocoder.boot yudao-module-im-api @@ -41,34 +41,34 @@ yudao-spring-boot-starter-security + + cn.iocoder.boot + yudao-spring-boot-starter-websocket + + cn.iocoder.boot yudao-spring-boot-starter-mybatis - cn.iocoder.boot - yudao-spring-boot-starter-test + yudao-spring-boot-starter-redis - - + cn.iocoder.boot yudao-spring-boot-starter-excel + + cn.iocoder.boot - yudao-spring-boot-starter-websocket + yudao-spring-boot-starter-test - - - org.redisson - redisson-spring-boot-starter - \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ConversationController.java index c94140b..6276c15 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationController.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ConversationController.java @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationRespVO; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; -import cn.iocoder.yudao.module.im.service.conversation.ImConversationService; +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO; +import cn.iocoder.yudao.module.im.service.conversation.ConversationService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -19,22 +19,22 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; // TODO @hao: 管理后台 - IM 会话 -@Tag(name = "管理后台 - 会话") +@Tag(name = "管理后台 - IM 会话") @RestController @RequestMapping("/im/conversation") @Validated -public class ImConversationController { +public class ConversationController { // TODO @hao: conversationService 即可 @Resource - private ImConversationService imConversationService; + private ConversationService conversationService; // TODO @hao:/list 会话列表;一般 get 是给单个对象,或者 get-count 这种;然后 conversation 已经是模块名了,所以可以简化 @GetMapping("/get-conversation") @Operation(summary = "获得用户的会话列表") @PreAuthorize("hasAuthority('im:conversation:query')") // TODO @hao:不用权限哈 public CommonResult> getConversationList() { - List conversationList = imConversationService.getConversationList(); + List conversationList = conversationService.getConversationList(); return success(BeanUtils.toBean(conversationList, ImConversationRespVO.class)); } @@ -44,7 +44,7 @@ public class ImConversationController { @Operation(summary = "置顶会话") @PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的 public CommonResult updateTop(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) { - imConversationService.updateTop(updateReqVO); + conversationService.updateTop(updateReqVO); return success(true); } @@ -54,7 +54,7 @@ public class ImConversationController { @Operation(summary = "更新最后已读时间") @PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的 public CommonResult updateLastReadTime(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) { - imConversationService.updateLastReadTime(updateReqVO); + conversationService.updateLastReadTime(updateReqVO); return success(true); } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationPageReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationPageReqVO.java index c3a24b3..e1308d8 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationPageReqVO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationPageReqVO.java @@ -22,7 +22,7 @@ public class ImConversationPageReqVO extends PageParam { private Long userId; @Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", example = "1") - private Integer conversationType; + private Integer type; @Schema(description = "单聊时,用户编号;群聊时,群编号", example = "21454") private Long targetId; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationSaveReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationSaveReqVO.java index 58d7123..b226f16 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationSaveReqVO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ImConversationSaveReqVO.java @@ -21,7 +21,7 @@ public class ImConversationSaveReqVO { @Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "类型:1 单聊;2 群聊;4 通知会话(预留)不能为空") - private Integer conversationType; + private Integer type; @Schema(description = "单聊时,用户编号;群聊时,群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21454") @NotEmpty(message = "单聊时,用户编号;群聊时,群编号不能为空") diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java index a1afcc9..abd97bf 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java @@ -25,7 +25,7 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO; import cn.iocoder.yudao.module.im.service.group.ImGroupService; @Tag(name = "管理后台 - 群") @@ -66,7 +66,7 @@ public class ImGroupController { @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('im:group:query')") public CommonResult getGroup(@RequestParam("id") Long id) { - ImGroupDO group = imGroupService.getGroup(id); + GroupDO group = imGroupService.getGroup(id); return success(BeanUtils.toBean(group, ImGroupRespVO.class)); } @@ -74,7 +74,7 @@ public class ImGroupController { @Operation(summary = "获得群分页") @PreAuthorize("@ss.hasPermission('im:group:query')") public CommonResult> getGroupPage(@Valid ImGroupPageReqVO pageReqVO) { - PageResult pageResult = imGroupService.getGroupPage(pageReqVO); + PageResult pageResult = imGroupService.getGroupPage(pageReqVO); return success(BeanUtils.toBean(pageResult, ImGroupRespVO.class)); } @@ -85,7 +85,7 @@ public class ImGroupController { public void exportGroupExcel(@Valid ImGroupPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = imGroupService.getGroupPage(pageReqVO).getList(); + List list = imGroupService.getGroupPage(pageReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "群.xls", "数据", ImGroupRespVO.class, BeanUtils.toBean(list, ImGroupRespVO.class)); diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/ImGroupMemberController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/ImGroupMemberController.java index c715b63..1a70ebb 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/ImGroupMemberController.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/ImGroupMemberController.java @@ -9,7 +9,7 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberRespVO; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO; import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/ImInboxController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/ImInboxController.java index 4912f72..4459d49 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/ImInboxController.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/ImInboxController.java @@ -8,8 +8,8 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxRespVO; -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO; +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO; import cn.iocoder.yudao.module.im.service.inbox.ImInboxService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -39,14 +39,14 @@ public class ImInboxController { @PostMapping("/create") @Operation(summary = "创建收件箱") @PreAuthorize("@ss.hasPermission('im:inbox:create')") - public CommonResult createInbox(@Valid @RequestBody ImInboxSaveReqVO createReqVO) { + public CommonResult createInbox(@Valid @RequestBody InboxSaveReqVO createReqVO) { return success(imInboxService.createInbox(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新收件箱") @PreAuthorize("@ss.hasPermission('im:inbox:update')") - public CommonResult updateInbox(@Valid @RequestBody ImInboxSaveReqVO updateReqVO) { + public CommonResult updateInbox(@Valid @RequestBody InboxSaveReqVO updateReqVO) { imInboxService.updateInbox(updateReqVO); return success(true); } @@ -65,7 +65,7 @@ public class ImInboxController { @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('im:inbox:query')") public CommonResult getInbox(@RequestParam("id") Long id) { - ImInboxDO inbox = imInboxService.getInbox(id); + InboxDO inbox = imInboxService.getInbox(id); return success(BeanUtils.toBean(inbox, ImInboxRespVO.class)); } @@ -73,7 +73,7 @@ public class ImInboxController { @Operation(summary = "获得收件箱分页") @PreAuthorize("@ss.hasPermission('im:inbox:query')") public CommonResult> getInboxPage(@Valid ImInboxPageReqVO pageReqVO) { - PageResult pageResult = imInboxService.getInboxPage(pageReqVO); + PageResult pageResult = imInboxService.getInboxPage(pageReqVO); return success(BeanUtils.toBean(pageResult, ImInboxRespVO.class)); } @@ -84,7 +84,7 @@ public class ImInboxController { public void exportInboxExcel(@Valid ImInboxPageReqVO pageReqVO, HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = imInboxService.getInboxPage(pageReqVO).getList(); + List list = imInboxService.getInboxPage(pageReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "收件箱.xls", "数据", ImInboxRespVO.class, BeanUtils.toBean(list, ImInboxRespVO.class)); diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveMessageReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveMessageReqVO.java new file mode 100644 index 0000000..f48a002 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveMessageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.im.controller.admin.inbox.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 收件箱保存消息 Request VO") +@Data +public class InboxSaveMessageReqVO { + + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer conversationType; // 对应 ImConversationTypeEnum 枚举 + + @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long fromId; // 根据 conversationType 区分 + + @Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String senderNickname; + + @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED) + private String senderAvatar; + + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494") + private Long receiverId; + + @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/controller/admin/inbox/vo/ImInboxSaveReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveReqVO.java index 678be51..b44a2b7 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/ImInboxSaveReqVO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveReqVO.java @@ -11,7 +11,7 @@ import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor -public class ImInboxSaveReqVO { +public class InboxSaveReqVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389") private Long id; @@ -28,7 +28,7 @@ public class ImInboxSaveReqVO { @NotNull(message = "序号,按照 user 递增不能为空") private Long sequence; - public ImInboxSaveReqVO(Long userId, Long messageId, Long sequence) { + public InboxSaveReqVO(Long userId, Long messageId, Long sequence) { this.userId = userId; this.messageId = messageId; this.sequence = sequence; 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/controller/admin/inbox/vo/InboxSendMessageReqVO.java index 23a1ad6..ae58c5e 100644 --- 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/controller/admin/inbox/vo/InboxSendMessageReqVO.java @@ -1,13 +1,13 @@ -package cn.iocoder.yudao.module.im.websocket.message; +package cn.iocoder.yudao.module.im.controller.admin.inbox.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDateTime; -@Schema(description = "管理后台 - 消息发送 receive") +@Schema(description = "管理后台 - 收件箱保存消息 Request VO") @Data -public class ImReceiveMessage { +public class InboxSendMessageReqVO { @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer conversationType; // 对应 ImConversationTypeEnum 枚举 @@ -15,7 +15,14 @@ public class ImReceiveMessage { @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Long fromId; // 根据 conversationType 区分 - // TODO @hao:昵称和头像,也直接发给接收人好了; + @Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") + private String senderNickname; + + @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED) + private String senderAvatar; + + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494") + private Long receiverId; @Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454") private Long messageId; @@ -29,10 +36,6 @@ public class ImReceiveMessage { @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime sendTime; - // TODO @hao:inboxId 不需要哈; - @Schema(description = "收件箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389") - private Long inboxId; - @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED) private Long sequence; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.java deleted file mode 100755 index 91026f8..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.message; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageRespVO; -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; -import cn.iocoder.yudao.module.im.service.message.ImMessageService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.validation.Valid; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -@Tag(name = "管理后台 - IM 消息") -@RestController -@RequestMapping("/im/message") -@Validated -public class ImMessageController { - - @Resource - private ImMessageService imMessageService; - - @GetMapping("/get-message-by-sequence") // TODO @hao:list-by-sequence - @Operation(summary = "拉取消息-增量拉取大于 seq 的消息") // TODO @hao:可以改成 拉取大于 sequence 的消息列表 - @Parameter(name = "sequence", description = "序号", required = true, example = "1") - @Parameter(name = "size", description = "条数", required = true, example = "10") - @PreAuthorize("@ss.hasPermission('im:message:query')") // TODO @hao:权限可以删除哈; - public CommonResult> loadMessage(@RequestParam("sequence") Long sequence, - @RequestParam("size") Integer size) { - // TODO @hao:方法名,可以改成 getMessageListBySequence - // TODO @hao:如果是返回列表,变量要用 messages, 或者 messageList,体现出是复数 - List message = imMessageService.loadMessage(getLoginUserId(), sequence, size); - return success(BeanUtils.toBean(message, ImMessageRespVO.class)); - } - - // TODO @hao:这个接口的使用场景是哪个哈? - @GetMapping("/get-all-message") - @Operation(summary = "拉取全部消息") - @Parameter(name = "size", description = "条数", required = true, example = "10") - @PreAuthorize("@ss.hasPermission('im:message:query')") - public CommonResult> loadAllMessage(@RequestParam("size") Integer size) { - List message = imMessageService.loadAllMessage(getLoginUserId(), size); - return success(BeanUtils.toBean(message, ImMessageRespVO.class)); - } - - // TODO @hao:是不是分页参数不太对哈?应该只有 conversationNo,sendTime 字段;然后,做链式分页的查询,不太适合传统的 pageSize + number 查询; - @GetMapping("/page") - @Operation(summary = "查询聊天记录-分页") - @PreAuthorize("@ss.hasPermission('im:message:query')") // TODO @hao:权限可以删除哈; - public CommonResult> getMessagePage(@Valid ImMessagePageReqVO pageReqVO) { - PageResult messagePage = imMessageService.getMessagePage(pageReqVO); - return success(BeanUtils.toBean(messagePage, ImMessageRespVO.class)); - } - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/MessageController.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/MessageController.java new file mode 100755 index 0000000..fc5d33a --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/MessageController.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.im.controller.admin.message; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; +import cn.iocoder.yudao.module.im.service.message.MessageService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +@Tag(name = "管理后台 - IM 消息") +@RestController +@RequestMapping("/im/message") +@Validated +public class MessageController { + + @Resource + private MessageService messageService; + + @PostMapping("/send") + @Operation(summary = "发送消息") + public CommonResult sendMessage(@Valid @RequestBody SendMessageReqVO message) { + return success(messageService.sendMessage(getLoginUserId(), message)); + } + + @GetMapping("/list-by-sequence") + @Operation(summary = "拉取大于 sequence 的消息列表") + @Parameter(name = "sequence", description = "序号", required = true, example = "1") + @Parameter(name = "size", description = "条数", required = true, example = "10") + public CommonResult> loadMessage(@RequestParam("sequence") Long sequence, + @RequestParam("size") Integer size) { + List messages = messageService.getMessageListBySequence(getLoginUserId(), sequence, size); + return success(BeanUtils.toBean(messages, ImMessageReqVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "查询聊天记录-分页") + public CommonResult> getMessagePage(@Valid MessagePageReqVO pageReqVO) { + //根据会话标志和发送时间进行分页查询 + List messagePage = messageService.getMessagePage(pageReqVO); + return success(BeanUtils.toBean(messagePage, ImMessageReqVO.class)); + } + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessagePageReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessagePageReqVO.java deleted file mode 100755 index ed8c2db..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessagePageReqVO.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.im.controller.admin.message.vo; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import com.alibaba.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.springframework.format.annotation.DateTimeFormat; - -import java.time.LocalDateTime; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@Schema(description = "管理后台 - 消息分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class ImMessagePageReqVO extends PageParam { - - @Schema(description = "客户端消息编号 uuid,用于排重", example = "3331") - private String clientMessageId; - - @Schema(description = "发送人编号", example = "23239") - private Long senderId; - - @Schema(description = "接收人编号", example = "32494") - private Long receiverId; - - @Schema(description = "发送人昵称", example = "李四") - private String senderNickname; - - @Schema(description = "发送人头像") - private String senderAvatar; - - @Schema(description = "会话类型", example = "2") - private Integer conversationType; - - @Schema(description = "会话标志") - private String conversationNo; - - @Schema(description = "消息类型", example = "1") - private Integer contentType; - - @Schema(description = "消息内容") - private String content; - - @Schema(description = "发送时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] sendTime; - - @Schema(description = "消息来源 100-用户发送;200-系统发送(一般是通知);") - private Integer sendFrom; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - - @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED) - private Integer messageStatus; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageRespVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageReqVO.java index 19e3886..0f0d4f2 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageRespVO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageReqVO.java @@ -1,77 +1,36 @@ package cn.iocoder.yudao.module.im.controller.admin.message.vo; import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; -import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; import lombok.Data; -import java.time.LocalDateTime; - -@Schema(description = "管理后台 - 消息 Response VO") +@Schema(description = "管理后台 - 消息 Request VO") @Data @ExcelIgnoreUnannotated -public class ImMessageRespVO { - - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30713") - @ExcelProperty("编号") - private Long id; +public class ImMessageReqVO { @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331") @ExcelProperty("客户端消息编号 uuid,用于排重") private String clientMessageId; - @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23239") - @ExcelProperty("发送人编号") - private Long senderId; - @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494") @ExcelProperty("接收人编号") private Long receiverId; - @Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") - @ExcelProperty("发送人昵称") - private String senderNickname; - - @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("发送人头像") - private String senderAvatar; - @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @ExcelProperty("会话类型") private Integer conversationType; - @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("会话标志") - private String conversationNo; - @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty("消息类型") - @InEnum(ImMessageTypeEnum.class) + @InEnum(MessageContentTypeEnum.class) private Integer contentType; @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("消息内容") private String content; - @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("发送时间") - private LocalDateTime sendTime; - - @Schema(description = "消息来源 100-用户发送;200-系统发送(一般是通知);", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("消息来源 100-用户发送;200-系统发送(一般是通知);") - private Integer sendFrom; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("消息状态") - @InEnum(ImMessageStatusEnum.class) - private Integer messageStatus; - } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/MessagePageReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/MessagePageReqVO.java new file mode 100755 index 0000000..01e7b70 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/MessagePageReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.im.controller.admin.message.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 消息分页 Request VO") +@Data +@ToString(callSuper = true) +public class MessagePageReqVO { + + @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "g_1000") + private String conversationNo; + + @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-27") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] sendTime; + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageReqVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageReqVO.java new file mode 100755 index 0000000..dd97a9c --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.im.controller.admin.message.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 发送消息 Request VO") +@Data +@ExcelIgnoreUnannotated +public class SendMessageReqVO { + + @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331") + @ExcelProperty("客户端消息编号 uuid,用于排重") + private String clientMessageId; + + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494") + @ExcelProperty("接收人编号") + private Long receiverId; + + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @ExcelProperty("会话类型") + private Integer conversationType; + + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("消息类型") + @InEnum(MessageContentTypeEnum.class) + private Integer contentType; + + @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("消息内容") + private String content; + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageRespVO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageRespVO.java new file mode 100755 index 0000000..79ac757 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.im.controller.admin.message.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 发送消息 Response VO") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SendMessageRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12") + private Long id; + + @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-27 12:00:00") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime sendTime; + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationDO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ConversationDO.java index 5a6fabd..0f8f22e 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationDO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ConversationDO.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.im.dal.dataobject.conversation; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -21,31 +22,28 @@ import java.time.LocalDateTime; @Builder @NoArgsConstructor @AllArgsConstructor -public class ImConversationDO extends BaseDO { +public class ConversationDO extends BaseDO { /** * 编号 */ @TableId private Long id; + /** * 所属用户 */ private Long userId; - // TODO @hao:注释可以改成,如下 + /** * 会话类型 - * - * 枚举 {@link cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum} - */ - /** - * 类型:1 单聊;2 群聊;4 通知会话(预留) + *

+ * 枚举 {@link ConversationTypeEnum} */ - // TODO @hao:conversationType 改成 type - private Integer conversationType; + private Integer type; /** * 聊天对象编号 - * + *

* 1. 单聊时,用户编号;群聊时,群编号 */ private Long targetId; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupDO.java index edd2b33..ce6b1a6 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupDO.java @@ -1,8 +1,10 @@ package cn.iocoder.yudao.module.im.dal.dataobject.group; -import lombok.*; -import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * IM 群信息 DO @@ -17,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @Builder @NoArgsConstructor @AllArgsConstructor -public class ImGroupDO extends BaseDO { +public class GroupDO extends BaseDO { /** * 编号 diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/groupmember/GroupMemberDO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupMemberDO.java index dc97b94..0ccffee 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/groupmember/GroupMemberDO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupMemberDO.java @@ -1,13 +1,9 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.groupmember; +package cn.iocoder.yudao.module.im.dal.dataobject.group; import lombok.*; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.*; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -// TODO @hao:这个挪到 group 包下; /** * IM 群成员 DO * diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/inbox/ImInboxDO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/inbox/InboxDO.java index 6f92474..62accc3 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/inbox/ImInboxDO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/inbox/InboxDO.java @@ -20,7 +20,7 @@ import lombok.*; @Builder @NoArgsConstructor @AllArgsConstructor -public class ImInboxDO extends BaseDO { +public class InboxDO extends BaseDO { /** * 编号 diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImMessageDO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/MessageDO.java index 2b1646c..7f89a93 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImMessageDO.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/MessageDO.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.im.dal.dataobject.message; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageSourceEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageStatusEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -21,7 +25,7 @@ import java.time.LocalDateTime; @Builder @NoArgsConstructor @AllArgsConstructor -public class ImMessageDO extends BaseDO { +public class MessageDO extends BaseDO { /** * 编号 @@ -32,57 +36,54 @@ public class ImMessageDO extends BaseDO { * 客户端消息编号 uuid,用于排重 */ private String clientMessageId; - // TODO @hao:senderId、receiverId 存储的具体值写下,对应的群之类的 /** - * 发送人编号 + * 发送人编号 存储的是用户编号 */ private Long senderId; /** * 接收人编号 + *

+ * 1. 单聊时,用户编号;群聊时,群编号 */ private Long receiverId; - // TODO @hao:冗余字段,要说明下的。例如说 /** - * 发送人昵称 - * + * 消息发送者昵称 + *

* 冗余 AdminUserDO 的 nickname 字段 */ private String senderNickname; /** - * 发送人头像 + * 消息发送者头像 + *

+ * 冗余 AdminUserDO 的 avatar 字段 */ private String senderAvatar; - // TODO @hao:关联枚举 /** - * 会话类型 + * 会话类型 枚举 {@link ConversationTypeEnum} */ private Integer conversationType; - // TODO @hao:关联字段 /** - * 会话标志 + * 会话标志 {@link ConversationTypeEnum} 的generateConversationNo() 方法生成 */ private String conversationNo; /** - * 消息类型 + * 消息类型 枚举 {@link MessageContentTypeEnum} */ private Integer contentType; - // TODO @hao:说明下是 json 格式,在哪个包看具体的格式 /** - * 消息内容 + * 消息内容 JSON 格式 对应 dal/dataobject/message/content 包 */ private String content; /** * 发送时间 */ private LocalDateTime sendTime; - // TODO @hao:搞个枚举,然后代码里注释说明下 /** - * 消息来源 100-用户发送;200-系统发送(一般是通知); + * 消息来源 枚举 {@link MessageSourceEnum} */ private Integer sendFrom; - // TODO @hao:搞个枚举,然后代码里注释说明下 /** - * 消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回 + * 消息状态 枚举 {@link MessageStatusEnum} */ private Integer messageStatus; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImAudioMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImAudioMessageBody.java deleted file mode 100644 index acc8d84..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImAudioMessageBody.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * 语音消息的 {@link ImMessageBody} - * - * @author 芋道源码 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -public class ImAudioMessageBody implements ImMessageBody { - - /** - * 语音 URL - */ - private String url; - /** - * 语音格式,例如说 arm、mp3、speex 等 - */ - private String format; - - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有 -//"dur":4551, //语音持续时长ms -// "md5":"87b94a090dec5c58f242b7132a530a01", //语音文件的md5值,按照字节流加密 -// "size":16420 //语音文件大小,单位为字节(Byte) - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImMessageBody.java deleted file mode 100644 index e5eddc0..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImMessageBody.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; - - -import cn.iocoder.yudao.module.im.jackson.ImMessageBodyDeserializer; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; - -/** - * IM 消息的 body 内容 - */ -@JsonDeserialize(using = ImMessageBodyDeserializer.class) -public interface ImMessageBody { -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java new file mode 100644 index 0000000..41420ac --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; + +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 语音消息的 {@link MessageDO 字段 content} 的内容 + * + * @author 芋道源码 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AudioMessage { + + /** + * 语音文件唯一 ID + */ + private String uuid; + + /** + * 语音文件的本地路径 + */ + private String soundPath; + + /** + * 语音文件下载地址 + */ + private String sourceUrl; + + /** + * 语音文件大小 + */ + private int dataSize; + + /** + * 语音时长 + */ + private int duration; + + /** + * 语音文件类型 + */ + private String soundType; + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java new file mode 100644 index 0000000..3eff9bf --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; + +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 名片消息的 {@link MessageDO 字段 content} 的内容 + * + * @author anhaohao + * @since 2024/3/23 下午5:53 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CardMessage { + + /** + * 用户 ID + */ + private String userID; + + /** + * 用户名 + */ + private String nickname; + + /** + * 用户头像 + */ + private int faceURL; + + /** + * 扩展字段 + */ + private String ex; +} diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImFileMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java index 2ed2384..2dd2b6b 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImFileMessageBody.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java @@ -1,18 +1,19 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * 文件消息的 {@link ImMessageBody} + * 文件消息的 {@link MessageDO 字段 content} 的内容 * * @author 芋道源码 */ @Data @AllArgsConstructor @NoArgsConstructor -public class ImFileMessageBody implements ImMessageBody { +public class FileMessage { /** * 文件名 @@ -23,9 +24,4 @@ public class ImFileMessageBody implements ImMessageBody { */ private String url; - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有 -// "md5":"79d62a35fa3d34c367b20c66afc2a500", //文件MD5,按照字节流加密 -// "ext":"ttf", //文件后缀类型 -// "size":91680 //大小,单位为字节(Byte) - } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImImageMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java index 1a81c28..cfdfcb1 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImImageMessageBody.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java @@ -1,30 +1,23 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * 图片消息的 {@link ImMessageBody} + * 图片消息的 {@link MessageDO 字段 content} 的内容 * * @author 芋道源码 */ @Data @AllArgsConstructor @NoArgsConstructor -public class ImImageMessageBody implements ImMessageBody { +public class ImageMessage { /** * 图片地址 */ private String url; - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有 -// "name":"图片发送于2015-05-07 13:59", //图片name -// "md5":"9894907e4ad9de4678091277509361f7", //图片文件md5,按照字节流加密 -// "ext":"jpg", //图片后缀 -// "w":6814, //宽,单位为像素 -// "h":2332, //高,单位为像素 -// "size":388245 //图片文件大小,单位为字节(Byte) - } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImLocationMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java index 3e9db26..a95c2d8 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImLocationMessageBody.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java @@ -1,22 +1,23 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * 地址位置消息的 {@link ImMessageBody} + * 地址位置消息的 {@link MessageDO 字段 content} 的内容 * * @author 芋道源码 */ @Data @AllArgsConstructor @NoArgsConstructor -public class ImLocationMessageBody implements ImMessageBody { +public class LocationMessage { /** * 地理位置 - * + *

* 例如说:中国 浙江省 杭州市 网商路 599号 */ private String address; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImTextMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java index 9e6f973..b7f13a4 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImTextMessageBody.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java @@ -1,21 +1,22 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * 文本消息的 {@link ImMessageBody} + * 文本消息的 {@link MessageDO 字段 content} 的内容 * * @author 芋道源码 */ @Data @AllArgsConstructor @NoArgsConstructor -public class ImTextMessageBody implements ImMessageBody { +public class TextMessage { /** - * 文本消息内容 + * 文本消息的具体内容 */ private String content; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImVideoMessageBody.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java index 5d64347..e757e50 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImVideoMessageBody.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java @@ -1,27 +1,19 @@ -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; +package cn.iocoder.yudao.module.im.dal.dataobject.message.content; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; import lombok.Data; /** - * 视频消息的 {@link ImMessageBody} + * 视频消息的 {@link MessageDO 字段 content} 的内容 * * @author 芋道源码 */ @Data -public class ImVideoMessageBody implements ImMessageBody { +public class VideoMessage { /** * 视频地址 */ private String url; - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有 -// "dur":8003, //视频持续时长ms -// "md5":"da2cef3e5663ee9c3547ef5d127f7e3e", //视频文件的md5值,按照字节流加密 -// "w":360, //宽,单位为像素 -// "h":480, //高,单位为像素 -// "size":16420 //视频文件大小,单位为字节(Byte)】 -// "ext":"mp4", //视频格式 - - } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ConversationMapper.java index d4bfb0c..73ade2e 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationMapper.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ConversationMapper.java @@ -4,33 +4,31 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO; import org.apache.ibatis.annotations.Mapper; -import java.util.Optional; - /** * IM 会话 Mapper * * @author 芋道源码 */ @Mapper -public interface ImConversationMapper extends BaseMapperX { +public interface ConversationMapper extends BaseMapperX { - default PageResult selectPage(ImConversationPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(ImConversationDO::getUserId, reqVO.getUserId()) - .eqIfPresent(ImConversationDO::getConversationType, reqVO.getConversationType()) - .eqIfPresent(ImConversationDO::getTargetId, reqVO.getTargetId()) - .eqIfPresent(ImConversationDO::getNo, reqVO.getNo()) - .eqIfPresent(ImConversationDO::getPinned, reqVO.getPinned()) - .betweenIfPresent(ImConversationDO::getLastReadTime, reqVO.getLastReadTime()) - .betweenIfPresent(ImConversationDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(ImConversationDO::getId)); + default PageResult selectPage(ImConversationPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ConversationDO::getUserId, reqVO.getUserId()) + .eqIfPresent(ConversationDO::getType, reqVO.getType()) + .eqIfPresent(ConversationDO::getTargetId, reqVO.getTargetId()) + .eqIfPresent(ConversationDO::getNo, reqVO.getNo()) + .eqIfPresent(ConversationDO::getPinned, reqVO.getPinned()) + .betweenIfPresent(ConversationDO::getLastReadTime, reqVO.getLastReadTime()) + .betweenIfPresent(ConversationDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ConversationDO::getId)); } // TODO @hao:1)no) {,要有空格哈;2)可以直接 selectOne(ImConversationDO::getNo, no) 父类做了封装 - default ImConversationDO selectByNo(String no){ - return selectOne(new LambdaQueryWrapperX().eq(ImConversationDO::getNo, no)); + default ConversationDO selectByNo(String no){ + return selectOne(new LambdaQueryWrapperX().eq(ConversationDO::getNo, no)); } } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java index ac301ee..6049550 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/group/ImGroupMapper.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.dal.mysql.group; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO; import org.apache.ibatis.annotations.Mapper; import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; @@ -13,18 +13,18 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; * @author 芋道源码 */ @Mapper -public interface ImGroupMapper extends BaseMapperX { +public interface ImGroupMapper extends BaseMapperX { - default PageResult selectPage(ImGroupPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(ImGroupDO::getGroupName, reqVO.getGroupName()) - .eqIfPresent(ImGroupDO::getOwnerId, reqVO.getOwnerId()) - .eqIfPresent(ImGroupDO::getHeadImage, reqVO.getHeadImage()) - .eqIfPresent(ImGroupDO::getHeadImageThumb, reqVO.getHeadImageThumb()) - .eqIfPresent(ImGroupDO::getNotice, reqVO.getNotice()) - .eqIfPresent(ImGroupDO::getRemark, reqVO.getRemark()) - .betweenIfPresent(ImGroupDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(ImGroupDO::getId)); + default PageResult selectPage(ImGroupPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(GroupDO::getGroupName, reqVO.getGroupName()) + .eqIfPresent(GroupDO::getOwnerId, reqVO.getOwnerId()) + .eqIfPresent(GroupDO::getHeadImage, reqVO.getHeadImage()) + .eqIfPresent(GroupDO::getHeadImageThumb, reqVO.getHeadImageThumb()) + .eqIfPresent(GroupDO::getNotice, reqVO.getNotice()) + .eqIfPresent(GroupDO::getRemark, reqVO.getRemark()) + .betweenIfPresent(GroupDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(GroupDO::getId)); } } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/groupmember/ImGroupMemberMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/groupmember/ImGroupMemberMapper.java index d42d1f9..505459a 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/groupmember/ImGroupMemberMapper.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/groupmember/ImGroupMemberMapper.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO; import org.apache.ibatis.annotations.Mapper; import java.util.List; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/inbox/ImInboxMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/inbox/ImInboxMapper.java index aae03ba..15c427e 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/inbox/ImInboxMapper.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/inbox/ImInboxMapper.java @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO; import org.apache.ibatis.annotations.Mapper; /** @@ -13,15 +13,15 @@ import org.apache.ibatis.annotations.Mapper; * @author 芋道源码 */ @Mapper -public interface ImInboxMapper extends BaseMapperX { +public interface ImInboxMapper extends BaseMapperX { - default PageResult selectPage(ImInboxPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(ImInboxDO::getUserId, reqVO.getUserId()) - .eqIfPresent(ImInboxDO::getMessageId, reqVO.getMessageId()) - .eqIfPresent(ImInboxDO::getSequence, reqVO.getSequence()) - .betweenIfPresent(ImInboxDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(ImInboxDO::getId)); + default PageResult selectPage(ImInboxPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(InboxDO::getUserId, reqVO.getUserId()) + .eqIfPresent(InboxDO::getMessageId, reqVO.getMessageId()) + .eqIfPresent(InboxDO::getSequence, reqVO.getSequence()) + .betweenIfPresent(InboxDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(InboxDO::getId)); } } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImMessageMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImMessageMapper.java deleted file mode 100755 index 54d53b9..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImMessageMapper.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.iocoder.yudao.module.im.dal.mysql.message; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; -import com.github.yulichang.wrapper.MPJLambdaWrapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * 消息 Mapper - * - * @author 芋道源码 - */ -@Mapper -public interface ImMessageMapper extends BaseMapperX { - - default PageResult selectPage(ImMessagePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(ImMessageDO::getClientMessageId, reqVO.getClientMessageId()) - .eqIfPresent(ImMessageDO::getSenderId, reqVO.getSenderId()) - .eqIfPresent(ImMessageDO::getReceiverId, reqVO.getReceiverId()) - .likeIfPresent(ImMessageDO::getSenderNickname, reqVO.getSenderNickname()) - .eqIfPresent(ImMessageDO::getSenderAvatar, reqVO.getSenderAvatar()) - .eqIfPresent(ImMessageDO::getConversationType, reqVO.getConversationType()) - .eqIfPresent(ImMessageDO::getConversationNo, reqVO.getConversationNo()) - .eqIfPresent(ImMessageDO::getContentType, reqVO.getContentType()) - .eqIfPresent(ImMessageDO::getContent, reqVO.getContent()) - .betweenIfPresent(ImMessageDO::getSendTime, reqVO.getSendTime()) - .eqIfPresent(ImMessageDO::getSendFrom, reqVO.getSendFrom()) - .betweenIfPresent(ImMessageDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(ImMessageDO::getId)); - } - - // TODO @hao:不链表哈;先从 ImInboxDO 查询出 messageId,然后再到 ImMessageDO 里 IN - default List getGreaterThanSequenceMessage(Long userId, Long sequence, Integer size) { - //查询 inbox 表中,大于 sequence 的消息,关联 message 表,按照 inbox 表 sequence 升序 - return selectJoinList(ImMessageDO.class, new MPJLambdaWrapper() - .selectAll(ImMessageDO.class) - .innerJoin(ImInboxDO.class, ImInboxDO::getMessageId, ImMessageDO::getId) - .eq(ImInboxDO::getUserId, userId) - .gt(ImInboxDO::getSequence, sequence) - .orderByAsc(ImInboxDO::getSequence) - .last("limit 0," + size)); - } - - // TODO @hao:在 dao 里,使用 selectListByUserId,查询用 select,条件用 by,这个算是 spring data 的 method dsl - default List getAllMessage(Long userId, Integer size) { - //查询 inbox 表中,100条消息,关联 message 表,按照 inbox 表 sequence 降序 - return selectJoinList(ImMessageDO.class, new MPJLambdaWrapper() - .selectAll(ImMessageDO.class) - .innerJoin(ImInboxDO.class, ImInboxDO::getMessageId, ImMessageDO::getId) - .eq(ImInboxDO::getUserId, userId) - .orderByDesc(ImInboxDO::getSequence) - .last("limit 0," + size)); - } - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/MessageMapper.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/MessageMapper.java new file mode 100755 index 0000000..90fa620 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/MessageMapper.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.im.dal.mysql.message; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO; +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; +import com.github.yulichang.wrapper.MPJLambdaWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 消息 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MessageMapper extends BaseMapperX { + + // TODO @hao:不链表哈;先从 ImInboxDO 查询出 messageId,然后再到 ImMessageDO 里 IN + default List getGreaterThanSequenceMessage(Long userId, Long sequence, Integer size) { + //查询 inbox 表中,大于 sequence 的消息,关联 message 表,按照 inbox 表 sequence 升序 + return selectJoinList(MessageDO.class, new MPJLambdaWrapper() + .selectAll(MessageDO.class) + .innerJoin(InboxDO.class, InboxDO::getMessageId, MessageDO::getId) + .eq(InboxDO::getUserId, userId) + .gt(InboxDO::getSequence, sequence) + .orderByAsc(InboxDO::getSequence) + .last("limit 0," + size)); + } + + // TODO @hao:在 dao 里,使用 selectListByUserId,查询用 select,条件用 by,这个算是 spring data 的 method dsl + default List getAllMessage(Long userId, Integer size) { + //查询 inbox 表中,100条消息,关联 message 表,按照 inbox 表 sequence 降序 + return selectJoinList(MessageDO.class, new MPJLambdaWrapper() + .selectAll(MessageDO.class) + .innerJoin(InboxDO.class, InboxDO::getMessageId, MessageDO::getId) + .eq(InboxDO::getUserId, userId) + .orderByDesc(InboxDO::getSequence) + .last("limit 0," + size)); + } + + default List getMessagePage(MessagePageReqVO pageReqVO) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(MessageDO::getConversationNo, pageReqVO.getConversationNo()) + .betweenIfPresent(MessageDO::getSendTime, pageReqVO.getSendTime()) + .orderByAsc(MessageDO::getSendTime)); + } + +} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java index 906c892..76dba12 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/RedisKeyConstants.java @@ -14,4 +14,11 @@ public interface RedisKeyConstants { * VALUE 数据类型: String */ String INBOX_SEQUENCE = "im_inbox_sequence:%s"; + + /** + * 收件箱的分布式锁 + * KEY 格式: im:inbox:lock:{userId} + * VALUE 数据类型: String + */ + String INBOX_LOCK = "im_inbox_lock:%s"; } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/InboxLockRedisDAO.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/InboxLockRedisDAO.java new file mode 100644 index 0000000..a247d09 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/InboxLockRedisDAO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.im.dal.redis.inbox; + +import jakarta.annotation.Resource; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Repository; + +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.INBOX_LOCK; + +/** + * 收件箱的锁 Redis DAO + * + * @author 芋道源码 + */ +@Repository +public class InboxLockRedisDAO { + + @Resource + private RedissonClient redissonClient; + + private static String formatKey(Long id) { + return String.format(INBOX_LOCK, id); + } + + public void lock(Long id, Long timeoutMillis, Runnable runnable) { + String lockKey = formatKey(id); + RLock lock = redissonClient.getLock(lockKey); + try { + lock.lock(timeoutMillis, TimeUnit.MILLISECONDS); + // 执行逻辑 + runnable.run(); + } finally { + lock.unlock(); + } + } + +} diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/SequenceGeneratorRedisDao.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/SequenceRedisDao.java index d1ceec7..ddbab25 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/SequenceGeneratorRedisDao.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/SequenceRedisDao.java @@ -1,19 +1,21 @@ package cn.iocoder.yudao.module.im.dal.redis.inbox; import jakarta.annotation.Resource; +import org.redisson.api.RedissonClient; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.INBOX_SEQUENCE; // TODO @芋艿:这个名字,需要在考虑下; + /** * 序号生成器 Redis DAO * * @author anhaohao */ @Repository -public class SequenceGeneratorRedisDao { +public class SequenceRedisDao { @Resource private RedisTemplate redisTemplate; @@ -22,6 +24,12 @@ public class SequenceGeneratorRedisDao { return String.format(INBOX_SEQUENCE, userId); } + /** + * 生成序号 + * + * @param userId 用户编号 + * @return 序号 + */ public Long generateSequence(Long userId) { return redisTemplate.opsForValue().increment(formatKey(userId), 1); } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/jackson/ImMessageBodyDeserializer.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/jackson/ImMessageBodyDeserializer.java deleted file mode 100644 index 2f7c4f8..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/jackson/ImMessageBodyDeserializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.yudao.module.im.jackson; - -import cn.iocoder.yudao.module.im.dal.dataobject.message.body.*; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; - -import java.io.IOException; - -// TODO @hao:可以讨论下:是不是前端传递 type + content,后端根据 type 判断后,直接 jsonutil 解析到对应的 body 就 ok 了 -public class ImMessageBodyDeserializer extends JsonDeserializer { - - @Override - public ImMessageBody deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - JsonNode node = p.getCodec().readTree(p); - // 根据 node 中的内容来判断应该实例化哪个子类 - if (node.has("content")) { - return new ImTextMessageBody(node.get("content").asText()); - } - if (node.has("url")) { - String url = node.get("url").asText(); - if (node.has("format")) { - return new ImAudioMessageBody(url, node.get("format").asText()); - } - return new ImImageMessageBody(url); - } - if (node.has("name")) { - return new ImFileMessageBody(node.get("name").asText(), node.get("url").asText()); - } - if (node.has("address")) { - return new ImLocationMessageBody(node.get("address").asText(), node.get("longitude").asDouble(), node.get("latitude").asDouble()); - } - // 如果没有匹配的属性,抛出异常 - throw ctxt.mappingException("Cannot deserialize to an instance of ImMessageBody"); - } - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ConversationService.java index d235a7e..0fa3a47 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationService.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ConversationService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.service.conversation; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO; import jakarta.validation.Valid; import java.util.List; @@ -13,7 +13,7 @@ import java.util.List; * * @author 芋道源码 */ -public interface ImConversationService { +public interface ConversationService { /** * 创建会话 @@ -43,7 +43,7 @@ public interface ImConversationService { * @param id 编号 * @return 会话 */ - ImConversationDO getConversation(Long id); + ConversationDO getConversation(Long id); /** * 获得会话分页 @@ -51,7 +51,7 @@ public interface ImConversationService { * @param pageReqVO 分页查询 * @return 会话分页 */ - PageResult getConversationPage(ImConversationPageReqVO pageReqVO); + PageResult getConversationPage(ImConversationPageReqVO pageReqVO); /** @@ -59,7 +59,7 @@ public interface ImConversationService { * * @return 会话列表 */ - List getConversationList(); + List getConversationList(); /** * 置顶会话 diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ConversationServiceImpl.java index a14a31b..7b1bd9a 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImpl.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ConversationServiceImpl.java @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO; import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; -import cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationMapper; +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO; +import cn.iocoder.yudao.module.im.dal.mysql.conversation.ConversationMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -24,17 +24,17 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_N */ @Service @Validated -public class ImConversationServiceImpl implements ImConversationService { +public class ConversationServiceImpl implements ConversationService { // TODO @hao: 自己模块的注入,不用带 im 前缀哈; @Resource - private ImConversationMapper imConversationMapper; + private ConversationMapper conversationMapper; // TODO @hao: 这个方法,是不是不需要哈 @Override public Long createConversation(ImConversationSaveReqVO createReqVO) { - ImConversationDO conversation = BeanUtils.toBean(createReqVO, ImConversationDO.class); - imConversationMapper.insert(conversation); + ConversationDO conversation = BeanUtils.toBean(createReqVO, ConversationDO.class); + conversationMapper.insert(conversation); return conversation.getId(); } @@ -44,8 +44,8 @@ public class ImConversationServiceImpl implements ImConversationService { // 校验存在 validateConversationExists(updateReqVO.getId()); // 更新 - ImConversationDO updateObj = BeanUtils.toBean(updateReqVO, ImConversationDO.class); - imConversationMapper.updateById(updateObj); + ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class); + conversationMapper.updateById(updateObj); } // TODO @hao: 考虑到可能和端上不同步,可以不校验是不是存储。另外,不基于 id 删除。要基于 no + userId 删除哈。说白了,对端上要屏蔽 id 字段 @@ -54,28 +54,28 @@ public class ImConversationServiceImpl implements ImConversationService { // 校验存在 validateConversationExists(id); // 删除 - imConversationMapper.deleteById(id); + conversationMapper.deleteById(id); } private void validateConversationExists(Long id) { - if (imConversationMapper.selectById(id) == null) { + if (conversationMapper.selectById(id) == null) { throw exception(CONVERSATION_NOT_EXISTS); } } @Override - public ImConversationDO getConversation(Long id) { - return imConversationMapper.selectById(id); + public ConversationDO getConversation(Long id) { + return conversationMapper.selectById(id); } @Override - public PageResult getConversationPage(ImConversationPageReqVO pageReqVO) { - return imConversationMapper.selectPage(pageReqVO); + public PageResult getConversationPage(ImConversationPageReqVO pageReqVO) { + return conversationMapper.selectPage(pageReqVO); } @Override - public List getConversationList() { - return imConversationMapper.selectList(); + public List getConversationList() { + return conversationMapper.selectList(); } @Override @@ -95,20 +95,20 @@ public class ImConversationServiceImpl implements ImConversationService { // 3. 做对应更新的 notify 推送 private void createOrUpdateConversation(ImConversationSaveReqVO updateReqVO) { // 操作会话(已读、置顶)时,才会延迟创建,要先判断是否存在,根据 no 查询是否存在,不存在则新增 - ImConversationDO conversation = imConversationMapper.selectByNo(updateReqVO.getNo()); + ConversationDO conversation = conversationMapper.selectByNo(updateReqVO.getNo()); if (conversation == null) { - ImConversationDO conversationDO = new ImConversationDO(); + ConversationDO conversationDO = new ConversationDO(); conversationDO.setNo(updateReqVO.getNo()); conversationDO.setUserId(updateReqVO.getUserId()); conversationDO.setTargetId(updateReqVO.getTargetId()); - conversationDO.setConversationType(updateReqVO.getConversationType()); + conversationDO.setType(updateReqVO.getType()); conversationDO.setPinned(updateReqVO.getPinned()); conversationDO.setLastReadTime(DateUtil.toLocalDateTime(new Date())); - imConversationMapper.insert(conversationDO); + conversationMapper.insert(conversationDO); } else { // 更新 - ImConversationDO updateObj = BeanUtils.toBean(updateReqVO, ImConversationDO.class); - imConversationMapper.updateById(updateObj); + ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class); + conversationMapper.updateById(updateObj); } } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java index 4ebc373..cd395b8 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupService.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.im.service.group; import jakarta.validation.*; import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; /** @@ -40,7 +40,7 @@ public interface ImGroupService { * @param id 编号 * @return 群 */ - ImGroupDO getGroup(Long id); + GroupDO getGroup(Long id); /** * 获得群分页 @@ -48,6 +48,6 @@ public interface ImGroupService { * @param pageReqVO 分页查询 * @return 群分页 */ - PageResult getGroupPage(ImGroupPageReqVO pageReqVO); + PageResult getGroupPage(ImGroupPageReqVO pageReqVO); } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java index e7e20e9..5cc2e1b 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImpl.java @@ -5,7 +5,7 @@ import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -29,7 +29,7 @@ public class ImGroupServiceImpl implements ImGroupService { @Override public Long createGroup(ImGroupSaveReqVO createReqVO) { // 插入 - ImGroupDO group = BeanUtils.toBean(createReqVO, ImGroupDO.class); + GroupDO group = BeanUtils.toBean(createReqVO, GroupDO.class); imGroupMapper.insert(group); // 返回 return group.getId(); @@ -40,7 +40,7 @@ public class ImGroupServiceImpl implements ImGroupService { // 校验存在 validateGroupExists(updateReqVO.getId()); // 更新 - ImGroupDO updateObj = BeanUtils.toBean(updateReqVO, ImGroupDO.class); + GroupDO updateObj = BeanUtils.toBean(updateReqVO, GroupDO.class); imGroupMapper.updateById(updateObj); } @@ -59,12 +59,12 @@ public class ImGroupServiceImpl implements ImGroupService { } @Override - public ImGroupDO getGroup(Long id) { + public GroupDO getGroup(Long id) { return imGroupMapper.selectById(id); } @Override - public PageResult getGroupPage(ImGroupPageReqVO pageReqVO) { + public PageResult getGroupPage(ImGroupPageReqVO pageReqVO) { return imGroupMapper.selectPage(pageReqVO); } diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberService.java index 4ee73ae..4c27936 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberService.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberService.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.service.groupmember; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO; import jakarta.validation.Valid; import java.util.List; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberServiceImpl.java index 3152f04..f4ebd31 100644 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberServiceImpl.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberServiceImpl.java @@ -5,7 +5,7 @@ import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.*; -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxService.java index 98c164a..948b554 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxService.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxService.java @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.im.service.inbox; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO; +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO; +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO; import jakarta.validation.Valid; // TODO @hao:不用的方法,删除下哈; @@ -20,14 +21,14 @@ public interface ImInboxService { * @param createReqVO 创建信息 * @return 编号 */ - Long createInbox(@Valid ImInboxSaveReqVO createReqVO); + Long createInbox(@Valid InboxSaveReqVO createReqVO); /** * 更新收件箱 * * @param updateReqVO 更新信息 */ - void updateInbox(@Valid ImInboxSaveReqVO updateReqVO); + void updateInbox(@Valid InboxSaveReqVO updateReqVO); /** * 删除收件箱 @@ -42,7 +43,7 @@ public interface ImInboxService { * @param id 编号 * @return 收件箱 */ - ImInboxDO getInbox(Long id); + InboxDO getInbox(Long id); /** * 获得收件箱分页 @@ -50,6 +51,11 @@ public interface ImInboxService { * @param pageReqVO 分页查询 * @return 收件箱分页 */ - PageResult getInboxPage(ImInboxPageReqVO pageReqVO); + PageResult getInboxPage(ImInboxPageReqVO pageReqVO); + /** + * 保存收件箱和发送消息 + * @param inboxSaveMessageReqVO 收件箱保存消息 Request VO + */ + void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessageReqVO); } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxServiceImpl.java index 2168fde..f7bea8c 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxServiceImpl.java +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxServiceImpl.java @@ -1,15 +1,27 @@ package cn.iocoder.yudao.module.im.service.inbox; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO; +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSendMessageReqVO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO; +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO; import cn.iocoder.yudao.module.im.dal.mysql.inbox.ImInboxMapper; +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.ImGroupMemberService; import jakarta.annotation.Resource; +import org.dromara.hutool.core.date.DateUnit; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXISTS; @@ -22,22 +34,33 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXIS @Validated public class ImInboxServiceImpl implements ImInboxService { + private static final Long INBOX_LOCK_TIMEOUT = 120 * DateUnit.SECOND.getMillis(); + private static final String IM_MESSAGE_RECEIVE = "im-message-receive"; + @Resource private ImInboxMapper imInboxMapper; + @Resource + private SequenceRedisDao sequenceRedisDao; // 序列生成器Redis DAO + @Resource + private InboxLockRedisDAO inboxLockRedisDAO; // 收件箱的锁 Redis DAO + @Resource + private WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器 + @Resource + private ImGroupMemberService imGroupMemberService; @Override - public Long createInbox(ImInboxSaveReqVO createReqVO) { - ImInboxDO inbox = BeanUtils.toBean(createReqVO, ImInboxDO.class); + public Long createInbox(InboxSaveReqVO createReqVO) { + InboxDO inbox = BeanUtils.toBean(createReqVO, InboxDO.class); imInboxMapper.insert(inbox); return inbox.getId(); } @Override - public void updateInbox(ImInboxSaveReqVO updateReqVO) { + public void updateInbox(InboxSaveReqVO updateReqVO) { // 校验存在 validateInboxExists(updateReqVO.getId()); // 更新 - ImInboxDO updateObj = BeanUtils.toBean(updateReqVO, ImInboxDO.class); + InboxDO updateObj = BeanUtils.toBean(updateReqVO, InboxDO.class); imInboxMapper.updateById(updateObj); } @@ -56,13 +79,45 @@ public class ImInboxServiceImpl implements ImInboxService { } @Override - public ImInboxDO getInbox(Long id) { + public InboxDO getInbox(Long id) { return imInboxMapper.selectById(id); } @Override - public PageResult getInboxPage(ImInboxPageReqVO pageReqVO) { + public PageResult getInboxPage(ImInboxPageReqVO pageReqVO) { return imInboxMapper.selectPage(pageReqVO); } + @Override + public void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessage) { + // 保存收件箱 + 发送消息给用户 + saveInboxAndSendMessageForUser(inboxSaveMessage.getFromId(), inboxSaveMessage); + + if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) { + saveInboxAndSendMessageForUser(inboxSaveMessage.getReceiverId(), inboxSaveMessage); + } else if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) { + List groupMembers = imGroupMemberService.selectByGroupId(inboxSaveMessage.getReceiverId()); + groupMembers.forEach(groupMemberDO -> saveInboxAndSendMessageForUser(groupMemberDO.getUserId(), inboxSaveMessage)); + } + } + + private void saveInboxAndSendMessageForUser(Long userId, InboxSaveMessageReqVO inboxSaveMessage) { + inboxLockRedisDAO.lock(userId, INBOX_LOCK_TIMEOUT, () -> { + Long userSequence = sequenceRedisDao.generateSequence(userId); + InboxDO inbox = new InboxDO(); + inbox.setUserId(userId); + inbox.setMessageId(inboxSaveMessage.getMessageId()); + inbox.setSequence(userSequence); + imInboxMapper.insert(inbox); + + //是发送人不发送 + if (userId.equals(inboxSaveMessage.getFromId())) { + return; + } + InboxSendMessageReqVO message = BeanUtils.toBean(inboxSaveMessage, InboxSendMessageReqVO.class); + message.setSequence(userSequence); + webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message); + }); + } + } \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageService.java deleted file mode 100755 index 061e1d7..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageService.java +++ /dev/null @@ -1,103 +0,0 @@ -package cn.iocoder.yudao.module.im.service.message; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; -import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; -import jakarta.validation.Valid; - -import java.util.List; - -/** - * 消息 Service 接口 - * - * @author 芋道源码 - */ -public interface ImMessageService { - - /** - * 创建消息 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createMessage(@Valid ImMessageSaveReqVO createReqVO); - - /** - * 更新消息 - * - * @param updateReqVO 更新信息 - */ - void updateMessage(@Valid ImMessageSaveReqVO updateReqVO); - - /** - * 删除消息 - * - * @param id 编号 - */ - void deleteMessage(Long id); - - /** - * 获得消息 - * - * @param id 编号 - * @return 消息 - */ - ImMessageDO getMessage(Long id); - - /** - * 获得消息分页 - * - * @param pageReqVO 分页查询 - * @return 消息分页 - */ - PageResult getMessagePage(ImMessagePageReqVO pageReqVO); - - - /** - * 保存私聊消息 - * - * @param imSendMessage 消息信息 - * @param fromUserId 发送人编号 - * @return id - */ - ImMessageDO savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId); - - /** - * 更新消息状态 - * - * @param messageId 消息id - * @param messageStatus 消息状态 - */ - void updateMessageStatus(Long messageId, Integer messageStatus); - - /** - * 保存群聊消息 - * - * @param message 消息 - * @param fromUserId 发送者用户ID - * @return id - */ - ImMessageDO saveGroupMessage(ImSendMessage message, Long fromUserId); - - /** - * 拉取消息-大于 seq 的消息 - * - * @param userId 用户id - * @param sequence 序列号 - * @param size 数量 - * @return 消息列表 - */ - List loadMessage(Long userId, Long sequence, Integer size); - - // TODO @hao;这种接口,项目里叫 getMessageListByUserId,尽量保持 getList 获取列表哈; - /** - * 拉取全部消息 - * - * @param userId 登录用户编号 - * @param size 数量 - * @return 消息列表 - */ - List loadAllMessage(Long userId, Integer size); -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImpl.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImpl.java deleted file mode 100755 index 6c5a98f..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImpl.java +++ /dev/null @@ -1,143 +0,0 @@ -package cn.iocoder.yudao.module.im.service.message; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO; -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; -import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; -import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import jakarta.annotation.Resource; -import org.dromara.hutool.core.date.TimeUtil; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_NOT_EXISTS; - -/** - * 消息 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class ImMessageServiceImpl implements ImMessageService { - - @Resource - private ImMessageMapper imMessageMapper; - @Resource - private AdminUserApi adminUserApi; - - @Override - public Long createMessage(ImMessageSaveReqVO createReqVO) { - // 插入 - ImMessageDO message = BeanUtils.toBean(createReqVO, ImMessageDO.class); - imMessageMapper.insert(message); - // 返回 - return message.getId(); - } - - @Override - public void updateMessage(ImMessageSaveReqVO updateReqVO) { - // 校验存在 - validateMessageExists(updateReqVO.getId()); - // 更新 - ImMessageDO updateObj = BeanUtils.toBean(updateReqVO, ImMessageDO.class); - imMessageMapper.updateById(updateObj); - } - - @Override - public void deleteMessage(Long id) { - // 校验存在 - validateMessageExists(id); - // 删除 - imMessageMapper.deleteById(id); - } - - private void validateMessageExists(Long id) { - if (imMessageMapper.selectById(id) == null) { - throw exception(MESSAGE_NOT_EXISTS); - } - } - - @Override - public ImMessageDO getMessage(Long id) { - return imMessageMapper.selectById(id); - } - - @Override - public PageResult getMessagePage(ImMessagePageReqVO pageReqVO) { - return imMessageMapper.selectPage(pageReqVO); - } - - - @Override - public ImMessageDO savePrivateMessage(ImSendMessage message, Long fromUserId) { - return saveImMessageDO(message, fromUserId); - } - - private ImMessageDO saveImMessageDO(ImSendMessage message, Long fromUserId) { - // TODO @hao:可以搞成 messageDO - // TODO @hao:链式调用 - ImMessageDO imMessageDO = new ImMessageDO(); - imMessageDO.setClientMessageId(message.getClientMessageId()); - imMessageDO.setSenderId(fromUserId); - imMessageDO.setReceiverId(message.getReceiverId()); - // 查询发送人昵称和发送人头像 - AdminUserRespDTO user = adminUserApi.getUser(fromUserId); - imMessageDO.setSenderNickname(user.getNickname()); - imMessageDO.setSenderAvatar(user.getAvatar()); - imMessageDO.setConversationType(message.getConversationType()); - imMessageDO.setContentType(message.getContentType()); - // 单聊:s_{userId}_{targetId} 群聊:群聊:g_{groupId} - // TODO @hao:这里的 conversationNo 的生成,可以写到工具类里,或者干脆放到 ImConversationTypeEnum 里; - if (message.getConversationType().equals(ImConversationTypeEnum.PRIVATE.getType())) { - imMessageDO.setConversationNo("s_" + fromUserId + "_" + message.getReceiverId()); - } else if (message.getConversationType().equals(ImConversationTypeEnum.GROUP.getType())) { - imMessageDO.setConversationNo("g_" + message.getReceiverId()); - } - imMessageDO.setContent(message.getContent()); - // TODO @hao:枚举哈; - // 消息来源 100-用户发送;200-系统发送(一般是通知);不能为空 - imMessageDO.setSendFrom(100); - imMessageDO.setSendTime(TimeUtil.now()); - // TODO @hao:服务端的消息,就是默认生成哈; - imMessageDO.setMessageStatus(ImMessageStatusEnum.SENDING.getStatus()); - imMessageMapper.insert(imMessageDO); - return imMessageDO; - } - - @Override - public void updateMessageStatus(Long messageId, Integer messageStatus) { - // 校验 id 是否存在 - validateMessageExists(messageId); - //更新消息状态 - ImMessageDO imMessageDO = new ImMessageDO(); - imMessageDO.setId(messageId); - imMessageDO.setMessageStatus(messageStatus); - imMessageMapper.updateById(imMessageDO); - } - - @Override - public ImMessageDO saveGroupMessage(ImSendMessage message, Long fromUserId) { - return saveImMessageDO(message, fromUserId); - } - - @Override - public List loadMessage(Long userId, Long sequence, Integer size) { - return imMessageMapper.getGreaterThanSequenceMessage(userId, sequence, size); - } - - @Override - public List loadAllMessage(Long userId, Integer size) { - return imMessageMapper.getAllMessage(userId, size); - } - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageService.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageService.java new file mode 100755 index 0000000..82b03dc --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageService.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.im.service.message; + +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; + +import java.util.List; + +/** + * 消息 Service 接口 + * + * @author 芋道源码 + */ +public interface MessageService { + + /** + * 获得消息分页 + * + * @param pageReqVO 分页查询 + * @return 消息分页 + */ + List getMessagePage(MessagePageReqVO pageReqVO); + + + /** + * 拉取消息-大于 seq 的消息 + * + * @param userId 用户id + * @param sequence 序列号 + * @param size 数量 + * @return 消息列表 + */ + List getMessageListBySequence(Long userId, Long sequence, Integer size); + + /** + * 发送消息 + * @param loginUserId 登录用户编号 + * @param message 消息 + * @return 消息编号 + */ + SendMessageRespVO sendMessage(Long loginUserId, SendMessageReqVO message); +} \ No newline at end of file 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 new file mode 100755 index 0000000..76d2623 --- /dev/null +++ b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java @@ -0,0 +1,122 @@ +package cn.iocoder.yudao.module.im.service.message; + +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO; +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO; +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO; +import cn.iocoder.yudao.module.im.dal.mysql.message.MessageMapper; +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageSourceEnum; +import cn.iocoder.yudao.module.im.enums.message.MessageStatusEnum; +import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService; +import cn.iocoder.yudao.module.im.service.inbox.ImInboxService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.dromara.hutool.core.date.TimeUtil; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_RECEIVER_NOT_EXISTS; + +/** + * 消息 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class MessageServiceImpl implements MessageService { + + @Resource + private MessageMapper messageMapper; + @Resource + private ImInboxService imInboxService; // IM收件箱服务 + @Resource + private AdminUserApi adminUserApi; + @Resource + private ImGroupMemberService imGroupMemberService; + + @Override + public List getMessagePage(MessagePageReqVO pageReqVO) { + return messageMapper.getMessagePage(pageReqVO); + } + + @Override + public List getMessageListBySequence(Long userId, Long sequence, Integer size) { + return messageMapper.getGreaterThanSequenceMessage(userId, sequence, size); + } + + @Override + public SendMessageRespVO sendMessage(Long fromUserId, SendMessageReqVO message) { + // 保存消息 + InboxSaveMessageReqVO inboxSaveMessageReqVO = new InboxSaveMessageReqVO(); + SendMessageRespVO sendMessageRespVO = saveMessage(fromUserId, message, inboxSaveMessageReqVO); + + // 保存收件箱 + 发送消息给用户 + imInboxService.saveInboxAndSendMessage(inboxSaveMessageReqVO); + return sendMessageRespVO; + } + + public SendMessageRespVO saveMessage(Long fromUserId, SendMessageReqVO message, InboxSaveMessageReqVO inboxSaveMessageReqVO) { + //需要校验 receiverId 存在 + validateReceiverIdExists(message); + // 查询发送人昵称和发送人头像 + AdminUserRespDTO fromUser = adminUserApi.getUser(fromUserId); + // 使用链式调用创建 MessageDO 对象 + MessageDO messageDO = new MessageDO() + .setClientMessageId(message.getClientMessageId()) + .setSenderId(fromUserId) + .setReceiverId(message.getReceiverId()) + .setSenderNickname(fromUser.getNickname()) + .setSenderAvatar(fromUser.getAvatar()) + .setConversationType(message.getConversationType()) + .setContentType(message.getContentType()) + .setConversationNo(ConversationTypeEnum.generateConversationNo(fromUserId, message.getReceiverId(), message.getConversationType())) + .setContent(message.getContent()) + .setSendFrom(MessageSourceEnum.USER_SEND.getStatus()) + .setSendTime(TimeUtil.now()) + .setMessageStatus(MessageStatusEnum.SENDING.getStatus()); + 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()); + + // 返回 SendMessageRespVO 对象 + return new SendMessageRespVO(messageDO.getId(), messageDO.getSendTime()); + } + + private void validateReceiverIdExists(SendMessageReqVO message) { + if (message.getReceiverId() == null) { + throw exception(MESSAGE_RECEIVER_NOT_EXISTS); + } + if (message.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) { + //校验用户是否存在; + AdminUserRespDTO receiverUser = adminUserApi.getUser(message.getReceiverId()); + if (receiverUser == null) { + throw exception(MESSAGE_RECEIVER_NOT_EXISTS); + } + + } else if (message.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) { + //校验群聊是否存在; + List groupMemberDOS = imGroupMemberService.selectByGroupId(message.getReceiverId()); + if (groupMemberDOS.isEmpty()) { + throw exception(MESSAGE_RECEIVER_NOT_EXISTS); + } + } + } + +} \ 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/ImWebSocketMessageListener.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java deleted file mode 100644 index be816f7..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java +++ /dev/null @@ -1,184 +0,0 @@ -package cn.iocoder.yudao.module.im.websocket; - -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; -import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener; -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender; -import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils; -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO; -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO; -import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao; -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum; -import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; -import cn.iocoder.yudao.module.im.service.conversation.ImConversationService; -import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService; -import cn.iocoder.yudao.module.im.service.inbox.ImInboxService; -import cn.iocoder.yudao.module.im.service.message.ImMessageService; -import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage; -import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.web.socket.WebSocketSession; - -import java.util.List; - -// 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 WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器 - @Resource - private ImMessageService imMessageService; // IM消息服务 - @Resource - private ImConversationService imConversationService; // IM会话服务 - @Resource - private ImInboxService imInboxService; // IM收件箱服务 - @Resource - private ImGroupMemberService imGroupMemberService; // 群成员服务 - @Resource - private SequenceGeneratorRedisDao sequenceGeneratorRedisDao; // 序列生成器Redis DAO - - /** - * 处理WebSocket消息 - * - * @param session WebSocket会话 - * @param message 发送的IM消息 - */ - @Override - public void onMessage(WebSocketSession session, ImSendMessage message) { - Long fromUserId = WebSocketFrameworkUtils.getLoginUserId(session); // 获取登录用户ID - - // 如果是私人消息,处理私人消息 - if (message.getConversationType().equals(ImConversationTypeEnum.PRIVATE.getType())) { - handlePrivateMessage(fromUserId, message); - } else if (message.getConversationType().equals(ImConversationTypeEnum.GROUP.getType())) { - // 处理群聊消息 - handleGroupMessage(fromUserId, message); - } else { - // TODO @hao:是不是应该会话类型哈?然后打印这种错误日志,最好把 message 整个打进去,这样更好定位完整的消息; - log.error("[onMessage][消息类型({}) 未支持]", message.getConversationType()); - } - } - - /** - * 处理群聊消息 - * - * @param fromUserId 发送者用户ID - * @param message 发送的IM消息 - */ - private void handleGroupMessage(Long fromUserId, ImSendMessage message) { - // TODO @hao:群存在; - // TODO @hao:发送人在群里; - ImMessageDO imMessageDO = imMessageService.saveGroupMessage(message, fromUserId); // 保存群聊消息 - Long groupId = message.getReceiverId(); - - // 发送消息给群聊成员 - // TODO @hao:变量名可以叫 groupMembers;一般不用 DO 后缀,除非为了区分; - List groupMemberDOList = imGroupMemberService.selectByGroupId(groupId); - groupMemberDOList.forEach(groupMemberDO -> { - // 过滤掉自己 - // TODO @hao:98 到 99 的代码,是不是可以融合到这里来; - if (groupMemberDO.getUserId().equals(fromUserId)) { - return; - } - Long receiverSequence = sequenceGeneratorRedisDao.generateSequence(groupMemberDO.getUserId()); // 生成接收者序列 - Long receiverInboxId = createAndSaveInbox(groupMemberDO.getUserId(), imMessageDO.getId(), receiverSequence); // 创建并保存接收者收件箱 - sendMessage(groupMemberDO.getUserId(), receiverInboxId, imMessageDO, message, receiverSequence); - }); - - Long fromUserSequence = sequenceGeneratorRedisDao.generateSequence(fromUserId); // 生成发送者序列 - Long fromUserInboxId = createAndSaveInbox(fromUserId, imMessageDO.getId(), fromUserSequence); // 创建并保存发送者收件箱 - - // 发送消息给发送者 - sendMessage(fromUserId, fromUserInboxId, imMessageDO, message, fromUserSequence); - - // 更新消息状态为成功 - imMessageService.updateMessageStatus(imMessageDO.getId(), ImMessageStatusEnum.SUCCESS.getStatus()); - } - - /** - * 处理私人消息 - * - * @param fromUserId 发送者用户ID - * @param message 发送的IM消息 - */ - private void handlePrivateMessage(Long fromUserId, ImSendMessage message) { - // TODO @hao:需要校验 receiverId 存在; - ImMessageDO imMessageDO = imMessageService.savePrivateMessage(message, fromUserId); // 保存私人消息 - Long receiverId = message.getReceiverId(); - - // TODO @hao:sequenceGeneratorRedisDao.generateSequence 和 createAndSaveInbox 步骤,要加锁;不然会有并发问题;如果有疑问,可以微信招我沟通哈;另外,创建 seq、保存收件箱、发送,可以统一封装到 imInboxService 里哈;这样,后续要发某个消息,就是丢个 message 对象进去; - Long fromUserSequence = sequenceGeneratorRedisDao.generateSequence(fromUserId); // 生成发送者序列 - Long fromUserInboxId = createAndSaveInbox(fromUserId, imMessageDO.getId(), fromUserSequence); // 创建并保存发送者收件箱 - - Long receiverSequence = sequenceGeneratorRedisDao.generateSequence(message.getReceiverId()); // 生成接收者序列 - Long receiverInboxId = createAndSaveInbox(message.getReceiverId(), imMessageDO.getId(), receiverSequence); // 创建并保存接收者收件箱 - - // 发送消息给接收者和发送者 - sendMessage(fromUserId, fromUserInboxId, imMessageDO, message, fromUserSequence); - sendMessage(receiverId, receiverInboxId, imMessageDO, message, receiverSequence); - - // 更新消息状态为成功 - // TODO @hao:后端消息的发送,默认就是 success 哈,不要区分 status;status 更多是前端使用的; - imMessageService.updateMessageStatus(imMessageDO.getId(), ImMessageStatusEnum.SUCCESS.getStatus()); - // 保存私人会话,只有在 client 操作会话(已读、置顶)时,才会延迟创建 - //imConversationService.savePrivateConversation(fromUserId, receiverId); - } - - /** - * 创建并保存收件箱 - * - * @param userId 用户ID - * @param messageId 消息ID - * @param sequence 序列 - * @return 收件箱ID - */ - private Long createAndSaveInbox(Long userId, Long messageId, Long sequence) { - ImInboxSaveReqVO inboxSaveReqVO = new ImInboxSaveReqVO(userId, messageId, sequence); // 创建收件箱保存请求VO - return imInboxService.createInbox(inboxSaveReqVO); // 创建收件箱 - } - - // TODO @hao:这个使用 WebSocketSenderApi 发送哈; - /** - * 发送消息 - * - * @param fromUserId 发送者用户ID - * @param inboxId 收件箱ID - * @param imMessageDO IM消息数据对象 - * @param message 发送的IM消息 - * @param sequence 序列 - */ - private void sendMessage(Long fromUserId, Long inboxId, ImMessageDO imMessageDO, ImSendMessage message, Long sequence) { - // TODO @hao:不要每个字段 set 占一行;想同类型的字段用一行,然后链式 set,会更简洁干净。 - ImReceiveMessage receiveMessage = new ImReceiveMessage(); // 创建接收消息 - receiveMessage.setFromId(fromUserId); // 设置发送者ID - receiveMessage.setConversationType(message.getConversationType()); // 设置会话类型 - receiveMessage.setContentType(message.getContentType()); // 设置内容类型 - receiveMessage.setContent(message.getContent()); // 设置内容 - receiveMessage.setMessageId(imMessageDO.getId()); // 设置消息ID - receiveMessage.setInboxId(inboxId); // 设置收件箱ID - receiveMessage.setSendTime(imMessageDO.getSendTime()); // 设置发送时间 - receiveMessage.setSequence(sequence); // 设置序列 - webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), fromUserId, ImWebSocketMessageListener.IM_MESSAGE_RECEIVE, receiveMessage); // 发送消息 - } - - /** - * 获取类型 - * - * @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/ImSendMessage.java b/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImSendMessage.java deleted file mode 100644 index 440e308..0000000 --- a/yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImSendMessage.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.im.websocket.message; - -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") - // TODO @hao:用下 InEnum 校验。这样可以少写 15 的注释哈;类似 contentType 也是; - private Integer conversationType; // 对应 ImConversationTypeEnum 枚举 - - @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - private Long receiverId; // 根据 conversationType 区分 - - @Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer contentType; // 参见 ImMessageTypeEnum 枚举 - - @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) - private String content; - -} \ No newline at end of file diff --git a/yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ImConversationMapper.xml b/yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ConversationMapper.xml index 37fd6fb..f6a9d5a 100755 --- a/yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ImConversationMapper.xml +++ b/yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ConversationMapper.xml @@ -1,6 +1,6 @@ - +