Commit 2b891cb4321ae3bb42dad7ffc30c4269413cba47

Authored by YunaiV
1 parent 84cea037

IM:code review 消息发送的实现

Showing 32 changed files with 99 additions and 90 deletions
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/conversation/ConversationTypeEnum.java
... ... @@ -6,6 +6,7 @@ import lombok.Getter;
6 6  
7 7 import java.util.Arrays;
8 8  
  9 +// TODO @anhaohao:IM 前缀还是要的哈
9 10 /**
10 11 * IM 会话类型枚举
11 12 * 参考 <a href="https://doc.rentsoft.cn/zh-Hans/sdks/enum/conversationType">“会话类型”</a> 文档
... ... @@ -38,7 +39,7 @@ public enum ConversationTypeEnum implements IntArrayValuable {
38 39 }
39 40  
40 41 /**
41   - * 生成会话编号
  42 + * 生成会话编号 TODO @anhaohao:方法注释,和下面参数之间,要有空格
42 43 * @param fromUserId 发送者编号
43 44 * @param receiverId 接收者编号
44 45 * @param conversationType 会话类型
... ...
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageContentTypeEnum.java
... ... @@ -6,7 +6,7 @@ import lombok.Getter;
6 6  
7 7 import java.util.Arrays;
8 8  
9   -
  9 +// TODO @anhaohao:IM 前缀还是要的哈
10 10 /**
11 11 * IM 消息的类型枚举
12 12 * <p>
... ... @@ -34,11 +34,11 @@ public enum MessageContentTypeEnum implements IntArrayValuable {
34 34 QUOTE(114, "引用消息"),
35 35 FACE(115, "表情消息"),
36 36 ADVANCED_REVOKE(118, "高级撤回消息"),
37   - //好友通知 1200-1299
  37 + // ========== 好友通知 1200-1299 ===========
38 38 FRIEND_ADDED(1201, "双方成为好友通知"),
39   - //系统通知 1400
  39 + // ========== 系统通知 1400 ==========
40 40 OA_NOTIFICATION(1400, "系统通知"),
41   - //群相关 1500-1599
  41 + // ========== 群相关 1500-1599 ==========
42 42 GROUP_CREATED(1501, "群创建通知"),
43 43 GROUP_INFO_CHANGED(1502, "群信息改变通知"),
44 44 MEMBER_QUIT(1504, "群成员退出通知"),
... ...
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageSourceEnum.java
... ... @@ -6,8 +6,9 @@ import lombok.RequiredArgsConstructor;
6 6  
7 7 import java.util.Arrays;
8 8  
  9 +// TODO @anhaohao:IM 前缀还是要的哈
9 10 /**
10   - * IM 消息的消息来源 100-用户发送;200-系统发送(一般是通知);不能为空
  11 + * IM 消息的消息来源
11 12 */
12 13 @RequiredArgsConstructor
13 14 @Getter
... ... @@ -18,11 +19,11 @@ public enum MessageSourceEnum implements IntArrayValuable {
18 19  
19 20 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(MessageSourceEnum::getStatus).toArray();
20 21  
  22 + // TODO @anhaohao:应该是 source
21 23 /**
22 24 * 状态
23 25 */
24 26 private final Integer status;
25   -
26 27 /**
27 28 * 名字
28 29 */
... ...
yudao-module-im/yudao-module-im-api/src/main/java/cn/iocoder/yudao/module/im/enums/message/MessageStatusEnum.java
... ... @@ -6,6 +6,15 @@ import lombok.RequiredArgsConstructor;
6 6  
7 7 import java.util.Arrays;
8 8  
  9 +// TODO @anhaohao:IM 前缀还是要的哈
  10 +// TODO TODO 状态是这些哈,客户端的视角:
  11 +//
  12 +//- 草稿(预留) 0
  13 +//- 发送中 1
  14 +//- 发送成功 2
  15 +//- 发送失败 3
  16 +//- 已删除 4
  17 +//- 已撤回 5
9 18 /**
10 19 * IM 消息的状态枚举
11 20 */
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/ConversationController.java
... ... @@ -18,6 +18,7 @@ import java.util.List;
18 18  
19 19 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
20 20  
  21 +// TODO @anhaohao:im 前缀少啦
21 22 @Tag(name = "管理后台 - IM 会话")
22 23 @RestController
23 24 @RequestMapping("/im/conversation")
... ... @@ -42,7 +43,6 @@ public class ConversationController {
42 43 return success(true);
43 44 }
44 45  
45   -
46 46 // TODO @hao:这个接口,需要单独的 VO 哈;
47 47 @PostMapping("/update-last-read-time")
48 48 @Operation(summary = "更新最后已读时间")
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ConversationLastTimeReqVO.java
... ... @@ -7,10 +7,12 @@ import lombok.Data;
7 7  
8 8 import java.time.LocalDateTime;
9 9  
  10 +// TODO @anhaohao:改成 ConversationUpdateLastReadTimeReqVO,项目目前都是动名词哈。更新置顶
10 11 @Schema(description = "管理后台 - 会话最后已读时间 Request VO")
11 12 @Data
12 13 public class ConversationLastTimeReqVO {
13 14  
  15 + // TODO @anhaohao:no 不用传递哈。因为 userId + targetId 可以推出来
14 16 @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "s_1_2")
15 17 @NotEmpty(message = "会话标志不能为空")
16 18 private String no;
... ... @@ -19,6 +21,7 @@ public class ConversationLastTimeReqVO {
19 21 @NotNull(message = "最后已读时间不能为空")
20 22 private LocalDateTime lastReadTime;
21 23  
  24 + // TODO @anhaohao:userId 不用传递,因为 token 已经能解析出当前用户
22 25 @Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
23 26 private Long userId;
24 27  
... ... @@ -26,6 +29,6 @@ public class ConversationLastTimeReqVO {
26 29 private Long targetId;
27 30  
28 31 @Schema(description = "会话类型",requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
29   - private Integer type; //枚举 ConversationTypeEnum
  32 + private Integer type; // 枚举 ConversationTypeEnum TODO ,这里可以使用 @InEnum 校验,这样这个注释就不用写了
30 33  
31 34 }
32 35 \ No newline at end of file
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/conversation/vo/ConversationPinnedReqVO.java
... ... @@ -8,10 +8,12 @@ import lombok.Data;
8 8  
9 9 import java.time.LocalDateTime;
10 10  
  11 +// TODO @anhaohao:改成 ConversationUpdatePinnedReqVO,项目目前都是动名词哈。更新置顶
11 12 @Schema(description = "管理后台 - 会话置顶 Request VO")
12 13 @Data
13 14 public class ConversationPinnedReqVO {
14 15  
  16 + // TODO @anhaohao:no 不用传递哈。因为 userId + targetId 可以推出来
15 17 @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "s_1_2")
16 18 @NotEmpty(message = "会话标志不能为空")
17 19 private String no;
... ... @@ -20,6 +22,7 @@ public class ConversationPinnedReqVO {
20 22 @NotNull(message = "是否置顶不能为空")
21 23 private Boolean pinned;
22 24  
  25 + // TODO @anhaohao:userId 不用传递,因为 token 已经能解析出当前用户
23 26 @Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
24 27 private Long userId;
25 28  
... ... @@ -27,8 +30,6 @@ public class ConversationPinnedReqVO {
27 30 private Long targetId;
28 31  
29 32 @Schema(description = "会话类型",requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
30   - private Integer type; //枚举 ConversationTypeEnum
31   -
32   -
  33 + private Integer type; // 枚举 ConversationTypeEnum TODO ,这里可以使用 @InEnum 校验,这样这个注释就不用写了
33 34  
34 35 }
35 36 \ No newline at end of file
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/group/ImGroupController.java
... ... @@ -28,6 +28,7 @@ import cn.iocoder.yudao.module.im.controller.admin.group.vo.*;
28 28 import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupDO;
29 29 import cn.iocoder.yudao.module.im.service.group.ImGroupService;
30 30  
  31 +// TODO @芋艿:得看看 create、update、delete、get、page 这几个接口,要保留哪些
31 32 @Tag(name = "管理后台 - 群")
32 33 @RestController
33 34 @RequestMapping("/im/group")
... ... @@ -78,6 +79,7 @@ public class ImGroupController {
78 79 return success(BeanUtils.toBean(pageResult, ImGroupRespVO.class));
79 80 }
80 81  
  82 + // TODO @anhaohao:导出可以先不做哈;
81 83 @GetMapping("/export-excel")
82 84 @Operation(summary = "导出群 Excel")
83 85 @PreAuthorize("@ss.hasPermission('im:group:export')")
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/groupmember/ImGroupMemberController.java
... ... @@ -27,6 +27,7 @@ import java.util.List;
27 27 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
28 28 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
29 29  
  30 +// TODO @芋艿:得看看 create、update、delete、get、page 这几个接口,要保留哪些
30 31 @Tag(name = "管理后台 - 群成员")
31 32 @RestController
32 33 @RequestMapping("/im/group-member")
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/inbox/vo/InboxSaveMessageReqVO.java
... ... @@ -5,6 +5,7 @@ import lombok.Data;
5 5  
6 6 import java.time.LocalDateTime;
7 7  
  8 +// TODO @anhaohao:im 前缀哈
8 9 @Schema(description = "管理后台 - 收件箱保存消息 Request VO")
9 10 @Data
10 11 public class InboxSaveMessageReqVO {
... ... @@ -20,7 +21,7 @@ public class InboxSaveMessageReqVO {
20 21  
21 22 @Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED)
22 23 private String senderAvatar;
23   -
  24 +
24 25 @Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
25 26 private Long receiverId;
26 27  
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/MessageController.java
... ... @@ -36,6 +36,7 @@ public class MessageController {
36 36 return success(messageService.sendMessage(getLoginUserId(), message));
37 37 }
38 38  
  39 + // TODO @anhaohao:我在想,这个接口,改成叫 pullMessageList,会不会更好理解?拉取消息列表
39 40 @GetMapping("/list-by-sequence")
40 41 @Operation(summary = "拉取大于 sequence 的消息列表")
41 42 @Parameter(name = "sequence", description = "序号", required = true, example = "1")
... ... @@ -46,6 +47,7 @@ public class MessageController {
46 47 return success(BeanUtils.toBean(messages, MessageReqVO.class));
47 48 }
48 49  
  50 + // TODO @anhaohao:直接叫 getMessageList,不叫历史哈;因为它只是给用户叫历史,对系统来说,就是消息列表
49 51 @GetMapping("/history")
50 52 @Operation(summary = "查询聊天记录-根据会话标志和发送时间进行分页查询")
51 53 public CommonResult<List<MessageReqVO>> getHistoryMessage(@Valid MessagePageReqVO pageReqVO) {
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/MessagePageReqVO.java
... ... @@ -10,14 +10,19 @@ import java.time.LocalDateTime;
10 10 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
11 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
12 12  
  13 +// TODO @anhaohao:这个类,不要交 Page,而是消息列表,MessageListReqVO
13 14 @Schema(description = "管理后台 - 消息分页 Request VO")
14 15 @Data
15 16 @ToString(callSuper = true)
16 17 public class MessagePageReqVO {
17 18  
  19 + // TODO @anhaohao:还是传递 targetId 和 conversationType,我们要弱化 no 的概念;
  20 +
18 21 @Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "g_1000")
19 22 private String conversationNo;
20 23  
  24 + // TODO @anhaohao:应该不传递时间范围,而是传递分页的时间,然后根据时间,查询消息
  25 +
21 26 @Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-27")
22 27 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
23 28 private LocalDateTime[] sendTime;
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/MessageReqVO.java
... ... @@ -12,6 +12,8 @@ import java.time.LocalDateTime;
12 12  
13 13 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
14 14  
  15 +// TODO @anhaohao:MessageRespVO 消息响应 Response VO
  16 +// TODO @anahaohao:每个 example 都写下;啊哈,漏了地方,要补下;因为 http mock 的时候,可以根据它去生成
15 17 @Schema(description = "管理后台 - 消息 Request VO")
16 18 @Data
17 19 public class MessageReqVO {
... ... @@ -22,6 +24,7 @@ public class MessageReqVO {
22 24 @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
23 25 private Integer conversationType; // 对应 ImConversationTypeEnum 枚举
24 26  
  27 + // TODO @anhaohao:这个应该是 senderId
25 28 @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
26 29 private Long fromId; // 根据 conversationType 区分
27 30  
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageReqVO.java
... ... @@ -7,6 +7,10 @@ import com.alibaba.excel.annotation.ExcelProperty;
7 7 import io.swagger.v3.oas.annotations.media.Schema;
8 8 import lombok.Data;
9 9  
  10 +// TODO @anhaohao:MessageSendReqVO,消息发送
  11 +
  12 +// TODO @anhaohao:不应该有 excel 相关的注解
  13 +
10 14 @Schema(description = "管理后台 - 发送消息 Request VO")
11 15 @Data
12 16 @ExcelIgnoreUnannotated
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/controller/admin/message/vo/SendMessageRespVO.java
... ... @@ -10,6 +10,8 @@ import java.time.LocalDateTime;
10 10  
11 11 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
12 12  
  13 +// TODO @anhaohao:MessageSendRespVO,消息发送结果
  14 +
13 15 @Schema(description = "管理后台 - 发送消息 Response VO")
14 16 @Data
15 17 @AllArgsConstructor
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/conversation/ConversationDO.java
... ... @@ -9,6 +9,7 @@ import lombok.*;
9 9  
10 10 import java.time.LocalDateTime;
11 11  
  12 +// TODO @anhaohao:还是有 IM 前缀哈
12 13 /**
13 14 * IM 会话 DO
14 15 *
... ... @@ -44,15 +45,19 @@ public class ConversationDO extends BaseDO {
44 45 /**
45 46 * 聊天对象编号
46 47 * <p>
47   - * 1. 单聊时,用户编号;群聊时,群编号
  48 + * 1. 单聊时,用户编号;
  49 + * 2. 群聊时,群编号
48 50 */
49 51 private Long targetId;
50 52 /**
51   - * 会话标志 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId 群聊:g_groupId
  53 + * 会话标志
  54 + *
  55 + * 1. 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId
  56 + * 2. 群聊:g_groupId
52 57 */
53 58 private String no;
54 59 /**
55   - * 是否置顶 0否 1是
  60 + * 是否置顶
56 61 */
57 62 private Boolean pinned;
58 63 /**
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupDO.java
... ... @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
7 7 import lombok.*;
8 8  
  9 +// TODO @anhaohao:还是要有 IM
9 10 /**
10 11 * IM 群信息 DO
11 12 *
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/group/GroupMemberDO.java
... ... @@ -4,6 +4,7 @@ import lombok.*;
4 4 import com.baomidou.mybatisplus.annotation.*;
5 5 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
6 6  
  7 +// TODO @anhaohao:还是要有 IM
7 8 /**
8 9 * IM 群成员 DO
9 10 *
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/inbox/InboxDO.java
1 1 package cn.iocoder.yudao.module.im.dal.dataobject.inbox;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
4 5 import com.baomidou.mybatisplus.annotation.KeySequence;
5 6 import com.baomidou.mybatisplus.annotation.TableId;
6 7 import com.baomidou.mybatisplus.annotation.TableName;
7 8 import lombok.*;
8 9  
  10 +// TODO @anhaohao:还是要有 IM
9 11 // TODO 我们要不要改成 ImMessageQueue 队列?从理解上,概念上,可能都更清晰一点哈。每个用户一个消息队列;
10 12 /**
11 13 * IM 收件箱 DO
... ... @@ -35,6 +37,8 @@ public class InboxDO extends BaseDO {
35 37 private Long userId;
36 38 /**
37 39 * 消息编号
  40 + *
  41 + * 关联 {@link MessageDO#getId()}
38 42 */
39 43 private Long messageId;
40 44 /**
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/MessageDO.java
... ... @@ -12,6 +12,7 @@ import lombok.*;
12 12  
13 13 import java.time.LocalDateTime;
14 14  
  15 +// TODO @anhaohao:还是要有 IM
15 16 /**
16 17 * IM 消息 DO
17 18 *
... ... @@ -63,15 +64,21 @@ public class MessageDO extends BaseDO {
63 64 */
64 65 private Integer conversationType;
65 66 /**
66   - * 会话标志 {@link ConversationTypeEnum} 的generateConversationNo() 方法生成
  67 + * 会话标志
  68 + *
  69 + * 生成规则:{@link ConversationTypeEnum#generateConversationNo(Long, Long, Integer)} 方法
67 70 */
68 71 private String conversationNo;
69 72 /**
70   - * 消息类型 枚举 {@link MessageContentTypeEnum}
  73 + * 消息类型
  74 + *
  75 + * 枚举 {@link MessageContentTypeEnum}
71 76 */
72 77 private Integer contentType;
73 78 /**
74   - * 消息内容 JSON 格式 对应 dal/dataobject/message/content 包
  79 + * 消息内容
  80 + *
  81 + * JSON 格式 对应 dal/dataobject/message/content 包
75 82 */
76 83 private String content;
77 84 /**
... ... @@ -79,11 +86,15 @@ public class MessageDO extends BaseDO {
79 86 */
80 87 private LocalDateTime sendTime;
81 88 /**
82   - * 消息来源 枚举 {@link MessageSourceEnum}
  89 + * 消息来源
  90 + *
  91 + * 枚举 {@link MessageSourceEnum}
83 92 */
84 93 private Integer sendFrom;
85 94 /**
86   - * 消息状态 枚举 {@link MessageStatusEnum}
  95 + * 消息状态
  96 + *
  97 + * 枚举 {@link MessageStatusEnum}
87 98 */
88 99 private Integer messageStatus;
89 100  
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/message/content/AudioMessage.java
... ... @@ -5,6 +5,8 @@ import lombok.AllArgsConstructor;
5 5 import lombok.Data;
6 6 import lombok.NoArgsConstructor;
7 7  
  8 +// TODO @anhaohao:要有 IM;
  9 +// TODO @芋艿:后续要挪到 api 包下,主要是给外部接口使用
8 10 /**
9 11 * 语音消息的 {@link MessageDO 字段 content} 的内容
10 12 *
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/inbox/InboxMapper.java
... ... @@ -15,12 +15,13 @@ import java.util.List;
15 15 @Mapper
16 16 public interface InboxMapper extends BaseMapperX<InboxDO> {
17 17  
  18 + // TODO @anhaohao:返回 List<InboxDO> ,转换成 messageId 交给上层;dao 尽量通用
18 19 default List<Long> selectMessageIdsByUserIdAndSequence(Long userId, Long sequence, Integer size) {
19 20 return selectList(new LambdaQueryWrapperX<InboxDO>()
20 21 .gt(InboxDO::getUserId, userId)
21 22 .gt(InboxDO::getSequence, sequence)
22 23 .orderByAsc(InboxDO::getSequence)
23   - .last("limit 0," + size))
  24 + .last("limit 0," + size)) // TODO @anhaohao:这里 limit 就可以了,不用从 limit 0 开始;
24 25 .stream()
25 26 .map(InboxDO::getMessageId)
26 27 .toList();
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/conversation/ConversationServiceImpl.java
... ... @@ -12,8 +12,6 @@ import org.springframework.validation.annotation.Validated;
12 12  
13 13 import java.util.List;
14 14  
15   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
16   -
17 15 /**
18 16 * IM 会话 Service 实现类
19 17 *
... ... @@ -43,6 +41,7 @@ public class ConversationServiceImpl implements ConversationService {
43 41 ConversationDO conversation = conversationMapper.selectByNo(updateReqVO.getNo());
44 42 if (conversation == null) {
45 43 ConversationDO conversationDO = new ConversationDO();
  44 + // TODO @hao:no 不是前端传递哈,后端生成;另外,其实可以把 insert 写成一个公用方法;get会话,拿不到就 insert;接着处理 update 操作;首次多 update 一次,无所谓的;没多少量的
46 45 conversationDO.setNo(updateReqVO.getNo());
47 46 conversationDO.setPinned(updateReqVO.getPinned());
48 47 conversationDO.setUserId(updateReqVO.getUserId());
... ... @@ -50,11 +49,10 @@ public class ConversationServiceImpl implements ConversationService {
50 49 conversationDO.setType(updateReqVO.getType());
51 50 conversationMapper.insert(conversationDO);
52 51 } else {
53   - // 更新
  52 + // 更新 TODO @anhaohao:这里不要 toBean,因为这里逻辑偏 toc,new ConversationDO 对象,然后逐个 set 需要的值;
54 53 ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class);
55 54 conversationMapper.updateById(updateObj);
56 55 }
57   -
58 56 }
59 57  
60 58 @Override
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/InboxService.java
... ... @@ -27,4 +27,5 @@ public interface InboxService {
27 27 * @return 消息编号列表
28 28 */
29 29 List<Long> selectMessageIdsByUserIdAndSequence(Long userId, Long sequence, Integer size);
  30 +
30 31 }
31 32 \ No newline at end of file
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/inbox/InboxServiceImpl.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.im.service.inbox;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5   -import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
6 5 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
7 6 import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSendMessageReqVO;
8 7 import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
... ... @@ -43,6 +42,7 @@ public class InboxServiceImpl implements InboxService {
43 42 @Resource
44 43 private GroupMemberService groupMemberService;
45 44  
  45 + // TODO @anhaohao:下面的逻辑,最好是,1. 保存收件箱 + 发送消息给用户; 2. xxx;这样看的人,会更有感觉哈;
46 46 @Override
47 47 public void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessage) {
48 48 // 保存收件箱 + 发送消息给用户
... ... @@ -64,12 +64,15 @@ public class InboxServiceImpl implements InboxService {
64 64 private void saveInboxAndSendMessageForUser(Long userId, InboxSaveMessageReqVO inboxSaveMessage) {
65 65 inboxLockRedisDAO.lock(userId, INBOX_LOCK_TIMEOUT, () -> {
66 66 Long userSequence = sequenceRedisDao.generateSequence(userId);
  67 + // TODO @anhaohao:链式调用;
67 68 InboxDO inbox = new InboxDO();
68 69 inbox.setUserId(userId);
69 70 inbox.setMessageId(inboxSaveMessage.getMessageId());
70 71 inbox.setSequence(userSequence);
71 72 inboxMapper.insert(inbox);
72 73  
  74 + // TODO @anhaohao:是不是 send 不用在加锁里面哈?!
  75 + // TODO @anhaohao:再进一步,是不是用 spring @async 可以并发推送噢
73 76 InboxSendMessageReqVO message = BeanUtils.toBean(inboxSaveMessage, InboxSendMessageReqVO.class);
74 77 message.setSequence(userSequence);
75 78 webSocketSenderApi.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message);
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/service/message/MessageServiceImpl.java
... ... @@ -58,20 +58,25 @@ public class MessageServiceImpl implements MessageService {
58 58 @Override
59 59 public SendMessageRespVO sendMessage(Long fromUserId, SendMessageReqVO message) {
60 60 // 保存消息
  61 + // TODO @anhaohao:InboxSaveMessageReqVO 不用 new 出来传递到 saveMessage 方法里;
61 62 InboxSaveMessageReqVO inboxSaveMessageReqVO = new InboxSaveMessageReqVO();
62 63 SendMessageRespVO sendMessageRespVO = saveMessage(fromUserId, message, inboxSaveMessageReqVO);
63 64  
64 65 // 保存收件箱 + 发送消息给用户
  66 + // TODO @anhaohao:考虑到少定义一些 VO,直接传递 MessageDO 就完事了;反正这两者也是强耦合的;
65 67 inboxService.saveInboxAndSendMessage(inboxSaveMessageReqVO);
66 68 return sendMessageRespVO;
67 69 }
68 70  
  71 + // TODO @anhaohao:这个方法,是不是定义成 private 哈;然后返回是 MessageDO 对象,设置最上面的 sendMessage 也是这个。最终 controller 转成 SendMessageRespVO
69 72 public SendMessageRespVO saveMessage(Long fromUserId, SendMessageReqVO message, InboxSaveMessageReqVO inboxSaveMessageReqVO) {
70   - //需要校验 receiverId 存在
  73 + // 需要校验 receiverId 存在
71 74 validateReceiverIdExists(message);
72 75 // 查询发送人昵称和发送人头像
73 76 AdminUserRespDTO fromUser = adminUserApi.getUser(fromUserId);
74 77 // 使用链式调用创建 MessageDO 对象
  78 + // TODO @anhaohao:一部分字段,可以 beanutils tobean 搞定;
  79 + // TODO @anhaohao:链式 set 的时候,要把相同的放在一行;例如说,setSenderNickname、setSenderAvatar;本质上,就是为了“同类”在一行,阅读起来简单;
75 80 MessageDO messageDO = new MessageDO()
76 81 .setClientMessageId(message.getClientMessageId())
77 82 .setSenderId(fromUserId)
... ... @@ -102,17 +107,19 @@ public class MessageServiceImpl implements MessageService {
102 107 return new SendMessageRespVO(messageDO.getId(), messageDO.getSendTime());
103 108 }
104 109  
  110 + // TODO @anhaohao:validateReceiver,更简单一点哈;不仅仅校验存在,未来还可以校验,自己是不是有好友关系、群聊是否在群聊里面等等
105 111 private void validateReceiverIdExists(SendMessageReqVO message) {
  112 + // TODO @anhaohao:这个不要这里校验,交给 validator 校验掉
106 113 if (message.getReceiverId() == null) {
107 114 throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
108 115 }
109 116 if (message.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) {
  117 + // TODO @anhaohao:// 之后要空一个空格,中英文协作习惯,中文和英文之间,不能连着;最后也不用 ;哈
110 118 //校验用户是否存在;
111 119 AdminUserRespDTO receiverUser = adminUserApi.getUser(message.getReceiverId());
112 120 if (receiverUser == null) {
113 121 throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
114 122 }
115   -
116 123 } else if (message.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
117 124 //校验群聊是否存在;
118 125 List<GroupMemberDO> groupMemberDOS = groupMemberService.selectByGroupId(message.getReceiverId());
... ...
yudao-module-im/yudao-module-im-biz/src/main/java/cn/iocoder/yudao/module/im/websocket/message/ImReceiveMessage.java
... ... @@ -15,6 +15,7 @@ public class ImReceiveMessage {
15 15 @InEnum(ConversationTypeEnum.class)
16 16 private Integer conversationType;
17 17  
  18 + // TODO @anhaohao:我们应该是 senderId;因为它和 receiverId 是相对应的哈。
18 19 @Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
19 20 private Long fromId; // 根据 conversationType 区分
20 21  
... ...
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/conversation/ConversationMapper.xml deleted
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">
3   -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.conversation.ConversationMapper">
4   -
5   - <!-- TODO @hao:xml 如果用不到,可以先删除哈 -->
6   - <!--
7   - 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
8   - 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
9   - 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
10   - 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
11   - -->
12   -
13   -</mapper>
14 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/group/ImGroupMapper.xml deleted
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">
3   -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.group.ImGroupMapper">
4   -
5   - <!--
6   - 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
7   - 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
8   - 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
9   - 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
10   - -->
11   -
12   -</mapper>
13 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/groupmember/ImGroupMemberMapper.xml deleted
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">
3   -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.groupmember.ImGroupMemberMapper">
4   -
5   - <!--
6   - 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
7   - 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
8   - 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
9   - 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
10   - -->
11   -
12   -</mapper>
13 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/inbox/InboxMapper.xml deleted
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">
3   -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.inbox.InboxMapper">
4   -
5   - <!--
6   - 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
7   - 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
8   - 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
9   - 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
10   - -->
11   -
12   -</mapper>
13 0 \ No newline at end of file
yudao-module-im/yudao-module-im-biz/src/main/resources/mapper/message/MessageMapper.xml deleted
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">
3   -<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.message.MessageMapper">
4   -
5   - <!--
6   - 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
7   - 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
8   - 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
9   - 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
10   - -->
11   -
12   -</mapper>
13 0 \ No newline at end of file