Commit 4015b2f213daf1713d711a640dd8a5908ef93ae6

Authored by 安浩浩
1 parent 0e79d8ec

新增:消息发送和代码优化

Showing 69 changed files with 958 additions and 1798 deletions
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/api/package-info.java
1 /** 1 /**
2 * @author anhaohao 2 * @author anhaohao
3 - * @date 2024/3/9 下午8:59 TODO @hao:没有 @date 这个,应该是 @since 哈 3 + * @since 2024/3/9 下午8:59
4 */ 4 */
5 package cn.iocoder.yudao.module.im.api; 5 package cn.iocoder.yudao.module.im.api;
6 \ No newline at end of file 6 \ No newline at end of file
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 { @@ -17,6 +17,7 @@ public interface ErrorCodeConstants {
17 17
18 // ========== 消息 (1-040-300-000) ========== 18 // ========== 消息 (1-040-300-000) ==========
19 ErrorCode MESSAGE_NOT_EXISTS = new ErrorCode(1_040_300_000, "消息不存在"); 19 ErrorCode MESSAGE_NOT_EXISTS = new ErrorCode(1_040_300_000, "消息不存在");
  20 + ErrorCode MESSAGE_RECEIVER_NOT_EXISTS = new ErrorCode(1_040_300_001, "接收人不存在");
20 21
21 // ========== 群 (1-040-400-000) ========== 22 // ========== 群 (1-040-400-000) ==========
22 ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_040_400_000, "群不存在"); 23 ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_040_400_000, "群不存在");
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ImConversationTypeEnum.java renamed to 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; @@ -4,26 +4,43 @@ import lombok.AllArgsConstructor;
4 import lombok.Getter; 4 import lombok.Getter;
5 5
6 /** 6 /**
7 - * IM 会话的类型枚举 7 + * IM 会话类型枚举
  8 + * 参考 <a href="https://doc.rentsoft.cn/zh-Hans/sdks/enum/conversationType">“会话类型”</a> 文档
8 * 9 *
9 - * @author 芋道源码 10 + * @author anhaohao
10 */ 11 */
11 @Getter 12 @Getter
12 @AllArgsConstructor 13 @AllArgsConstructor
13 -public enum ImConversationTypeEnum { 14 +public enum ConversationTypeEnum {
14 15
15 - // TODO @hao:单聊,我们使用 SINGLE,主要 private 这个单词在 java 里太特殊了;  
16 - PRIVATE(1, "单聊"),  
17 - GROUP(2, "群聊"),  
18 - NOTICE(4, "通知会话"); 16 + SINGLE(1, "单聊"),
  17 + GROUP(3, "群聊"),
  18 + NOTIFICATION(4, "通知会话");
19 19
20 /** 20 /**
21 * 类型 21 * 类型
22 */ 22 */
23 private final Integer type; 23 private final Integer type;
  24 +
24 /** 25 /**
25 * 名字 26 * 名字
26 */ 27 */
27 private final String name; 28 private final String name;
28 29
  30 + /**
  31 + * 生成会话编号
  32 + * @param fromUserId 发送者编号
  33 + * @param receiverId 接收者编号
  34 + * @param conversationType 会话类型
  35 + * @return 会话编号
  36 + */
  37 + public static String generateConversationNo(Long fromUserId, Long receiverId, Integer conversationType) {
  38 + if (conversationType.equals(ConversationTypeEnum.SINGLE.getType())) {
  39 + return "s_" + fromUserId + "_" + receiverId;
  40 + } else if (conversationType.equals(ConversationTypeEnum.GROUP.getType())) {
  41 + return "g_" + receiverId;
  42 + }
  43 + return null;
  44 + }
  45 +
29 } 46 }
30 \ No newline at end of file 47 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java deleted
1 -package cn.iocoder.yudao.module.im.enums.message;  
2 -  
3 -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;  
4 -import lombok.AllArgsConstructor;  
5 -import lombok.Getter;  
6 -  
7 -import java.util.Arrays;  
8 -  
9 -// TODO @hao:类型保持和 openim 一致  
10 -/**  
11 - * IM 消息的类型枚举  
12 - * <p>  
13 - * 参考 <a href="https://doc.yunxin.163.com/messaging/docs/zg3NzA3NTA?platform=web#消息类型">“消息类型”</a> 文档  
14 - *  
15 - * @author 芋道源码  
16 - */  
17 -@Getter  
18 -@AllArgsConstructor  
19 -public enum ImMessageTypeEnum implements IntArrayValuable {  
20 -  
21 - TEXT(1, "文本"), // 消息内容为普通文本  
22 - IMAGE(2, "图片"), // 消息内容为图片 URL 地址、尺寸、图片大小等信息  
23 - AUDIO(3, "语音"), // 消息内容为语音文件的 URL 地址、时长、大小、格式等信息  
24 - VIDEO(4, "视频"), // 消息内容为视频文件的 URL 地址、时长、大小、格式等信息  
25 - FILE(5, "文件"), // 消息内容为文件的 URL 地址、大小、格式等信息  
26 - LOCATION(6, "地理位置"), // 消息内容为地理位置标题、经度、纬度信息  
27 - // TODO @芋艿:下面两种,貌似企业微信设计的更好:https://developer.work.weixin.qq.com/document/path/90240  
28 - TIP(7, "提示"), // 又叫做 Tip 消息,没有推送和通知栏提醒,主要用于会话内的通知提醒,例如进入会话时出现的欢迎消息,或是会话过程中命中敏感词后的提示消息等场景  
29 - NOTIFICATION(8, "通知"), // 主要用于群组、聊天室和超大群的事件通知,由服务端下发,客户端无法发送事件通知消息。通知类消息有在线、离线、漫游机制;没有通知栏提醒  
30 - ;  
31 -  
32 - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageTypeEnum::getType).toArray();  
33 - /**  
34 - * 类型  
35 - */  
36 - private final Integer type;  
37 - /**  
38 - * 名字  
39 - */  
40 - private final String name;  
41 -  
42 - @Override  
43 - public int[] array() {  
44 - return ARRAYS;  
45 - }  
46 -  
47 -}  
48 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageContentTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.enums.message;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +
  10 +/**
  11 + * IM 消息的类型枚举
  12 + * <p>
  13 + * 参考 <a href="https://doc.rentsoft.cn/zh-Hans/sdks/enum/messageContentType">“消息类型”</a> 文档
  14 + *
  15 + * @author anhaohao
  16 + */
  17 +@Getter
  18 +@AllArgsConstructor
  19 +public enum MessageContentTypeEnum implements IntArrayValuable {
  20 +
  21 + TEXT(101, "文本消息"),
  22 + PICTURE(102, "图片消息"),
  23 + VOICE(103, "语音消息"),
  24 + VIDEO(104, "视频消息"),
  25 + FILE(105, "文件消息"),
  26 + AT_TEXT(106, "@消息"),
  27 + MERGE(107, "合并消息"),
  28 + CARD(108, "名片消息"),
  29 + LOCATION(109, "位置消息"),
  30 + CUSTOM(110, "自定义消息"),
  31 + REVOKE_RECEIPT(111, "撤回消息回执"),
  32 + C2C_RECEIPT(112, "单聊消息回执"),
  33 + TYPING(113, "输入状态"),
  34 + QUOTE(114, "引用消息"),
  35 + FACE(115, "表情消息"),
  36 + ADVANCED_REVOKE(118, "高级撤回消息"),
  37 + //好友通知 1200-1299
  38 + FRIEND_ADDED(1201, "双方成为好友通知"),
  39 + //系统通知 1400
  40 + OA_NOTIFICATION(1400, "系统通知"),
  41 + //群相关 1500-1599
  42 + GROUP_CREATED(1501, "群创建通知"),
  43 + GROUP_INFO_CHANGED(1502, "群信息改变通知"),
  44 + MEMBER_QUIT(1504, "群成员退出通知"),
  45 + GROUP_OWNER_CHANGED(1507, "群主更换通知"),
  46 + MEMBER_KICKED(1508, "群成员被踢通知"),
  47 + MEMBER_INVITED(1509, "邀请群成员通知"),
  48 + MEMBER_ENTER(1510, "群成员进群通知"),
  49 + GROUP_DISMISSED(1511, "解散群通知"),
  50 + GROUP_MEMBER_MUTED(1512, "群成员禁言通知"),
  51 + GROUP_MEMBER_CANCEL_MUTED(1513, "取消群成员禁言通知"),
  52 + GROUP_MUTED(1514, "群禁言通知"),
  53 + GROUP_CANCEL_MUTED(1515, "取消群禁言通知"),
  54 + GROUP_ANNOUNCEMENT_UPDATED(1519, "群公告改变通知"),
  55 + GROUP_NAME_UPDATED(1520, "群名称改变通知"),
  56 +
  57 + BURN_CHANGE(1701, "阅后即焚开启或关闭通知"),
  58 + REVOKE(2101, "撤回消息通知");;
  59 +
  60 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageContentTypeEnum::getType).toArray();
  61 +
  62 + /**
  63 + * 类型
  64 + */
  65 + private final Integer type;
  66 +
  67 + /**
  68 + * 名字
  69 + */
  70 + private final String name;
  71 +
  72 + @Override
  73 + public int[] array() {
  74 + return ARRAYS;
  75 + }
  76 +
  77 +}
0 \ No newline at end of file 78 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageSourceEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.enums.message;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IM 消息的消息来源 100-用户发送;200-系统发送(一般是通知);不能为空
  11 + */
  12 +@RequiredArgsConstructor
  13 +@Getter
  14 +public enum MessageSourceEnum implements IntArrayValuable {
  15 +
  16 + USER_SEND(100, "用户发送"),
  17 + SYSTEM_SEND(200, "系统发送");
  18 +
  19 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageSourceEnum::getStatus).toArray();
  20 +
  21 + /**
  22 + * 状态
  23 + */
  24 + private final Integer status;
  25 +
  26 + /**
  27 + * 名字
  28 + */
  29 + private final String name;
  30 +
  31 + @Override
  32 + public int[] array() {
  33 + return ARRAYS;
  34 + }
  35 +
  36 +}
0 \ No newline at end of file 37 \ No newline at end of file
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageStatusEnum.java renamed to 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; @@ -6,21 +6,27 @@ import lombok.RequiredArgsConstructor;
6 6
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 -// TODO @hao:注释哈; 9 +/**
  10 + * IM 消息的状态枚举
  11 + */
10 @RequiredArgsConstructor 12 @RequiredArgsConstructor
11 @Getter 13 @Getter
12 -public enum ImMessageStatusEnum implements IntArrayValuable { 14 +public enum MessageStatusEnum implements IntArrayValuable {
13 15
14 SENDING(1, "发送中"), 16 SENDING(1, "发送中"),
15 - SUCCESS(2, "发送成功"),  
16 - FAILURE(3, "发送失败"),  
17 - DELETED(4, "已删除"),  
18 - RECALL(5, "已撤回");  
19 -  
20 - // TODO @hao:静态变量,和普通变量,最好空一行;  
21 - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageStatusEnum::getStatus).toArray();  
22 - // TODO @hao:注释哈; 17 + SUCCEED(2, "发送成功"),
  18 + FAILED(3, "发送失败");
  19 +
  20 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageStatusEnum::getStatus).toArray();
  21 +
  22 + /**
  23 + * 状态
  24 + */
23 private final Integer status; 25 private final Integer status;
  26 +
  27 + /**
  28 + * 名字
  29 + */
24 private final String name; 30 private final String name;
25 31
26 @Override 32 @Override
yudao-module-im/yudao-module-im-biz/pom.xml
@@ -5,19 +5,19 @@ @@ -5,19 +5,19 @@
5 <parent> 5 <parent>
6 <artifactId>yudao-module-im</artifactId> 6 <artifactId>yudao-module-im</artifactId>
7 <groupId>cn.iocoder.boot</groupId> 7 <groupId>cn.iocoder.boot</groupId>
8 - <version>${revision}</version> <!-- 1. 修改 version 为 ${revision} TODO @hao:这种都去掉哈; --> 8 + <version>${revision}</version>
9 </parent> 9 </parent>
10 <modelVersion>4.0.0</modelVersion> 10 <modelVersion>4.0.0</modelVersion>
11 - <packaging>jar</packaging> <!-- 2. 新增 packaging 为 jar --> 11 + <packaging>jar</packaging>
12 12
13 <artifactId>yudao-module-im-biz</artifactId> 13 <artifactId>yudao-module-im-biz</artifactId>
14 14
15 - <name>${project.artifactId}</name> <!-- 3. 新增 name 为 ${project.artifactId} -->  
16 - <description> <!-- 4. 新增 description 为该模块的描述 --> 15 + <name>${project.artifactId}</name>
  16 + <description>
17 im 模块,主要实现 im 模块的业务逻辑。 17 im 模块,主要实现 im 模块的业务逻辑。
18 </description> 18 </description>
19 19
20 - <dependencies> <!-- 5. 新增依赖,这里引入的都是比较常用的业务组件、技术组件 --> 20 + <dependencies>
21 <dependency> 21 <dependency>
22 <groupId>cn.iocoder.boot</groupId> 22 <groupId>cn.iocoder.boot</groupId>
23 <artifactId>yudao-module-im-api</artifactId> 23 <artifactId>yudao-module-im-api</artifactId>
@@ -41,34 +41,34 @@ @@ -41,34 +41,34 @@
41 <artifactId>yudao-spring-boot-starter-security</artifactId> 41 <artifactId>yudao-spring-boot-starter-security</artifactId>
42 </dependency> 42 </dependency>
43 43
  44 + <dependency>
  45 + <groupId>cn.iocoder.boot</groupId>
  46 + <artifactId>yudao-spring-boot-starter-websocket</artifactId>
  47 + </dependency>
  48 +
44 <!-- DB 相关 --> 49 <!-- DB 相关 -->
45 <dependency> 50 <dependency>
46 <groupId>cn.iocoder.boot</groupId> 51 <groupId>cn.iocoder.boot</groupId>
47 <artifactId>yudao-spring-boot-starter-mybatis</artifactId> 52 <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
48 </dependency> 53 </dependency>
49 54
50 - <!-- Test 测试相关 -->  
51 <dependency> 55 <dependency>
52 <groupId>cn.iocoder.boot</groupId> 56 <groupId>cn.iocoder.boot</groupId>
53 - <artifactId>yudao-spring-boot-starter-test</artifactId> 57 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
54 </dependency> 58 </dependency>
55 59
56 - <!-- TODO @hao:下面几个依赖的位置不太对。主要是它不属于 test,可以参考别的模块,顺序调整下哈 -->  
57 - 60 + <!-- 工具类相关 -->
58 <dependency> 61 <dependency>
59 <groupId>cn.iocoder.boot</groupId> 62 <groupId>cn.iocoder.boot</groupId>
60 <artifactId>yudao-spring-boot-starter-excel</artifactId> 63 <artifactId>yudao-spring-boot-starter-excel</artifactId>
61 </dependency> 64 </dependency>
  65 +
  66 + <!-- Test 测试相关 -->
62 <dependency> 67 <dependency>
63 <groupId>cn.iocoder.boot</groupId> 68 <groupId>cn.iocoder.boot</groupId>
64 - <artifactId>yudao-spring-boot-starter-websocket</artifactId> 69 + <artifactId>yudao-spring-boot-starter-test</artifactId>
65 </dependency> 70 </dependency>
66 71
67 - <!-- TODO @hao:引入我们自己的 redis starter 哈 -->  
68 - <dependency>  
69 - <groupId>org.redisson</groupId>  
70 - <artifactId>redisson-spring-boot-starter</artifactId>  
71 - </dependency>  
72 </dependencies> 72 </dependencies>
73 73
74 </project> 74 </project>
75 \ No newline at end of file 75 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ImConversationController.java renamed to 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; @@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationRespVO; 5 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationRespVO;
6 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO;
7 -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO;  
8 -import cn.iocoder.yudao.module.im.service.conversation.ImConversationService; 7 +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
  8 +import cn.iocoder.yudao.module.im.service.conversation.ConversationService;
9 import io.swagger.v3.oas.annotations.Operation; 9 import io.swagger.v3.oas.annotations.Operation;
10 import io.swagger.v3.oas.annotations.tags.Tag; 10 import io.swagger.v3.oas.annotations.tags.Tag;
11 import jakarta.annotation.Resource; 11 import jakarta.annotation.Resource;
@@ -19,22 +19,22 @@ import java.util.List; @@ -19,22 +19,22 @@ import java.util.List;
19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
20 20
21 // TODO @hao: 管理后台 - IM 会话 21 // TODO @hao: 管理后台 - IM 会话
22 -@Tag(name = "管理后台 - 会话") 22 +@Tag(name = "管理后台 - IM 会话")
23 @RestController 23 @RestController
24 @RequestMapping("/im/conversation") 24 @RequestMapping("/im/conversation")
25 @Validated 25 @Validated
26 -public class ImConversationController { 26 +public class ConversationController {
27 27
28 // TODO @hao: conversationService 即可 28 // TODO @hao: conversationService 即可
29 @Resource 29 @Resource
30 - private ImConversationService imConversationService; 30 + private ConversationService conversationService;
31 31
32 // TODO @hao:/list 会话列表;一般 get 是给单个对象,或者 get-count 这种;然后 conversation 已经是模块名了,所以可以简化 32 // TODO @hao:/list 会话列表;一般 get 是给单个对象,或者 get-count 这种;然后 conversation 已经是模块名了,所以可以简化
33 @GetMapping("/get-conversation") 33 @GetMapping("/get-conversation")
34 @Operation(summary = "获得用户的会话列表") 34 @Operation(summary = "获得用户的会话列表")
35 @PreAuthorize("hasAuthority('im:conversation:query')") // TODO @hao:不用权限哈 35 @PreAuthorize("hasAuthority('im:conversation:query')") // TODO @hao:不用权限哈
36 public CommonResult<List<ImConversationRespVO>> getConversationList() { 36 public CommonResult<List<ImConversationRespVO>> getConversationList() {
37 - List<ImConversationDO> conversationList = imConversationService.getConversationList(); 37 + List<ConversationDO> conversationList = conversationService.getConversationList();
38 return success(BeanUtils.toBean(conversationList, ImConversationRespVO.class)); 38 return success(BeanUtils.toBean(conversationList, ImConversationRespVO.class));
39 } 39 }
40 40
@@ -44,7 +44,7 @@ public class ImConversationController { @@ -44,7 +44,7 @@ public class ImConversationController {
44 @Operation(summary = "置顶会话") 44 @Operation(summary = "置顶会话")
45 @PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的 45 @PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的
46 public CommonResult<Boolean> updateTop(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) { 46 public CommonResult<Boolean> updateTop(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) {
47 - imConversationService.updateTop(updateReqVO); 47 + conversationService.updateTop(updateReqVO);
48 return success(true); 48 return success(true);
49 } 49 }
50 50
@@ -54,7 +54,7 @@ public class ImConversationController { @@ -54,7 +54,7 @@ public class ImConversationController {
54 @Operation(summary = "更新最后已读时间") 54 @Operation(summary = "更新最后已读时间")
55 @PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的 55 @PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的
56 public CommonResult<Boolean> updateLastReadTime(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) { 56 public CommonResult<Boolean> updateLastReadTime(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) {
57 - imConversationService.updateLastReadTime(updateReqVO); 57 + conversationService.updateLastReadTime(updateReqVO);
58 return success(true); 58 return success(true);
59 } 59 }
60 60
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 { @@ -22,7 +22,7 @@ public class ImConversationPageReqVO extends PageParam {
22 private Long userId; 22 private Long userId;
23 23
24 @Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", example = "1") 24 @Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", example = "1")
25 - private Integer conversationType; 25 + private Integer type;
26 26
27 @Schema(description = "单聊时,用户编号;群聊时,群编号", example = "21454") 27 @Schema(description = "单聊时,用户编号;群聊时,群编号", example = "21454")
28 private Long targetId; 28 private Long targetId;
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 { @@ -21,7 +21,7 @@ public class ImConversationSaveReqVO {
21 21
22 @Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 22 @Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
23 @NotNull(message = "类型:1 单聊;2 群聊;4 通知会话(预留)不能为空") 23 @NotNull(message = "类型:1 单聊;2 群聊;4 通知会话(预留)不能为空")
24 - private Integer conversationType; 24 + private Integer type;
25 25
26 @Schema(description = "单聊时,用户编号;群聊时,群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21454") 26 @Schema(description = "单聊时,用户编号;群聊时,群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21454")
27 @NotEmpty(message = "单聊时,用户编号;群聊时,群编号不能为空") 27 @NotEmpty(message = "单聊时,用户编号;群聊时,群编号不能为空")
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; @@ -25,7 +25,7 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
25 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; 25 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
26 26
27 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; 27 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
28 -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; 28 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO;
29 import cn.iocoder.yudao.module.im.service.group.ImGroupService; 29 import cn.iocoder.yudao.module.im.service.group.ImGroupService;
30 30
31 @Tag(name = "管理后台 - 群") 31 @Tag(name = "管理后台 - 群")
@@ -66,7 +66,7 @@ public class ImGroupController { @@ -66,7 +66,7 @@ public class ImGroupController {
66 @Parameter(name = "id", description = "编号", required = true, example = "1024") 66 @Parameter(name = "id", description = "编号", required = true, example = "1024")
67 @PreAuthorize("@ss.hasPermission('im:group:query')") 67 @PreAuthorize("@ss.hasPermission('im:group:query')")
68 public CommonResult<ImGroupRespVO> getGroup(@RequestParam("id") Long id) { 68 public CommonResult<ImGroupRespVO> getGroup(@RequestParam("id") Long id) {
69 - ImGroupDO group = imGroupService.getGroup(id); 69 + GroupDO group = imGroupService.getGroup(id);
70 return success(BeanUtils.toBean(group, ImGroupRespVO.class)); 70 return success(BeanUtils.toBean(group, ImGroupRespVO.class));
71 } 71 }
72 72
@@ -74,7 +74,7 @@ public class ImGroupController { @@ -74,7 +74,7 @@ public class ImGroupController {
74 @Operation(summary = "获得群分页") 74 @Operation(summary = "获得群分页")
75 @PreAuthorize("@ss.hasPermission('im:group:query')") 75 @PreAuthorize("@ss.hasPermission('im:group:query')")
76 public CommonResult<PageResult<ImGroupRespVO>> getGroupPage(@Valid ImGroupPageReqVO pageReqVO) { 76 public CommonResult<PageResult<ImGroupRespVO>> getGroupPage(@Valid ImGroupPageReqVO pageReqVO) {
77 - PageResult<ImGroupDO> pageResult = imGroupService.getGroupPage(pageReqVO); 77 + PageResult<GroupDO> pageResult = imGroupService.getGroupPage(pageReqVO);
78 return success(BeanUtils.toBean(pageResult, ImGroupRespVO.class)); 78 return success(BeanUtils.toBean(pageResult, ImGroupRespVO.class));
79 } 79 }
80 80
@@ -85,7 +85,7 @@ public class ImGroupController { @@ -85,7 +85,7 @@ public class ImGroupController {
85 public void exportGroupExcel(@Valid ImGroupPageReqVO pageReqVO, 85 public void exportGroupExcel(@Valid ImGroupPageReqVO pageReqVO,
86 HttpServletResponse response) throws IOException { 86 HttpServletResponse response) throws IOException {
87 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); 87 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
88 - List<ImGroupDO> list = imGroupService.getGroupPage(pageReqVO).getList(); 88 + List<GroupDO> list = imGroupService.getGroupPage(pageReqVO).getList();
89 // 导出 Excel 89 // 导出 Excel
90 ExcelUtils.write(response, "群.xls", "数据", ImGroupRespVO.class, 90 ExcelUtils.write(response, "群.xls", "数据", ImGroupRespVO.class,
91 BeanUtils.toBean(list, ImGroupRespVO.class)); 91 BeanUtils.toBean(list, ImGroupRespVO.class));
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; @@ -9,7 +9,7 @@ import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
9 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO; 9 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO;
10 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberRespVO; 10 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberRespVO;
11 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO; 11 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO;
12 -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; 12 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
13 import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService; 13 import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;
14 import io.swagger.v3.oas.annotations.Operation; 14 import io.swagger.v3.oas.annotations.Operation;
15 import io.swagger.v3.oas.annotations.Parameter; 15 import io.swagger.v3.oas.annotations.Parameter;
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; @@ -8,8 +8,8 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
8 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; 8 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
9 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; 9 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
10 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxRespVO; 10 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxRespVO;
11 -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;  
12 -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; 11 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO;
  12 +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
13 import cn.iocoder.yudao.module.im.service.inbox.ImInboxService; 13 import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
14 import io.swagger.v3.oas.annotations.Operation; 14 import io.swagger.v3.oas.annotations.Operation;
15 import io.swagger.v3.oas.annotations.Parameter; 15 import io.swagger.v3.oas.annotations.Parameter;
@@ -39,14 +39,14 @@ public class ImInboxController { @@ -39,14 +39,14 @@ public class ImInboxController {
39 @PostMapping("/create") 39 @PostMapping("/create")
40 @Operation(summary = "创建收件箱") 40 @Operation(summary = "创建收件箱")
41 @PreAuthorize("@ss.hasPermission('im:inbox:create')") 41 @PreAuthorize("@ss.hasPermission('im:inbox:create')")
42 - public CommonResult<Long> createInbox(@Valid @RequestBody ImInboxSaveReqVO createReqVO) { 42 + public CommonResult<Long> createInbox(@Valid @RequestBody InboxSaveReqVO createReqVO) {
43 return success(imInboxService.createInbox(createReqVO)); 43 return success(imInboxService.createInbox(createReqVO));
44 } 44 }
45 45
46 @PutMapping("/update") 46 @PutMapping("/update")
47 @Operation(summary = "更新收件箱") 47 @Operation(summary = "更新收件箱")
48 @PreAuthorize("@ss.hasPermission('im:inbox:update')") 48 @PreAuthorize("@ss.hasPermission('im:inbox:update')")
49 - public CommonResult<Boolean> updateInbox(@Valid @RequestBody ImInboxSaveReqVO updateReqVO) { 49 + public CommonResult<Boolean> updateInbox(@Valid @RequestBody InboxSaveReqVO updateReqVO) {
50 imInboxService.updateInbox(updateReqVO); 50 imInboxService.updateInbox(updateReqVO);
51 return success(true); 51 return success(true);
52 } 52 }
@@ -65,7 +65,7 @@ public class ImInboxController { @@ -65,7 +65,7 @@ public class ImInboxController {
65 @Parameter(name = "id", description = "编号", required = true, example = "1024") 65 @Parameter(name = "id", description = "编号", required = true, example = "1024")
66 @PreAuthorize("@ss.hasPermission('im:inbox:query')") 66 @PreAuthorize("@ss.hasPermission('im:inbox:query')")
67 public CommonResult<ImInboxRespVO> getInbox(@RequestParam("id") Long id) { 67 public CommonResult<ImInboxRespVO> getInbox(@RequestParam("id") Long id) {
68 - ImInboxDO inbox = imInboxService.getInbox(id); 68 + InboxDO inbox = imInboxService.getInbox(id);
69 return success(BeanUtils.toBean(inbox, ImInboxRespVO.class)); 69 return success(BeanUtils.toBean(inbox, ImInboxRespVO.class));
70 } 70 }
71 71
@@ -73,7 +73,7 @@ public class ImInboxController { @@ -73,7 +73,7 @@ public class ImInboxController {
73 @Operation(summary = "获得收件箱分页") 73 @Operation(summary = "获得收件箱分页")
74 @PreAuthorize("@ss.hasPermission('im:inbox:query')") 74 @PreAuthorize("@ss.hasPermission('im:inbox:query')")
75 public CommonResult<PageResult<ImInboxRespVO>> getInboxPage(@Valid ImInboxPageReqVO pageReqVO) { 75 public CommonResult<PageResult<ImInboxRespVO>> getInboxPage(@Valid ImInboxPageReqVO pageReqVO) {
76 - PageResult<ImInboxDO> pageResult = imInboxService.getInboxPage(pageReqVO); 76 + PageResult<InboxDO> pageResult = imInboxService.getInboxPage(pageReqVO);
77 return success(BeanUtils.toBean(pageResult, ImInboxRespVO.class)); 77 return success(BeanUtils.toBean(pageResult, ImInboxRespVO.class));
78 } 78 }
79 79
@@ -84,7 +84,7 @@ public class ImInboxController { @@ -84,7 +84,7 @@ public class ImInboxController {
84 public void exportInboxExcel(@Valid ImInboxPageReqVO pageReqVO, 84 public void exportInboxExcel(@Valid ImInboxPageReqVO pageReqVO,
85 HttpServletResponse response) throws IOException { 85 HttpServletResponse response) throws IOException {
86 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); 86 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
87 - List<ImInboxDO> list = imInboxService.getInboxPage(pageReqVO).getList(); 87 + List<InboxDO> list = imInboxService.getInboxPage(pageReqVO).getList();
88 // 导出 Excel 88 // 导出 Excel
89 ExcelUtils.write(response, "收件箱.xls", "数据", ImInboxRespVO.class, 89 ExcelUtils.write(response, "收件箱.xls", "数据", ImInboxRespVO.class,
90 BeanUtils.toBean(list, ImInboxRespVO.class)); 90 BeanUtils.toBean(list, ImInboxRespVO.class));
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveMessageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.controller.admin.inbox.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - 收件箱保存消息 Request VO")
  9 +@Data
  10 +public class InboxSaveMessageReqVO {
  11 +
  12 + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  13 + private Integer conversationType; // 对应 ImConversationTypeEnum 枚举
  14 +
  15 + @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  16 + private Long fromId; // 根据 conversationType 区分
  17 +
  18 + @Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  19 + private String senderNickname;
  20 +
  21 + @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private String senderAvatar;
  23 +
  24 + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
  25 + private Long receiverId;
  26 +
  27 + @Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
  28 + private Long messageId;
  29 +
  30 + @Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  31 + private Integer contentType; // 参见 ImMessageTypeEnum 枚举
  32 +
  33 + @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
  34 + private String content;
  35 +
  36 + @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
  37 + private LocalDateTime sendTime;
  38 +
  39 +// @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED)
  40 +// private Long sequence;
  41 +
  42 +}
0 \ No newline at end of file 43 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/ImInboxSaveReqVO.java renamed to 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; @@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
11 @Data 11 @Data
12 @AllArgsConstructor 12 @AllArgsConstructor
13 @NoArgsConstructor 13 @NoArgsConstructor
14 -public class ImInboxSaveReqVO { 14 +public class InboxSaveReqVO {
15 15
16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389") 16 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389")
17 private Long id; 17 private Long id;
@@ -28,7 +28,7 @@ public class ImInboxSaveReqVO { @@ -28,7 +28,7 @@ public class ImInboxSaveReqVO {
28 @NotNull(message = "序号,按照 user 递增不能为空") 28 @NotNull(message = "序号,按照 user 递增不能为空")
29 private Long sequence; 29 private Long sequence;
30 30
31 - public ImInboxSaveReqVO(Long userId, Long messageId, Long sequence) { 31 + public InboxSaveReqVO(Long userId, Long messageId, Long sequence) {
32 this.userId = userId; 32 this.userId = userId;
33 this.messageId = messageId; 33 this.messageId = messageId;
34 this.sequence = sequence; 34 this.sequence = sequence;
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImReceiveMessage.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSendMessageReqVO.java
1 -package cn.iocoder.yudao.module.im.websocket.message; 1 +package cn.iocoder.yudao.module.im.controller.admin.inbox.vo;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
7 7
8 -@Schema(description = "管理后台 - 消息发送 receive") 8 +@Schema(description = "管理后台 - 收件箱保存消息 Request VO")
9 @Data 9 @Data
10 -public class ImReceiveMessage { 10 +public class InboxSendMessageReqVO {
11 11
12 @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 12 @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
13 private Integer conversationType; // 对应 ImConversationTypeEnum 枚举 13 private Integer conversationType; // 对应 ImConversationTypeEnum 枚举
@@ -15,7 +15,14 @@ public class ImReceiveMessage { @@ -15,7 +15,14 @@ public class ImReceiveMessage {
15 @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 15 @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
16 private Long fromId; // 根据 conversationType 区分 16 private Long fromId; // 根据 conversationType 区分
17 17
18 - // TODO @hao:昵称和头像,也直接发给接收人好了; 18 + @Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  19 + private String senderNickname;
  20 +
  21 + @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private String senderAvatar;
  23 +
  24 + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
  25 + private Long receiverId;
19 26
20 @Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454") 27 @Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
21 private Long messageId; 28 private Long messageId;
@@ -29,10 +36,6 @@ public class ImReceiveMessage { @@ -29,10 +36,6 @@ public class ImReceiveMessage {
29 @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED) 36 @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
30 private LocalDateTime sendTime; 37 private LocalDateTime sendTime;
31 38
32 - // TODO @hao:inboxId 不需要哈;  
33 - @Schema(description = "收件箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389")  
34 - private Long inboxId;  
35 -  
36 @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED) 39 @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED)
37 private Long sequence; 40 private Long sequence;
38 41
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/ImMessageController.java deleted
1 -package cn.iocoder.yudao.module.im.controller.admin.message;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
4 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
5 -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;  
6 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO;  
7 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageRespVO;  
8 -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;  
9 -import cn.iocoder.yudao.module.im.service.message.ImMessageService;  
10 -import io.swagger.v3.oas.annotations.Operation;  
11 -import io.swagger.v3.oas.annotations.Parameter;  
12 -import io.swagger.v3.oas.annotations.tags.Tag;  
13 -import jakarta.annotation.Resource;  
14 -import jakarta.validation.Valid;  
15 -import org.springframework.security.access.prepost.PreAuthorize;  
16 -import org.springframework.validation.annotation.Validated;  
17 -import org.springframework.web.bind.annotation.GetMapping;  
18 -import org.springframework.web.bind.annotation.RequestMapping;  
19 -import org.springframework.web.bind.annotation.RequestParam;  
20 -import org.springframework.web.bind.annotation.RestController;  
21 -  
22 -import java.util.List;  
23 -  
24 -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;  
25 -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;  
26 -  
27 -@Tag(name = "管理后台 - IM 消息")  
28 -@RestController  
29 -@RequestMapping("/im/message")  
30 -@Validated  
31 -public class ImMessageController {  
32 -  
33 - @Resource  
34 - private ImMessageService imMessageService;  
35 -  
36 - @GetMapping("/get-message-by-sequence") // TODO @hao:list-by-sequence  
37 - @Operation(summary = "拉取消息-增量拉取大于 seq 的消息") // TODO @hao:可以改成 拉取大于 sequence 的消息列表  
38 - @Parameter(name = "sequence", description = "序号", required = true, example = "1")  
39 - @Parameter(name = "size", description = "条数", required = true, example = "10")  
40 - @PreAuthorize("@ss.hasPermission('im:message:query')") // TODO @hao:权限可以删除哈;  
41 - public CommonResult<List<ImMessageRespVO>> loadMessage(@RequestParam("sequence") Long sequence,  
42 - @RequestParam("size") Integer size) {  
43 - // TODO @hao:方法名,可以改成 getMessageListBySequence  
44 - // TODO @hao:如果是返回列表,变量要用 messages, 或者 messageList,体现出是复数  
45 - List<ImMessageDO> message = imMessageService.loadMessage(getLoginUserId(), sequence, size);  
46 - return success(BeanUtils.toBean(message, ImMessageRespVO.class));  
47 - }  
48 -  
49 - // TODO @hao:这个接口的使用场景是哪个哈?  
50 - @GetMapping("/get-all-message")  
51 - @Operation(summary = "拉取全部消息")  
52 - @Parameter(name = "size", description = "条数", required = true, example = "10")  
53 - @PreAuthorize("@ss.hasPermission('im:message:query')")  
54 - public CommonResult<List<ImMessageRespVO>> loadAllMessage(@RequestParam("size") Integer size) {  
55 - List<ImMessageDO> message = imMessageService.loadAllMessage(getLoginUserId(), size);  
56 - return success(BeanUtils.toBean(message, ImMessageRespVO.class));  
57 - }  
58 -  
59 - // TODO @hao:是不是分页参数不太对哈?应该只有 conversationNo,sendTime 字段;然后,做链式分页的查询,不太适合传统的 pageSize + number 查询;  
60 - @GetMapping("/page")  
61 - @Operation(summary = "查询聊天记录-分页")  
62 - @PreAuthorize("@ss.hasPermission('im:message:query')") // TODO @hao:权限可以删除哈;  
63 - public CommonResult<PageResult<ImMessageRespVO>> getMessagePage(@Valid ImMessagePageReqVO pageReqVO) {  
64 - PageResult<ImMessageDO> messagePage = imMessageService.getMessagePage(pageReqVO);  
65 - return success(BeanUtils.toBean(messagePage, ImMessageRespVO.class));  
66 - }  
67 -  
68 -}  
69 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/MessageController.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.controller.admin.message;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO;
  6 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageReqVO;
  7 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO;
  8 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO;
  9 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
  10 +import cn.iocoder.yudao.module.im.service.message.MessageService;
  11 +import io.swagger.v3.oas.annotations.Operation;
  12 +import io.swagger.v3.oas.annotations.Parameter;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import java.util.List;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
  23 +
  24 +@Tag(name = "管理后台 - IM 消息")
  25 +@RestController
  26 +@RequestMapping("/im/message")
  27 +@Validated
  28 +public class MessageController {
  29 +
  30 + @Resource
  31 + private MessageService messageService;
  32 +
  33 + @PostMapping("/send")
  34 + @Operation(summary = "发送消息")
  35 + public CommonResult<SendMessageRespVO> sendMessage(@Valid @RequestBody SendMessageReqVO message) {
  36 + return success(messageService.sendMessage(getLoginUserId(), message));
  37 + }
  38 +
  39 + @GetMapping("/list-by-sequence")
  40 + @Operation(summary = "拉取大于 sequence 的消息列表")
  41 + @Parameter(name = "sequence", description = "序号", required = true, example = "1")
  42 + @Parameter(name = "size", description = "条数", required = true, example = "10")
  43 + public CommonResult<List<ImMessageReqVO>> loadMessage(@RequestParam("sequence") Long sequence,
  44 + @RequestParam("size") Integer size) {
  45 + List<MessageDO> messages = messageService.getMessageListBySequence(getLoginUserId(), sequence, size);
  46 + return success(BeanUtils.toBean(messages, ImMessageReqVO.class));
  47 + }
  48 +
  49 + @GetMapping("/page")
  50 + @Operation(summary = "查询聊天记录-分页")
  51 + public CommonResult<List<ImMessageReqVO>> getMessagePage(@Valid MessagePageReqVO pageReqVO) {
  52 + //根据会话标志和发送时间进行分页查询
  53 + List<MessageDO> messagePage = messageService.getMessagePage(pageReqVO);
  54 + return success(BeanUtils.toBean(messagePage, ImMessageReqVO.class));
  55 + }
  56 +
  57 +}
0 \ No newline at end of file 58 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessagePageReqVO.java deleted
1 -package cn.iocoder.yudao.module.im.controller.admin.message.vo;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageParam;  
4 -import com.alibaba.excel.annotation.ExcelProperty;  
5 -import io.swagger.v3.oas.annotations.media.Schema;  
6 -import lombok.Data;  
7 -import lombok.EqualsAndHashCode;  
8 -import lombok.ToString;  
9 -import org.springframework.format.annotation.DateTimeFormat;  
10 -  
11 -import java.time.LocalDateTime;  
12 -  
13 -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;  
14 -  
15 -@Schema(description = "管理后台 - 消息分页 Request VO")  
16 -@Data  
17 -@EqualsAndHashCode(callSuper = true)  
18 -@ToString(callSuper = true)  
19 -public class ImMessagePageReqVO extends PageParam {  
20 -  
21 - @Schema(description = "客户端消息编号 uuid,用于排重", example = "3331")  
22 - private String clientMessageId;  
23 -  
24 - @Schema(description = "发送人编号", example = "23239")  
25 - private Long senderId;  
26 -  
27 - @Schema(description = "接收人编号", example = "32494")  
28 - private Long receiverId;  
29 -  
30 - @Schema(description = "发送人昵称", example = "李四")  
31 - private String senderNickname;  
32 -  
33 - @Schema(description = "发送人头像")  
34 - private String senderAvatar;  
35 -  
36 - @Schema(description = "会话类型", example = "2")  
37 - private Integer conversationType;  
38 -  
39 - @Schema(description = "会话标志")  
40 - private String conversationNo;  
41 -  
42 - @Schema(description = "消息类型", example = "1")  
43 - private Integer contentType;  
44 -  
45 - @Schema(description = "消息内容")  
46 - private String content;  
47 -  
48 - @Schema(description = "发送时间")  
49 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
50 - private LocalDateTime[] sendTime;  
51 -  
52 - @Schema(description = "消息来源 100-用户发送;200-系统发送(一般是通知);")  
53 - private Integer sendFrom;  
54 -  
55 - @Schema(description = "创建时间")  
56 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
57 - private LocalDateTime[] createTime;  
58 -  
59 - @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)  
60 - private Integer messageStatus;  
61 -  
62 -}  
63 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageRespVO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/ImMessageReqVO.java
1 package cn.iocoder.yudao.module.im.controller.admin.message.vo; 1 package cn.iocoder.yudao.module.im.controller.admin.message.vo;
2 2
3 import cn.iocoder.yudao.framework.common.validation.InEnum; 3 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 -import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;  
5 -import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; 4 +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum;
6 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; 5 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
7 import com.alibaba.excel.annotation.ExcelProperty; 6 import com.alibaba.excel.annotation.ExcelProperty;
8 import io.swagger.v3.oas.annotations.media.Schema; 7 import io.swagger.v3.oas.annotations.media.Schema;
9 -import jakarta.validation.constraints.NotNull;  
10 import lombok.Data; 8 import lombok.Data;
11 9
12 -import java.time.LocalDateTime;  
13 -  
14 -@Schema(description = "管理后台 - 消息 Response VO") 10 +@Schema(description = "管理后台 - 消息 Request VO")
15 @Data 11 @Data
16 @ExcelIgnoreUnannotated 12 @ExcelIgnoreUnannotated
17 -public class ImMessageRespVO {  
18 -  
19 - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30713")  
20 - @ExcelProperty("编号")  
21 - private Long id; 13 +public class ImMessageReqVO {
22 14
23 @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331") 15 @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331")
24 @ExcelProperty("客户端消息编号 uuid,用于排重") 16 @ExcelProperty("客户端消息编号 uuid,用于排重")
25 private String clientMessageId; 17 private String clientMessageId;
26 18
27 - @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23239")  
28 - @ExcelProperty("发送人编号")  
29 - private Long senderId;  
30 -  
31 @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494") 19 @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
32 @ExcelProperty("接收人编号") 20 @ExcelProperty("接收人编号")
33 private Long receiverId; 21 private Long receiverId;
34 22
35 - @Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")  
36 - @ExcelProperty("发送人昵称")  
37 - private String senderNickname;  
38 -  
39 - @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED)  
40 - @ExcelProperty("发送人头像")  
41 - private String senderAvatar;  
42 -  
43 @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") 23 @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
44 @ExcelProperty("会话类型") 24 @ExcelProperty("会话类型")
45 private Integer conversationType; 25 private Integer conversationType;
46 26
47 - @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED)  
48 - @ExcelProperty("会话标志")  
49 - private String conversationNo;  
50 -  
51 @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 27 @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
52 @ExcelProperty("消息类型") 28 @ExcelProperty("消息类型")
53 - @InEnum(ImMessageTypeEnum.class) 29 + @InEnum(MessageContentTypeEnum.class)
54 private Integer contentType; 30 private Integer contentType;
55 31
56 @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED) 32 @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
57 @ExcelProperty("消息内容") 33 @ExcelProperty("消息内容")
58 private String content; 34 private String content;
59 35
60 - @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)  
61 - @ExcelProperty("发送时间")  
62 - private LocalDateTime sendTime;  
63 -  
64 - @Schema(description = "消息来源 100-用户发送;200-系统发送(一般是通知);", requiredMode = Schema.RequiredMode.REQUIRED)  
65 - @ExcelProperty("消息来源 100-用户发送;200-系统发送(一般是通知);")  
66 - private Integer sendFrom;  
67 -  
68 - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)  
69 - @ExcelProperty("创建时间")  
70 - private LocalDateTime createTime;  
71 -  
72 - @Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)  
73 - @ExcelProperty("消息状态")  
74 - @InEnum(ImMessageStatusEnum.class)  
75 - private Integer messageStatus;  
76 -  
77 } 36 }
78 \ No newline at end of file 37 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/MessagePageReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.controller.admin.message.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.ToString;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +@Schema(description = "管理后台 - 消息分页 Request VO")
  14 +@Data
  15 +@ToString(callSuper = true)
  16 +public class MessagePageReqVO {
  17 +
  18 + @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "g_1000")
  19 + private String conversationNo;
  20 +
  21 + @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-27")
  22 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  23 + private LocalDateTime[] sendTime;
  24 +
  25 +}
0 \ No newline at end of file 26 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.controller.admin.message.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum;
  5 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  6 +import com.alibaba.excel.annotation.ExcelProperty;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - 发送消息 Request VO")
  11 +@Data
  12 +@ExcelIgnoreUnannotated
  13 +public class SendMessageReqVO {
  14 +
  15 + @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331")
  16 + @ExcelProperty("客户端消息编号 uuid,用于排重")
  17 + private String clientMessageId;
  18 +
  19 + @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
  20 + @ExcelProperty("接收人编号")
  21 + private Long receiverId;
  22 +
  23 + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  24 + @ExcelProperty("会话类型")
  25 + private Integer conversationType;
  26 +
  27 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  28 + @ExcelProperty("消息类型")
  29 + @InEnum(MessageContentTypeEnum.class)
  30 + private Integer contentType;
  31 +
  32 + @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
  33 + @ExcelProperty("消息内容")
  34 + private String content;
  35 +
  36 +}
0 \ No newline at end of file 37 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.controller.admin.message.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +@Schema(description = "管理后台 - 发送消息 Response VO")
  14 +@Data
  15 +@AllArgsConstructor
  16 +@NoArgsConstructor
  17 +public class SendMessageRespVO {
  18 +
  19 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
  20 + private Long id;
  21 +
  22 + @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-27 12:00:00")
  23 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  24 + private LocalDateTime sendTime;
  25 +
  26 +}
0 \ No newline at end of file 27 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ImConversationDO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ConversationDO.java
1 package cn.iocoder.yudao.module.im.dal.dataobject.conversation; 1 package cn.iocoder.yudao.module.im.dal.dataobject.conversation;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 5 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
@@ -21,31 +22,28 @@ import java.time.LocalDateTime; @@ -21,31 +22,28 @@ import java.time.LocalDateTime;
21 @Builder 22 @Builder
22 @NoArgsConstructor 23 @NoArgsConstructor
23 @AllArgsConstructor 24 @AllArgsConstructor
24 -public class ImConversationDO extends BaseDO { 25 +public class ConversationDO extends BaseDO {
25 26
26 /** 27 /**
27 * 编号 28 * 编号
28 */ 29 */
29 @TableId 30 @TableId
30 private Long id; 31 private Long id;
  32 +
31 /** 33 /**
32 * 所属用户 34 * 所属用户
33 */ 35 */
34 private Long userId; 36 private Long userId;
35 - // TODO @hao:注释可以改成,如下 37 +
36 /** 38 /**
37 * 会话类型 39 * 会话类型
38 - *  
39 - * 枚举 {@link cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum}  
40 - */  
41 - /**  
42 - * 类型:1 单聊;2 群聊;4 通知会话(预留) 40 + * <p>
  41 + * 枚举 {@link ConversationTypeEnum}
43 */ 42 */
44 - // TODO @hao:conversationType 改成 type  
45 - private Integer conversationType; 43 + private Integer type;
46 /** 44 /**
47 * 聊天对象编号 45 * 聊天对象编号
48 - * 46 + * <p>
49 * 1. 单聊时,用户编号;群聊时,群编号 47 * 1. 单聊时,用户编号;群聊时,群编号
50 */ 48 */
51 private Long targetId; 49 private Long targetId;
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/ImGroupDO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupDO.java
1 package cn.iocoder.yudao.module.im.dal.dataobject.group; 1 package cn.iocoder.yudao.module.im.dal.dataobject.group;
2 2
3 -import lombok.*;  
4 -import com.baomidou.mybatisplus.annotation.*;  
5 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
6 8
7 /** 9 /**
8 * IM 群信息 DO 10 * IM 群信息 DO
@@ -17,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @@ -17,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
17 @Builder 19 @Builder
18 @NoArgsConstructor 20 @NoArgsConstructor
19 @AllArgsConstructor 21 @AllArgsConstructor
20 -public class ImGroupDO extends BaseDO { 22 +public class GroupDO extends BaseDO {
21 23
22 /** 24 /**
23 * 编号 25 * 编号
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/groupmember/GroupMemberDO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupMemberDO.java
1 -package cn.iocoder.yudao.module.im.dal.dataobject.groupmember; 1 +package cn.iocoder.yudao.module.im.dal.dataobject.group;
2 2
3 import lombok.*; 3 import lombok.*;
4 -import java.util.*;  
5 -import java.time.LocalDateTime;  
6 -import java.time.LocalDateTime;  
7 import com.baomidou.mybatisplus.annotation.*; 4 import com.baomidou.mybatisplus.annotation.*;
8 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 5 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
9 6
10 -// TODO @hao:这个挪到 group 包下;  
11 /** 7 /**
12 * IM 群成员 DO 8 * IM 群成员 DO
13 * 9 *
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/inbox/ImInboxDO.java renamed to 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.*; @@ -20,7 +20,7 @@ import lombok.*;
20 @Builder 20 @Builder
21 @NoArgsConstructor 21 @NoArgsConstructor
22 @AllArgsConstructor 22 @AllArgsConstructor
23 -public class ImInboxDO extends BaseDO { 23 +public class InboxDO extends BaseDO {
24 24
25 /** 25 /**
26 * 编号 26 * 编号
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/ImMessageDO.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/MessageDO.java
1 package cn.iocoder.yudao.module.im.dal.dataobject.message; 1 package cn.iocoder.yudao.module.im.dal.dataobject.message;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
  5 +import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum;
  6 +import cn.iocoder.yudao.module.im.enums.message.MessageSourceEnum;
  7 +import cn.iocoder.yudao.module.im.enums.message.MessageStatusEnum;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 8 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 9 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 10 import com.baomidou.mybatisplus.annotation.TableName;
@@ -21,7 +25,7 @@ import java.time.LocalDateTime; @@ -21,7 +25,7 @@ import java.time.LocalDateTime;
21 @Builder 25 @Builder
22 @NoArgsConstructor 26 @NoArgsConstructor
23 @AllArgsConstructor 27 @AllArgsConstructor
24 -public class ImMessageDO extends BaseDO { 28 +public class MessageDO extends BaseDO {
25 29
26 /** 30 /**
27 * 编号 31 * 编号
@@ -32,57 +36,54 @@ public class ImMessageDO extends BaseDO { @@ -32,57 +36,54 @@ public class ImMessageDO extends BaseDO {
32 * 客户端消息编号 uuid,用于排重 36 * 客户端消息编号 uuid,用于排重
33 */ 37 */
34 private String clientMessageId; 38 private String clientMessageId;
35 - // TODO @hao:senderId、receiverId 存储的具体值写下,对应的群之类的  
36 /** 39 /**
37 - * 发送人编号 40 + * 发送人编号 存储的是用户编号
38 */ 41 */
39 private Long senderId; 42 private Long senderId;
40 /** 43 /**
41 * 接收人编号 44 * 接收人编号
  45 + * <p>
  46 + * 1. 单聊时,用户编号;群聊时,群编号
42 */ 47 */
43 private Long receiverId; 48 private Long receiverId;
44 - // TODO @hao:冗余字段,要说明下的。例如说  
45 /** 49 /**
46 - * 发送人昵称  
47 - * 50 + * 消息发送者昵称
  51 + * <p>
48 * 冗余 AdminUserDO 的 nickname 字段 52 * 冗余 AdminUserDO 的 nickname 字段
49 */ 53 */
50 private String senderNickname; 54 private String senderNickname;
51 /** 55 /**
52 - * 发送人头像 56 + * 消息发送者头像
  57 + * <p>
  58 + * 冗余 AdminUserDO 的 avatar 字段
53 */ 59 */
54 private String senderAvatar; 60 private String senderAvatar;
55 - // TODO @hao:关联枚举  
56 /** 61 /**
57 - * 会话类型 62 + * 会话类型 枚举 {@link ConversationTypeEnum}
58 */ 63 */
59 private Integer conversationType; 64 private Integer conversationType;
60 - // TODO @hao:关联字段  
61 /** 65 /**
62 - * 会话标志 66 + * 会话标志 {@link ConversationTypeEnum} 的generateConversationNo() 方法生成
63 */ 67 */
64 private String conversationNo; 68 private String conversationNo;
65 /** 69 /**
66 - * 消息类型 70 + * 消息类型 枚举 {@link MessageContentTypeEnum}
67 */ 71 */
68 private Integer contentType; 72 private Integer contentType;
69 - // TODO @hao:说明下是 json 格式,在哪个包看具体的格式  
70 /** 73 /**
71 - * 消息内容 74 + * 消息内容 JSON 格式 对应 dal/dataobject/message/content 包
72 */ 75 */
73 private String content; 76 private String content;
74 /** 77 /**
75 * 发送时间 78 * 发送时间
76 */ 79 */
77 private LocalDateTime sendTime; 80 private LocalDateTime sendTime;
78 - // TODO @hao:搞个枚举,然后代码里注释说明下  
79 /** 81 /**
80 - * 消息来源 100-用户发送;200-系统发送(一般是通知); 82 + * 消息来源 枚举 {@link MessageSourceEnum}
81 */ 83 */
82 private Integer sendFrom; 84 private Integer sendFrom;
83 - // TODO @hao:搞个枚举,然后代码里注释说明下  
84 /** 85 /**
85 - * 消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回 86 + * 消息状态 枚举 {@link MessageStatusEnum}
86 */ 87 */
87 private Integer messageStatus; 88 private Integer messageStatus;
88 89
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImAudioMessageBody.java deleted
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body;  
2 -  
3 -import lombok.AllArgsConstructor;  
4 -import lombok.Data;  
5 -import lombok.NoArgsConstructor;  
6 -  
7 -/**  
8 - * 语音消息的 {@link ImMessageBody}  
9 - *  
10 - * @author 芋道源码  
11 - */  
12 -@Data  
13 -@AllArgsConstructor  
14 -@NoArgsConstructor  
15 -public class ImAudioMessageBody implements ImMessageBody {  
16 -  
17 - /**  
18 - * 语音 URL  
19 - */  
20 - private String url;  
21 - /**  
22 - * 语音格式,例如说 arm、mp3、speex 等  
23 - */  
24 - private String format;  
25 -  
26 - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有  
27 -//"dur":4551, //语音持续时长ms  
28 -// "md5":"87b94a090dec5c58f242b7132a530a01", //语音文件的md5值,按照字节流加密  
29 -// "size":16420 //语音文件大小,单位为字节(Byte)  
30 -  
31 -}  
32 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImMessageBody.java deleted
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body;  
2 -  
3 -  
4 -import cn.iocoder.yudao.module.im.jackson.ImMessageBodyDeserializer;  
5 -import com.fasterxml.jackson.databind.annotation.JsonDeserialize;  
6 -  
7 -/**  
8 - * IM 消息的 body 内容  
9 - */  
10 -@JsonDeserialize(using = ImMessageBodyDeserializer.class)  
11 -public interface ImMessageBody {  
12 -}  
13 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
  2 +
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +
  8 +/**
  9 + * 语音消息的 {@link MessageDO 字段 content} 的内容
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +@AllArgsConstructor
  15 +@NoArgsConstructor
  16 +public class AudioMessage {
  17 +
  18 + /**
  19 + * 语音文件唯一 ID
  20 + */
  21 + private String uuid;
  22 +
  23 + /**
  24 + * 语音文件的本地路径
  25 + */
  26 + private String soundPath;
  27 +
  28 + /**
  29 + * 语音文件下载地址
  30 + */
  31 + private String sourceUrl;
  32 +
  33 + /**
  34 + * 语音文件大小
  35 + */
  36 + private int dataSize;
  37 +
  38 + /**
  39 + * 语音时长
  40 + */
  41 + private int duration;
  42 +
  43 + /**
  44 + * 语音文件类型
  45 + */
  46 + private String soundType;
  47 +
  48 +}
0 \ No newline at end of file 49 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/CardMessage.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
  2 +
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Data;
  6 +import lombok.NoArgsConstructor;
  7 +
  8 +/**
  9 + * 名片消息的 {@link MessageDO 字段 content} 的内容
  10 + *
  11 + * @author anhaohao
  12 + * @since 2024/3/23 下午5:53
  13 + */
  14 +@Data
  15 +@AllArgsConstructor
  16 +@NoArgsConstructor
  17 +public class CardMessage {
  18 +
  19 + /**
  20 + * 用户 ID
  21 + */
  22 + private String userID;
  23 +
  24 + /**
  25 + * 用户名
  26 + */
  27 + private String nickname;
  28 +
  29 + /**
  30 + * 用户头像
  31 + */
  32 + private int faceURL;
  33 +
  34 + /**
  35 + * 扩展字段
  36 + */
  37 + private String ex;
  38 +}
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImFileMessageBody.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/FileMessage.java
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; 1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
2 2
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
3 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.NoArgsConstructor; 6 import lombok.NoArgsConstructor;
6 7
7 /** 8 /**
8 - * 文件消息的 {@link ImMessageBody} 9 + * 文件消息的 {@link MessageDO 字段 content} 的内容
9 * 10 *
10 * @author 芋道源码 11 * @author 芋道源码
11 */ 12 */
12 @Data 13 @Data
13 @AllArgsConstructor 14 @AllArgsConstructor
14 @NoArgsConstructor 15 @NoArgsConstructor
15 -public class ImFileMessageBody implements ImMessageBody { 16 +public class FileMessage {
16 17
17 /** 18 /**
18 * 文件名 19 * 文件名
@@ -23,9 +24,4 @@ public class ImFileMessageBody implements ImMessageBody { @@ -23,9 +24,4 @@ public class ImFileMessageBody implements ImMessageBody {
23 */ 24 */
24 private String url; 25 private String url;
25 26
26 - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有  
27 -// "md5":"79d62a35fa3d34c367b20c66afc2a500", //文件MD5,按照字节流加密  
28 -// "ext":"ttf", //文件后缀类型  
29 -// "size":91680 //大小,单位为字节(Byte)  
30 -  
31 } 27 }
32 \ No newline at end of file 28 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImImageMessageBody.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/ImageMessage.java
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; 1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
2 2
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
3 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.NoArgsConstructor; 6 import lombok.NoArgsConstructor;
6 7
7 /** 8 /**
8 - * 图片消息的 {@link ImMessageBody} 9 + * 图片消息的 {@link MessageDO 字段 content} 的内容
9 * 10 *
10 * @author 芋道源码 11 * @author 芋道源码
11 */ 12 */
12 @Data 13 @Data
13 @AllArgsConstructor 14 @AllArgsConstructor
14 @NoArgsConstructor 15 @NoArgsConstructor
15 -public class ImImageMessageBody implements ImMessageBody { 16 +public class ImageMessage {
16 17
17 /** 18 /**
18 * 图片地址 19 * 图片地址
19 */ 20 */
20 private String url; 21 private String url;
21 22
22 - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有  
23 -// "name":"图片发送于2015-05-07 13:59", //图片name  
24 -// "md5":"9894907e4ad9de4678091277509361f7", //图片文件md5,按照字节流加密  
25 -// "ext":"jpg", //图片后缀  
26 -// "w":6814, //宽,单位为像素  
27 -// "h":2332, //高,单位为像素  
28 -// "size":388245 //图片文件大小,单位为字节(Byte)  
29 -  
30 } 23 }
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImLocationMessageBody.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/LocationMessage.java
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; 1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
2 2
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
3 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.NoArgsConstructor; 6 import lombok.NoArgsConstructor;
6 7
7 /** 8 /**
8 - * 地址位置消息的 {@link ImMessageBody} 9 + * 地址位置消息的 {@link MessageDO 字段 content} 的内容
9 * 10 *
10 * @author 芋道源码 11 * @author 芋道源码
11 */ 12 */
12 @Data 13 @Data
13 @AllArgsConstructor 14 @AllArgsConstructor
14 @NoArgsConstructor 15 @NoArgsConstructor
15 -public class ImLocationMessageBody implements ImMessageBody { 16 +public class LocationMessage {
16 17
17 /** 18 /**
18 * 地理位置 19 * 地理位置
19 - * 20 + * <p>
20 * 例如说:中国 浙江省 杭州市 网商路 599号 21 * 例如说:中国 浙江省 杭州市 网商路 599号
21 */ 22 */
22 private String address; 23 private String address;
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImTextMessageBody.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/TextMessage.java
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; 1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
2 2
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
3 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
4 import lombok.Data; 5 import lombok.Data;
5 import lombok.NoArgsConstructor; 6 import lombok.NoArgsConstructor;
6 7
7 /** 8 /**
8 - * 文本消息的 {@link ImMessageBody} 9 + * 文本消息的 {@link MessageDO 字段 content} 的内容
9 * 10 *
10 * @author 芋道源码 11 * @author 芋道源码
11 */ 12 */
12 @Data 13 @Data
13 @AllArgsConstructor 14 @AllArgsConstructor
14 @NoArgsConstructor 15 @NoArgsConstructor
15 -public class ImTextMessageBody implements ImMessageBody { 16 +public class TextMessage {
16 17
17 /** 18 /**
18 - * 文本消息内容 19 + * 文本消息的具体内容
19 */ 20 */
20 private String content; 21 private String content;
21 22
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/body/ImVideoMessageBody.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/VideoMessage.java
1 -package cn.iocoder.yudao.module.im.dal.dataobject.message.body; 1 +package cn.iocoder.yudao.module.im.dal.dataobject.message.content;
2 2
  3 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
3 import lombok.Data; 4 import lombok.Data;
4 5
5 /** 6 /**
6 - * 视频消息的 {@link ImMessageBody} 7 + * 视频消息的 {@link MessageDO 字段 content} 的内容
7 * 8 *
8 * @author 芋道源码 9 * @author 芋道源码
9 */ 10 */
10 @Data 11 @Data
11 -public class ImVideoMessageBody implements ImMessageBody { 12 +public class VideoMessage {
12 13
13 /** 14 /**
14 * 视频地址 15 * 视频地址
15 */ 16 */
16 private String url; 17 private String url;
17 18
18 - // TODO 芋艿:要不要以下字段?待定;云信有、企业微信没有  
19 -// "dur":8003, //视频持续时长ms  
20 -// "md5":"da2cef3e5663ee9c3547ef5d127f7e3e", //视频文件的md5值,按照字节流加密  
21 -// "w":360, //宽,单位为像素  
22 -// "h":480, //高,单位为像素  
23 -// "size":16420 //视频文件大小,单位为字节(Byte)】  
24 -// "ext":"mp4", //视频格式  
25 -  
26 -  
27 } 19 }
28 \ No newline at end of file 20 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/conversation/ImConversationMapper.java renamed to 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; @@ -4,33 +4,31 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO;
7 -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; 7 +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
10 -import java.util.Optional;  
11 -  
12 /** 10 /**
13 * IM 会话 Mapper 11 * IM 会话 Mapper
14 * 12 *
15 * @author 芋道源码 13 * @author 芋道源码
16 */ 14 */
17 @Mapper 15 @Mapper
18 -public interface ImConversationMapper extends BaseMapperX<ImConversationDO> { 16 +public interface ConversationMapper extends BaseMapperX<ConversationDO> {
19 17
20 - default PageResult<ImConversationDO> selectPage(ImConversationPageReqVO reqVO) {  
21 - return selectPage(reqVO, new LambdaQueryWrapperX<ImConversationDO>()  
22 - .eqIfPresent(ImConversationDO::getUserId, reqVO.getUserId())  
23 - .eqIfPresent(ImConversationDO::getConversationType, reqVO.getConversationType())  
24 - .eqIfPresent(ImConversationDO::getTargetId, reqVO.getTargetId())  
25 - .eqIfPresent(ImConversationDO::getNo, reqVO.getNo())  
26 - .eqIfPresent(ImConversationDO::getPinned, reqVO.getPinned())  
27 - .betweenIfPresent(ImConversationDO::getLastReadTime, reqVO.getLastReadTime())  
28 - .betweenIfPresent(ImConversationDO::getCreateTime, reqVO.getCreateTime())  
29 - .orderByDesc(ImConversationDO::getId)); 18 + default PageResult<ConversationDO> selectPage(ImConversationPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<ConversationDO>()
  20 + .eqIfPresent(ConversationDO::getUserId, reqVO.getUserId())
  21 + .eqIfPresent(ConversationDO::getType, reqVO.getType())
  22 + .eqIfPresent(ConversationDO::getTargetId, reqVO.getTargetId())
  23 + .eqIfPresent(ConversationDO::getNo, reqVO.getNo())
  24 + .eqIfPresent(ConversationDO::getPinned, reqVO.getPinned())
  25 + .betweenIfPresent(ConversationDO::getLastReadTime, reqVO.getLastReadTime())
  26 + .betweenIfPresent(ConversationDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(ConversationDO::getId));
30 } 28 }
31 29
32 // TODO @hao:1)no) {,要有空格哈;2)可以直接 selectOne(ImConversationDO::getNo, no) 父类做了封装 30 // TODO @hao:1)no) {,要有空格哈;2)可以直接 selectOne(ImConversationDO::getNo, no) 父类做了封装
33 - default ImConversationDO selectByNo(String no){  
34 - return selectOne(new LambdaQueryWrapperX<ImConversationDO>().eq(ImConversationDO::getNo, no)); 31 + default ConversationDO selectByNo(String no){
  32 + return selectOne(new LambdaQueryWrapperX<ConversationDO>().eq(ConversationDO::getNo, no));
35 } 33 }
36 } 34 }
37 \ No newline at end of file 35 \ No newline at end of file
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; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.dal.mysql.group;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
6 -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; 6 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO;
7 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
8 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; 8 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
9 9
@@ -13,18 +13,18 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; @@ -13,18 +13,18 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
13 * @author 芋道源码 13 * @author 芋道源码
14 */ 14 */
15 @Mapper 15 @Mapper
16 -public interface ImGroupMapper extends BaseMapperX<ImGroupDO> { 16 +public interface ImGroupMapper extends BaseMapperX<GroupDO> {
17 17
18 - default PageResult<ImGroupDO> selectPage(ImGroupPageReqVO reqVO) {  
19 - return selectPage(reqVO, new LambdaQueryWrapperX<ImGroupDO>()  
20 - .likeIfPresent(ImGroupDO::getGroupName, reqVO.getGroupName())  
21 - .eqIfPresent(ImGroupDO::getOwnerId, reqVO.getOwnerId())  
22 - .eqIfPresent(ImGroupDO::getHeadImage, reqVO.getHeadImage())  
23 - .eqIfPresent(ImGroupDO::getHeadImageThumb, reqVO.getHeadImageThumb())  
24 - .eqIfPresent(ImGroupDO::getNotice, reqVO.getNotice())  
25 - .eqIfPresent(ImGroupDO::getRemark, reqVO.getRemark())  
26 - .betweenIfPresent(ImGroupDO::getCreateTime, reqVO.getCreateTime())  
27 - .orderByDesc(ImGroupDO::getId)); 18 + default PageResult<GroupDO> selectPage(ImGroupPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<GroupDO>()
  20 + .likeIfPresent(GroupDO::getGroupName, reqVO.getGroupName())
  21 + .eqIfPresent(GroupDO::getOwnerId, reqVO.getOwnerId())
  22 + .eqIfPresent(GroupDO::getHeadImage, reqVO.getHeadImage())
  23 + .eqIfPresent(GroupDO::getHeadImageThumb, reqVO.getHeadImageThumb())
  24 + .eqIfPresent(GroupDO::getNotice, reqVO.getNotice())
  25 + .eqIfPresent(GroupDO::getRemark, reqVO.getRemark())
  26 + .betweenIfPresent(GroupDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(GroupDO::getId));
28 } 28 }
29 29
30 } 30 }
31 \ No newline at end of file 31 \ No newline at end of file
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; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO;
7 -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; 7 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
10 import java.util.List; 10 import java.util.List;
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; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
7 -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; 7 +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
10 /** 10 /**
@@ -13,15 +13,15 @@ import org.apache.ibatis.annotations.Mapper; @@ -13,15 +13,15 @@ import org.apache.ibatis.annotations.Mapper;
13 * @author 芋道源码 13 * @author 芋道源码
14 */ 14 */
15 @Mapper 15 @Mapper
16 -public interface ImInboxMapper extends BaseMapperX<ImInboxDO> { 16 +public interface ImInboxMapper extends BaseMapperX<InboxDO> {
17 17
18 - default PageResult<ImInboxDO> selectPage(ImInboxPageReqVO reqVO) {  
19 - return selectPage(reqVO, new LambdaQueryWrapperX<ImInboxDO>()  
20 - .eqIfPresent(ImInboxDO::getUserId, reqVO.getUserId())  
21 - .eqIfPresent(ImInboxDO::getMessageId, reqVO.getMessageId())  
22 - .eqIfPresent(ImInboxDO::getSequence, reqVO.getSequence())  
23 - .betweenIfPresent(ImInboxDO::getCreateTime, reqVO.getCreateTime())  
24 - .orderByDesc(ImInboxDO::getId)); 18 + default PageResult<InboxDO> selectPage(ImInboxPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<InboxDO>()
  20 + .eqIfPresent(InboxDO::getUserId, reqVO.getUserId())
  21 + .eqIfPresent(InboxDO::getMessageId, reqVO.getMessageId())
  22 + .eqIfPresent(InboxDO::getSequence, reqVO.getSequence())
  23 + .betweenIfPresent(InboxDO::getCreateTime, reqVO.getCreateTime())
  24 + .orderByDesc(InboxDO::getId));
25 } 25 }
26 26
27 } 27 }
28 \ No newline at end of file 28 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/ImMessageMapper.java deleted
1 -package cn.iocoder.yudao.module.im.dal.mysql.message;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
4 -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;  
5 -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;  
6 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO;  
7 -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO;  
8 -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;  
9 -import com.github.yulichang.wrapper.MPJLambdaWrapper;  
10 -import org.apache.ibatis.annotations.Mapper;  
11 -  
12 -import java.util.List;  
13 -  
14 -/**  
15 - * 消息 Mapper  
16 - *  
17 - * @author 芋道源码  
18 - */  
19 -@Mapper  
20 -public interface ImMessageMapper extends BaseMapperX<ImMessageDO> {  
21 -  
22 - default PageResult<ImMessageDO> selectPage(ImMessagePageReqVO reqVO) {  
23 - return selectPage(reqVO, new LambdaQueryWrapperX<ImMessageDO>()  
24 - .eqIfPresent(ImMessageDO::getClientMessageId, reqVO.getClientMessageId())  
25 - .eqIfPresent(ImMessageDO::getSenderId, reqVO.getSenderId())  
26 - .eqIfPresent(ImMessageDO::getReceiverId, reqVO.getReceiverId())  
27 - .likeIfPresent(ImMessageDO::getSenderNickname, reqVO.getSenderNickname())  
28 - .eqIfPresent(ImMessageDO::getSenderAvatar, reqVO.getSenderAvatar())  
29 - .eqIfPresent(ImMessageDO::getConversationType, reqVO.getConversationType())  
30 - .eqIfPresent(ImMessageDO::getConversationNo, reqVO.getConversationNo())  
31 - .eqIfPresent(ImMessageDO::getContentType, reqVO.getContentType())  
32 - .eqIfPresent(ImMessageDO::getContent, reqVO.getContent())  
33 - .betweenIfPresent(ImMessageDO::getSendTime, reqVO.getSendTime())  
34 - .eqIfPresent(ImMessageDO::getSendFrom, reqVO.getSendFrom())  
35 - .betweenIfPresent(ImMessageDO::getCreateTime, reqVO.getCreateTime())  
36 - .orderByDesc(ImMessageDO::getId));  
37 - }  
38 -  
39 - // TODO @hao:不链表哈;先从 ImInboxDO 查询出 messageId,然后再到 ImMessageDO 里 IN  
40 - default List<ImMessageDO> getGreaterThanSequenceMessage(Long userId, Long sequence, Integer size) {  
41 - //查询 inbox 表中,大于 sequence 的消息,关联 message 表,按照 inbox 表 sequence 升序  
42 - return selectJoinList(ImMessageDO.class, new MPJLambdaWrapper<ImMessageDO>()  
43 - .selectAll(ImMessageDO.class)  
44 - .innerJoin(ImInboxDO.class, ImInboxDO::getMessageId, ImMessageDO::getId)  
45 - .eq(ImInboxDO::getUserId, userId)  
46 - .gt(ImInboxDO::getSequence, sequence)  
47 - .orderByAsc(ImInboxDO::getSequence)  
48 - .last("limit 0," + size));  
49 - }  
50 -  
51 - // TODO @hao:在 dao 里,使用 selectListByUserId,查询用 select,条件用 by,这个算是 spring data 的 method dsl  
52 - default List<ImMessageDO> getAllMessage(Long userId, Integer size) {  
53 - //查询 inbox 表中,100条消息,关联 message 表,按照 inbox 表 sequence 降序  
54 - return selectJoinList(ImMessageDO.class, new MPJLambdaWrapper<ImMessageDO>()  
55 - .selectAll(ImMessageDO.class)  
56 - .innerJoin(ImInboxDO.class, ImInboxDO::getMessageId, ImMessageDO::getId)  
57 - .eq(ImInboxDO::getUserId, userId)  
58 - .orderByDesc(ImInboxDO::getSequence)  
59 - .last("limit 0," + size));  
60 - }  
61 -  
62 -}  
63 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/message/MessageMapper.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.dal.mysql.message;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO;
  6 +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
  7 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
  8 +import com.github.yulichang.wrapper.MPJLambdaWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * 消息 Mapper
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Mapper
  19 +public interface MessageMapper extends BaseMapperX<MessageDO> {
  20 +
  21 + // TODO @hao:不链表哈;先从 ImInboxDO 查询出 messageId,然后再到 ImMessageDO 里 IN
  22 + default List<MessageDO> getGreaterThanSequenceMessage(Long userId, Long sequence, Integer size) {
  23 + //查询 inbox 表中,大于 sequence 的消息,关联 message 表,按照 inbox 表 sequence 升序
  24 + return selectJoinList(MessageDO.class, new MPJLambdaWrapper<MessageDO>()
  25 + .selectAll(MessageDO.class)
  26 + .innerJoin(InboxDO.class, InboxDO::getMessageId, MessageDO::getId)
  27 + .eq(InboxDO::getUserId, userId)
  28 + .gt(InboxDO::getSequence, sequence)
  29 + .orderByAsc(InboxDO::getSequence)
  30 + .last("limit 0," + size));
  31 + }
  32 +
  33 + // TODO @hao:在 dao 里,使用 selectListByUserId,查询用 select,条件用 by,这个算是 spring data 的 method dsl
  34 + default List<MessageDO> getAllMessage(Long userId, Integer size) {
  35 + //查询 inbox 表中,100条消息,关联 message 表,按照 inbox 表 sequence 降序
  36 + return selectJoinList(MessageDO.class, new MPJLambdaWrapper<MessageDO>()
  37 + .selectAll(MessageDO.class)
  38 + .innerJoin(InboxDO.class, InboxDO::getMessageId, MessageDO::getId)
  39 + .eq(InboxDO::getUserId, userId)
  40 + .orderByDesc(InboxDO::getSequence)
  41 + .last("limit 0," + size));
  42 + }
  43 +
  44 + default List<MessageDO> getMessagePage(MessagePageReqVO pageReqVO) {
  45 + return selectList(new LambdaQueryWrapperX<MessageDO>()
  46 + .eqIfPresent(MessageDO::getConversationNo, pageReqVO.getConversationNo())
  47 + .betweenIfPresent(MessageDO::getSendTime, pageReqVO.getSendTime())
  48 + .orderByAsc(MessageDO::getSendTime));
  49 + }
  50 +
  51 +}
0 \ No newline at end of file 52 \ No newline at end of file
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 { @@ -14,4 +14,11 @@ public interface RedisKeyConstants {
14 * VALUE 数据类型: String 14 * VALUE 数据类型: String
15 */ 15 */
16 String INBOX_SEQUENCE = "im_inbox_sequence:%s"; 16 String INBOX_SEQUENCE = "im_inbox_sequence:%s";
  17 +
  18 + /**
  19 + * 收件箱的分布式锁
  20 + * KEY 格式: im:inbox:lock:{userId}
  21 + * VALUE 数据类型: String
  22 + */
  23 + String INBOX_LOCK = "im_inbox_lock:%s";
17 } 24 }
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/InboxLockRedisDAO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.dal.redis.inbox;
  2 +
  3 +import jakarta.annotation.Resource;
  4 +import org.redisson.api.RLock;
  5 +import org.redisson.api.RedissonClient;
  6 +import org.springframework.stereotype.Repository;
  7 +
  8 +import java.util.concurrent.TimeUnit;
  9 +
  10 +import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.INBOX_LOCK;
  11 +
  12 +/**
  13 + * 收件箱的锁 Redis DAO
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Repository
  18 +public class InboxLockRedisDAO {
  19 +
  20 + @Resource
  21 + private RedissonClient redissonClient;
  22 +
  23 + private static String formatKey(Long id) {
  24 + return String.format(INBOX_LOCK, id);
  25 + }
  26 +
  27 + public void lock(Long id, Long timeoutMillis, Runnable runnable) {
  28 + String lockKey = formatKey(id);
  29 + RLock lock = redissonClient.getLock(lockKey);
  30 + try {
  31 + lock.lock(timeoutMillis, TimeUnit.MILLISECONDS);
  32 + // 执行逻辑
  33 + runnable.run();
  34 + } finally {
  35 + lock.unlock();
  36 + }
  37 + }
  38 +
  39 +}
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/SequenceGeneratorRedisDao.java renamed to yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/redis/inbox/SequenceRedisDao.java
1 package cn.iocoder.yudao.module.im.dal.redis.inbox; 1 package cn.iocoder.yudao.module.im.dal.redis.inbox;
2 2
3 import jakarta.annotation.Resource; 3 import jakarta.annotation.Resource;
  4 +import org.redisson.api.RedissonClient;
4 import org.springframework.data.redis.core.RedisTemplate; 5 import org.springframework.data.redis.core.RedisTemplate;
5 import org.springframework.stereotype.Repository; 6 import org.springframework.stereotype.Repository;
6 7
7 import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.INBOX_SEQUENCE; 8 import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.INBOX_SEQUENCE;
8 9
9 // TODO @芋艿:这个名字,需要在考虑下; 10 // TODO @芋艿:这个名字,需要在考虑下;
  11 +
10 /** 12 /**
11 * 序号生成器 Redis DAO 13 * 序号生成器 Redis DAO
12 * 14 *
13 * @author anhaohao 15 * @author anhaohao
14 */ 16 */
15 @Repository 17 @Repository
16 -public class SequenceGeneratorRedisDao { 18 +public class SequenceRedisDao {
17 19
18 @Resource 20 @Resource
19 private RedisTemplate<String, Long> redisTemplate; 21 private RedisTemplate<String, Long> redisTemplate;
@@ -22,6 +24,12 @@ public class SequenceGeneratorRedisDao { @@ -22,6 +24,12 @@ public class SequenceGeneratorRedisDao {
22 return String.format(INBOX_SEQUENCE, userId); 24 return String.format(INBOX_SEQUENCE, userId);
23 } 25 }
24 26
  27 + /**
  28 + * 生成序号
  29 + *
  30 + * @param userId 用户编号
  31 + * @return 序号
  32 + */
25 public Long generateSequence(Long userId) { 33 public Long generateSequence(Long userId) {
26 return redisTemplate.opsForValue().increment(formatKey(userId), 1); 34 return redisTemplate.opsForValue().increment(formatKey(userId), 1);
27 } 35 }
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/jackson/ImMessageBodyDeserializer.java deleted
1 -package cn.iocoder.yudao.module.im.jackson;  
2 -  
3 -import cn.iocoder.yudao.module.im.dal.dataobject.message.body.*;  
4 -import com.fasterxml.jackson.core.JsonParser;  
5 -import com.fasterxml.jackson.databind.DeserializationContext;  
6 -import com.fasterxml.jackson.databind.JsonDeserializer;  
7 -import com.fasterxml.jackson.databind.JsonNode;  
8 -  
9 -import java.io.IOException;  
10 -  
11 -// TODO @hao:可以讨论下:是不是前端传递 type + content,后端根据 type 判断后,直接 jsonutil 解析到对应的 body 就 ok 了  
12 -public class ImMessageBodyDeserializer extends JsonDeserializer<ImMessageBody> {  
13 -  
14 - @Override  
15 - public ImMessageBody deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {  
16 - JsonNode node = p.getCodec().readTree(p);  
17 - // 根据 node 中的内容来判断应该实例化哪个子类  
18 - if (node.has("content")) {  
19 - return new ImTextMessageBody(node.get("content").asText());  
20 - }  
21 - if (node.has("url")) {  
22 - String url = node.get("url").asText();  
23 - if (node.has("format")) {  
24 - return new ImAudioMessageBody(url, node.get("format").asText());  
25 - }  
26 - return new ImImageMessageBody(url);  
27 - }  
28 - if (node.has("name")) {  
29 - return new ImFileMessageBody(node.get("name").asText(), node.get("url").asText());  
30 - }  
31 - if (node.has("address")) {  
32 - return new ImLocationMessageBody(node.get("address").asText(), node.get("longitude").asDouble(), node.get("latitude").asDouble());  
33 - }  
34 - // 如果没有匹配的属性,抛出异常  
35 - throw ctxt.mappingException("Cannot deserialize to an instance of ImMessageBody");  
36 - }  
37 -  
38 -}  
39 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationService.java renamed to 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; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.service.conversation;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO; 4 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO;
5 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO; 5 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO;
6 -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO; 6 +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
7 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
8 8
9 import java.util.List; 9 import java.util.List;
@@ -13,7 +13,7 @@ import java.util.List; @@ -13,7 +13,7 @@ import java.util.List;
13 * 13 *
14 * @author 芋道源码 14 * @author 芋道源码
15 */ 15 */
16 -public interface ImConversationService { 16 +public interface ConversationService {
17 17
18 /** 18 /**
19 * 创建会话 19 * 创建会话
@@ -43,7 +43,7 @@ public interface ImConversationService { @@ -43,7 +43,7 @@ public interface ImConversationService {
43 * @param id 编号 43 * @param id 编号
44 * @return 会话 44 * @return 会话
45 */ 45 */
46 - ImConversationDO getConversation(Long id); 46 + ConversationDO getConversation(Long id);
47 47
48 /** 48 /**
49 * 获得会话分页 49 * 获得会话分页
@@ -51,7 +51,7 @@ public interface ImConversationService { @@ -51,7 +51,7 @@ public interface ImConversationService {
51 * @param pageReqVO 分页查询 51 * @param pageReqVO 分页查询
52 * @return 会话分页 52 * @return 会话分页
53 */ 53 */
54 - PageResult<ImConversationDO> getConversationPage(ImConversationPageReqVO pageReqVO); 54 + PageResult<ConversationDO> getConversationPage(ImConversationPageReqVO pageReqVO);
55 55
56 56
57 /** 57 /**
@@ -59,7 +59,7 @@ public interface ImConversationService { @@ -59,7 +59,7 @@ public interface ImConversationService {
59 * 59 *
60 * @return 会话列表 60 * @return 会话列表
61 */ 61 */
62 - List<ImConversationDO> getConversationList(); 62 + List<ConversationDO> getConversationList();
63 63
64 /** 64 /**
65 * 置顶会话 65 * 置顶会话
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImpl.java renamed to 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; @@ -5,8 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO;
7 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO; 7 import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO;
8 -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO;  
9 -import cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationMapper; 8 +import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
  9 +import cn.iocoder.yudao.module.im.dal.mysql.conversation.ConversationMapper;
10 import jakarta.annotation.Resource; 10 import jakarta.annotation.Resource;
11 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
12 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
@@ -24,17 +24,17 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_N @@ -24,17 +24,17 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_N
24 */ 24 */
25 @Service 25 @Service
26 @Validated 26 @Validated
27 -public class ImConversationServiceImpl implements ImConversationService { 27 +public class ConversationServiceImpl implements ConversationService {
28 28
29 // TODO @hao: 自己模块的注入,不用带 im 前缀哈; 29 // TODO @hao: 自己模块的注入,不用带 im 前缀哈;
30 @Resource 30 @Resource
31 - private ImConversationMapper imConversationMapper; 31 + private ConversationMapper conversationMapper;
32 32
33 // TODO @hao: 这个方法,是不是不需要哈 33 // TODO @hao: 这个方法,是不是不需要哈
34 @Override 34 @Override
35 public Long createConversation(ImConversationSaveReqVO createReqVO) { 35 public Long createConversation(ImConversationSaveReqVO createReqVO) {
36 - ImConversationDO conversation = BeanUtils.toBean(createReqVO, ImConversationDO.class);  
37 - imConversationMapper.insert(conversation); 36 + ConversationDO conversation = BeanUtils.toBean(createReqVO, ConversationDO.class);
  37 + conversationMapper.insert(conversation);
38 return conversation.getId(); 38 return conversation.getId();
39 } 39 }
40 40
@@ -44,8 +44,8 @@ public class ImConversationServiceImpl implements ImConversationService { @@ -44,8 +44,8 @@ public class ImConversationServiceImpl implements ImConversationService {
44 // 校验存在 44 // 校验存在
45 validateConversationExists(updateReqVO.getId()); 45 validateConversationExists(updateReqVO.getId());
46 // 更新 46 // 更新
47 - ImConversationDO updateObj = BeanUtils.toBean(updateReqVO, ImConversationDO.class);  
48 - imConversationMapper.updateById(updateObj); 47 + ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class);
  48 + conversationMapper.updateById(updateObj);
49 } 49 }
50 50
51 // TODO @hao: 考虑到可能和端上不同步,可以不校验是不是存储。另外,不基于 id 删除。要基于 no + userId 删除哈。说白了,对端上要屏蔽 id 字段 51 // TODO @hao: 考虑到可能和端上不同步,可以不校验是不是存储。另外,不基于 id 删除。要基于 no + userId 删除哈。说白了,对端上要屏蔽 id 字段
@@ -54,28 +54,28 @@ public class ImConversationServiceImpl implements ImConversationService { @@ -54,28 +54,28 @@ public class ImConversationServiceImpl implements ImConversationService {
54 // 校验存在 54 // 校验存在
55 validateConversationExists(id); 55 validateConversationExists(id);
56 // 删除 56 // 删除
57 - imConversationMapper.deleteById(id); 57 + conversationMapper.deleteById(id);
58 } 58 }
59 59
60 private void validateConversationExists(Long id) { 60 private void validateConversationExists(Long id) {
61 - if (imConversationMapper.selectById(id) == null) { 61 + if (conversationMapper.selectById(id) == null) {
62 throw exception(CONVERSATION_NOT_EXISTS); 62 throw exception(CONVERSATION_NOT_EXISTS);
63 } 63 }
64 } 64 }
65 65
66 @Override 66 @Override
67 - public ImConversationDO getConversation(Long id) {  
68 - return imConversationMapper.selectById(id); 67 + public ConversationDO getConversation(Long id) {
  68 + return conversationMapper.selectById(id);
69 } 69 }
70 70
71 @Override 71 @Override
72 - public PageResult<ImConversationDO> getConversationPage(ImConversationPageReqVO pageReqVO) {  
73 - return imConversationMapper.selectPage(pageReqVO); 72 + public PageResult<ConversationDO> getConversationPage(ImConversationPageReqVO pageReqVO) {
  73 + return conversationMapper.selectPage(pageReqVO);
74 } 74 }
75 75
76 @Override 76 @Override
77 - public List<ImConversationDO> getConversationList() {  
78 - return imConversationMapper.selectList(); 77 + public List<ConversationDO> getConversationList() {
  78 + return conversationMapper.selectList();
79 } 79 }
80 80
81 @Override 81 @Override
@@ -95,20 +95,20 @@ public class ImConversationServiceImpl implements ImConversationService { @@ -95,20 +95,20 @@ public class ImConversationServiceImpl implements ImConversationService {
95 // 3. 做对应更新的 notify 推送 95 // 3. 做对应更新的 notify 推送
96 private void createOrUpdateConversation(ImConversationSaveReqVO updateReqVO) { 96 private void createOrUpdateConversation(ImConversationSaveReqVO updateReqVO) {
97 // 操作会话(已读、置顶)时,才会延迟创建,要先判断是否存在,根据 no 查询是否存在,不存在则新增 97 // 操作会话(已读、置顶)时,才会延迟创建,要先判断是否存在,根据 no 查询是否存在,不存在则新增
98 - ImConversationDO conversation = imConversationMapper.selectByNo(updateReqVO.getNo()); 98 + ConversationDO conversation = conversationMapper.selectByNo(updateReqVO.getNo());
99 if (conversation == null) { 99 if (conversation == null) {
100 - ImConversationDO conversationDO = new ImConversationDO(); 100 + ConversationDO conversationDO = new ConversationDO();
101 conversationDO.setNo(updateReqVO.getNo()); 101 conversationDO.setNo(updateReqVO.getNo());
102 conversationDO.setUserId(updateReqVO.getUserId()); 102 conversationDO.setUserId(updateReqVO.getUserId());
103 conversationDO.setTargetId(updateReqVO.getTargetId()); 103 conversationDO.setTargetId(updateReqVO.getTargetId());
104 - conversationDO.setConversationType(updateReqVO.getConversationType()); 104 + conversationDO.setType(updateReqVO.getType());
105 conversationDO.setPinned(updateReqVO.getPinned()); 105 conversationDO.setPinned(updateReqVO.getPinned());
106 conversationDO.setLastReadTime(DateUtil.toLocalDateTime(new Date())); 106 conversationDO.setLastReadTime(DateUtil.toLocalDateTime(new Date()));
107 - imConversationMapper.insert(conversationDO); 107 + conversationMapper.insert(conversationDO);
108 } else { 108 } else {
109 // 更新 109 // 更新
110 - ImConversationDO updateObj = BeanUtils.toBean(updateReqVO, ImConversationDO.class);  
111 - imConversationMapper.updateById(updateObj); 110 + ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class);
  111 + conversationMapper.updateById(updateObj);
112 } 112 }
113 } 113 }
114 114
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; @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.im.service.group;
2 2
3 import jakarta.validation.*; 3 import jakarta.validation.*;
4 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; 4 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
5 -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; 5 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7
8 /** 8 /**
@@ -40,7 +40,7 @@ public interface ImGroupService { @@ -40,7 +40,7 @@ public interface ImGroupService {
40 * @param id 编号 40 * @param id 编号
41 * @return 群 41 * @return 群
42 */ 42 */
43 - ImGroupDO getGroup(Long id); 43 + GroupDO getGroup(Long id);
44 44
45 /** 45 /**
46 * 获得群分页 46 * 获得群分页
@@ -48,6 +48,6 @@ public interface ImGroupService { @@ -48,6 +48,6 @@ public interface ImGroupService {
48 * @param pageReqVO 分页查询 48 * @param pageReqVO 分页查询
49 * @return 群分页 49 * @return 群分页
50 */ 50 */
51 - PageResult<ImGroupDO> getGroupPage(ImGroupPageReqVO pageReqVO); 51 + PageResult<GroupDO> getGroupPage(ImGroupPageReqVO pageReqVO);
52 52
53 } 53 }
54 \ No newline at end of file 54 \ No newline at end of file
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; @@ -5,7 +5,7 @@ import jakarta.annotation.Resource;
5 import org.springframework.validation.annotation.Validated; 5 import org.springframework.validation.annotation.Validated;
6 6
7 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*; 7 import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
8 -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO; 8 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
11 11
@@ -29,7 +29,7 @@ public class ImGroupServiceImpl implements ImGroupService { @@ -29,7 +29,7 @@ public class ImGroupServiceImpl implements ImGroupService {
29 @Override 29 @Override
30 public Long createGroup(ImGroupSaveReqVO createReqVO) { 30 public Long createGroup(ImGroupSaveReqVO createReqVO) {
31 // 插入 31 // 插入
32 - ImGroupDO group = BeanUtils.toBean(createReqVO, ImGroupDO.class); 32 + GroupDO group = BeanUtils.toBean(createReqVO, GroupDO.class);
33 imGroupMapper.insert(group); 33 imGroupMapper.insert(group);
34 // 返回 34 // 返回
35 return group.getId(); 35 return group.getId();
@@ -40,7 +40,7 @@ public class ImGroupServiceImpl implements ImGroupService { @@ -40,7 +40,7 @@ public class ImGroupServiceImpl implements ImGroupService {
40 // 校验存在 40 // 校验存在
41 validateGroupExists(updateReqVO.getId()); 41 validateGroupExists(updateReqVO.getId());
42 // 更新 42 // 更新
43 - ImGroupDO updateObj = BeanUtils.toBean(updateReqVO, ImGroupDO.class); 43 + GroupDO updateObj = BeanUtils.toBean(updateReqVO, GroupDO.class);
44 imGroupMapper.updateById(updateObj); 44 imGroupMapper.updateById(updateObj);
45 } 45 }
46 46
@@ -59,12 +59,12 @@ public class ImGroupServiceImpl implements ImGroupService { @@ -59,12 +59,12 @@ public class ImGroupServiceImpl implements ImGroupService {
59 } 59 }
60 60
61 @Override 61 @Override
62 - public ImGroupDO getGroup(Long id) { 62 + public GroupDO getGroup(Long id) {
63 return imGroupMapper.selectById(id); 63 return imGroupMapper.selectById(id);
64 } 64 }
65 65
66 @Override 66 @Override
67 - public PageResult<ImGroupDO> getGroupPage(ImGroupPageReqVO pageReqVO) { 67 + public PageResult<GroupDO> getGroupPage(ImGroupPageReqVO pageReqVO) {
68 return imGroupMapper.selectPage(pageReqVO); 68 return imGroupMapper.selectPage(pageReqVO);
69 } 69 }
70 70
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; @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.service.groupmember;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO; 4 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberPageReqVO;
5 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO; 5 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO;
6 -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; 6 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
7 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
8 8
9 import java.util.List; 9 import java.util.List;
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; @@ -5,7 +5,7 @@ import jakarta.annotation.Resource;
5 import org.springframework.validation.annotation.Validated; 5 import org.springframework.validation.annotation.Validated;
6 6
7 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.*; 7 import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.*;
8 -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO; 8 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
11 11
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; @@ -2,8 +2,9 @@ package cn.iocoder.yudao.module.im.service.inbox;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; 4 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
5 -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;  
6 -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; 5 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO;
  6 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
  7 +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
7 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
8 9
9 // TODO @hao:不用的方法,删除下哈; 10 // TODO @hao:不用的方法,删除下哈;
@@ -20,14 +21,14 @@ public interface ImInboxService { @@ -20,14 +21,14 @@ public interface ImInboxService {
20 * @param createReqVO 创建信息 21 * @param createReqVO 创建信息
21 * @return 编号 22 * @return 编号
22 */ 23 */
23 - Long createInbox(@Valid ImInboxSaveReqVO createReqVO); 24 + Long createInbox(@Valid InboxSaveReqVO createReqVO);
24 25
25 /** 26 /**
26 * 更新收件箱 27 * 更新收件箱
27 * 28 *
28 * @param updateReqVO 更新信息 29 * @param updateReqVO 更新信息
29 */ 30 */
30 - void updateInbox(@Valid ImInboxSaveReqVO updateReqVO); 31 + void updateInbox(@Valid InboxSaveReqVO updateReqVO);
31 32
32 /** 33 /**
33 * 删除收件箱 34 * 删除收件箱
@@ -42,7 +43,7 @@ public interface ImInboxService { @@ -42,7 +43,7 @@ public interface ImInboxService {
42 * @param id 编号 43 * @param id 编号
43 * @return 收件箱 44 * @return 收件箱
44 */ 45 */
45 - ImInboxDO getInbox(Long id); 46 + InboxDO getInbox(Long id);
46 47
47 /** 48 /**
48 * 获得收件箱分页 49 * 获得收件箱分页
@@ -50,6 +51,11 @@ public interface ImInboxService { @@ -50,6 +51,11 @@ public interface ImInboxService {
50 * @param pageReqVO 分页查询 51 * @param pageReqVO 分页查询
51 * @return 收件箱分页 52 * @return 收件箱分页
52 */ 53 */
53 - PageResult<ImInboxDO> getInboxPage(ImInboxPageReqVO pageReqVO); 54 + PageResult<InboxDO> getInboxPage(ImInboxPageReqVO pageReqVO);
54 55
  56 + /**
  57 + * 保存收件箱和发送消息
  58 + * @param inboxSaveMessageReqVO 收件箱保存消息 Request VO
  59 + */
  60 + void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessageReqVO);
55 } 61 }
56 \ No newline at end of file 62 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxServiceImpl.java
1 package cn.iocoder.yudao.module.im.service.inbox; 1 package cn.iocoder.yudao.module.im.service.inbox;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
5 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO; 7 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
6 -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;  
7 -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO; 8 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
  9 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO;
  10 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSendMessageReqVO;
  11 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
  12 +import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
8 import cn.iocoder.yudao.module.im.dal.mysql.inbox.ImInboxMapper; 13 import cn.iocoder.yudao.module.im.dal.mysql.inbox.ImInboxMapper;
  14 +import cn.iocoder.yudao.module.im.dal.redis.inbox.InboxLockRedisDAO;
  15 +import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceRedisDao;
  16 +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
  17 +import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;
9 import jakarta.annotation.Resource; 18 import jakarta.annotation.Resource;
  19 +import org.dromara.hutool.core.date.DateUnit;
10 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
11 import org.springframework.validation.annotation.Validated; 21 import org.springframework.validation.annotation.Validated;
12 22
  23 +import java.util.List;
  24 +
13 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 25 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
14 import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXISTS; 26 import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXISTS;
15 27
@@ -22,22 +34,33 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXIS @@ -22,22 +34,33 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXIS
22 @Validated 34 @Validated
23 public class ImInboxServiceImpl implements ImInboxService { 35 public class ImInboxServiceImpl implements ImInboxService {
24 36
  37 + private static final Long INBOX_LOCK_TIMEOUT = 120 * DateUnit.SECOND.getMillis();
  38 + private static final String IM_MESSAGE_RECEIVE = "im-message-receive";
  39 +
25 @Resource 40 @Resource
26 private ImInboxMapper imInboxMapper; 41 private ImInboxMapper imInboxMapper;
  42 + @Resource
  43 + private SequenceRedisDao sequenceRedisDao; // 序列生成器Redis DAO
  44 + @Resource
  45 + private InboxLockRedisDAO inboxLockRedisDAO; // 收件箱的锁 Redis DAO
  46 + @Resource
  47 + private WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器
  48 + @Resource
  49 + private ImGroupMemberService imGroupMemberService;
27 50
28 @Override 51 @Override
29 - public Long createInbox(ImInboxSaveReqVO createReqVO) {  
30 - ImInboxDO inbox = BeanUtils.toBean(createReqVO, ImInboxDO.class); 52 + public Long createInbox(InboxSaveReqVO createReqVO) {
  53 + InboxDO inbox = BeanUtils.toBean(createReqVO, InboxDO.class);
31 imInboxMapper.insert(inbox); 54 imInboxMapper.insert(inbox);
32 return inbox.getId(); 55 return inbox.getId();
33 } 56 }
34 57
35 @Override 58 @Override
36 - public void updateInbox(ImInboxSaveReqVO updateReqVO) { 59 + public void updateInbox(InboxSaveReqVO updateReqVO) {
37 // 校验存在 60 // 校验存在
38 validateInboxExists(updateReqVO.getId()); 61 validateInboxExists(updateReqVO.getId());
39 // 更新 62 // 更新
40 - ImInboxDO updateObj = BeanUtils.toBean(updateReqVO, ImInboxDO.class); 63 + InboxDO updateObj = BeanUtils.toBean(updateReqVO, InboxDO.class);
41 imInboxMapper.updateById(updateObj); 64 imInboxMapper.updateById(updateObj);
42 } 65 }
43 66
@@ -56,13 +79,45 @@ public class ImInboxServiceImpl implements ImInboxService { @@ -56,13 +79,45 @@ public class ImInboxServiceImpl implements ImInboxService {
56 } 79 }
57 80
58 @Override 81 @Override
59 - public ImInboxDO getInbox(Long id) { 82 + public InboxDO getInbox(Long id) {
60 return imInboxMapper.selectById(id); 83 return imInboxMapper.selectById(id);
61 } 84 }
62 85
63 @Override 86 @Override
64 - public PageResult<ImInboxDO> getInboxPage(ImInboxPageReqVO pageReqVO) { 87 + public PageResult<InboxDO> getInboxPage(ImInboxPageReqVO pageReqVO) {
65 return imInboxMapper.selectPage(pageReqVO); 88 return imInboxMapper.selectPage(pageReqVO);
66 } 89 }
67 90
  91 + @Override
  92 + public void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessage) {
  93 + // 保存收件箱 + 发送消息给用户
  94 + saveInboxAndSendMessageForUser(inboxSaveMessage.getFromId(), inboxSaveMessage);
  95 +
  96 + if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) {
  97 + saveInboxAndSendMessageForUser(inboxSaveMessage.getReceiverId(), inboxSaveMessage);
  98 + } else if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
  99 + List<GroupMemberDO> groupMembers = imGroupMemberService.selectByGroupId(inboxSaveMessage.getReceiverId());
  100 + groupMembers.forEach(groupMemberDO -> saveInboxAndSendMessageForUser(groupMemberDO.getUserId(), inboxSaveMessage));
  101 + }
  102 + }
  103 +
  104 + private void saveInboxAndSendMessageForUser(Long userId, InboxSaveMessageReqVO inboxSaveMessage) {
  105 + inboxLockRedisDAO.lock(userId, INBOX_LOCK_TIMEOUT, () -> {
  106 + Long userSequence = sequenceRedisDao.generateSequence(userId);
  107 + InboxDO inbox = new InboxDO();
  108 + inbox.setUserId(userId);
  109 + inbox.setMessageId(inboxSaveMessage.getMessageId());
  110 + inbox.setSequence(userSequence);
  111 + imInboxMapper.insert(inbox);
  112 +
  113 + //是发送人不发送
  114 + if (userId.equals(inboxSaveMessage.getFromId())) {
  115 + return;
  116 + }
  117 + InboxSendMessageReqVO message = BeanUtils.toBean(inboxSaveMessage, InboxSendMessageReqVO.class);
  118 + message.setSequence(userSequence);
  119 + webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message);
  120 + });
  121 + }
  122 +
68 } 123 }
69 \ No newline at end of file 124 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageService.java deleted
1 -package cn.iocoder.yudao.module.im.service.message;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
4 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO;  
5 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO;  
6 -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;  
7 -import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;  
8 -import jakarta.validation.Valid;  
9 -  
10 -import java.util.List;  
11 -  
12 -/**  
13 - * 消息 Service 接口  
14 - *  
15 - * @author 芋道源码  
16 - */  
17 -public interface ImMessageService {  
18 -  
19 - /**  
20 - * 创建消息  
21 - *  
22 - * @param createReqVO 创建信息  
23 - * @return 编号  
24 - */  
25 - Long createMessage(@Valid ImMessageSaveReqVO createReqVO);  
26 -  
27 - /**  
28 - * 更新消息  
29 - *  
30 - * @param updateReqVO 更新信息  
31 - */  
32 - void updateMessage(@Valid ImMessageSaveReqVO updateReqVO);  
33 -  
34 - /**  
35 - * 删除消息  
36 - *  
37 - * @param id 编号  
38 - */  
39 - void deleteMessage(Long id);  
40 -  
41 - /**  
42 - * 获得消息  
43 - *  
44 - * @param id 编号  
45 - * @return 消息  
46 - */  
47 - ImMessageDO getMessage(Long id);  
48 -  
49 - /**  
50 - * 获得消息分页  
51 - *  
52 - * @param pageReqVO 分页查询  
53 - * @return 消息分页  
54 - */  
55 - PageResult<ImMessageDO> getMessagePage(ImMessagePageReqVO pageReqVO);  
56 -  
57 -  
58 - /**  
59 - * 保存私聊消息  
60 - *  
61 - * @param imSendMessage 消息信息  
62 - * @param fromUserId 发送人编号  
63 - * @return id  
64 - */  
65 - ImMessageDO savePrivateMessage(ImSendMessage imSendMessage, Long fromUserId);  
66 -  
67 - /**  
68 - * 更新消息状态  
69 - *  
70 - * @param messageId 消息id  
71 - * @param messageStatus 消息状态  
72 - */  
73 - void updateMessageStatus(Long messageId, Integer messageStatus);  
74 -  
75 - /**  
76 - * 保存群聊消息  
77 - *  
78 - * @param message 消息  
79 - * @param fromUserId 发送者用户ID  
80 - * @return id  
81 - */  
82 - ImMessageDO saveGroupMessage(ImSendMessage message, Long fromUserId);  
83 -  
84 - /**  
85 - * 拉取消息-大于 seq 的消息  
86 - *  
87 - * @param userId 用户id  
88 - * @param sequence 序列号  
89 - * @param size 数量  
90 - * @return 消息列表  
91 - */  
92 - List<ImMessageDO> loadMessage(Long userId, Long sequence, Integer size);  
93 -  
94 - // TODO @hao;这种接口,项目里叫 getMessageListByUserId,尽量保持 getList 获取列表哈;  
95 - /**  
96 - * 拉取全部消息  
97 - *  
98 - * @param userId 登录用户编号  
99 - * @param size 数量  
100 - * @return 消息列表  
101 - */  
102 - List<ImMessageDO> loadAllMessage(Long userId, Integer size);  
103 -}  
104 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.im.service.message;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
4 -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;  
5 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessagePageReqVO;  
6 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageSaveReqVO;  
7 -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;  
8 -import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper;  
9 -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum;  
10 -import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;  
11 -import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;  
12 -import cn.iocoder.yudao.module.system.api.user.AdminUserApi;  
13 -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;  
14 -import jakarta.annotation.Resource;  
15 -import org.dromara.hutool.core.date.TimeUtil;  
16 -import org.springframework.stereotype.Service;  
17 -import org.springframework.validation.annotation.Validated;  
18 -  
19 -import java.util.List;  
20 -  
21 -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;  
22 -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_NOT_EXISTS;  
23 -  
24 -/**  
25 - * 消息 Service 实现类  
26 - *  
27 - * @author 芋道源码  
28 - */  
29 -@Service  
30 -@Validated  
31 -public class ImMessageServiceImpl implements ImMessageService {  
32 -  
33 - @Resource  
34 - private ImMessageMapper imMessageMapper;  
35 - @Resource  
36 - private AdminUserApi adminUserApi;  
37 -  
38 - @Override  
39 - public Long createMessage(ImMessageSaveReqVO createReqVO) {  
40 - // 插入  
41 - ImMessageDO message = BeanUtils.toBean(createReqVO, ImMessageDO.class);  
42 - imMessageMapper.insert(message);  
43 - // 返回  
44 - return message.getId();  
45 - }  
46 -  
47 - @Override  
48 - public void updateMessage(ImMessageSaveReqVO updateReqVO) {  
49 - // 校验存在  
50 - validateMessageExists(updateReqVO.getId());  
51 - // 更新  
52 - ImMessageDO updateObj = BeanUtils.toBean(updateReqVO, ImMessageDO.class);  
53 - imMessageMapper.updateById(updateObj);  
54 - }  
55 -  
56 - @Override  
57 - public void deleteMessage(Long id) {  
58 - // 校验存在  
59 - validateMessageExists(id);  
60 - // 删除  
61 - imMessageMapper.deleteById(id);  
62 - }  
63 -  
64 - private void validateMessageExists(Long id) {  
65 - if (imMessageMapper.selectById(id) == null) {  
66 - throw exception(MESSAGE_NOT_EXISTS);  
67 - }  
68 - }  
69 -  
70 - @Override  
71 - public ImMessageDO getMessage(Long id) {  
72 - return imMessageMapper.selectById(id);  
73 - }  
74 -  
75 - @Override  
76 - public PageResult<ImMessageDO> getMessagePage(ImMessagePageReqVO pageReqVO) {  
77 - return imMessageMapper.selectPage(pageReqVO);  
78 - }  
79 -  
80 -  
81 - @Override  
82 - public ImMessageDO savePrivateMessage(ImSendMessage message, Long fromUserId) {  
83 - return saveImMessageDO(message, fromUserId);  
84 - }  
85 -  
86 - private ImMessageDO saveImMessageDO(ImSendMessage message, Long fromUserId) {  
87 - // TODO @hao:可以搞成 messageDO  
88 - // TODO @hao:链式调用  
89 - ImMessageDO imMessageDO = new ImMessageDO();  
90 - imMessageDO.setClientMessageId(message.getClientMessageId());  
91 - imMessageDO.setSenderId(fromUserId);  
92 - imMessageDO.setReceiverId(message.getReceiverId());  
93 - // 查询发送人昵称和发送人头像  
94 - AdminUserRespDTO user = adminUserApi.getUser(fromUserId);  
95 - imMessageDO.setSenderNickname(user.getNickname());  
96 - imMessageDO.setSenderAvatar(user.getAvatar());  
97 - imMessageDO.setConversationType(message.getConversationType());  
98 - imMessageDO.setContentType(message.getContentType());  
99 - // 单聊:s_{userId}_{targetId} 群聊:群聊:g_{groupId}  
100 - // TODO @hao:这里的 conversationNo 的生成,可以写到工具类里,或者干脆放到 ImConversationTypeEnum 里;  
101 - if (message.getConversationType().equals(ImConversationTypeEnum.PRIVATE.getType())) {  
102 - imMessageDO.setConversationNo("s_" + fromUserId + "_" + message.getReceiverId());  
103 - } else if (message.getConversationType().equals(ImConversationTypeEnum.GROUP.getType())) {  
104 - imMessageDO.setConversationNo("g_" + message.getReceiverId());  
105 - }  
106 - imMessageDO.setContent(message.getContent());  
107 - // TODO @hao:枚举哈;  
108 - // 消息来源 100-用户发送;200-系统发送(一般是通知);不能为空  
109 - imMessageDO.setSendFrom(100);  
110 - imMessageDO.setSendTime(TimeUtil.now());  
111 - // TODO @hao:服务端的消息,就是默认生成哈;  
112 - imMessageDO.setMessageStatus(ImMessageStatusEnum.SENDING.getStatus());  
113 - imMessageMapper.insert(imMessageDO);  
114 - return imMessageDO;  
115 - }  
116 -  
117 - @Override  
118 - public void updateMessageStatus(Long messageId, Integer messageStatus) {  
119 - // 校验 id 是否存在  
120 - validateMessageExists(messageId);  
121 - //更新消息状态  
122 - ImMessageDO imMessageDO = new ImMessageDO();  
123 - imMessageDO.setId(messageId);  
124 - imMessageDO.setMessageStatus(messageStatus);  
125 - imMessageMapper.updateById(imMessageDO);  
126 - }  
127 -  
128 - @Override  
129 - public ImMessageDO saveGroupMessage(ImSendMessage message, Long fromUserId) {  
130 - return saveImMessageDO(message, fromUserId);  
131 - }  
132 -  
133 - @Override  
134 - public List<ImMessageDO> loadMessage(Long userId, Long sequence, Integer size) {  
135 - return imMessageMapper.getGreaterThanSequenceMessage(userId, sequence, size);  
136 - }  
137 -  
138 - @Override  
139 - public List<ImMessageDO> loadAllMessage(Long userId, Integer size) {  
140 - return imMessageMapper.getAllMessage(userId, size);  
141 - }  
142 -  
143 -}  
144 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageService.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.service.message;
  2 +
  3 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO;
  4 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO;
  5 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO;
  6 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 消息 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface MessageService {
  16 +
  17 + /**
  18 + * 获得消息分页
  19 + *
  20 + * @param pageReqVO 分页查询
  21 + * @return 消息分页
  22 + */
  23 + List<MessageDO> getMessagePage(MessagePageReqVO pageReqVO);
  24 +
  25 +
  26 + /**
  27 + * 拉取消息-大于 seq 的消息
  28 + *
  29 + * @param userId 用户id
  30 + * @param sequence 序列号
  31 + * @param size 数量
  32 + * @return 消息列表
  33 + */
  34 + List<MessageDO> getMessageListBySequence(Long userId, Long sequence, Integer size);
  35 +
  36 + /**
  37 + * 发送消息
  38 + * @param loginUserId 登录用户编号
  39 + * @param message 消息
  40 + * @return 消息编号
  41 + */
  42 + SendMessageRespVO sendMessage(Long loginUserId, SendMessageReqVO message);
  43 +}
0 \ No newline at end of file 44 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java 0 → 100755
  1 +package cn.iocoder.yudao.module.im.service.message;
  2 +
  3 +import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
  4 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO;
  5 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO;
  6 +import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO;
  7 +import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
  8 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
  9 +import cn.iocoder.yudao.module.im.dal.mysql.message.MessageMapper;
  10 +import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
  11 +import cn.iocoder.yudao.module.im.enums.message.MessageSourceEnum;
  12 +import cn.iocoder.yudao.module.im.enums.message.MessageStatusEnum;
  13 +import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;
  14 +import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
  15 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  16 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  17 +import jakarta.annotation.Resource;
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.dromara.hutool.core.date.TimeUtil;
  20 +import org.springframework.stereotype.Service;
  21 +import org.springframework.validation.annotation.Validated;
  22 +
  23 +import java.util.List;
  24 +
  25 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  26 +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.MESSAGE_RECEIVER_NOT_EXISTS;
  27 +
  28 +/**
  29 + * 消息 Service 实现类
  30 + *
  31 + * @author 芋道源码
  32 + */
  33 +@Service
  34 +@Validated
  35 +@Slf4j
  36 +public class MessageServiceImpl implements MessageService {
  37 +
  38 + @Resource
  39 + private MessageMapper messageMapper;
  40 + @Resource
  41 + private ImInboxService imInboxService; // IM收件箱服务
  42 + @Resource
  43 + private AdminUserApi adminUserApi;
  44 + @Resource
  45 + private ImGroupMemberService imGroupMemberService;
  46 +
  47 + @Override
  48 + public List<MessageDO> getMessagePage(MessagePageReqVO pageReqVO) {
  49 + return messageMapper.getMessagePage(pageReqVO);
  50 + }
  51 +
  52 + @Override
  53 + public List<MessageDO> getMessageListBySequence(Long userId, Long sequence, Integer size) {
  54 + return messageMapper.getGreaterThanSequenceMessage(userId, sequence, size);
  55 + }
  56 +
  57 + @Override
  58 + public SendMessageRespVO sendMessage(Long fromUserId, SendMessageReqVO message) {
  59 + // 保存消息
  60 + InboxSaveMessageReqVO inboxSaveMessageReqVO = new InboxSaveMessageReqVO();
  61 + SendMessageRespVO sendMessageRespVO = saveMessage(fromUserId, message, inboxSaveMessageReqVO);
  62 +
  63 + // 保存收件箱 + 发送消息给用户
  64 + imInboxService.saveInboxAndSendMessage(inboxSaveMessageReqVO);
  65 + return sendMessageRespVO;
  66 + }
  67 +
  68 + public SendMessageRespVO saveMessage(Long fromUserId, SendMessageReqVO message, InboxSaveMessageReqVO inboxSaveMessageReqVO) {
  69 + //需要校验 receiverId 存在
  70 + validateReceiverIdExists(message);
  71 + // 查询发送人昵称和发送人头像
  72 + AdminUserRespDTO fromUser = adminUserApi.getUser(fromUserId);
  73 + // 使用链式调用创建 MessageDO 对象
  74 + MessageDO messageDO = new MessageDO()
  75 + .setClientMessageId(message.getClientMessageId())
  76 + .setSenderId(fromUserId)
  77 + .setReceiverId(message.getReceiverId())
  78 + .setSenderNickname(fromUser.getNickname())
  79 + .setSenderAvatar(fromUser.getAvatar())
  80 + .setConversationType(message.getConversationType())
  81 + .setContentType(message.getContentType())
  82 + .setConversationNo(ConversationTypeEnum.generateConversationNo(fromUserId, message.getReceiverId(), message.getConversationType()))
  83 + .setContent(message.getContent())
  84 + .setSendFrom(MessageSourceEnum.USER_SEND.getStatus())
  85 + .setSendTime(TimeUtil.now())
  86 + .setMessageStatus(MessageStatusEnum.SENDING.getStatus());
  87 + messageMapper.insert(messageDO);
  88 +
  89 + // 设置 InboxSaveMessageReqVO 对象
  90 + inboxSaveMessageReqVO.setConversationType(message.getConversationType());
  91 + inboxSaveMessageReqVO.setFromId(fromUserId);
  92 + inboxSaveMessageReqVO.setReceiverId(message.getReceiverId());
  93 + inboxSaveMessageReqVO.setMessageId(messageDO.getId());
  94 + inboxSaveMessageReqVO.setContentType(message.getContentType());
  95 + inboxSaveMessageReqVO.setContent(message.getContent());
  96 + inboxSaveMessageReqVO.setSendTime(messageDO.getSendTime());
  97 +
  98 + // 返回 SendMessageRespVO 对象
  99 + return new SendMessageRespVO(messageDO.getId(), messageDO.getSendTime());
  100 + }
  101 +
  102 + private void validateReceiverIdExists(SendMessageReqVO message) {
  103 + if (message.getReceiverId() == null) {
  104 + throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
  105 + }
  106 + if (message.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) {
  107 + //校验用户是否存在;
  108 + AdminUserRespDTO receiverUser = adminUserApi.getUser(message.getReceiverId());
  109 + if (receiverUser == null) {
  110 + throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
  111 + }
  112 +
  113 + } else if (message.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
  114 + //校验群聊是否存在;
  115 + List<GroupMemberDO> groupMemberDOS = imGroupMemberService.selectByGroupId(message.getReceiverId());
  116 + if (groupMemberDOS.isEmpty()) {
  117 + throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
  118 + }
  119 + }
  120 + }
  121 +
  122 +}
0 \ No newline at end of file 123 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/ImWebSocketMessageListener.java deleted
1 -package cn.iocoder.yudao.module.im.websocket;  
2 -  
3 -import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;  
4 -import cn.iocoder.yudao.framework.websocket.core.listener.WebSocketMessageListener;  
5 -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;  
6 -import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;  
7 -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;  
8 -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO;  
9 -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;  
10 -import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceGeneratorRedisDao;  
11 -import cn.iocoder.yudao.module.im.enums.conversation.ImConversationTypeEnum;  
12 -import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum;  
13 -import cn.iocoder.yudao.module.im.service.conversation.ImConversationService;  
14 -import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;  
15 -import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;  
16 -import cn.iocoder.yudao.module.im.service.message.ImMessageService;  
17 -import cn.iocoder.yudao.module.im.websocket.message.ImReceiveMessage;  
18 -import cn.iocoder.yudao.module.im.websocket.message.ImSendMessage;  
19 -import jakarta.annotation.Resource;  
20 -import lombok.extern.slf4j.Slf4j;  
21 -import org.springframework.stereotype.Component;  
22 -import org.springframework.web.socket.WebSocketSession;  
23 -  
24 -import java.util.List;  
25 -  
26 -// TODO @hao:消息发送,使用 http 上行。因为在 cloud 框架下,我们比较难去 Listener。因为 im-server 不会自己启动 websocket 路径  
27 -/**  
28 - * WebSocket im  
29 - *  
30 - * @author 芋道源码  
31 - */  
32 -@Component  
33 -@Slf4j  
34 -public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSendMessage> {  
35 -  
36 - public static final String IM_MESSAGE_RECEIVE = "im-message-receive";  
37 - @Resource  
38 - private WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器  
39 - @Resource  
40 - private ImMessageService imMessageService; // IM消息服务  
41 - @Resource  
42 - private ImConversationService imConversationService; // IM会话服务  
43 - @Resource  
44 - private ImInboxService imInboxService; // IM收件箱服务  
45 - @Resource  
46 - private ImGroupMemberService imGroupMemberService; // 群成员服务  
47 - @Resource  
48 - private SequenceGeneratorRedisDao sequenceGeneratorRedisDao; // 序列生成器Redis DAO  
49 -  
50 - /**  
51 - * 处理WebSocket消息  
52 - *  
53 - * @param session WebSocket会话  
54 - * @param message 发送的IM消息  
55 - */  
56 - @Override  
57 - public void onMessage(WebSocketSession session, ImSendMessage message) {  
58 - Long fromUserId = WebSocketFrameworkUtils.getLoginUserId(session); // 获取登录用户ID  
59 -  
60 - // 如果是私人消息,处理私人消息  
61 - if (message.getConversationType().equals(ImConversationTypeEnum.PRIVATE.getType())) {  
62 - handlePrivateMessage(fromUserId, message);  
63 - } else if (message.getConversationType().equals(ImConversationTypeEnum.GROUP.getType())) {  
64 - // 处理群聊消息  
65 - handleGroupMessage(fromUserId, message);  
66 - } else {  
67 - // TODO @hao:是不是应该会话类型哈?然后打印这种错误日志,最好把 message 整个打进去,这样更好定位完整的消息;  
68 - log.error("[onMessage][消息类型({}) 未支持]", message.getConversationType());  
69 - }  
70 - }  
71 -  
72 - /**  
73 - * 处理群聊消息  
74 - *  
75 - * @param fromUserId 发送者用户ID  
76 - * @param message 发送的IM消息  
77 - */  
78 - private void handleGroupMessage(Long fromUserId, ImSendMessage message) {  
79 - // TODO @hao:群存在;  
80 - // TODO @hao:发送人在群里;  
81 - ImMessageDO imMessageDO = imMessageService.saveGroupMessage(message, fromUserId); // 保存群聊消息  
82 - Long groupId = message.getReceiverId();  
83 -  
84 - // 发送消息给群聊成员  
85 - // TODO @hao:变量名可以叫 groupMembers;一般不用 DO 后缀,除非为了区分;  
86 - List<GroupMemberDO> groupMemberDOList = imGroupMemberService.selectByGroupId(groupId);  
87 - groupMemberDOList.forEach(groupMemberDO -> {  
88 - // 过滤掉自己  
89 - // TODO @hao:98 到 99 的代码,是不是可以融合到这里来;  
90 - if (groupMemberDO.getUserId().equals(fromUserId)) {  
91 - return;  
92 - }  
93 - Long receiverSequence = sequenceGeneratorRedisDao.generateSequence(groupMemberDO.getUserId()); // 生成接收者序列  
94 - Long receiverInboxId = createAndSaveInbox(groupMemberDO.getUserId(), imMessageDO.getId(), receiverSequence); // 创建并保存接收者收件箱  
95 - sendMessage(groupMemberDO.getUserId(), receiverInboxId, imMessageDO, message, receiverSequence);  
96 - });  
97 -  
98 - Long fromUserSequence = sequenceGeneratorRedisDao.generateSequence(fromUserId); // 生成发送者序列  
99 - Long fromUserInboxId = createAndSaveInbox(fromUserId, imMessageDO.getId(), fromUserSequence); // 创建并保存发送者收件箱  
100 -  
101 - // 发送消息给发送者  
102 - sendMessage(fromUserId, fromUserInboxId, imMessageDO, message, fromUserSequence);  
103 -  
104 - // 更新消息状态为成功  
105 - imMessageService.updateMessageStatus(imMessageDO.getId(), ImMessageStatusEnum.SUCCESS.getStatus());  
106 - }  
107 -  
108 - /**  
109 - * 处理私人消息  
110 - *  
111 - * @param fromUserId 发送者用户ID  
112 - * @param message 发送的IM消息  
113 - */  
114 - private void handlePrivateMessage(Long fromUserId, ImSendMessage message) {  
115 - // TODO @hao:需要校验 receiverId 存在;  
116 - ImMessageDO imMessageDO = imMessageService.savePrivateMessage(message, fromUserId); // 保存私人消息  
117 - Long receiverId = message.getReceiverId();  
118 -  
119 - // TODO @hao:sequenceGeneratorRedisDao.generateSequence 和 createAndSaveInbox 步骤,要加锁;不然会有并发问题;如果有疑问,可以微信招我沟通哈;另外,创建 seq、保存收件箱、发送,可以统一封装到 imInboxService 里哈;这样,后续要发某个消息,就是丢个 message 对象进去;  
120 - Long fromUserSequence = sequenceGeneratorRedisDao.generateSequence(fromUserId); // 生成发送者序列  
121 - Long fromUserInboxId = createAndSaveInbox(fromUserId, imMessageDO.getId(), fromUserSequence); // 创建并保存发送者收件箱  
122 -  
123 - Long receiverSequence = sequenceGeneratorRedisDao.generateSequence(message.getReceiverId()); // 生成接收者序列  
124 - Long receiverInboxId = createAndSaveInbox(message.getReceiverId(), imMessageDO.getId(), receiverSequence); // 创建并保存接收者收件箱  
125 -  
126 - // 发送消息给接收者和发送者  
127 - sendMessage(fromUserId, fromUserInboxId, imMessageDO, message, fromUserSequence);  
128 - sendMessage(receiverId, receiverInboxId, imMessageDO, message, receiverSequence);  
129 -  
130 - // 更新消息状态为成功  
131 - // TODO @hao:后端消息的发送,默认就是 success 哈,不要区分 status;status 更多是前端使用的;  
132 - imMessageService.updateMessageStatus(imMessageDO.getId(), ImMessageStatusEnum.SUCCESS.getStatus());  
133 - // 保存私人会话,只有在 client 操作会话(已读、置顶)时,才会延迟创建  
134 - //imConversationService.savePrivateConversation(fromUserId, receiverId);  
135 - }  
136 -  
137 - /**  
138 - * 创建并保存收件箱  
139 - *  
140 - * @param userId 用户ID  
141 - * @param messageId 消息ID  
142 - * @param sequence 序列  
143 - * @return 收件箱ID  
144 - */  
145 - private Long createAndSaveInbox(Long userId, Long messageId, Long sequence) {  
146 - ImInboxSaveReqVO inboxSaveReqVO = new ImInboxSaveReqVO(userId, messageId, sequence); // 创建收件箱保存请求VO  
147 - return imInboxService.createInbox(inboxSaveReqVO); // 创建收件箱  
148 - }  
149 -  
150 - // TODO @hao:这个使用 WebSocketSenderApi 发送哈;  
151 - /**  
152 - * 发送消息  
153 - *  
154 - * @param fromUserId 发送者用户ID  
155 - * @param inboxId 收件箱ID  
156 - * @param imMessageDO IM消息数据对象  
157 - * @param message 发送的IM消息  
158 - * @param sequence 序列  
159 - */  
160 - private void sendMessage(Long fromUserId, Long inboxId, ImMessageDO imMessageDO, ImSendMessage message, Long sequence) {  
161 - // TODO @hao:不要每个字段 set 占一行;想同类型的字段用一行,然后链式 set,会更简洁干净。  
162 - ImReceiveMessage receiveMessage = new ImReceiveMessage(); // 创建接收消息  
163 - receiveMessage.setFromId(fromUserId); // 设置发送者ID  
164 - receiveMessage.setConversationType(message.getConversationType()); // 设置会话类型  
165 - receiveMessage.setContentType(message.getContentType()); // 设置内容类型  
166 - receiveMessage.setContent(message.getContent()); // 设置内容  
167 - receiveMessage.setMessageId(imMessageDO.getId()); // 设置消息ID  
168 - receiveMessage.setInboxId(inboxId); // 设置收件箱ID  
169 - receiveMessage.setSendTime(imMessageDO.getSendTime()); // 设置发送时间  
170 - receiveMessage.setSequence(sequence); // 设置序列  
171 - webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), fromUserId, ImWebSocketMessageListener.IM_MESSAGE_RECEIVE, receiveMessage); // 发送消息  
172 - }  
173 -  
174 - /**  
175 - * 获取类型  
176 - *  
177 - * @return 类型  
178 - */  
179 - @Override  
180 - public String getType() {  
181 - return "im-message-send";  
182 - }  
183 -  
184 -}  
185 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImSendMessage.java deleted
1 -package cn.iocoder.yudao.module.im.websocket.message;  
2 -  
3 -import io.swagger.v3.oas.annotations.media.Schema;  
4 -import lombok.Data;  
5 -  
6 -@Schema(description = "管理后台 - IM 消息发送 send")  
7 -@Data  
8 -public class ImSendMessage {  
9 -  
10 - @Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331")  
11 - private String clientMessageId;  
12 -  
13 - @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
14 - // TODO @hao:用下 InEnum 校验。这样可以少写 15 的注释哈;类似 contentType 也是;  
15 - private Integer conversationType; // 对应 ImConversationTypeEnum 枚举  
16 -  
17 - @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")  
18 - private Long receiverId; // 根据 conversationType 区分  
19 -  
20 - @Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
21 - private Integer contentType; // 参见 ImMessageTypeEnum 枚举  
22 -  
23 - @Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)  
24 - private String content;  
25 -  
26 -}  
27 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ImConversationMapper.xml renamed to yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ConversationMapper.xml
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationMapper"> 3 +<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.conversation.ConversationMapper">
4 4
5 <!-- TODO @hao:xml 如果用不到,可以先删除哈 --> 5 <!-- TODO @hao:xml 如果用不到,可以先删除哈 -->
6 <!-- 6 <!--
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/message/ImMessageMapper.xml renamed to yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/message/MessageMapper.xml
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3 -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper"> 3 +<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.message.MessageMapper">
4 4
5 <!-- 5 <!--
6 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。 6 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
yudao-module-im/yudao-module-im-biz/src/test/java/cn/iocoder/yudao/module/im/service/conversation/ImConversationServiceImplTest.java deleted
1 -package cn.iocoder.yudao.module.im.service.conversation;  
2 -  
3 -import org.junit.jupiter.api.Disabled;  
4 -import org.junit.jupiter.api.Test;  
5 -  
6 -import jakarta.annotation.Resource;  
7 -  
8 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
9 -  
10 -import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.*;  
11 -import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ImConversationDO;  
12 -import cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationMapper;  
13 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
14 -  
15 -import org.springframework.context.annotation.Import;  
16 -  
17 -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;  
18 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;  
19 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;  
20 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;  
21 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;  
22 -import static org.junit.jupiter.api.Assertions.*;  
23 -  
24 -// TODO @hao:单测可以先都删除,等后面搞了在弄  
25 -/**  
26 - * {@link ImConversationServiceImpl} 的单元测试类  
27 - *  
28 - * @author 芋道源码  
29 - */  
30 -@Import(ImConversationServiceImpl.class)  
31 -public class ImConversationServiceImplTest extends BaseDbUnitTest {  
32 -  
33 - @Resource  
34 - private ImConversationServiceImpl conversationService;  
35 -  
36 - @Resource  
37 - private ImConversationMapper imConversationMapper;  
38 -  
39 - @Test  
40 - public void testCreateConversation_success() {  
41 - // 准备参数  
42 - ImConversationSaveReqVO createReqVO = randomPojo(ImConversationSaveReqVO.class).setId(null);  
43 -  
44 - // 调用  
45 - Long conversationId = conversationService.createConversation(createReqVO);  
46 - // 断言  
47 - assertNotNull(conversationId);  
48 - // 校验记录的属性是否正确  
49 - ImConversationDO conversation = imConversationMapper.selectById(conversationId);  
50 - assertPojoEquals(createReqVO, conversation, "id");  
51 - }  
52 -  
53 - @Test  
54 - public void testUpdateConversation_success() {  
55 - // mock 数据  
56 - ImConversationDO dbConversation = randomPojo(ImConversationDO.class);  
57 - imConversationMapper.insert(dbConversation);// @Sql: 先插入出一条存在的数据  
58 - // 准备参数  
59 - ImConversationSaveReqVO updateReqVO = randomPojo(ImConversationSaveReqVO.class, o -> {  
60 - o.setId(dbConversation.getId()); // 设置更新的 ID  
61 - });  
62 -  
63 - // 调用  
64 - conversationService.updateConversation(updateReqVO);  
65 - // 校验是否更新正确  
66 - ImConversationDO conversation = imConversationMapper.selectById(updateReqVO.getId()); // 获取最新的  
67 - assertPojoEquals(updateReqVO, conversation);  
68 - }  
69 -  
70 - @Test  
71 - public void testUpdateConversation_notExists() {  
72 - // 准备参数  
73 - ImConversationSaveReqVO updateReqVO = randomPojo(ImConversationSaveReqVO.class);  
74 -  
75 - // 调用, 并断言异常  
76 - assertServiceException(() -> conversationService.updateConversation(updateReqVO), CONVERSATION_NOT_EXISTS);  
77 - }  
78 -  
79 - @Test  
80 - public void testDeleteConversation_success() {  
81 - // mock 数据  
82 - ImConversationDO dbConversation = randomPojo(ImConversationDO.class);  
83 - imConversationMapper.insert(dbConversation);// @Sql: 先插入出一条存在的数据  
84 - // 准备参数  
85 - Long id = dbConversation.getId();  
86 -  
87 - // 调用  
88 - conversationService.deleteConversation(id);  
89 - // 校验数据不存在了  
90 - assertNull(imConversationMapper.selectById(id));  
91 - }  
92 -  
93 - @Test  
94 - public void testDeleteConversation_notExists() {  
95 - // 准备参数  
96 - Long id = randomLongId();  
97 -  
98 - // 调用, 并断言异常  
99 - assertServiceException(() -> conversationService.deleteConversation(id), CONVERSATION_NOT_EXISTS);  
100 - }  
101 -  
102 - @Test  
103 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
104 - public void testGetConversationPage() {  
105 - // mock 数据  
106 - ImConversationDO dbConversation = randomPojo(ImConversationDO.class, o -> { // 等会查询到  
107 - o.setUserId(null);  
108 - o.setConversationType(null);  
109 - o.setTargetId(null);  
110 - o.setNo(null);  
111 - o.setPinned(null);  
112 - o.setLastReadTime(null);  
113 - o.setCreateTime(null);  
114 - });  
115 - imConversationMapper.insert(dbConversation);  
116 - // 测试 userId 不匹配  
117 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setUserId(null)));  
118 - // 测试 conversationType 不匹配  
119 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setConversationType(null)));  
120 - // 测试 targetId 不匹配  
121 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setTargetId(null)));  
122 - // 测试 no 不匹配  
123 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setNo(null)));  
124 - // 测试 pinned 不匹配  
125 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setPinned(null)));  
126 - // 测试 lastReadTime 不匹配  
127 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setLastReadTime(null)));  
128 - // 测试 createTime 不匹配  
129 - imConversationMapper.insert(cloneIgnoreId(dbConversation, o -> o.setCreateTime(null)));  
130 - // 准备参数  
131 - ImConversationPageReqVO reqVO = new ImConversationPageReqVO();  
132 - reqVO.setUserId(null);  
133 - reqVO.setConversationType(null);  
134 - reqVO.setTargetId(null);  
135 - reqVO.setNo(null);  
136 - reqVO.setPinned(null);  
137 - reqVO.setLastReadTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
138 - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
139 -  
140 - // 调用  
141 - PageResult<ImConversationDO> pageResult = conversationService.getConversationPage(reqVO);  
142 - // 断言  
143 - assertEquals(1, pageResult.getTotal());  
144 - assertEquals(1, pageResult.getList().size());  
145 - assertPojoEquals(dbConversation, pageResult.getList().get(0));  
146 - }  
147 -  
148 -}  
149 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/test/java/cn/iocoder/yudao/module/im/service/group/ImGroupServiceImplTest.java deleted
1 -package cn.iocoder.yudao.module.im.service.group;  
2 -  
3 -import org.junit.jupiter.api.Disabled;  
4 -import org.junit.jupiter.api.Test;  
5 -  
6 -import jakarta.annotation.Resource;  
7 -  
8 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
9 -  
10 -import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;  
11 -import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;  
12 -import cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMapper;  
13 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
14 -  
15 -import org.springframework.context.annotation.Import;  
16 -  
17 -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;  
18 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;  
19 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;  
20 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;  
21 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;  
22 -import static org.junit.jupiter.api.Assertions.*;  
23 -  
24 -/**  
25 - * {@link ImGroupServiceImpl} 的单元测试类  
26 - *  
27 - * @author 芋道源码  
28 - */  
29 -@Import(ImGroupServiceImpl.class)  
30 -public class ImGroupServiceImplTest extends BaseDbUnitTest {  
31 -  
32 - @Resource  
33 - private ImGroupServiceImpl groupService;  
34 -  
35 - @Resource  
36 - private ImGroupMapper imGroupMapper;  
37 -  
38 - @Test  
39 - public void testCreateGroup_success() {  
40 - // 准备参数  
41 - ImGroupSaveReqVO createReqVO = randomPojo(ImGroupSaveReqVO.class).setId(null);  
42 -  
43 - // 调用  
44 - Long groupId = groupService.createGroup(createReqVO);  
45 - // 断言  
46 - assertNotNull(groupId);  
47 - // 校验记录的属性是否正确  
48 - ImGroupDO group = imGroupMapper.selectById(groupId);  
49 - assertPojoEquals(createReqVO, group, "id");  
50 - }  
51 -  
52 - @Test  
53 - public void testUpdateGroup_success() {  
54 - // mock 数据  
55 - ImGroupDO dbGroup = randomPojo(ImGroupDO.class);  
56 - imGroupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据  
57 - // 准备参数  
58 - ImGroupSaveReqVO updateReqVO = randomPojo(ImGroupSaveReqVO.class, o -> {  
59 - o.setId(dbGroup.getId()); // 设置更新的 ID  
60 - });  
61 -  
62 - // 调用  
63 - groupService.updateGroup(updateReqVO);  
64 - // 校验是否更新正确  
65 - ImGroupDO group = imGroupMapper.selectById(updateReqVO.getId()); // 获取最新的  
66 - assertPojoEquals(updateReqVO, group);  
67 - }  
68 -  
69 - @Test  
70 - public void testUpdateGroup_notExists() {  
71 - // 准备参数  
72 - ImGroupSaveReqVO updateReqVO = randomPojo(ImGroupSaveReqVO.class);  
73 -  
74 - // 调用, 并断言异常  
75 - assertServiceException(() -> groupService.updateGroup(updateReqVO), GROUP_NOT_EXISTS);  
76 - }  
77 -  
78 - @Test  
79 - public void testDeleteGroup_success() {  
80 - // mock 数据  
81 - ImGroupDO dbGroup = randomPojo(ImGroupDO.class);  
82 - imGroupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据  
83 - // 准备参数  
84 - Long id = dbGroup.getId();  
85 -  
86 - // 调用  
87 - groupService.deleteGroup(id);  
88 - // 校验数据不存在了  
89 - assertNull(imGroupMapper.selectById(id));  
90 - }  
91 -  
92 - @Test  
93 - public void testDeleteGroup_notExists() {  
94 - // 准备参数  
95 - Long id = randomLongId();  
96 -  
97 - // 调用, 并断言异常  
98 - assertServiceException(() -> groupService.deleteGroup(id), GROUP_NOT_EXISTS);  
99 - }  
100 -  
101 - @Test  
102 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
103 - public void testGetGroupPage() {  
104 - // mock 数据  
105 - ImGroupDO dbGroup = randomPojo(ImGroupDO.class, o -> { // 等会查询到  
106 - o.setGroupName(null);  
107 - o.setOwnerId(null);  
108 - o.setHeadImage(null);  
109 - o.setHeadImageThumb(null);  
110 - o.setNotice(null);  
111 - o.setRemark(null);  
112 - o.setCreateTime(null);  
113 - });  
114 - imGroupMapper.insert(dbGroup);  
115 - // 测试 groupName 不匹配  
116 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setGroupName(null)));  
117 - // 测试 ownerId 不匹配  
118 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setOwnerId(null)));  
119 - // 测试 headImage 不匹配  
120 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setHeadImage(null)));  
121 - // 测试 headImageThumb 不匹配  
122 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setHeadImageThumb(null)));  
123 - // 测试 notice 不匹配  
124 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setNotice(null)));  
125 - // 测试 remark 不匹配  
126 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setRemark(null)));  
127 - // 测试 createTime 不匹配  
128 - imGroupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setCreateTime(null)));  
129 - // 准备参数  
130 - ImGroupPageReqVO reqVO = new ImGroupPageReqVO();  
131 - reqVO.setGroupName(null);  
132 - reqVO.setOwnerId(null);  
133 - reqVO.setHeadImage(null);  
134 - reqVO.setHeadImageThumb(null);  
135 - reqVO.setNotice(null);  
136 - reqVO.setRemark(null);  
137 - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
138 -  
139 - // 调用  
140 - PageResult<ImGroupDO> pageResult = groupService.getGroupPage(reqVO);  
141 - // 断言  
142 - assertEquals(1, pageResult.getTotal());  
143 - assertEquals(1, pageResult.getList().size());  
144 - assertPojoEquals(dbGroup, pageResult.getList().get(0));  
145 - }  
146 -  
147 -}  
148 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/test/java/cn/iocoder/yudao/module/im/service/groupmember/ImGroupMemberServiceImplTest.java deleted
1 -package cn.iocoder.yudao.module.im.service.groupmember;  
2 -  
3 -import org.junit.jupiter.api.Disabled;  
4 -import org.junit.jupiter.api.Test;  
5 -  
6 -import jakarta.annotation.Resource;  
7 -  
8 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
9 -  
10 -import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.*;  
11 -import cn.iocoder.yudao.module.im.dal.dataobject.groupmember.GroupMemberDO;  
12 -import cn.iocoder.yudao.module.im.dal.mysql.groupmember.ImGroupMemberMapper;  
13 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
14 -  
15 -import org.springframework.context.annotation.Import;  
16 -  
17 -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;  
18 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;  
19 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;  
20 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;  
21 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;  
22 -import static org.junit.jupiter.api.Assertions.*;  
23 -  
24 -/**  
25 - * {@link ImGroupMemberServiceImpl} 的单元测试类  
26 - *  
27 - * @author 芋道源码  
28 - */  
29 -@Import(ImGroupMemberServiceImpl.class)  
30 -public class ImGroupMemberServiceImplTest extends BaseDbUnitTest {  
31 -  
32 - @Resource  
33 - private ImGroupMemberServiceImpl groupMemberService;  
34 -  
35 - @Resource  
36 - private ImGroupMemberMapper imGroupMemberMapper;  
37 -  
38 - @Test  
39 - public void testCreateGroupMember_success() {  
40 - // 准备参数  
41 - ImGroupMemberSaveReqVO createReqVO = randomPojo(ImGroupMemberSaveReqVO.class).setId(null);  
42 -  
43 - // 调用  
44 - Long groupMemberId = groupMemberService.createGroupMember(createReqVO);  
45 - // 断言  
46 - assertNotNull(groupMemberId);  
47 - // 校验记录的属性是否正确  
48 - GroupMemberDO groupMember = imGroupMemberMapper.selectById(groupMemberId);  
49 - assertPojoEquals(createReqVO, groupMember, "id");  
50 - }  
51 -  
52 - @Test  
53 - public void testUpdateGroupMember_success() {  
54 - // mock 数据  
55 - GroupMemberDO dbGroupMember = randomPojo(GroupMemberDO.class);  
56 - imGroupMemberMapper.insert(dbGroupMember);// @Sql: 先插入出一条存在的数据  
57 - // 准备参数  
58 - ImGroupMemberSaveReqVO updateReqVO = randomPojo(ImGroupMemberSaveReqVO.class, o -> {  
59 - o.setId(dbGroupMember.getId()); // 设置更新的 ID  
60 - });  
61 -  
62 - // 调用  
63 - groupMemberService.updateGroupMember(updateReqVO);  
64 - // 校验是否更新正确  
65 - GroupMemberDO groupMember = imGroupMemberMapper.selectById(updateReqVO.getId()); // 获取最新的  
66 - assertPojoEquals(updateReqVO, groupMember);  
67 - }  
68 -  
69 - @Test  
70 - public void testUpdateGroupMember_notExists() {  
71 - // 准备参数  
72 - ImGroupMemberSaveReqVO updateReqVO = randomPojo(ImGroupMemberSaveReqVO.class);  
73 -  
74 - // 调用, 并断言异常  
75 - assertServiceException(() -> groupMemberService.updateGroupMember(updateReqVO), GROUP_MEMBER_NOT_EXISTS);  
76 - }  
77 -  
78 - @Test  
79 - public void testDeleteGroupMember_success() {  
80 - // mock 数据  
81 - GroupMemberDO dbGroupMember = randomPojo(GroupMemberDO.class);  
82 - imGroupMemberMapper.insert(dbGroupMember);// @Sql: 先插入出一条存在的数据  
83 - // 准备参数  
84 - Long id = dbGroupMember.getId();  
85 -  
86 - // 调用  
87 - groupMemberService.deleteGroupMember(id);  
88 - // 校验数据不存在了  
89 - assertNull(imGroupMemberMapper.selectById(id));  
90 - }  
91 -  
92 - @Test  
93 - public void testDeleteGroupMember_notExists() {  
94 - // 准备参数  
95 - Long id = randomLongId();  
96 -  
97 - // 调用, 并断言异常  
98 - assertServiceException(() -> groupMemberService.deleteGroupMember(id), GROUP_MEMBER_NOT_EXISTS);  
99 - }  
100 -  
101 - @Test  
102 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
103 - public void testGetGroupMemberPage() {  
104 - // mock 数据  
105 - GroupMemberDO dbGroupMember = randomPojo(GroupMemberDO.class, o -> { // 等会查询到  
106 - o.setGroupId(null);  
107 - o.setUserId(null);  
108 - o.setNickname(null);  
109 - o.setAvatar(null);  
110 - o.setAliasName(null);  
111 - o.setRemark(null);  
112 - o.setCreateTime(null);  
113 - });  
114 - imGroupMemberMapper.insert(dbGroupMember);  
115 - // 测试 groupId 不匹配  
116 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setGroupId(null)));  
117 - // 测试 userId 不匹配  
118 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setUserId(null)));  
119 - // 测试 nickname 不匹配  
120 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setNickname(null)));  
121 - // 测试 avatar 不匹配  
122 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setAvatar(null)));  
123 - // 测试 aliasName 不匹配  
124 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setAliasName(null)));  
125 - // 测试 remark 不匹配  
126 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setRemark(null)));  
127 - // 测试 createTime 不匹配  
128 - imGroupMemberMapper.insert(cloneIgnoreId(dbGroupMember, o -> o.setCreateTime(null)));  
129 - // 准备参数  
130 - ImGroupMemberPageReqVO reqVO = new ImGroupMemberPageReqVO();  
131 - reqVO.setGroupId(null);  
132 - reqVO.setUserId(null);  
133 - reqVO.setNickname(null);  
134 - reqVO.setAvatar(null);  
135 - reqVO.setAliasName(null);  
136 - reqVO.setRemark(null);  
137 - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
138 -  
139 - // 调用  
140 - PageResult<GroupMemberDO> pageResult = groupMemberService.getGroupMemberPage(reqVO);  
141 - // 断言  
142 - assertEquals(1, pageResult.getTotal());  
143 - assertEquals(1, pageResult.getList().size());  
144 - assertPojoEquals(dbGroupMember, pageResult.getList().get(0));  
145 - }  
146 -  
147 -}  
148 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/test/java/cn/iocoder/yudao/module/im/service/inbox/ImInboxServiceImplTest.java deleted
1 -package cn.iocoder.yudao.module.im.service.inbox;  
2 -  
3 -import org.junit.jupiter.api.Disabled;  
4 -import org.junit.jupiter.api.Test;  
5 -  
6 -import jakarta.annotation.Resource;  
7 -  
8 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
9 -  
10 -import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.*;  
11 -import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO;  
12 -import cn.iocoder.yudao.module.im.dal.mysql.inbox.ImInboxMapper;  
13 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
14 -  
15 -import org.springframework.context.annotation.Import;  
16 -  
17 -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;  
18 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;  
19 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;  
20 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;  
21 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;  
22 -import static org.junit.jupiter.api.Assertions.*;  
23 -  
24 -/**  
25 - * {@link ImInboxServiceImpl} 的单元测试类  
26 - *  
27 - * @author 芋道源码  
28 - */  
29 -@Import(ImInboxServiceImpl.class)  
30 -public class ImInboxServiceImplTest extends BaseDbUnitTest {  
31 -  
32 - @Resource  
33 - private ImInboxServiceImpl inboxService;  
34 -  
35 - @Resource  
36 - private ImInboxMapper imInboxMapper;  
37 -  
38 - @Test  
39 - public void testCreateInbox_success() {  
40 - // 准备参数  
41 - ImInboxSaveReqVO createReqVO = randomPojo(ImInboxSaveReqVO.class).setId(null);  
42 -  
43 - // 调用  
44 - Long inboxId = inboxService.createInbox(createReqVO);  
45 - // 断言  
46 - assertNotNull(inboxId);  
47 - // 校验记录的属性是否正确  
48 - ImInboxDO inbox = imInboxMapper.selectById(inboxId);  
49 - assertPojoEquals(createReqVO, inbox, "id");  
50 - }  
51 -  
52 - @Test  
53 - public void testUpdateInbox_success() {  
54 - // mock 数据  
55 - ImInboxDO dbInbox = randomPojo(ImInboxDO.class);  
56 - imInboxMapper.insert(dbInbox);// @Sql: 先插入出一条存在的数据  
57 - // 准备参数  
58 - ImInboxSaveReqVO updateReqVO = randomPojo(ImInboxSaveReqVO.class, o -> {  
59 - o.setId(dbInbox.getId()); // 设置更新的 ID  
60 - });  
61 -  
62 - // 调用  
63 - inboxService.updateInbox(updateReqVO);  
64 - // 校验是否更新正确  
65 - ImInboxDO inbox = imInboxMapper.selectById(updateReqVO.getId()); // 获取最新的  
66 - assertPojoEquals(updateReqVO, inbox);  
67 - }  
68 -  
69 - @Test  
70 - public void testUpdateInbox_notExists() {  
71 - // 准备参数  
72 - ImInboxSaveReqVO updateReqVO = randomPojo(ImInboxSaveReqVO.class);  
73 -  
74 - // 调用, 并断言异常  
75 - assertServiceException(() -> inboxService.updateInbox(updateReqVO), INBOX_NOT_EXISTS);  
76 - }  
77 -  
78 - @Test  
79 - public void testDeleteInbox_success() {  
80 - // mock 数据  
81 - ImInboxDO dbInbox = randomPojo(ImInboxDO.class);  
82 - imInboxMapper.insert(dbInbox);// @Sql: 先插入出一条存在的数据  
83 - // 准备参数  
84 - Long id = dbInbox.getId();  
85 -  
86 - // 调用  
87 - inboxService.deleteInbox(id);  
88 - // 校验数据不存在了  
89 - assertNull(imInboxMapper.selectById(id));  
90 - }  
91 -  
92 - @Test  
93 - public void testDeleteInbox_notExists() {  
94 - // 准备参数  
95 - Long id = randomLongId();  
96 -  
97 - // 调用, 并断言异常  
98 - assertServiceException(() -> inboxService.deleteInbox(id), INBOX_NOT_EXISTS);  
99 - }  
100 -  
101 - @Test  
102 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
103 - public void testGetInboxPage() {  
104 - // mock 数据  
105 - ImInboxDO dbInbox = randomPojo(ImInboxDO.class, o -> { // 等会查询到  
106 - o.setUserId(null);  
107 - o.setMessageId(null);  
108 - o.setSequence(null);  
109 - o.setCreateTime(null);  
110 - });  
111 - imInboxMapper.insert(dbInbox);  
112 - // 测试 userId 不匹配  
113 - imInboxMapper.insert(cloneIgnoreId(dbInbox, o -> o.setUserId(null)));  
114 - // 测试 messageId 不匹配  
115 - imInboxMapper.insert(cloneIgnoreId(dbInbox, o -> o.setMessageId(null)));  
116 - // 测试 sequence 不匹配  
117 - imInboxMapper.insert(cloneIgnoreId(dbInbox, o -> o.setSequence(null)));  
118 - // 测试 createTime 不匹配  
119 - imInboxMapper.insert(cloneIgnoreId(dbInbox, o -> o.setCreateTime(null)));  
120 - // 准备参数  
121 - ImInboxPageReqVO reqVO = new ImInboxPageReqVO();  
122 - reqVO.setUserId(null);  
123 - reqVO.setMessageId(null);  
124 - reqVO.setSequence(null);  
125 - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
126 -  
127 - // 调用  
128 - PageResult<ImInboxDO> pageResult = inboxService.getInboxPage(reqVO);  
129 - // 断言  
130 - assertEquals(1, pageResult.getTotal());  
131 - assertEquals(1, pageResult.getList().size());  
132 - assertPojoEquals(dbInbox, pageResult.getList().get(0));  
133 - }  
134 -  
135 -}  
136 \ No newline at end of file 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/test/java/cn/iocoder/yudao/module/im/service/message/ImMessageServiceImplTest.java deleted
1 -package cn.iocoder.yudao.module.im.service.message;  
2 -  
3 -import org.junit.jupiter.api.Disabled;  
4 -import org.junit.jupiter.api.Test;  
5 -  
6 -import jakarta.annotation.Resource;  
7 -  
8 -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;  
9 -  
10 -import cn.iocoder.yudao.module.im.controller.admin.message.vo.*;  
11 -import cn.iocoder.yudao.module.im.dal.dataobject.message.ImMessageDO;  
12 -import cn.iocoder.yudao.module.im.dal.mysql.message.ImMessageMapper;  
13 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
14 -  
15 -import org.springframework.context.annotation.Import;  
16 -  
17 -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;  
18 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;  
19 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;  
20 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;  
21 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;  
22 -import static org.junit.jupiter.api.Assertions.*;  
23 -  
24 -/**  
25 - * {@link ImMessageServiceImpl} 的单元测试类  
26 - *  
27 - * @author 芋道源码  
28 - */  
29 -@Import(ImMessageServiceImpl.class)  
30 -public class ImMessageServiceImplTest extends BaseDbUnitTest {  
31 -  
32 - @Resource  
33 - private ImMessageServiceImpl messageService;  
34 -  
35 - @Resource  
36 - private ImMessageMapper imMessageMapper;  
37 -  
38 - @Test  
39 - public void testCreateMessage_success() {  
40 - // 准备参数  
41 - ImMessageSaveReqVO createReqVO = randomPojo(ImMessageSaveReqVO.class).setId(null);  
42 -  
43 - // 调用  
44 - Long messageId = messageService.createMessage(createReqVO);  
45 - // 断言  
46 - assertNotNull(messageId);  
47 - // 校验记录的属性是否正确  
48 - ImMessageDO message = imMessageMapper.selectById(messageId);  
49 - assertPojoEquals(createReqVO, message, "id");  
50 - }  
51 -  
52 - @Test  
53 - public void testUpdateMessage_success() {  
54 - // mock 数据  
55 - ImMessageDO dbMessage = randomPojo(ImMessageDO.class);  
56 - imMessageMapper.insert(dbMessage);// @Sql: 先插入出一条存在的数据  
57 - // 准备参数  
58 - ImMessageSaveReqVO updateReqVO = randomPojo(ImMessageSaveReqVO.class, o -> {  
59 - o.setId(dbMessage.getId()); // 设置更新的 ID  
60 - });  
61 -  
62 - // 调用  
63 - messageService.updateMessage(updateReqVO);  
64 - // 校验是否更新正确  
65 - ImMessageDO message = imMessageMapper.selectById(updateReqVO.getId()); // 获取最新的  
66 - assertPojoEquals(updateReqVO, message);  
67 - }  
68 -  
69 - @Test  
70 - public void testUpdateMessage_notExists() {  
71 - // 准备参数  
72 - ImMessageSaveReqVO updateReqVO = randomPojo(ImMessageSaveReqVO.class);  
73 -  
74 - // 调用, 并断言异常  
75 - assertServiceException(() -> messageService.updateMessage(updateReqVO), MESSAGE_NOT_EXISTS);  
76 - }  
77 -  
78 - @Test  
79 - public void testDeleteMessage_success() {  
80 - // mock 数据  
81 - ImMessageDO dbMessage = randomPojo(ImMessageDO.class);  
82 - imMessageMapper.insert(dbMessage);// @Sql: 先插入出一条存在的数据  
83 - // 准备参数  
84 - Long id = dbMessage.getId();  
85 -  
86 - // 调用  
87 - messageService.deleteMessage(id);  
88 - // 校验数据不存在了  
89 - assertNull(imMessageMapper.selectById(id));  
90 - }  
91 -  
92 - @Test  
93 - public void testDeleteMessage_notExists() {  
94 - // 准备参数  
95 - Long id = randomLongId();  
96 -  
97 - // 调用, 并断言异常  
98 - assertServiceException(() -> messageService.deleteMessage(id), MESSAGE_NOT_EXISTS);  
99 - }  
100 -  
101 - @Test  
102 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
103 - public void testGetMessagePage() {  
104 - // mock 数据  
105 - ImMessageDO dbMessage = randomPojo(ImMessageDO.class, o -> { // 等会查询到  
106 - o.setClientMessageId(null);  
107 - o.setSenderId(null);  
108 - o.setReceiverId(null);  
109 - o.setSenderNickname(null);  
110 - o.setSenderAvatar(null);  
111 - o.setConversationType(null);  
112 - o.setConversationNo(null);  
113 - o.setContentType(null);  
114 - o.setContent(null);  
115 - o.setSendTime(null);  
116 - o.setSendFrom(null);  
117 - o.setCreateTime(null);  
118 - });  
119 - imMessageMapper.insert(dbMessage);  
120 - // 测试 clientMessageId 不匹配  
121 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setClientMessageId(null)));  
122 - // 测试 senderId 不匹配  
123 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setSenderId(null)));  
124 - // 测试 receiverId 不匹配  
125 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setReceiverId(null)));  
126 - // 测试 senderNickname 不匹配  
127 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setSenderNickname(null)));  
128 - // 测试 senderAvatar 不匹配  
129 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setSenderAvatar(null)));  
130 - // 测试 conversationType 不匹配  
131 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setConversationType(null)));  
132 - // 测试 conversationNo 不匹配  
133 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setConversationNo(null)));  
134 - // 测试 contentType 不匹配  
135 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setContentType(null)));  
136 - // 测试 content 不匹配  
137 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setContent(null)));  
138 - // 测试 sendTime 不匹配  
139 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setSendTime(null)));  
140 - // 测试 sendFrom 不匹配  
141 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setSendFrom(null)));  
142 - // 测试 createTime 不匹配  
143 - imMessageMapper.insert(cloneIgnoreId(dbMessage, o -> o.setCreateTime(null)));  
144 - // 准备参数  
145 - ImMessagePageReqVO reqVO = new ImMessagePageReqVO();  
146 - reqVO.setClientMessageId(null);  
147 - reqVO.setSenderId(null);  
148 - reqVO.setReceiverId(null);  
149 - reqVO.setSenderNickname(null);  
150 - reqVO.setSenderAvatar(null);  
151 - reqVO.setConversationType(null);  
152 - reqVO.setConversationNo(null);  
153 - reqVO.setContentType(null);  
154 - reqVO.setContent(null);  
155 - reqVO.setSendTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
156 - reqVO.setSendFrom(null);  
157 - reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));  
158 -  
159 - // 调用  
160 - PageResult<ImMessageDO> pageResult = messageService.getMessagePage(reqVO);  
161 - // 断言  
162 - assertEquals(1, pageResult.getTotal());  
163 - assertEquals(1, pageResult.getList().size());  
164 - assertPojoEquals(dbMessage, pageResult.getList().get(0));  
165 - }  
166 -  
167 -}  
168 \ No newline at end of file 0 \ No newline at end of file