im:code review 消息发送的逻辑
This commit is contained in:
parent
9c1764e36e
commit
0e79d8ec53
|
@ -12,6 +12,7 @@ import lombok.Getter;
|
|||
@AllArgsConstructor
|
||||
public enum ImConversationTypeEnum {
|
||||
|
||||
// TODO @hao:单聊,我们使用 SINGLE,主要 private 这个单词在 java 里太特殊了;
|
||||
PRIVATE(1, "单聊"),
|
||||
GROUP(2, "群聊"),
|
||||
NOTICE(4, "通知会话");
|
||||
|
|
|
@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
// TODO @hao:注释哈;
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum ImMessageStatusEnum implements IntArrayValuable {
|
||||
|
@ -16,7 +17,9 @@ public enum ImMessageStatusEnum implements IntArrayValuable {
|
|||
DELETED(4, "已删除"),
|
||||
RECALL(5, "已撤回");
|
||||
|
||||
// TODO @hao:静态变量,和普通变量,最好空一行;
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ImMessageStatusEnum::getStatus).toArray();
|
||||
// TODO @hao:注释哈;
|
||||
private final Integer status;
|
||||
private final String name;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.time.LocalDateTime;
|
|||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
// TODO @hao:这个是不是删除掉,应该不会有这个 VO 哈
|
||||
@Schema(description = "管理后台 - 收件箱分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
|
|
@ -7,6 +7,7 @@ import lombok.Data;
|
|||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
// TODO @hao:这个是不是删除掉,应该不会有这个 VO 哈;应该给前端的,是要屏蔽掉这个表,最终返回的都是 Message 哈;说白了,这个 inbox 是后端的内部实现
|
||||
@Schema(description = "管理后台 - 收件箱 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
|
|
|
@ -6,6 +6,7 @@ import lombok.AllArgsConstructor;
|
|||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
// TODO @hao:这个是不是删除掉,应该不会有这个 VO 哈
|
||||
@Schema(description = "管理后台 - 收件箱新增/修改 Request VO")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.List;
|
|||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 消息")
|
||||
@Tag(name = "管理后台 - IM 消息")
|
||||
@RestController
|
||||
@RequestMapping("/im/message")
|
||||
@Validated
|
||||
|
@ -33,19 +33,20 @@ public class ImMessageController {
|
|||
@Resource
|
||||
private ImMessageService imMessageService;
|
||||
|
||||
@GetMapping("/get-message-by-sequence")
|
||||
@Operation(summary = "拉取消息-增量拉取大于 seq 的消息")
|
||||
@GetMapping("/get-message-by-sequence") // TODO @hao:list-by-sequence
|
||||
@Operation(summary = "拉取消息-增量拉取大于 seq 的消息") // TODO @hao:可以改成 拉取大于 sequence 的消息列表
|
||||
@Parameter(name = "sequence", description = "序号", required = true, example = "1")
|
||||
@Parameter(name = "size", description = "条数", required = true, example = "10")
|
||||
@PreAuthorize("@ss.hasPermission('im:message:query')")
|
||||
public CommonResult<List<ImMessageRespVO>> loadMessage(
|
||||
@RequestParam("sequence") Long sequence,
|
||||
@PreAuthorize("@ss.hasPermission('im:message:query')") // TODO @hao:权限可以删除哈;
|
||||
public CommonResult<List<ImMessageRespVO>> loadMessage(@RequestParam("sequence") Long sequence,
|
||||
@RequestParam("size") Integer size) {
|
||||
// TODO @hao:方法名,可以改成 getMessageListBySequence
|
||||
// TODO @hao:如果是返回列表,变量要用 messages, 或者 messageList,体现出是复数
|
||||
List<ImMessageDO> message = imMessageService.loadMessage(getLoginUserId(), sequence, size);
|
||||
return success(BeanUtils.toBean(message, ImMessageRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
// TODO @hao:这个接口的使用场景是哪个哈?
|
||||
@GetMapping("/get-all-message")
|
||||
@Operation(summary = "拉取全部消息")
|
||||
@Parameter(name = "size", description = "条数", required = true, example = "10")
|
||||
|
@ -55,14 +56,13 @@ public class ImMessageController {
|
|||
return success(BeanUtils.toBean(message, ImMessageRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
// TODO @hao:是不是分页参数不太对哈?应该只有 conversationNo,sendTime 字段;然后,做链式分页的查询,不太适合传统的 pageSize + number 查询;
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "查询聊天记录-分页")
|
||||
@PreAuthorize("@ss.hasPermission('im:message:query')")
|
||||
@PreAuthorize("@ss.hasPermission('im:message:query')") // TODO @hao:权限可以删除哈;
|
||||
public CommonResult<PageResult<ImMessageRespVO>> getMessagePage(@Valid ImMessagePageReqVO pageReqVO) {
|
||||
PageResult<ImMessageDO> messagePage = imMessageService.getMessagePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(messagePage, ImMessageRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 会话 Mapper
|
||||
* IM 会话 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
@ -29,6 +29,7 @@ public interface ImConversationMapper extends BaseMapperX<ImConversationDO> {
|
|||
.orderByDesc(ImConversationDO::getId));
|
||||
}
|
||||
|
||||
// TODO @hao:1)no) {,要有空格哈;2)可以直接 selectOne(ImConversationDO::getNo, no) 父类做了封装
|
||||
default ImConversationDO selectByNo(String no){
|
||||
return selectOne(new LambdaQueryWrapperX<ImConversationDO>().eq(ImConversationDO::getNo, no));
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO;
|
|||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 收件箱 Mapper
|
||||
* IM 收件箱 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,7 @@ public interface ImMessageMapper extends BaseMapperX<ImMessageDO> {
|
|||
.orderByDesc(ImMessageDO::getId));
|
||||
}
|
||||
|
||||
// TODO @hao:不链表哈;先从 ImInboxDO 查询出 messageId,然后再到 ImMessageDO 里 IN
|
||||
default List<ImMessageDO> getGreaterThanSequenceMessage(Long userId, Long sequence, Integer size) {
|
||||
//查询 inbox 表中,大于 sequence 的消息,关联 message 表,按照 inbox 表 sequence 升序
|
||||
return selectJoinList(ImMessageDO.class, new MPJLambdaWrapper<ImMessageDO>()
|
||||
|
@ -47,6 +48,7 @@ public interface ImMessageMapper extends BaseMapperX<ImMessageDO> {
|
|||
.last("limit 0," + size));
|
||||
}
|
||||
|
||||
// TODO @hao:在 dao 里,使用 selectListByUserId,查询用 select,条件用 by,这个算是 spring data 的 method dsl
|
||||
default List<ImMessageDO> getAllMessage(Long userId, Integer size) {
|
||||
//查询 inbox 表中,100条消息,关联 message 表,按照 inbox 表 sequence 降序
|
||||
return selectJoinList(ImMessageDO.class, new MPJLambdaWrapper<ImMessageDO>()
|
||||
|
@ -56,4 +58,5 @@ public interface ImMessageMapper extends BaseMapperX<ImMessageDO> {
|
|||
.orderByDesc(ImInboxDO::getSequence)
|
||||
.last("limit 0," + size));
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ import org.springframework.stereotype.Repository;
|
|||
|
||||
import static cn.iocoder.yudao.module.im.dal.redis.RedisKeyConstants.INBOX_SEQUENCE;
|
||||
|
||||
// TODO @芋艿:这个名字,需要在考虑下;
|
||||
/**
|
||||
* 序号生成器 Redis DAO
|
||||
*
|
||||
|
|
|
@ -9,7 +9,7 @@ import jakarta.validation.Valid;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会话 Service 接口
|
||||
* IM 会话 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
@ -74,4 +74,5 @@ public interface ImConversationService {
|
|||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateLastReadTime(ImConversationSaveReqVO updateReqVO);
|
||||
|
||||
}
|
|
@ -18,7 +18,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
|
|||
import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
* 会话 Service 实现类
|
||||
* IM 会话 Service 实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
@ -26,18 +26,19 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_N
|
|||
@Validated
|
||||
public class ImConversationServiceImpl implements ImConversationService {
|
||||
|
||||
// TODO @hao: 自己模块的注入,不用带 im 前缀哈;
|
||||
@Resource
|
||||
private ImConversationMapper imConversationMapper;
|
||||
|
||||
// TODO @hao: 这个方法,是不是不需要哈
|
||||
@Override
|
||||
public Long createConversation(ImConversationSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
ImConversationDO conversation = BeanUtils.toBean(createReqVO, ImConversationDO.class);
|
||||
imConversationMapper.insert(conversation);
|
||||
// 返回
|
||||
return conversation.getId();
|
||||
}
|
||||
|
||||
// TODO @hao: 这个方法,是不是不需要哈
|
||||
@Override
|
||||
public void updateConversation(ImConversationSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
|
@ -47,6 +48,7 @@ public class ImConversationServiceImpl implements ImConversationService {
|
|||
imConversationMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
// TODO @hao: 考虑到可能和端上不同步,可以不校验是不是存储。另外,不基于 id 删除。要基于 no + userId 删除哈。说白了,对端上要屏蔽 id 字段
|
||||
@Override
|
||||
public void deleteConversation(Long id) {
|
||||
// 校验存在
|
||||
|
@ -86,6 +88,11 @@ public class ImConversationServiceImpl implements ImConversationService {
|
|||
createOrUpdateConversation(updateReqVO);
|
||||
}
|
||||
|
||||
// TODO @hao:updateTop 和 updateLastReadTime 使用独立的逻辑实现,不使用统一的 ImConversationSaveReqVO;
|
||||
// TODO 大体步骤建议:
|
||||
// 1. 先 getOrderCreateConversation,查询会话,不存在则插入;
|
||||
// 2. 更新对应的字段
|
||||
// 3. 做对应更新的 notify 推送
|
||||
private void createOrUpdateConversation(ImConversationSaveReqVO updateReqVO) {
|
||||
// 操作会话(已读、置顶)时,才会延迟创建,要先判断是否存在,根据 no 查询是否存在,不存在则新增
|
||||
ImConversationDO conversation = imConversationMapper.selectByNo(updateReqVO.getNo());
|
||||
|
|
|
@ -6,8 +6,9 @@ import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxSaveReqVO;
|
|||
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.ImInboxDO;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
// TODO @hao:不用的方法,删除下哈;
|
||||
/**
|
||||
* 收件箱 Service 接口
|
||||
* IM 收件箱 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
|
|
|
@ -27,10 +27,8 @@ public class ImInboxServiceImpl implements ImInboxService {
|
|||
|
||||
@Override
|
||||
public Long createInbox(ImInboxSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
ImInboxDO inbox = BeanUtils.toBean(createReqVO, ImInboxDO.class);
|
||||
imInboxMapper.insert(inbox);
|
||||
// 返回
|
||||
return inbox.getId();
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ public interface ImMessageService {
|
|||
*/
|
||||
List<ImMessageDO> loadMessage(Long userId, Long sequence, Integer size);
|
||||
|
||||
// TODO @hao;这种接口,项目里叫 getMessageListByUserId,尽量保持 getList 获取列表哈;
|
||||
/**
|
||||
* 拉取全部消息
|
||||
*
|
||||
|
|
|
@ -84,6 +84,8 @@ public class ImMessageServiceImpl implements ImMessageService {
|
|||
}
|
||||
|
||||
private ImMessageDO saveImMessageDO(ImSendMessage message, Long fromUserId) {
|
||||
// TODO @hao:可以搞成 messageDO
|
||||
// TODO @hao:链式调用
|
||||
ImMessageDO imMessageDO = new ImMessageDO();
|
||||
imMessageDO.setClientMessageId(message.getClientMessageId());
|
||||
imMessageDO.setSenderId(fromUserId);
|
||||
|
@ -95,15 +97,18 @@ public class ImMessageServiceImpl implements ImMessageService {
|
|||
imMessageDO.setConversationType(message.getConversationType());
|
||||
imMessageDO.setContentType(message.getContentType());
|
||||
// 单聊:s_{userId}_{targetId} 群聊:群聊:g_{groupId}
|
||||
// TODO @hao:这里的 conversationNo 的生成,可以写到工具类里,或者干脆放到 ImConversationTypeEnum 里;
|
||||
if (message.getConversationType().equals(ImConversationTypeEnum.PRIVATE.getType())) {
|
||||
imMessageDO.setConversationNo("s_" + fromUserId + "_" + message.getReceiverId());
|
||||
} else if (message.getConversationType().equals(ImConversationTypeEnum.GROUP.getType())) {
|
||||
imMessageDO.setConversationNo("g_" + message.getReceiverId());
|
||||
}
|
||||
imMessageDO.setContent(message.getContent());
|
||||
// TODO @hao:枚举哈;
|
||||
// 消息来源 100-用户发送;200-系统发送(一般是通知);不能为空
|
||||
imMessageDO.setSendFrom(100);
|
||||
imMessageDO.setSendTime(TimeUtil.now());
|
||||
// TODO @hao:服务端的消息,就是默认生成哈;
|
||||
imMessageDO.setMessageStatus(ImMessageStatusEnum.SENDING.getStatus());
|
||||
imMessageMapper.insert(imMessageDO);
|
||||
return imMessageDO;
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.web.socket.WebSocketSession;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
// TODO @hao:消息发送,使用 http 上行。因为在 cloud 框架下,我们比较难去 Listener。因为 im-server 不会自己启动 websocket 路径
|
||||
/**
|
||||
* WebSocket im
|
||||
*
|
||||
|
@ -63,6 +64,7 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
|
|||
// 处理群聊消息
|
||||
handleGroupMessage(fromUserId, message);
|
||||
} else {
|
||||
// TODO @hao:是不是应该会话类型哈?然后打印这种错误日志,最好把 message 整个打进去,这样更好定位完整的消息;
|
||||
log.error("[onMessage][消息类型({}) 未支持]", message.getConversationType());
|
||||
}
|
||||
}
|
||||
|
@ -74,13 +76,17 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
|
|||
* @param message 发送的IM消息
|
||||
*/
|
||||
private void handleGroupMessage(Long fromUserId, ImSendMessage message) {
|
||||
// TODO @hao:群存在;
|
||||
// TODO @hao:发送人在群里;
|
||||
ImMessageDO imMessageDO = imMessageService.saveGroupMessage(message, fromUserId); // 保存群聊消息
|
||||
Long groupId = message.getReceiverId();
|
||||
|
||||
// 发送消息给群聊成员
|
||||
// TODO @hao:变量名可以叫 groupMembers;一般不用 DO 后缀,除非为了区分;
|
||||
List<GroupMemberDO> groupMemberDOList = imGroupMemberService.selectByGroupId(groupId);
|
||||
groupMemberDOList.forEach(groupMemberDO -> {
|
||||
// 过滤掉自己
|
||||
// TODO @hao:98 到 99 的代码,是不是可以融合到这里来;
|
||||
if (groupMemberDO.getUserId().equals(fromUserId)) {
|
||||
return;
|
||||
}
|
||||
|
@ -106,11 +112,14 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
|
|||
* @param message 发送的IM消息
|
||||
*/
|
||||
private void handlePrivateMessage(Long fromUserId, ImSendMessage message) {
|
||||
// TODO @hao:需要校验 receiverId 存在;
|
||||
ImMessageDO imMessageDO = imMessageService.savePrivateMessage(message, fromUserId); // 保存私人消息
|
||||
Long receiverId = message.getReceiverId();
|
||||
|
||||
// TODO @hao:sequenceGeneratorRedisDao.generateSequence 和 createAndSaveInbox 步骤,要加锁;不然会有并发问题;如果有疑问,可以微信招我沟通哈;另外,创建 seq、保存收件箱、发送,可以统一封装到 imInboxService 里哈;这样,后续要发某个消息,就是丢个 message 对象进去;
|
||||
Long fromUserSequence = sequenceGeneratorRedisDao.generateSequence(fromUserId); // 生成发送者序列
|
||||
Long fromUserInboxId = createAndSaveInbox(fromUserId, imMessageDO.getId(), fromUserSequence); // 创建并保存发送者收件箱
|
||||
|
||||
Long receiverSequence = sequenceGeneratorRedisDao.generateSequence(message.getReceiverId()); // 生成接收者序列
|
||||
Long receiverInboxId = createAndSaveInbox(message.getReceiverId(), imMessageDO.getId(), receiverSequence); // 创建并保存接收者收件箱
|
||||
|
||||
|
@ -119,6 +128,7 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
|
|||
sendMessage(receiverId, receiverInboxId, imMessageDO, message, receiverSequence);
|
||||
|
||||
// 更新消息状态为成功
|
||||
// TODO @hao:后端消息的发送,默认就是 success 哈,不要区分 status;status 更多是前端使用的;
|
||||
imMessageService.updateMessageStatus(imMessageDO.getId(), ImMessageStatusEnum.SUCCESS.getStatus());
|
||||
// 保存私人会话,只有在 client 操作会话(已读、置顶)时,才会延迟创建
|
||||
//imConversationService.savePrivateConversation(fromUserId, receiverId);
|
||||
|
@ -137,6 +147,7 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
|
|||
return imInboxService.createInbox(inboxSaveReqVO); // 创建收件箱
|
||||
}
|
||||
|
||||
// TODO @hao:这个使用 WebSocketSenderApi 发送哈;
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
|
@ -147,6 +158,7 @@ public class ImWebSocketMessageListener implements WebSocketMessageListener<ImSe
|
|||
* @param sequence 序列
|
||||
*/
|
||||
private void sendMessage(Long fromUserId, Long inboxId, ImMessageDO imMessageDO, ImSendMessage message, Long sequence) {
|
||||
// TODO @hao:不要每个字段 set 占一行;想同类型的字段用一行,然后链式 set,会更简洁干净。
|
||||
ImReceiveMessage receiveMessage = new ImReceiveMessage(); // 创建接收消息
|
||||
receiveMessage.setFromId(fromUserId); // 设置发送者ID
|
||||
receiveMessage.setConversationType(message.getConversationType()); // 设置会话类型
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package cn.iocoder.yudao.module.im.websocket.message;
|
||||
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.body.ImMessageBody;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
@ -17,22 +15,25 @@ public class ImReceiveMessage {
|
|||
@Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long fromId; // 根据 conversationType 区分
|
||||
|
||||
// TODO @hao:昵称和头像,也直接发给接收人好了;
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
|
||||
private Long messageId;
|
||||
|
||||
@Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer contentType; // 参见 ImMessageTypeEnum 枚举
|
||||
|
||||
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String content;
|
||||
|
||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
|
||||
private Long messageId;
|
||||
|
||||
@Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime sendTime;
|
||||
|
||||
// TODO @hao:inboxId 不需要哈;
|
||||
@Schema(description = "收件箱编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389")
|
||||
private Long inboxId;
|
||||
|
||||
@Schema(description = "序号,按照 user 递增", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long sequence;
|
||||
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
package cn.iocoder.yudao.module.im.websocket.message;
|
||||
|
||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.body.ImMessageBody;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 消息发送 send")
|
||||
@Schema(description = "管理后台 - IM 消息发送 send")
|
||||
@Data
|
||||
public class ImSendMessage {
|
||||
|
||||
|
@ -13,6 +11,7 @@ public class ImSendMessage {
|
|||
private String clientMessageId;
|
||||
|
||||
@Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
// TODO @hao:用下 InEnum 校验。这样可以少写 15 的注释哈;类似 contentType 也是;
|
||||
private Integer conversationType; // 对应 ImConversationTypeEnum 枚举
|
||||
|
||||
@Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.conversation.ImConversationMapper">
|
||||
|
||||
<!-- TODO @hao:xml 如果用不到,可以先删除哈 -->
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
|
|
|
@ -41,6 +41,7 @@ public class AdminUserRespDTO {
|
|||
*/
|
||||
private String mobile;
|
||||
|
||||
// TODO @hao:这种字段的添加,最好和 do 保持一致的顺序哈;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue