修改:置顶会话和更新最后已读时间
This commit is contained in:
parent
4015b2f213
commit
51e724fc90
|
@ -2,15 +2,15 @@ package cn.iocoder.yudao.module.im.controller.admin.conversation;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ConversationLastTimeReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationRespVO;
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationRespVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ConversationPinnedReqVO;
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
||||||
import cn.iocoder.yudao.module.im.service.conversation.ConversationService;
|
import cn.iocoder.yudao.module.im.service.conversation.ConversationService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@ -18,33 +18,27 @@ import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
// TODO @hao: 管理后台 - IM 会话
|
|
||||||
@Tag(name = "管理后台 - IM 会话")
|
@Tag(name = "管理后台 - IM 会话")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/im/conversation")
|
@RequestMapping("/im/conversation")
|
||||||
@Validated
|
@Validated
|
||||||
public class ConversationController {
|
public class ConversationController {
|
||||||
|
|
||||||
// TODO @hao: conversationService 即可
|
|
||||||
@Resource
|
@Resource
|
||||||
private ConversationService conversationService;
|
private ConversationService conversationService;
|
||||||
|
|
||||||
// TODO @hao:/list 会话列表;一般 get 是给单个对象,或者 get-count 这种;然后 conversation 已经是模块名了,所以可以简化
|
@GetMapping("/list")
|
||||||
@GetMapping("/get-conversation")
|
|
||||||
@Operation(summary = "获得用户的会话列表")
|
@Operation(summary = "获得用户的会话列表")
|
||||||
@PreAuthorize("hasAuthority('im:conversation:query')") // TODO @hao:不用权限哈
|
|
||||||
public CommonResult<List<ImConversationRespVO>> getConversationList() {
|
public CommonResult<List<ImConversationRespVO>> getConversationList() {
|
||||||
List<ConversationDO> conversationList = conversationService.getConversationList();
|
List<ConversationDO> conversationList = conversationService.getConversationList();
|
||||||
return success(BeanUtils.toBean(conversationList, ImConversationRespVO.class));
|
return success(BeanUtils.toBean(conversationList, ImConversationRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @hao:/update-pinned 保持和 db 字段一致哈;
|
|
||||||
// TODO @hao:这个接口,需要单独的 VO 哈;
|
// TODO @hao:这个接口,需要单独的 VO 哈;
|
||||||
@PostMapping("/update-top")
|
@PostMapping("/update-pinned")
|
||||||
@Operation(summary = "置顶会话")
|
@Operation(summary = "置顶会话")
|
||||||
@PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的
|
public CommonResult<Boolean> updatePinned(@Valid @RequestBody ConversationPinnedReqVO updateReqVO) {
|
||||||
public CommonResult<Boolean> updateTop(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) {
|
conversationService.updatePinned(updateReqVO);
|
||||||
conversationService.updateTop(updateReqVO);
|
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +46,7 @@ public class ConversationController {
|
||||||
// TODO @hao:这个接口,需要单独的 VO 哈;
|
// TODO @hao:这个接口,需要单独的 VO 哈;
|
||||||
@PostMapping("/update-last-read-time")
|
@PostMapping("/update-last-read-time")
|
||||||
@Operation(summary = "更新最后已读时间")
|
@Operation(summary = "更新最后已读时间")
|
||||||
@PreAuthorize("hasAuthority('im:conversation:update')") // TODO @hao:不用权限哈;因为肯定会判断是不是自己的
|
public CommonResult<Boolean> updateLastReadTime(@Valid @RequestBody ConversationLastTimeReqVO updateReqVO) {
|
||||||
public CommonResult<Boolean> updateLastReadTime(@Valid @RequestBody ImConversationSaveReqVO updateReqVO) {
|
|
||||||
conversationService.updateLastReadTime(updateReqVO);
|
conversationService.updateLastReadTime(updateReqVO);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package cn.iocoder.yudao.module.im.controller.admin.conversation.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 会话最后已读时间 Request VO")
|
||||||
|
@Data
|
||||||
|
public class ConversationLastTimeReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "s_1_2")
|
||||||
|
@NotEmpty(message = "会话标志不能为空")
|
||||||
|
private String no;
|
||||||
|
|
||||||
|
@Schema(description = "最后已读时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-01 00:00:00")
|
||||||
|
@NotNull(message = "最后已读时间不能为空")
|
||||||
|
private LocalDateTime lastReadTime;
|
||||||
|
|
||||||
|
@Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||||
|
private Long targetId;
|
||||||
|
|
||||||
|
@Schema(description = "会话类型",requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer type; //枚举 ConversationTypeEnum
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package cn.iocoder.yudao.module.im.controller.admin.conversation.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 会话置顶 Request VO")
|
||||||
|
@Data
|
||||||
|
public class ConversationPinnedReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "s_1_2")
|
||||||
|
@NotEmpty(message = "会话标志不能为空")
|
||||||
|
private String no;
|
||||||
|
|
||||||
|
@Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
@NotNull(message = "是否置顶不能为空")
|
||||||
|
private Boolean pinned;
|
||||||
|
|
||||||
|
@Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||||
|
private Long targetId;
|
||||||
|
|
||||||
|
@Schema(description = "会话类型",requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer type; //枚举 ConversationTypeEnum
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.conversation.vo;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.ToString;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
|
||||||
|
|
||||||
// TODO @hao:这个貌似业务上,暂时用不到,可以考虑删除哈。
|
|
||||||
@Schema(description = "管理后台 - IM 会话分页 Request VO")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class ImConversationPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "所属用户", example = "11545")
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", example = "1")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "单聊时,用户编号;群聊时,群编号", example = "21454")
|
|
||||||
private Long targetId;
|
|
||||||
|
|
||||||
@Schema(description = "会话标志 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId 群聊:g_groupId")
|
|
||||||
private String no;
|
|
||||||
|
|
||||||
@Schema(description = "是否置顶 0否 1是")
|
|
||||||
private Boolean pinned;
|
|
||||||
|
|
||||||
@Schema(description = "最后已读时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime[] lastReadTime;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime[] createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -9,45 +9,30 @@ import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 会话 Response VO")
|
@Schema(description = "管理后台 - 会话 Response VO")
|
||||||
@Data
|
@Data
|
||||||
@ExcelIgnoreUnannotated // TODO @hao:excel 的注解可以先删除
|
|
||||||
public class ImConversationRespVO {
|
public class ImConversationRespVO {
|
||||||
|
|
||||||
// TODO @hao:example 都写下
|
|
||||||
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13905")
|
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13905")
|
||||||
@ExcelProperty("编号")
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "11545")
|
@Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@ExcelProperty("所属用户")
|
|
||||||
private Long userId;
|
private Long userId;
|
||||||
|
|
||||||
// TODO @hao:@Schema 可以改成“会话类型”,不用把具体的数字写在上面哈。这样后续改动,会比较难改
|
@Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@ExcelProperty("类型:1 单聊;2 群聊;4 通知会话(预留)")
|
|
||||||
private Integer conversationType;
|
private Integer conversationType;
|
||||||
|
|
||||||
// TODO @hao:只写,聊天对象编号
|
@Schema(description = "聊天对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||||
@Schema(description = "单聊时,用户编号;群聊时,群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21454")
|
|
||||||
@ExcelProperty("单聊时,用户编号;群聊时,群编号")
|
|
||||||
private Long targetId;
|
private Long targetId;
|
||||||
|
|
||||||
// TODO @hao:只写 no 即可。
|
@Schema(description = "会话标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "s_1_2")
|
||||||
@Schema(description = "会话标志 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId 群聊:g_groupId", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@ExcelProperty("会话标志 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId 群聊:g_groupId")
|
|
||||||
private String no;
|
private String no;
|
||||||
|
|
||||||
// TODO @hao:只写 是否置顶;0 1 是数据库的结果哈;
|
@Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
@Schema(description = "是否置顶 0否 1是", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@ExcelProperty("是否置顶 0否 1是")
|
|
||||||
private Boolean pinned;
|
private Boolean pinned;
|
||||||
|
|
||||||
@Schema(description = "最后已读时间")
|
@Schema(description = "最后已读时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-03-01 00:00:00")
|
||||||
@ExcelProperty("最后已读时间")
|
|
||||||
private LocalDateTime lastReadTime;
|
private LocalDateTime lastReadTime;
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
private LocalDateTime createTime;
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,41 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.conversation.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
// TODO @hao:这个貌似业务上,暂时用不到,可以考虑删除哈。
|
|
||||||
@Schema(description = "管理后台 - 会话新增/修改 Request VO")
|
|
||||||
@Data
|
|
||||||
public class ImConversationSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13905")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "所属用户", requiredMode = Schema.RequiredMode.REQUIRED, example = "11545")
|
|
||||||
@NotNull(message = "所属用户不能为空")
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@Schema(description = "类型:1 单聊;2 群聊;4 通知会话(预留)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@NotNull(message = "类型:1 单聊;2 群聊;4 通知会话(预留)不能为空")
|
|
||||||
private Integer type;
|
|
||||||
|
|
||||||
@Schema(description = "单聊时,用户编号;群聊时,群编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21454")
|
|
||||||
@NotEmpty(message = "单聊时,用户编号;群聊时,群编号不能为空")
|
|
||||||
private Long targetId;
|
|
||||||
|
|
||||||
@Schema(description = "会话标志 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId 群聊:g_groupId", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotEmpty(message = "会话标志 单聊:s_{userId}_{targetId},需要排序 userId 和 targetId 群聊:g_groupId不能为空")
|
|
||||||
private String no;
|
|
||||||
|
|
||||||
@Schema(description = "是否置顶 0否 1是", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "是否置顶 0否 1是不能为空")
|
|
||||||
private Boolean pinned;
|
|
||||||
|
|
||||||
@Schema(description = "最后已读时间")
|
|
||||||
private LocalDateTime lastReadTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberP
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberRespVO;
|
import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberRespVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.groupmember.vo.ImGroupMemberSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
|
||||||
import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;
|
import cn.iocoder.yudao.module.im.service.groupmember.GroupMemberService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
@ -34,20 +34,20 @@ import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.E
|
||||||
public class ImGroupMemberController {
|
public class ImGroupMemberController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ImGroupMemberService imGroupMemberService;
|
private GroupMemberService groupMemberService;
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建群成员")
|
@Operation(summary = "创建群成员")
|
||||||
@PreAuthorize("@ss.hasPermission('im:group-member:create')")
|
@PreAuthorize("@ss.hasPermission('im:group-member:create')")
|
||||||
public CommonResult<Long> createGroupMember(@Valid @RequestBody ImGroupMemberSaveReqVO createReqVO) {
|
public CommonResult<Long> createGroupMember(@Valid @RequestBody ImGroupMemberSaveReqVO createReqVO) {
|
||||||
return success(imGroupMemberService.createGroupMember(createReqVO));
|
return success(groupMemberService.createGroupMember(createReqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/update")
|
@PutMapping("/update")
|
||||||
@Operation(summary = "更新群成员")
|
@Operation(summary = "更新群成员")
|
||||||
@PreAuthorize("@ss.hasPermission('im:group-member:update')")
|
@PreAuthorize("@ss.hasPermission('im:group-member:update')")
|
||||||
public CommonResult<Boolean> updateGroupMember(@Valid @RequestBody ImGroupMemberSaveReqVO updateReqVO) {
|
public CommonResult<Boolean> updateGroupMember(@Valid @RequestBody ImGroupMemberSaveReqVO updateReqVO) {
|
||||||
imGroupMemberService.updateGroupMember(updateReqVO);
|
groupMemberService.updateGroupMember(updateReqVO);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public class ImGroupMemberController {
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
@Parameter(name = "id", description = "编号", required = true)
|
||||||
@PreAuthorize("@ss.hasPermission('im:group-member:delete')")
|
@PreAuthorize("@ss.hasPermission('im:group-member:delete')")
|
||||||
public CommonResult<Boolean> deleteGroupMember(@RequestParam("id") Long id) {
|
public CommonResult<Boolean> deleteGroupMember(@RequestParam("id") Long id) {
|
||||||
imGroupMemberService.deleteGroupMember(id);
|
groupMemberService.deleteGroupMember(id);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public class ImGroupMemberController {
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||||
@PreAuthorize("@ss.hasPermission('im:group-member:query')")
|
@PreAuthorize("@ss.hasPermission('im:group-member:query')")
|
||||||
public CommonResult<ImGroupMemberRespVO> getGroupMember(@RequestParam("id") Long id) {
|
public CommonResult<ImGroupMemberRespVO> getGroupMember(@RequestParam("id") Long id) {
|
||||||
GroupMemberDO groupMember = imGroupMemberService.getGroupMember(id);
|
GroupMemberDO groupMember = groupMemberService.getGroupMember(id);
|
||||||
return success(BeanUtils.toBean(groupMember, ImGroupMemberRespVO.class));
|
return success(BeanUtils.toBean(groupMember, ImGroupMemberRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public class ImGroupMemberController {
|
||||||
@Operation(summary = "获得群成员分页")
|
@Operation(summary = "获得群成员分页")
|
||||||
@PreAuthorize("@ss.hasPermission('im:group-member:query')")
|
@PreAuthorize("@ss.hasPermission('im:group-member:query')")
|
||||||
public CommonResult<PageResult<ImGroupMemberRespVO>> getGroupMemberPage(@Valid ImGroupMemberPageReqVO pageReqVO) {
|
public CommonResult<PageResult<ImGroupMemberRespVO>> getGroupMemberPage(@Valid ImGroupMemberPageReqVO pageReqVO) {
|
||||||
PageResult<GroupMemberDO> pageResult = imGroupMemberService.getGroupMemberPage(pageReqVO);
|
PageResult<GroupMemberDO> pageResult = groupMemberService.getGroupMemberPage(pageReqVO);
|
||||||
return success(BeanUtils.toBean(pageResult, ImGroupMemberRespVO.class));
|
return success(BeanUtils.toBean(pageResult, ImGroupMemberRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ public class ImGroupMemberController {
|
||||||
public void exportGroupMemberExcel(@Valid ImGroupMemberPageReqVO pageReqVO,
|
public void exportGroupMemberExcel(@Valid ImGroupMemberPageReqVO pageReqVO,
|
||||||
HttpServletResponse response) throws IOException {
|
HttpServletResponse response) throws IOException {
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||||
List<GroupMemberDO> list = imGroupMemberService.getGroupMemberPage(pageReqVO).getList();
|
List<GroupMemberDO> list = groupMemberService.getGroupMemberPage(pageReqVO).getList();
|
||||||
// 导出 Excel
|
// 导出 Excel
|
||||||
ExcelUtils.write(response, "群成员.xls", "数据", ImGroupMemberRespVO.class,
|
ExcelUtils.write(response, "群成员.xls", "数据", ImGroupMemberRespVO.class,
|
||||||
BeanUtils.toBean(list, ImGroupMemberRespVO.class));
|
BeanUtils.toBean(list, ImGroupMemberRespVO.class));
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.inbox;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
||||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxRespVO;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
|
|
||||||
import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
||||||
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
|
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 收件箱")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/im/inbox")
|
|
||||||
@Validated
|
|
||||||
public class ImInboxController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private ImInboxService imInboxService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
|
||||||
@Operation(summary = "创建收件箱")
|
|
||||||
@PreAuthorize("@ss.hasPermission('im:inbox:create')")
|
|
||||||
public CommonResult<Long> createInbox(@Valid @RequestBody InboxSaveReqVO createReqVO) {
|
|
||||||
return success(imInboxService.createInbox(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/update")
|
|
||||||
@Operation(summary = "更新收件箱")
|
|
||||||
@PreAuthorize("@ss.hasPermission('im:inbox:update')")
|
|
||||||
public CommonResult<Boolean> updateInbox(@Valid @RequestBody InboxSaveReqVO updateReqVO) {
|
|
||||||
imInboxService.updateInbox(updateReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/delete")
|
|
||||||
@Operation(summary = "删除收件箱")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true)
|
|
||||||
@PreAuthorize("@ss.hasPermission('im:inbox:delete')")
|
|
||||||
public CommonResult<Boolean> deleteInbox(@RequestParam("id") Long id) {
|
|
||||||
imInboxService.deleteInbox(id);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/get")
|
|
||||||
@Operation(summary = "获得收件箱")
|
|
||||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
|
||||||
@PreAuthorize("@ss.hasPermission('im:inbox:query')")
|
|
||||||
public CommonResult<ImInboxRespVO> getInbox(@RequestParam("id") Long id) {
|
|
||||||
InboxDO inbox = imInboxService.getInbox(id);
|
|
||||||
return success(BeanUtils.toBean(inbox, ImInboxRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "获得收件箱分页")
|
|
||||||
@PreAuthorize("@ss.hasPermission('im:inbox:query')")
|
|
||||||
public CommonResult<PageResult<ImInboxRespVO>> getInboxPage(@Valid ImInboxPageReqVO pageReqVO) {
|
|
||||||
PageResult<InboxDO> pageResult = imInboxService.getInboxPage(pageReqVO);
|
|
||||||
return success(BeanUtils.toBean(pageResult, ImInboxRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/export-excel")
|
|
||||||
@Operation(summary = "导出收件箱 Excel")
|
|
||||||
@PreAuthorize("@ss.hasPermission('im:inbox:export')")
|
|
||||||
@OperateLog(type = EXPORT)
|
|
||||||
public void exportInboxExcel(@Valid ImInboxPageReqVO pageReqVO,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
||||||
List<InboxDO> list = imInboxService.getInboxPage(pageReqVO).getList();
|
|
||||||
// 导出 Excel
|
|
||||||
ExcelUtils.write(response, "收件箱.xls", "数据", ImInboxRespVO.class,
|
|
||||||
BeanUtils.toBean(list, ImInboxRespVO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
* @author anhaohao
|
||||||
|
* @since 2024/3/27 下午11:36
|
||||||
|
*/
|
||||||
|
package cn.iocoder.yudao.module.im.controller.admin.inbox;
|
|
@ -1,34 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.inbox.vo;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.ToString;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
|
||||||
|
|
||||||
// TODO @hao:这个是不是删除掉,应该不会有这个 VO 哈
|
|
||||||
@Schema(description = "管理后台 - 收件箱分页 Request VO")
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class ImInboxPageReqVO extends PageParam {
|
|
||||||
|
|
||||||
@Schema(description = "用户编号", example = "3979")
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@Schema(description = "消息编号", example = "12454")
|
|
||||||
private Long messageId;
|
|
||||||
|
|
||||||
@Schema(description = "序号,按照 user 递增")
|
|
||||||
private Long sequence;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime[] createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.inbox.vo;
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
// TODO @hao:这个是不是删除掉,应该不会有这个 VO 哈;应该给前端的,是要屏蔽掉这个表,最终返回的都是 Message 哈;说白了,这个 inbox 是后端的内部实现
|
|
||||||
@Schema(description = "管理后台 - 收件箱 Response VO")
|
|
||||||
@Data
|
|
||||||
@ExcelIgnoreUnannotated
|
|
||||||
public class ImInboxRespVO {
|
|
||||||
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389")
|
|
||||||
@ExcelProperty("编号")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3979")
|
|
||||||
@ExcelProperty("用户编号")
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
|
|
||||||
@ExcelProperty("消息编号")
|
|
||||||
private Long messageId;
|
|
||||||
|
|
||||||
@Schema(description = "序号,按照 user 递增", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@ExcelProperty("序号,按照 user 递增")
|
|
||||||
private Long sequence;
|
|
||||||
|
|
||||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@ExcelProperty("创建时间")
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.inbox.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
// TODO @hao:这个是不是删除掉,应该不会有这个 VO 哈
|
|
||||||
@Schema(description = "管理后台 - 收件箱新增/修改 Request VO")
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class InboxSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18389")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3979")
|
|
||||||
@NotNull(message = "用户编号不能为空")
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
|
|
||||||
@NotNull(message = "消息编号不能为空")
|
|
||||||
private Long messageId;
|
|
||||||
|
|
||||||
@Schema(description = "序号,按照 user 递增", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "序号,按照 user 递增不能为空")
|
|
||||||
private Long sequence;
|
|
||||||
|
|
||||||
public InboxSaveReqVO(Long userId, Long messageId, Long sequence) {
|
|
||||||
this.userId = userId;
|
|
||||||
this.messageId = messageId;
|
|
||||||
this.sequence = sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.im.controller.admin.message;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessagePageReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.message.vo.ImMessageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.message.vo.MessageReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO;
|
import cn.iocoder.yudao.module.im.controller.admin.message.vo.SendMessageRespVO;
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.message.MessageDO;
|
||||||
|
@ -40,18 +40,18 @@ public class MessageController {
|
||||||
@Operation(summary = "拉取大于 sequence 的消息列表")
|
@Operation(summary = "拉取大于 sequence 的消息列表")
|
||||||
@Parameter(name = "sequence", description = "序号", required = true, example = "1")
|
@Parameter(name = "sequence", description = "序号", required = true, example = "1")
|
||||||
@Parameter(name = "size", description = "条数", required = true, example = "10")
|
@Parameter(name = "size", description = "条数", required = true, example = "10")
|
||||||
public CommonResult<List<ImMessageReqVO>> loadMessage(@RequestParam("sequence") Long sequence,
|
public CommonResult<List<MessageReqVO>> getMessageListBySequence(@RequestParam("sequence") Long sequence,
|
||||||
@RequestParam("size") Integer size) {
|
@RequestParam("size") Integer size) {
|
||||||
List<MessageDO> messages = messageService.getMessageListBySequence(getLoginUserId(), sequence, size);
|
List<MessageDO> messages = messageService.getMessageListBySequence(getLoginUserId(), sequence, size);
|
||||||
return success(BeanUtils.toBean(messages, ImMessageReqVO.class));
|
return success(BeanUtils.toBean(messages, MessageReqVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/history")
|
||||||
@Operation(summary = "查询聊天记录-分页")
|
@Operation(summary = "查询聊天记录-根据会话标志和发送时间进行分页查询")
|
||||||
public CommonResult<List<ImMessageReqVO>> getMessagePage(@Valid MessagePageReqVO pageReqVO) {
|
public CommonResult<List<MessageReqVO>> getHistoryMessage(@Valid MessagePageReqVO pageReqVO) {
|
||||||
//根据会话标志和发送时间进行分页查询
|
//根据会话标志和发送时间进行分页查询
|
||||||
List<MessageDO> messagePage = messageService.getMessagePage(pageReqVO);
|
List<MessageDO> messagePage = messageService.getHistoryMessage(pageReqVO);
|
||||||
return success(BeanUtils.toBean(messagePage, ImMessageReqVO.class));
|
return success(BeanUtils.toBean(messagePage, MessageReqVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.message.vo;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
|
||||||
import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum;
|
|
||||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 消息 Request VO")
|
|
||||||
@Data
|
|
||||||
@ExcelIgnoreUnannotated
|
|
||||||
public class ImMessageReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331")
|
|
||||||
@ExcelProperty("客户端消息编号 uuid,用于排重")
|
|
||||||
private String clientMessageId;
|
|
||||||
|
|
||||||
@Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
|
|
||||||
@ExcelProperty("接收人编号")
|
|
||||||
private Long receiverId;
|
|
||||||
|
|
||||||
@Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
|
||||||
@ExcelProperty("会话类型")
|
|
||||||
private Integer conversationType;
|
|
||||||
|
|
||||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@ExcelProperty("消息类型")
|
|
||||||
@InEnum(MessageContentTypeEnum.class)
|
|
||||||
private Integer contentType;
|
|
||||||
|
|
||||||
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@ExcelProperty("消息内容")
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.controller.admin.message.vo;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 消息新增/修改 Request VO")
|
|
||||||
@Data
|
|
||||||
public class ImMessageSaveReqVO {
|
|
||||||
|
|
||||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30713")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "客户端消息编号 uuid,用于排重", requiredMode = Schema.RequiredMode.REQUIRED, example = "3331")
|
|
||||||
@NotEmpty(message = "客户端消息编号 uuid,用于排重不能为空")
|
|
||||||
private String clientMessageId;
|
|
||||||
|
|
||||||
@Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23239")
|
|
||||||
@NotNull(message = "发送人编号不能为空")
|
|
||||||
private Long senderId;
|
|
||||||
|
|
||||||
@Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
|
|
||||||
@NotNull(message = "接收人编号不能为空")
|
|
||||||
private Long receiverId;
|
|
||||||
|
|
||||||
@Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
|
||||||
@NotEmpty(message = "发送人昵称不能为空")
|
|
||||||
private String senderNickname;
|
|
||||||
|
|
||||||
@Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotEmpty(message = "发送人头像不能为空")
|
|
||||||
private String senderAvatar;
|
|
||||||
|
|
||||||
@Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
|
||||||
@NotNull(message = "会话类型不能为空")
|
|
||||||
private Integer conversationType;
|
|
||||||
|
|
||||||
@Schema(description = "会话标志 conversation_no = a_b", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotEmpty(message = "会话标志不能为空")
|
|
||||||
private String conversationNo;
|
|
||||||
|
|
||||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
|
||||||
@NotNull(message = "消息类型不能为空")
|
|
||||||
private Integer contentType;
|
|
||||||
|
|
||||||
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotEmpty(message = "消息内容不能为空")
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
@Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
private LocalDateTime sendTime;
|
|
||||||
|
|
||||||
@Schema(description = "消息来源 100-用户发送;200-系统发送(一般是通知);", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "消息来源 100-用户发送;200-系统发送(一般是通知);不能为空")
|
|
||||||
private Integer sendFrom;
|
|
||||||
|
|
||||||
@Schema(description = "消息状态 1 发送中、2 发送成功、3 发送失败、4 已删除、5 已撤回", requiredMode = Schema.RequiredMode.REQUIRED)
|
|
||||||
@NotNull(message = "消息状态不能为空")
|
|
||||||
private Integer messageStatus;
|
|
||||||
}
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package cn.iocoder.yudao.module.im.controller.admin.message.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||||
|
import cn.iocoder.yudao.module.im.enums.message.MessageContentTypeEnum;
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 消息 Request VO")
|
||||||
|
@Data
|
||||||
|
public class MessageReqVO {
|
||||||
|
|
||||||
|
@Schema(description = "消息编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12454")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer conversationType; // 对应 ImConversationTypeEnum 枚举
|
||||||
|
|
||||||
|
@Schema(description = "发送人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||||
|
private Long fromId; // 根据 conversationType 区分
|
||||||
|
|
||||||
|
@Schema(description = "发送人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||||
|
private String senderNickname;
|
||||||
|
|
||||||
|
@Schema(description = "发送人头像", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String senderAvatar;
|
||||||
|
|
||||||
|
@Schema(description = "接收人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32494")
|
||||||
|
private Long receiverId;
|
||||||
|
|
||||||
|
@Schema(description = "内容类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||||
|
private Integer contentType; // 参见 ImMessageTypeEnum 枚举
|
||||||
|
|
||||||
|
@Schema(description = "消息内容", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Schema(description = "发送时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private LocalDateTime sendTime;
|
||||||
|
|
||||||
|
@Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Long sequence;
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.im.dal.mysql.conversation;
|
package cn.iocoder.yudao.module.im.dal.mysql.conversation;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@ -15,20 +13,7 @@ import org.apache.ibatis.annotations.Mapper;
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ConversationMapper extends BaseMapperX<ConversationDO> {
|
public interface ConversationMapper extends BaseMapperX<ConversationDO> {
|
||||||
|
|
||||||
default PageResult<ConversationDO> selectPage(ImConversationPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<ConversationDO>()
|
|
||||||
.eqIfPresent(ConversationDO::getUserId, reqVO.getUserId())
|
|
||||||
.eqIfPresent(ConversationDO::getType, reqVO.getType())
|
|
||||||
.eqIfPresent(ConversationDO::getTargetId, reqVO.getTargetId())
|
|
||||||
.eqIfPresent(ConversationDO::getNo, reqVO.getNo())
|
|
||||||
.eqIfPresent(ConversationDO::getPinned, reqVO.getPinned())
|
|
||||||
.betweenIfPresent(ConversationDO::getLastReadTime, reqVO.getLastReadTime())
|
|
||||||
.betweenIfPresent(ConversationDO::getCreateTime, reqVO.getCreateTime())
|
|
||||||
.orderByDesc(ConversationDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @hao:1)no) {,要有空格哈;2)可以直接 selectOne(ImConversationDO::getNo, no) 父类做了封装
|
|
||||||
default ConversationDO selectByNo(String no){
|
default ConversationDO selectByNo(String no){
|
||||||
return selectOne(new LambdaQueryWrapperX<ConversationDO>().eq(ConversationDO::getNo, no));
|
return selectOne(ConversationDO::getNo, no);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.dal.mysql.inbox;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IM 收件箱 Mapper
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface ImInboxMapper extends BaseMapperX<InboxDO> {
|
|
||||||
|
|
||||||
default PageResult<InboxDO> selectPage(ImInboxPageReqVO reqVO) {
|
|
||||||
return selectPage(reqVO, new LambdaQueryWrapperX<InboxDO>()
|
|
||||||
.eqIfPresent(InboxDO::getUserId, reqVO.getUserId())
|
|
||||||
.eqIfPresent(InboxDO::getMessageId, reqVO.getMessageId())
|
|
||||||
.eqIfPresent(InboxDO::getSequence, reqVO.getSequence())
|
|
||||||
.betweenIfPresent(InboxDO::getCreateTime, reqVO.getCreateTime())
|
|
||||||
.orderByDesc(InboxDO::getId));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package cn.iocoder.yudao.module.im.dal.mysql.inbox;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM 收件箱 Mapper
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface InboxMapper extends BaseMapperX<InboxDO> {
|
||||||
|
|
||||||
|
default List<Long> selectMessageIdsByUserIdAndSequence(Long userId, Long sequence, Integer size) {
|
||||||
|
return selectList(new LambdaQueryWrapperX<InboxDO>()
|
||||||
|
.gt(InboxDO::getUserId, userId)
|
||||||
|
.gt(InboxDO::getSequence, sequence)
|
||||||
|
.orderByAsc(InboxDO::getSequence)
|
||||||
|
.last("limit 0," + size))
|
||||||
|
.stream()
|
||||||
|
.map(InboxDO::getMessageId)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default PageResult<InboxDO> selectPage(ImInboxPageReqVO reqVO) {
|
||||||
|
// return selectPage(reqVO, new LambdaQueryWrapperX<InboxDO>()
|
||||||
|
// .eqIfPresent(InboxDO::getUserId, reqVO.getUserId())
|
||||||
|
// .eqIfPresent(InboxDO::getMessageId, reqVO.getMessageId())
|
||||||
|
// .eqIfPresent(InboxDO::getSequence, reqVO.getSequence())
|
||||||
|
// .betweenIfPresent(InboxDO::getCreateTime, reqVO.getCreateTime())
|
||||||
|
// .orderByDesc(InboxDO::getId));
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -18,30 +18,7 @@ import java.util.List;
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface MessageMapper extends BaseMapperX<MessageDO> {
|
public interface MessageMapper extends BaseMapperX<MessageDO> {
|
||||||
|
|
||||||
// TODO @hao:不链表哈;先从 ImInboxDO 查询出 messageId,然后再到 ImMessageDO 里 IN
|
default List<MessageDO> getHistoryMessage(MessagePageReqVO pageReqVO) {
|
||||||
default List<MessageDO> getGreaterThanSequenceMessage(Long userId, Long sequence, Integer size) {
|
|
||||||
//查询 inbox 表中,大于 sequence 的消息,关联 message 表,按照 inbox 表 sequence 升序
|
|
||||||
return selectJoinList(MessageDO.class, new MPJLambdaWrapper<MessageDO>()
|
|
||||||
.selectAll(MessageDO.class)
|
|
||||||
.innerJoin(InboxDO.class, InboxDO::getMessageId, MessageDO::getId)
|
|
||||||
.eq(InboxDO::getUserId, userId)
|
|
||||||
.gt(InboxDO::getSequence, sequence)
|
|
||||||
.orderByAsc(InboxDO::getSequence)
|
|
||||||
.last("limit 0," + size));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @hao:在 dao 里,使用 selectListByUserId,查询用 select,条件用 by,这个算是 spring data 的 method dsl
|
|
||||||
default List<MessageDO> getAllMessage(Long userId, Integer size) {
|
|
||||||
//查询 inbox 表中,100条消息,关联 message 表,按照 inbox 表 sequence 降序
|
|
||||||
return selectJoinList(MessageDO.class, new MPJLambdaWrapper<MessageDO>()
|
|
||||||
.selectAll(MessageDO.class)
|
|
||||||
.innerJoin(InboxDO.class, InboxDO::getMessageId, MessageDO::getId)
|
|
||||||
.eq(InboxDO::getUserId, userId)
|
|
||||||
.orderByDesc(InboxDO::getSequence)
|
|
||||||
.last("limit 0," + size));
|
|
||||||
}
|
|
||||||
|
|
||||||
default List<MessageDO> getMessagePage(MessagePageReqVO pageReqVO) {
|
|
||||||
return selectList(new LambdaQueryWrapperX<MessageDO>()
|
return selectList(new LambdaQueryWrapperX<MessageDO>()
|
||||||
.eqIfPresent(MessageDO::getConversationNo, pageReqVO.getConversationNo())
|
.eqIfPresent(MessageDO::getConversationNo, pageReqVO.getConversationNo())
|
||||||
.betweenIfPresent(MessageDO::getSendTime, pageReqVO.getSendTime())
|
.betweenIfPresent(MessageDO::getSendTime, pageReqVO.getSendTime())
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package cn.iocoder.yudao.module.im.service.conversation;
|
package cn.iocoder.yudao.module.im.service.conversation;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ConversationLastTimeReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ConversationPinnedReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
||||||
import jakarta.validation.Valid;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -15,45 +13,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public interface ConversationService {
|
public interface ConversationService {
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建会话
|
|
||||||
*
|
|
||||||
* @param createReqVO 创建信息
|
|
||||||
* @return 编号
|
|
||||||
*/
|
|
||||||
Long createConversation(@Valid ImConversationSaveReqVO createReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新会话
|
|
||||||
*
|
|
||||||
* @param updateReqVO 更新信息
|
|
||||||
*/
|
|
||||||
void updateConversation(@Valid ImConversationSaveReqVO updateReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除会话
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
*/
|
|
||||||
void deleteConversation(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得会话
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 会话
|
|
||||||
*/
|
|
||||||
ConversationDO getConversation(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得会话分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 会话分页
|
|
||||||
*/
|
|
||||||
PageResult<ConversationDO> getConversationPage(ImConversationPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得用户的会话列表
|
* 获得用户的会话列表
|
||||||
*
|
*
|
||||||
|
@ -66,13 +25,13 @@ public interface ConversationService {
|
||||||
*
|
*
|
||||||
* @param updateReqVO 更新信息
|
* @param updateReqVO 更新信息
|
||||||
*/
|
*/
|
||||||
void updateTop(ImConversationSaveReqVO updateReqVO);
|
void updatePinned(ConversationPinnedReqVO updateReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新最后已读时间
|
* 更新最后已读时间
|
||||||
*
|
*
|
||||||
* @param updateReqVO 更新信息
|
* @param updateReqVO 更新信息
|
||||||
*/
|
*/
|
||||||
void updateLastReadTime(ImConversationSaveReqVO updateReqVO);
|
void updateLastReadTime(ConversationLastTimeReqVO updateReqVO);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,21 +1,18 @@
|
||||||
package cn.iocoder.yudao.module.im.service.conversation;
|
package cn.iocoder.yudao.module.im.service.conversation;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationPageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ConversationLastTimeReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ImConversationSaveReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.conversation.vo.ConversationPinnedReqVO;
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.conversation.ConversationDO;
|
||||||
import cn.iocoder.yudao.module.im.dal.mysql.conversation.ConversationMapper;
|
import cn.iocoder.yudao.module.im.dal.mysql.conversation.ConversationMapper;
|
||||||
|
import cn.iocoder.yudao.module.im.service.inbox.InboxService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_NOT_EXISTS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM 会话 Service 实现类
|
* IM 会话 Service 实现类
|
||||||
|
@ -26,52 +23,10 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.CONVERSATION_N
|
||||||
@Validated
|
@Validated
|
||||||
public class ConversationServiceImpl implements ConversationService {
|
public class ConversationServiceImpl implements ConversationService {
|
||||||
|
|
||||||
// TODO @hao: 自己模块的注入,不用带 im 前缀哈;
|
|
||||||
@Resource
|
@Resource
|
||||||
private ConversationMapper conversationMapper;
|
private ConversationMapper conversationMapper;
|
||||||
|
@Resource
|
||||||
// TODO @hao: 这个方法,是不是不需要哈
|
private InboxService inboxService;
|
||||||
@Override
|
|
||||||
public Long createConversation(ImConversationSaveReqVO createReqVO) {
|
|
||||||
ConversationDO conversation = BeanUtils.toBean(createReqVO, ConversationDO.class);
|
|
||||||
conversationMapper.insert(conversation);
|
|
||||||
return conversation.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @hao: 这个方法,是不是不需要哈
|
|
||||||
@Override
|
|
||||||
public void updateConversation(ImConversationSaveReqVO updateReqVO) {
|
|
||||||
// 校验存在
|
|
||||||
validateConversationExists(updateReqVO.getId());
|
|
||||||
// 更新
|
|
||||||
ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class);
|
|
||||||
conversationMapper.updateById(updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @hao: 考虑到可能和端上不同步,可以不校验是不是存储。另外,不基于 id 删除。要基于 no + userId 删除哈。说白了,对端上要屏蔽 id 字段
|
|
||||||
@Override
|
|
||||||
public void deleteConversation(Long id) {
|
|
||||||
// 校验存在
|
|
||||||
validateConversationExists(id);
|
|
||||||
// 删除
|
|
||||||
conversationMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateConversationExists(Long id) {
|
|
||||||
if (conversationMapper.selectById(id) == null) {
|
|
||||||
throw exception(CONVERSATION_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConversationDO getConversation(Long id) {
|
|
||||||
return conversationMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<ConversationDO> getConversationPage(ImConversationPageReqVO pageReqVO) {
|
|
||||||
return conversationMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ConversationDO> getConversationList() {
|
public List<ConversationDO> getConversationList() {
|
||||||
|
@ -79,31 +34,39 @@ public class ConversationServiceImpl implements ConversationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTop(ImConversationSaveReqVO updateReqVO) {
|
public void updatePinned(ConversationPinnedReqVO updateReqVO) {
|
||||||
createOrUpdateConversation(updateReqVO);
|
// TODO @hao:updateTop 和 updateLastReadTime 使用独立的逻辑实现,不使用统一的 ImConversationSaveReqVO;
|
||||||
}
|
// TODO 大体步骤建议:
|
||||||
|
// 1. 先 getOrderCreateConversation,查询会话,不存在则插入;
|
||||||
@Override
|
// 2. 更新对应的字段
|
||||||
public void updateLastReadTime(ImConversationSaveReqVO updateReqVO) {
|
// 3. 做对应更新的 notify 推送
|
||||||
createOrUpdateConversation(updateReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @hao:updateTop 和 updateLastReadTime 使用独立的逻辑实现,不使用统一的 ImConversationSaveReqVO;
|
|
||||||
// TODO 大体步骤建议:
|
|
||||||
// 1. 先 getOrderCreateConversation,查询会话,不存在则插入;
|
|
||||||
// 2. 更新对应的字段
|
|
||||||
// 3. 做对应更新的 notify 推送
|
|
||||||
private void createOrUpdateConversation(ImConversationSaveReqVO updateReqVO) {
|
|
||||||
// 操作会话(已读、置顶)时,才会延迟创建,要先判断是否存在,根据 no 查询是否存在,不存在则新增
|
|
||||||
ConversationDO conversation = conversationMapper.selectByNo(updateReqVO.getNo());
|
ConversationDO conversation = conversationMapper.selectByNo(updateReqVO.getNo());
|
||||||
if (conversation == null) {
|
if (conversation == null) {
|
||||||
ConversationDO conversationDO = new ConversationDO();
|
ConversationDO conversationDO = new ConversationDO();
|
||||||
conversationDO.setNo(updateReqVO.getNo());
|
conversationDO.setNo(updateReqVO.getNo());
|
||||||
|
conversationDO.setPinned(updateReqVO.getPinned());
|
||||||
|
conversationDO.setUserId(updateReqVO.getUserId());
|
||||||
|
conversationDO.setTargetId(updateReqVO.getTargetId());
|
||||||
|
conversationDO.setType(updateReqVO.getType());
|
||||||
|
conversationMapper.insert(conversationDO);
|
||||||
|
} else {
|
||||||
|
// 更新
|
||||||
|
ConversationDO updateObj = BeanUtils.toBean(updateReqVO, ConversationDO.class);
|
||||||
|
conversationMapper.updateById(updateObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateLastReadTime(ConversationLastTimeReqVO updateReqVO) {
|
||||||
|
ConversationDO conversation = conversationMapper.selectByNo(updateReqVO.getNo());
|
||||||
|
if (conversation == null) {
|
||||||
|
ConversationDO conversationDO = new ConversationDO();
|
||||||
|
conversationDO.setNo(updateReqVO.getNo());
|
||||||
|
conversationDO.setLastReadTime(updateReqVO.getLastReadTime());
|
||||||
conversationDO.setUserId(updateReqVO.getUserId());
|
conversationDO.setUserId(updateReqVO.getUserId());
|
||||||
conversationDO.setTargetId(updateReqVO.getTargetId());
|
conversationDO.setTargetId(updateReqVO.getTargetId());
|
||||||
conversationDO.setType(updateReqVO.getType());
|
conversationDO.setType(updateReqVO.getType());
|
||||||
conversationDO.setPinned(updateReqVO.getPinned());
|
|
||||||
conversationDO.setLastReadTime(DateUtil.toLocalDateTime(new Date()));
|
|
||||||
conversationMapper.insert(conversationDO);
|
conversationMapper.insert(conversationDO);
|
||||||
} else {
|
} else {
|
||||||
// 更新
|
// 更新
|
||||||
|
|
|
@ -13,7 +13,7 @@ import java.util.List;
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
public interface ImGroupMemberService {
|
public interface GroupMemberService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建群成员
|
* 创建群成员
|
|
@ -23,7 +23,7 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.*;
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Validated
|
@Validated
|
||||||
public class ImGroupMemberServiceImpl implements ImGroupMemberService {
|
public class GroupMemberServiceImpl implements GroupMemberService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ImGroupMemberMapper imGroupMemberMapper;
|
private ImGroupMemberMapper imGroupMemberMapper;
|
|
@ -1,61 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.im.service.inbox;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
|
|
||||||
// TODO @hao:不用的方法,删除下哈;
|
|
||||||
/**
|
|
||||||
* IM 收件箱 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface ImInboxService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建收件箱
|
|
||||||
*
|
|
||||||
* @param createReqVO 创建信息
|
|
||||||
* @return 编号
|
|
||||||
*/
|
|
||||||
Long createInbox(@Valid InboxSaveReqVO createReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新收件箱
|
|
||||||
*
|
|
||||||
* @param updateReqVO 更新信息
|
|
||||||
*/
|
|
||||||
void updateInbox(@Valid InboxSaveReqVO updateReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除收件箱
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
*/
|
|
||||||
void deleteInbox(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得收件箱
|
|
||||||
*
|
|
||||||
* @param id 编号
|
|
||||||
* @return 收件箱
|
|
||||||
*/
|
|
||||||
InboxDO getInbox(Long id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得收件箱分页
|
|
||||||
*
|
|
||||||
* @param pageReqVO 分页查询
|
|
||||||
* @return 收件箱分页
|
|
||||||
*/
|
|
||||||
PageResult<InboxDO> getInboxPage(ImInboxPageReqVO pageReqVO);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存收件箱和发送消息
|
|
||||||
* @param inboxSaveMessageReqVO 收件箱保存消息 Request VO
|
|
||||||
*/
|
|
||||||
void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessageReqVO);
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package cn.iocoder.yudao.module.im.service.inbox;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IM 收件箱 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface InboxService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存收件箱和发送消息
|
||||||
|
*
|
||||||
|
* @param inboxSaveMessageReqVO 收件箱保存消息 Request VO
|
||||||
|
*/
|
||||||
|
void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得大于 sequence 的消息ids
|
||||||
|
*
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @param sequence 序列号
|
||||||
|
* @param size 数量
|
||||||
|
* @return 消息编号列表
|
||||||
|
*/
|
||||||
|
List<Long> selectMessageIdsByUserIdAndSequence(Long userId, Long sequence, Integer size);
|
||||||
|
}
|
|
@ -1,20 +1,17 @@
|
||||||
package cn.iocoder.yudao.module.im.service.inbox;
|
package cn.iocoder.yudao.module.im.service.inbox;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.ImInboxPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveMessageReqVO;
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSendMessageReqVO;
|
import cn.iocoder.yudao.module.im.controller.admin.inbox.vo.InboxSendMessageReqVO;
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.group.GroupMemberDO;
|
||||||
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
|
import cn.iocoder.yudao.module.im.dal.dataobject.inbox.InboxDO;
|
||||||
import cn.iocoder.yudao.module.im.dal.mysql.inbox.ImInboxMapper;
|
import cn.iocoder.yudao.module.im.dal.mysql.inbox.InboxMapper;
|
||||||
import cn.iocoder.yudao.module.im.dal.redis.inbox.InboxLockRedisDAO;
|
import cn.iocoder.yudao.module.im.dal.redis.inbox.InboxLockRedisDAO;
|
||||||
import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceRedisDao;
|
import cn.iocoder.yudao.module.im.dal.redis.inbox.SequenceRedisDao;
|
||||||
import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
|
import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
|
||||||
import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;
|
import cn.iocoder.yudao.module.im.service.groupmember.GroupMemberService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.dromara.hutool.core.date.DateUnit;
|
import org.dromara.hutool.core.date.DateUnit;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -22,9 +19,6 @@ import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
||||||
import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXISTS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 收件箱 Service 实现类
|
* 收件箱 Service 实现类
|
||||||
*
|
*
|
||||||
|
@ -32,13 +26,13 @@ import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.INBOX_NOT_EXIS
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Validated
|
@Validated
|
||||||
public class ImInboxServiceImpl implements ImInboxService {
|
public class InboxServiceImpl implements InboxService {
|
||||||
|
|
||||||
private static final Long INBOX_LOCK_TIMEOUT = 120 * DateUnit.SECOND.getMillis();
|
private static final Long INBOX_LOCK_TIMEOUT = 120 * DateUnit.SECOND.getMillis();
|
||||||
private static final String IM_MESSAGE_RECEIVE = "im-message-receive";
|
private static final String IM_MESSAGE_RECEIVE = "im-message-receive";
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ImInboxMapper imInboxMapper;
|
private InboxMapper inboxMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private SequenceRedisDao sequenceRedisDao; // 序列生成器Redis DAO
|
private SequenceRedisDao sequenceRedisDao; // 序列生成器Redis DAO
|
||||||
@Resource
|
@Resource
|
||||||
|
@ -46,47 +40,7 @@ public class ImInboxServiceImpl implements ImInboxService {
|
||||||
@Resource
|
@Resource
|
||||||
private WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器
|
private WebSocketMessageSender webSocketMessageSender; // WebSocket消息发送器
|
||||||
@Resource
|
@Resource
|
||||||
private ImGroupMemberService imGroupMemberService;
|
private GroupMemberService groupMemberService;
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long createInbox(InboxSaveReqVO createReqVO) {
|
|
||||||
InboxDO inbox = BeanUtils.toBean(createReqVO, InboxDO.class);
|
|
||||||
imInboxMapper.insert(inbox);
|
|
||||||
return inbox.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateInbox(InboxSaveReqVO updateReqVO) {
|
|
||||||
// 校验存在
|
|
||||||
validateInboxExists(updateReqVO.getId());
|
|
||||||
// 更新
|
|
||||||
InboxDO updateObj = BeanUtils.toBean(updateReqVO, InboxDO.class);
|
|
||||||
imInboxMapper.updateById(updateObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteInbox(Long id) {
|
|
||||||
// 校验存在
|
|
||||||
validateInboxExists(id);
|
|
||||||
// 删除
|
|
||||||
imInboxMapper.deleteById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateInboxExists(Long id) {
|
|
||||||
if (imInboxMapper.selectById(id) == null) {
|
|
||||||
throw exception(INBOX_NOT_EXISTS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InboxDO getInbox(Long id) {
|
|
||||||
return imInboxMapper.selectById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<InboxDO> getInboxPage(ImInboxPageReqVO pageReqVO) {
|
|
||||||
return imInboxMapper.selectPage(pageReqVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessage) {
|
public void saveInboxAndSendMessage(InboxSaveMessageReqVO inboxSaveMessage) {
|
||||||
|
@ -96,11 +50,16 @@ public class ImInboxServiceImpl implements ImInboxService {
|
||||||
if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) {
|
if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.SINGLE.getType())) {
|
||||||
saveInboxAndSendMessageForUser(inboxSaveMessage.getReceiverId(), inboxSaveMessage);
|
saveInboxAndSendMessageForUser(inboxSaveMessage.getReceiverId(), inboxSaveMessage);
|
||||||
} else if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
|
} else if (inboxSaveMessage.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
|
||||||
List<GroupMemberDO> groupMembers = imGroupMemberService.selectByGroupId(inboxSaveMessage.getReceiverId());
|
List<GroupMemberDO> groupMembers = groupMemberService.selectByGroupId(inboxSaveMessage.getReceiverId());
|
||||||
groupMembers.forEach(groupMemberDO -> saveInboxAndSendMessageForUser(groupMemberDO.getUserId(), inboxSaveMessage));
|
groupMembers.forEach(groupMemberDO -> saveInboxAndSendMessageForUser(groupMemberDO.getUserId(), inboxSaveMessage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Long> selectMessageIdsByUserIdAndSequence(Long userId, Long sequence, Integer size) {
|
||||||
|
return inboxMapper.selectMessageIdsByUserIdAndSequence(userId, sequence, size);
|
||||||
|
}
|
||||||
|
|
||||||
private void saveInboxAndSendMessageForUser(Long userId, InboxSaveMessageReqVO inboxSaveMessage) {
|
private void saveInboxAndSendMessageForUser(Long userId, InboxSaveMessageReqVO inboxSaveMessage) {
|
||||||
inboxLockRedisDAO.lock(userId, INBOX_LOCK_TIMEOUT, () -> {
|
inboxLockRedisDAO.lock(userId, INBOX_LOCK_TIMEOUT, () -> {
|
||||||
Long userSequence = sequenceRedisDao.generateSequence(userId);
|
Long userSequence = sequenceRedisDao.generateSequence(userId);
|
||||||
|
@ -108,12 +67,8 @@ public class ImInboxServiceImpl implements ImInboxService {
|
||||||
inbox.setUserId(userId);
|
inbox.setUserId(userId);
|
||||||
inbox.setMessageId(inboxSaveMessage.getMessageId());
|
inbox.setMessageId(inboxSaveMessage.getMessageId());
|
||||||
inbox.setSequence(userSequence);
|
inbox.setSequence(userSequence);
|
||||||
imInboxMapper.insert(inbox);
|
inboxMapper.insert(inbox);
|
||||||
|
|
||||||
//是发送人不发送
|
|
||||||
if (userId.equals(inboxSaveMessage.getFromId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
InboxSendMessageReqVO message = BeanUtils.toBean(inboxSaveMessage, InboxSendMessageReqVO.class);
|
InboxSendMessageReqVO message = BeanUtils.toBean(inboxSaveMessage, InboxSendMessageReqVO.class);
|
||||||
message.setSequence(userSequence);
|
message.setSequence(userSequence);
|
||||||
webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message);
|
webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), userId, IM_MESSAGE_RECEIVE, message);
|
|
@ -15,13 +15,12 @@ import java.util.List;
|
||||||
public interface MessageService {
|
public interface MessageService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得消息分页
|
* 获得历史消息
|
||||||
*
|
*
|
||||||
* @param pageReqVO 分页查询
|
* @param pageReqVO 分页查询
|
||||||
* @return 消息分页
|
* @return 消息分页
|
||||||
*/
|
*/
|
||||||
List<MessageDO> getMessagePage(MessagePageReqVO pageReqVO);
|
List<MessageDO> getHistoryMessage(MessagePageReqVO pageReqVO);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拉取消息-大于 seq 的消息
|
* 拉取消息-大于 seq 的消息
|
||||||
|
|
|
@ -10,8 +10,8 @@ import cn.iocoder.yudao.module.im.dal.mysql.message.MessageMapper;
|
||||||
import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
|
import cn.iocoder.yudao.module.im.enums.conversation.ConversationTypeEnum;
|
||||||
import cn.iocoder.yudao.module.im.enums.message.MessageSourceEnum;
|
import cn.iocoder.yudao.module.im.enums.message.MessageSourceEnum;
|
||||||
import cn.iocoder.yudao.module.im.enums.message.MessageStatusEnum;
|
import cn.iocoder.yudao.module.im.enums.message.MessageStatusEnum;
|
||||||
import cn.iocoder.yudao.module.im.service.groupmember.ImGroupMemberService;
|
import cn.iocoder.yudao.module.im.service.groupmember.GroupMemberService;
|
||||||
import cn.iocoder.yudao.module.im.service.inbox.ImInboxService;
|
import cn.iocoder.yudao.module.im.service.inbox.InboxService;
|
||||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -38,20 +38,21 @@ public class MessageServiceImpl implements MessageService {
|
||||||
@Resource
|
@Resource
|
||||||
private MessageMapper messageMapper;
|
private MessageMapper messageMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private ImInboxService imInboxService; // IM收件箱服务
|
private InboxService inboxService;
|
||||||
@Resource
|
@Resource
|
||||||
private AdminUserApi adminUserApi;
|
private AdminUserApi adminUserApi;
|
||||||
@Resource
|
@Resource
|
||||||
private ImGroupMemberService imGroupMemberService;
|
private GroupMemberService groupMemberService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MessageDO> getMessagePage(MessagePageReqVO pageReqVO) {
|
public List<MessageDO> getHistoryMessage(MessagePageReqVO pageReqVO) {
|
||||||
return messageMapper.getMessagePage(pageReqVO);
|
return messageMapper.getHistoryMessage(pageReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MessageDO> getMessageListBySequence(Long userId, Long sequence, Integer size) {
|
public List<MessageDO> getMessageListBySequence(Long userId, Long sequence, Integer size) {
|
||||||
return messageMapper.getGreaterThanSequenceMessage(userId, sequence, size);
|
List<Long> messageIds = inboxService.selectMessageIdsByUserIdAndSequence(userId, sequence, size);
|
||||||
|
return messageMapper.selectBatchIds(messageIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -61,7 +62,7 @@ public class MessageServiceImpl implements MessageService {
|
||||||
SendMessageRespVO sendMessageRespVO = saveMessage(fromUserId, message, inboxSaveMessageReqVO);
|
SendMessageRespVO sendMessageRespVO = saveMessage(fromUserId, message, inboxSaveMessageReqVO);
|
||||||
|
|
||||||
// 保存收件箱 + 发送消息给用户
|
// 保存收件箱 + 发送消息给用户
|
||||||
imInboxService.saveInboxAndSendMessage(inboxSaveMessageReqVO);
|
inboxService.saveInboxAndSendMessage(inboxSaveMessageReqVO);
|
||||||
return sendMessageRespVO;
|
return sendMessageRespVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ public class MessageServiceImpl implements MessageService {
|
||||||
|
|
||||||
} else if (message.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
|
} else if (message.getConversationType().equals(ConversationTypeEnum.GROUP.getType())) {
|
||||||
//校验群聊是否存在;
|
//校验群聊是否存在;
|
||||||
List<GroupMemberDO> groupMemberDOS = imGroupMemberService.selectByGroupId(message.getReceiverId());
|
List<GroupMemberDO> groupMemberDOS = groupMemberService.selectByGroupId(message.getReceiverId());
|
||||||
if (groupMemberDOS.isEmpty()) {
|
if (groupMemberDOS.isEmpty()) {
|
||||||
throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
|
throw exception(MESSAGE_RECEIVER_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!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.inbox.ImInboxMapper">
|
<mapper namespace="cn.iocoder.yudao.module.im.dal.mysql.inbox.InboxMapper">
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
Loading…
Reference in New Issue