消息接口
This commit is contained in:
parent
3b9712b361
commit
e815bc6e05
@ -31,11 +31,11 @@ public class BaseEntity implements Serializable {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String searchValue;
|
private String searchValue;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* 创建部门
|
// * 创建部门
|
||||||
*/
|
// */
|
||||||
@TableField(fill = FieldFill.INSERT)
|
// @TableField(fill = FieldFill.INSERT)
|
||||||
private Long createDept;
|
// private Long createDept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建者
|
* 创建者
|
||||||
|
@ -45,7 +45,7 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
|
|||||||
// 填充创建人、更新人和创建部门信息
|
// 填充创建人、更新人和创建部门信息
|
||||||
baseEntity.setCreateBy(userId);
|
baseEntity.setCreateBy(userId);
|
||||||
baseEntity.setUpdateBy(userId);
|
baseEntity.setUpdateBy(userId);
|
||||||
baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
|
// baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
<artifactId>ruoyi-common-core</artifactId>
|
<artifactId>ruoyi-common-core</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -112,6 +113,23 @@
|
|||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring Boot WebSocket -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jakarta WebSocket API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.websocket</groupId>
|
||||||
|
<artifactId>jakarta.websocket-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jakarta WebSocket Implementation -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -0,0 +1,178 @@
|
|||||||
|
package org.dromara.system.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.service.UserService;
|
||||||
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.core.validate.QueryGroup;
|
||||||
|
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||||
|
import org.dromara.common.log.annotation.Log;
|
||||||
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.common.web.core.BaseController;
|
||||||
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import org.dromara.system.domain.SysUser;
|
||||||
|
import org.dromara.system.domain.bo.SysMessageBo;
|
||||||
|
import org.dromara.system.domain.bo.SysUserBo;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.dromara.system.domain.vo.SysUserVo;
|
||||||
|
import org.dromara.system.service.ISysMessageService;
|
||||||
|
import org.dromara.system.service.ISysUserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息管理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/system/message")
|
||||||
|
public class SysMessageController extends BaseController {
|
||||||
|
|
||||||
|
private final ISysMessageService messageService;
|
||||||
|
private final ISysUserService userService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户ID
|
||||||
|
*/
|
||||||
|
private Long getUserId() {
|
||||||
|
return LoginHelper.getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息列表
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:list")
|
||||||
|
@PostMapping("/list")
|
||||||
|
public R<Page<SysMessageVo>> list(@RequestBody SysMessageBo bo, @RequestBody Page page) {
|
||||||
|
Page<SysMessage> messagePage = messageService.page(page, bo.toWrapper());
|
||||||
|
Page<SysMessageVo> voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
|
||||||
|
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
|
||||||
|
return R.ok(voPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取消息详细信息
|
||||||
|
*
|
||||||
|
* @param id 消息ID
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:query")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public R<SysMessageVo> getInfo(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
||||||
|
return R.ok(messageService.selectMessageById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:send")
|
||||||
|
@Log(title = "消息管理", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping("/send")
|
||||||
|
public R<Void> send(@Validated(AddGroup.class) @RequestBody SysMessageBo bo) {
|
||||||
|
List<SysUserVo> users = userService.selectUserListByDept(null);
|
||||||
|
List<Long> userIds;
|
||||||
|
|
||||||
|
switch (bo.getSendScope()) {
|
||||||
|
case "all":
|
||||||
|
// 全部用户
|
||||||
|
userIds = users.stream().map(SysUserVo::getUserId).toList();
|
||||||
|
break;
|
||||||
|
case "expert":
|
||||||
|
// 达人
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "expert".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
case "merchant":
|
||||||
|
// 商户
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "merchant".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
case "user":
|
||||||
|
// 普通用户
|
||||||
|
userIds = users.stream()
|
||||||
|
.filter(user -> "user".equals(user.getUserType()))
|
||||||
|
.map(SysUserVo::getUserId)
|
||||||
|
.toList();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 其他情况(如指定userIds)
|
||||||
|
userIds = bo.getUserIds();
|
||||||
|
}
|
||||||
|
|
||||||
|
return toAjax(messageService.sendMessageToUsers(bo, userIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记消息为已读
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:mark")
|
||||||
|
@Log(title = "消息管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping("/mark/{id}")
|
||||||
|
public R<Void> markAsRead(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
|
||||||
|
return toAjax(messageService.markAsRead(id, getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除消息
|
||||||
|
*
|
||||||
|
* @param ids 消息ID串
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:remove")
|
||||||
|
@Log(title = "消息管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public R<Void> remove(@NotEmpty(message = "消息ID不能为空") @PathVariable Long[] ids) {
|
||||||
|
return toAjax(messageService.deleteMessageByIds(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取未读消息列表
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:list")
|
||||||
|
@GetMapping("/unread")
|
||||||
|
public TableDataInfo<SysMessageVo> unreadList(PageQuery pageQuery) {
|
||||||
|
return messageService.selectPageUnreadMessages(getUserId(), pageQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取已读消息列表
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:list")
|
||||||
|
@GetMapping("/read")
|
||||||
|
public TableDataInfo<SysMessageVo> readList(PageQuery pageQuery) {
|
||||||
|
return messageService.selectPageReadMessages(getUserId(), pageQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户列表
|
||||||
|
*/
|
||||||
|
// @SaCheckPermission("system:message:list")
|
||||||
|
// @GetMapping("/user/list")
|
||||||
|
// public R<TableDataInfo<SysUserVo>> getUserList() {
|
||||||
|
// PageQuery pageQuery = new PageQuery();
|
||||||
|
// pageQuery.setPageNum(1);
|
||||||
|
// pageQuery.setPageSize(Integer.MAX_VALUE);
|
||||||
|
// TableDataInfo<SysUserVo> users = userService.selectPageUserList(new SysUserBo(), pageQuery);
|
||||||
|
// return R.ok(users);
|
||||||
|
// }
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package org.dromara.system.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||||
|
import org.dromara.common.log.annotation.Log;
|
||||||
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.common.web.core.BaseController;
|
||||||
|
import org.dromara.system.domain.bo.SysMessageTemplateBo;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||||
|
import org.dromara.system.service.ISysMessageTemplateService;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板管理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/message/template")
|
||||||
|
public class SysMessageTemplateController extends BaseController {
|
||||||
|
|
||||||
|
private final ISysMessageTemplateService templateService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息模板列表
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:template:list")
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo<SysMessageTemplateVo> list(SysMessageTemplateBo bo, PageQuery pageQuery) {
|
||||||
|
return templateService.selectTemplatePage(bo, pageQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取消息模板详细信息
|
||||||
|
*
|
||||||
|
* @param id 消息模板ID
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:template:query")
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public R<SysMessageTemplateVo> getInfo(@NotNull(message = "消息模板ID不能为空") @PathVariable Long id) {
|
||||||
|
return R.ok(templateService.selectTemplateById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增消息模板
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:template:add")
|
||||||
|
@Log(title = "消息模板管理", businessType = BusinessType.INSERT)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping()
|
||||||
|
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysMessageTemplateBo bo) {
|
||||||
|
return toAjax(templateService.insertTemplate(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改消息模板
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:template:edit")
|
||||||
|
@Log(title = "消息模板管理", businessType = BusinessType.UPDATE)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PutMapping()
|
||||||
|
public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysMessageTemplateBo bo) {
|
||||||
|
return toAjax(templateService.updateTemplate(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除消息模板
|
||||||
|
*
|
||||||
|
* @param ids 消息模板ID串
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("system:message:template:remove")
|
||||||
|
@Log(title = "消息模板管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{ids}")
|
||||||
|
public R<Void> remove(@NotEmpty(message = "消息模板ID不能为空") @PathVariable Long[] ids) {
|
||||||
|
return toAjax(templateService.deleteTemplateByIds(ids));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package org.dromara.system.converter;
|
||||||
|
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息对象转换器
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface SysMessageConvert {
|
||||||
|
|
||||||
|
SysMessageConvert INSTANCE = Mappers.getMapper(SysMessageConvert.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysMessage转SysMessageVo
|
||||||
|
*/
|
||||||
|
SysMessageVo convert(SysMessage sysMessage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysMessage列表转SysMessageVo列表
|
||||||
|
*/
|
||||||
|
List<SysMessageVo> convertList(List<SysMessage> sysMessageList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysMessageVo转SysMessage
|
||||||
|
*/
|
||||||
|
SysMessage convert(SysMessageVo sysMessageVo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SysMessageVo列表转SysMessage列表
|
||||||
|
*/
|
||||||
|
List<SysMessage> convertListVoToEntity(List<SysMessageVo> sysMessageVoList);
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.dromara.system.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
import org.dromara.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息对象 sys_message
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("sys_message")
|
||||||
|
public class SysMessage extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 主键ID */
|
||||||
|
@TableId(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 消息标题 */
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 消息内容 */
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||||
|
private String msgType;
|
||||||
|
|
||||||
|
/** 触发条件 */
|
||||||
|
private String subType;
|
||||||
|
|
||||||
|
/** 发送者ID */
|
||||||
|
private Long senderId;
|
||||||
|
|
||||||
|
/** 定时发送时间 */
|
||||||
|
private Date scheduledTime;
|
||||||
|
|
||||||
|
// /** 状态(0正常 1停用) */
|
||||||
|
// private String status;
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package org.dromara.system.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
import org.dromara.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板对象 sys_message_template
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("sys_message_template")
|
||||||
|
public class SysMessageTemplate extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板类型(1通知 2公告 3消息)
|
||||||
|
*/
|
||||||
|
private String templateType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板编码
|
||||||
|
*/
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板名称
|
||||||
|
*/
|
||||||
|
private String templateName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板内容
|
||||||
|
*/
|
||||||
|
private String templateContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板参数
|
||||||
|
*/
|
||||||
|
private String templateParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0正常 1停用)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package org.dromara.system.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
import org.dromara.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息用户关联对象 sys_message_user
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("sys_message_user")
|
||||||
|
public class SysMessageUser extends BaseEntity {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息ID
|
||||||
|
*/
|
||||||
|
private Long messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已读(0未读 1已读)
|
||||||
|
*/
|
||||||
|
private Boolean isRead;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阅读时间
|
||||||
|
*/
|
||||||
|
private Date readTime;
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package org.dromara.system.domain.bo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息业务对象
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ExcelIgnoreUnannotated
|
||||||
|
public class SysMessageBo extends BaseEntity {
|
||||||
|
|
||||||
|
/** 主键ID */
|
||||||
|
@ExcelProperty(value = "消息ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 消息标题 */
|
||||||
|
@NotBlank(message = "消息标题不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
@Size(min = 0, max = 100, message = "消息标题长度不能超过100个字符")
|
||||||
|
@ExcelProperty(value = "消息标题")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 消息内容 */
|
||||||
|
@NotBlank(message = "消息内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
@ExcelProperty(value = "消息内容")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||||
|
@NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
@ExcelProperty(value = "消息类型")
|
||||||
|
private String msgType;
|
||||||
|
|
||||||
|
/** 触发条件 */
|
||||||
|
@ExcelProperty(value = "触发条件")
|
||||||
|
private String subType;
|
||||||
|
|
||||||
|
/** 发送者ID */
|
||||||
|
@ExcelProperty(value = "发送者ID")
|
||||||
|
private Long senderId;
|
||||||
|
|
||||||
|
/** 定时发送时间 */
|
||||||
|
@ExcelProperty(value = "定时发送时间")
|
||||||
|
private Date scheduledTime;
|
||||||
|
|
||||||
|
// /** 状态(0正常 1停用) */
|
||||||
|
// @ExcelProperty(value = "状态")
|
||||||
|
// private String status;
|
||||||
|
|
||||||
|
/** 发送范围(all:全部用户, userType:按用户类型, userIds:指定用户) */
|
||||||
|
private String sendScope;
|
||||||
|
|
||||||
|
/** 接收用户ID列表 */
|
||||||
|
private List<Long> userIds;
|
||||||
|
|
||||||
|
// /** 用户类型(1普通用户 2商家 3达人 4代理) */
|
||||||
|
// private String userType;
|
||||||
|
|
||||||
|
/** 是否发送给所有用户 */
|
||||||
|
private Boolean sendToAll;
|
||||||
|
|
||||||
|
public SysMessage toEntity() {
|
||||||
|
SysMessage entity = new SysMessage();
|
||||||
|
entity.setId(this.getId());
|
||||||
|
entity.setTitle(this.getTitle());
|
||||||
|
entity.setContent(this.getContent());
|
||||||
|
entity.setMsgType(this.getMsgType());
|
||||||
|
entity.setSubType(this.getSubType());
|
||||||
|
entity.setSenderId(this.getSenderId());
|
||||||
|
entity.setScheduledTime(this.getScheduledTime());
|
||||||
|
// entity.setStatus(this.getStatus());
|
||||||
|
entity.setCreateBy(this.getCreateBy());
|
||||||
|
entity.setCreateTime(this.getCreateTime());
|
||||||
|
entity.setUpdateBy(this.getUpdateBy());
|
||||||
|
entity.setUpdateTime(this.getUpdateTime());
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为查询条件
|
||||||
|
*/
|
||||||
|
public LambdaQueryWrapper<SysMessage> toWrapper() {
|
||||||
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.like(StringUtils.isNotBlank(this.getTitle()), SysMessage::getTitle, this.getTitle())
|
||||||
|
.eq(StringUtils.isNotBlank(this.getMsgType()), SysMessage::getMsgType, this.getMsgType())
|
||||||
|
.orderByDesc(SysMessage::getCreateTime);
|
||||||
|
return lqw;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package org.dromara.system.domain.bo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
|
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||||
|
import org.dromara.system.domain.SysMessageTemplate;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板业务对象 sys_message_template
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SysMessageTemplateBo extends BaseEntity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
@NotNull(message = "模板ID不能为空", groups = { EditGroup.class })
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板类型(1通知 2公告 3消息)
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
private String templateType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板编码
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
@Size(min = 0, max = 64, message = "模板编码长度不能超过64个字符")
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板名称
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
@Size(min = 0, max = 100, message = "模板名称长度不能超过100个字符")
|
||||||
|
private String templateName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板内容
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模板内容不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
private String templateContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板参数
|
||||||
|
*/
|
||||||
|
private String templateParams;
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 状态(0正常 1停用)
|
||||||
|
// */
|
||||||
|
// @NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||||
|
// private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为实体对象
|
||||||
|
*/
|
||||||
|
public SysMessageTemplate toEntity() {
|
||||||
|
SysMessageTemplate entity = new SysMessageTemplate();
|
||||||
|
entity.setId(this.getId());
|
||||||
|
entity.setTemplateType(this.getTemplateType());
|
||||||
|
entity.setTemplateCode(this.getTemplateCode());
|
||||||
|
entity.setTemplateName(this.getTemplateName());
|
||||||
|
entity.setTemplateContent(this.getTemplateContent());
|
||||||
|
entity.setTemplateParams(this.getTemplateParams());
|
||||||
|
// entity.setStatus(this.getStatus());
|
||||||
|
entity.setRemark(this.getRemark());
|
||||||
|
entity.setCreateBy(this.getCreateBy());
|
||||||
|
entity.setCreateTime(this.getCreateTime());
|
||||||
|
entity.setUpdateBy(this.getUpdateBy());
|
||||||
|
entity.setUpdateTime(this.getUpdateTime());
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.dromara.system.domain.event;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.springframework.context.ApplicationEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息事件
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class MessageEvent extends ApplicationEvent {
|
||||||
|
|
||||||
|
private final SysMessageVo message;
|
||||||
|
private final Long userId;
|
||||||
|
|
||||||
|
public MessageEvent(Object source, SysMessageVo message, Long userId) {
|
||||||
|
super(source);
|
||||||
|
this.message = message;
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.dromara.system.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板视图对象 sys_message_template
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
//@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SysMessageTemplateVo implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板类型(1通知 2公告 3消息)
|
||||||
|
*/
|
||||||
|
private String templateType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板编码
|
||||||
|
*/
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板名称
|
||||||
|
*/
|
||||||
|
private String templateName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板内容
|
||||||
|
*/
|
||||||
|
private String templateContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模板参数
|
||||||
|
*/
|
||||||
|
private String templateParams;
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 状态(0正常 1停用)
|
||||||
|
// */
|
||||||
|
// private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package org.dromara.system.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.dromara.common.tenant.core.TenantEntity;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息用户关联视图对象 sys_message_user
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
//@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class SysMessageUserVo implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息ID
|
||||||
|
*/
|
||||||
|
private Long messageId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已读(0未读 1已读)
|
||||||
|
*/
|
||||||
|
private Boolean isRead;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阅读时间
|
||||||
|
*/
|
||||||
|
private Date readTime;
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package org.dromara.system.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import io.github.linpeilie.annotations.AutoMapper;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import org.dromara.system.domain.SysNotice;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息视图对象
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AutoMapper(target = SysMessage.class)
|
||||||
|
public class SysMessageVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 主键ID */
|
||||||
|
@ExcelProperty(value = "消息ID")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 消息标题 */
|
||||||
|
@ExcelProperty(value = "消息标题")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/** 消息内容 */
|
||||||
|
@ExcelProperty(value = "消息内容")
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/** 消息类型(AUTO自动/MANUAL手动) */
|
||||||
|
@ExcelProperty(value = "消息类型")
|
||||||
|
private String msgType;
|
||||||
|
|
||||||
|
/** 触发条件 */
|
||||||
|
@ExcelProperty(value = "触发条件")
|
||||||
|
private String subType;
|
||||||
|
|
||||||
|
/** 发送者ID */
|
||||||
|
@ExcelProperty(value = "发送者ID")
|
||||||
|
private Long senderId;
|
||||||
|
|
||||||
|
/** 发送者名称 */
|
||||||
|
@ExcelProperty(value = "发送者")
|
||||||
|
private String senderName;
|
||||||
|
|
||||||
|
/** 定时发送时间 */
|
||||||
|
@ExcelProperty(value = "定时发送时间")
|
||||||
|
private Date scheduledTime;
|
||||||
|
|
||||||
|
// /** 状态(0正常 1停用) */
|
||||||
|
// @ExcelProperty(value = "状态")
|
||||||
|
// private String status;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
@ExcelProperty(value = "创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.dromara.system.event;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.system.domain.event.MessageEvent;
|
||||||
|
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息事件监听器
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MessageEventListener {
|
||||||
|
|
||||||
|
private final MessageWebSocketServer messageWebSocketServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理消息事件
|
||||||
|
*/
|
||||||
|
@Async
|
||||||
|
@EventListener
|
||||||
|
public void handleMessageEvent(MessageEvent event) {
|
||||||
|
try {
|
||||||
|
messageWebSocketServer.sendMessage(event.getUserId(), String.valueOf(event.getMessage()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理消息事件失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.dromara.system.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息Mapper接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface SysMessageMapper extends BaseMapper<SysMessage> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户未读消息分页列表
|
||||||
|
*
|
||||||
|
* @param page 分页参数
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 消息分页列表
|
||||||
|
*/
|
||||||
|
Page<SysMessageVo> selectPageUnreadMessages(Page<SysMessageVo> page, Long userId);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.dromara.system.mapper;
|
||||||
|
|
||||||
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
|
import org.dromara.system.domain.SysMessageTemplate;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板Mapper接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface SysMessageTemplateMapper extends BaseMapperPlus<SysMessageTemplate, SysMessageTemplateVo> {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.dromara.system.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
|
import org.dromara.system.domain.SysMessageUser;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageUserVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息用户关联Mapper接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface SysMessageUserMapper extends BaseMapperPlus<SysMessageUser, SysMessageUserVo> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新消息读取状态
|
||||||
|
*
|
||||||
|
* @param messageId 消息ID
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param isRead 是否已读
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
default int updateReadStatus(Long messageId, Long userId, boolean isRead) {
|
||||||
|
LambdaQueryWrapper<SysMessageUser> lqw = Wrappers.lambdaQuery();
|
||||||
|
lqw.eq(SysMessageUser::getMessageId, messageId)
|
||||||
|
.eq(SysMessageUser::getUserId, userId);
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setIsRead(isRead);
|
||||||
|
return update(messageUser, lqw);
|
||||||
|
}
|
||||||
|
}
|
@ -120,4 +120,19 @@ public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
|
|||||||
})
|
})
|
||||||
int updateById(@Param(Constants.ENTITY) SysUser user);
|
int updateById(@Param(Constants.ENTITY) SysUser user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户类型查询用户ID列表
|
||||||
|
*
|
||||||
|
* @param userType 用户类型
|
||||||
|
* @return 用户ID列表
|
||||||
|
*/
|
||||||
|
List<Long> selectUserIdsByType(@Param("userType") String userType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有用户ID
|
||||||
|
*
|
||||||
|
* @return 用户ID列表
|
||||||
|
*/
|
||||||
|
List<Long> selectAllUserIds();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package org.dromara.system.service;
|
||||||
|
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket消息服务接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface IMessageWebSocketService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息给指定用户
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
void sendMessage(Long userId, SysMessageVo message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 广播消息给所有在线用户
|
||||||
|
*
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
void broadcastMessage(SysMessageVo message);
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
package org.dromara.system.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import org.dromara.system.domain.bo.SysMessageBo;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息Service接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface ISysMessageService extends IService<SysMessage> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询消息列表
|
||||||
|
*/
|
||||||
|
TableDataInfo<SysMessageVo> selectPageMessageList(SysMessageBo bo, PageQuery pageQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息给指定用户
|
||||||
|
*
|
||||||
|
* @param message 消息内容
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int sendMessageToUser(SysMessageBo message, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息给多个用户
|
||||||
|
*
|
||||||
|
* @param message 消息内容
|
||||||
|
* @param userIds 用户ID列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int sendMessageToUsers(SysMessageBo message, List<Long> userIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送自动消息
|
||||||
|
*
|
||||||
|
* @param message 消息信息
|
||||||
|
* @param userIds 用户ID列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int sendAutoMessage(SysMessageBo message, List<Long> userIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记消息为已读
|
||||||
|
*
|
||||||
|
* @param messageId 消息ID
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int markAsRead(Long messageId, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户未读消息分页列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param pageQuery 分页参数
|
||||||
|
* @return 消息分页列表
|
||||||
|
*/
|
||||||
|
TableDataInfo<SysMessageVo> selectPageUnreadMessages(Long userId, PageQuery pageQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户已读消息分页列表
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param pageQuery 分页参数
|
||||||
|
* @return 消息分页列表
|
||||||
|
*/
|
||||||
|
TableDataInfo<SysMessageVo> selectPageReadMessages(Long userId, PageQuery pageQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息列表
|
||||||
|
*
|
||||||
|
* @param message 消息信息
|
||||||
|
* @return 消息列表
|
||||||
|
*/
|
||||||
|
List<SysMessageVo> selectMessageList(SysMessageBo message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息详细信息
|
||||||
|
*
|
||||||
|
* @param id 消息ID
|
||||||
|
* @return 消息信息
|
||||||
|
*/
|
||||||
|
SysMessageVo selectMessageById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增消息
|
||||||
|
*
|
||||||
|
* @param message 消息信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertMessage(SysMessageBo message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改消息
|
||||||
|
*
|
||||||
|
* @param message 消息信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateMessage(SysMessageBo message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除消息
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的消息ID数组
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteMessageByIds(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除消息信息
|
||||||
|
*
|
||||||
|
* @param id 消息ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteMessageById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将BO对象转换为查询条件
|
||||||
|
*
|
||||||
|
* @param bo 业务对象
|
||||||
|
* @return 查询条件
|
||||||
|
*/
|
||||||
|
LambdaQueryWrapper<SysMessage> toWrapper(SysMessageBo bo);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package org.dromara.system.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.system.domain.SysMessageTemplate;
|
||||||
|
import org.dromara.system.domain.bo.SysMessageTemplateBo;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板Service接口
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public interface ISysMessageTemplateService extends IService<SysMessageTemplate> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息模板列表
|
||||||
|
*
|
||||||
|
* @param template 消息模板信息
|
||||||
|
* @return 消息模板列表
|
||||||
|
*/
|
||||||
|
List<SysMessageTemplateVo> selectTemplateList(SysMessageTemplateBo template);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息模板分页列表
|
||||||
|
*
|
||||||
|
* @param template 消息模板信息
|
||||||
|
* @param pageQuery 分页参数
|
||||||
|
* @return 消息模板分页列表
|
||||||
|
*/
|
||||||
|
TableDataInfo<SysMessageTemplateVo> selectTemplatePage(SysMessageTemplateBo template, PageQuery pageQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询消息模板详细信息
|
||||||
|
*
|
||||||
|
* @param id 消息模板ID
|
||||||
|
* @return 消息模板信息
|
||||||
|
*/
|
||||||
|
SysMessageTemplateVo selectTemplateById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增消息模板
|
||||||
|
*
|
||||||
|
* @param template 消息模板信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int insertTemplate(SysMessageTemplateBo template);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改消息模板
|
||||||
|
*
|
||||||
|
* @param template 消息模板信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateTemplate(SysMessageTemplateBo template);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除消息模板
|
||||||
|
*
|
||||||
|
* @param ids 需要删除的消息模板ID数组
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteTemplateByIds(Long[] ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除消息模板信息
|
||||||
|
*
|
||||||
|
* @param id 消息模板ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int deleteTemplateById(Long id);
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.dromara.system.service.IMessageWebSocketService;
|
||||||
|
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket消息服务实现类
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MessageWebSocketServiceImpl implements IMessageWebSocketService {
|
||||||
|
|
||||||
|
private final MessageWebSocketServer messageWebSocketServer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Long userId, SysMessageVo message) {
|
||||||
|
messageWebSocketServer.sendMessage(userId, String.valueOf(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void broadcastMessage(SysMessageVo message) {
|
||||||
|
messageWebSocketServer.broadcastMessage(String.valueOf(message));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,182 @@
|
|||||||
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
import org.dromara.system.domain.SysMessageUser;
|
||||||
|
import org.dromara.system.domain.bo.SysMessageBo;
|
||||||
|
import org.dromara.system.domain.event.MessageEvent;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.dromara.system.mapper.SysMessageMapper;
|
||||||
|
import org.dromara.system.mapper.SysMessageUserMapper;
|
||||||
|
import org.dromara.system.service.ISysMessageService;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息Service业务层处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMessage> implements ISysMessageService {
|
||||||
|
|
||||||
|
private final SysMessageMapper messageMapper;
|
||||||
|
private final SysMessageUserMapper messageUserMapper;
|
||||||
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<SysMessageVo> selectPageMessageList(SysMessageBo bo, PageQuery pageQuery) {
|
||||||
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.like(StringUtils.isNotBlank(bo.getTitle()), SysMessage::getTitle, bo.getTitle())
|
||||||
|
.eq(StringUtils.isNotBlank(bo.getMsgType()), SysMessage::getMsgType, bo.getMsgType())
|
||||||
|
// .eq(StringUtils.isNotBlank(bo.getStatus()), SysMessage::getStatus, bo.getStatus())
|
||||||
|
.orderByDesc(SysMessage::getCreateTime);
|
||||||
|
Page<SysMessage> page = messageMapper.selectPage(pageQuery.build(), lqw);
|
||||||
|
List<SysMessageVo> records = MapstructUtils.convert(page.getRecords(), SysMessageVo.class);
|
||||||
|
Page<SysMessageVo> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||||
|
voPage.setRecords(records);
|
||||||
|
return TableDataInfo.build(voPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int sendMessageToUser(SysMessageBo message, Long userId) {
|
||||||
|
// 保存消息
|
||||||
|
SysMessage entity = message.toEntity();
|
||||||
|
messageMapper.insert(entity);
|
||||||
|
// 创建消息用户关联
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setMessageId(entity.getId());
|
||||||
|
messageUser.setUserId(userId);
|
||||||
|
messageUser.setIsRead(false);
|
||||||
|
int rows = messageUserMapper.insert(messageUser);
|
||||||
|
// 发送WebSocket消息
|
||||||
|
if (rows > 0) {
|
||||||
|
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||||
|
eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int sendMessageToUsers(SysMessageBo message, List<Long> userIds) {
|
||||||
|
// 保存消息
|
||||||
|
SysMessage entity = message.toEntity();
|
||||||
|
messageMapper.insert(entity);
|
||||||
|
// 批量创建消息用户关联
|
||||||
|
int count = 0;
|
||||||
|
for (Long userId : userIds) {
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setMessageId(entity.getId());
|
||||||
|
messageUser.setUserId(userId);
|
||||||
|
messageUser.setIsRead(false);
|
||||||
|
int rows = messageUserMapper.insert(messageUser);
|
||||||
|
if (rows > 0) {
|
||||||
|
count++;
|
||||||
|
// 发送WebSocket消息
|
||||||
|
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||||
|
eventPublisher.publishEvent(new MessageEvent(this, messageVo, userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int sendAutoMessage(SysMessageBo message, List<Long> userIds) {
|
||||||
|
message.setMsgType("AUTO");
|
||||||
|
return sendMessageToUsers(message, userIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int markAsRead(Long messageId, Long userId) {
|
||||||
|
LambdaQueryWrapper<SysMessageUser> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.eq(SysMessageUser::getMessageId, messageId)
|
||||||
|
.eq(SysMessageUser::getUserId, userId);
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setIsRead(true);
|
||||||
|
return messageUserMapper.update(messageUser, lqw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<SysMessageVo> selectPageUnreadMessages(Long userId, PageQuery pageQuery) {
|
||||||
|
Page<SysMessageVo> page = messageMapper.selectPageUnreadMessages(pageQuery.build(), userId);
|
||||||
|
return TableDataInfo.build(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<SysMessageVo> selectPageReadMessages(Long userId, PageQuery pageQuery) {
|
||||||
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
|
// lqw.eq(SysMessage::getStatus, "0")
|
||||||
|
// .inSql(SysMessage::getId,
|
||||||
|
// "SELECT message_id FROM sys_message_user WHERE user_id = " + userId + " AND is_read = 1")
|
||||||
|
// .orderByDesc(SysMessage::getCreateTime);
|
||||||
|
//
|
||||||
|
Page<SysMessage> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||||
|
Page<SysMessage> resultPage = messageMapper.selectPage(page, lqw);
|
||||||
|
List<SysMessageVo> records = MapstructUtils.convert(resultPage.getRecords(), SysMessageVo.class);
|
||||||
|
Page<SysMessageVo> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
|
||||||
|
voPage.setRecords(records);
|
||||||
|
return TableDataInfo.build(voPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysMessageVo> selectMessageList(SysMessageBo message) {
|
||||||
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.eq(StringUtils.isNotBlank(message.getMsgType()), SysMessage::getMsgType, message.getMsgType())
|
||||||
|
.eq(StringUtils.isNotBlank(message.getSubType()), SysMessage::getSubType, message.getSubType())
|
||||||
|
.eq(message.getSenderId() != null, SysMessage::getSenderId, message.getSenderId())
|
||||||
|
// .eq(StringUtils.isNotBlank(message.getStatus()), SysMessage::getStatus, message.getStatus())
|
||||||
|
.orderByDesc(SysMessage::getCreateTime);
|
||||||
|
return MapstructUtils.convert(messageMapper.selectList(lqw), SysMessageVo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SysMessageVo selectMessageById(Long id) {
|
||||||
|
return MapstructUtils.convert(messageMapper.selectById(id), SysMessageVo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertMessage(SysMessageBo message) {
|
||||||
|
return messageMapper.insert(message.toEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateMessage(SysMessageBo message) {
|
||||||
|
return messageMapper.updateById(message.toEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteMessageByIds(Long[] ids) {
|
||||||
|
return messageMapper.deleteBatchIds(List.of(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteMessageById(Long id) {
|
||||||
|
return messageMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LambdaQueryWrapper<SysMessage> toWrapper(SysMessageBo bo) {
|
||||||
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.like(StringUtils.isNotBlank(bo.getTitle()), SysMessage::getTitle, bo.getTitle())
|
||||||
|
.eq(StringUtils.isNotBlank(bo.getMsgType()), SysMessage::getMsgType, bo.getMsgType())
|
||||||
|
.orderByDesc(SysMessage::getCreateTime);
|
||||||
|
return lqw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
import org.dromara.system.domain.SysMessageTemplate;
|
||||||
|
import org.dromara.system.domain.bo.SysMessageTemplateBo;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageTemplateVo;
|
||||||
|
import org.dromara.system.mapper.SysMessageTemplateMapper;
|
||||||
|
import org.dromara.system.service.ISysMessageTemplateService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息模板Service业务层处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class SysMessageTemplateServiceImpl extends ServiceImpl<SysMessageTemplateMapper, SysMessageTemplate> implements ISysMessageTemplateService {
|
||||||
|
|
||||||
|
private final SysMessageTemplateMapper templateMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<SysMessageTemplateVo> selectTemplatePage(SysMessageTemplateBo bo, PageQuery pageQuery) {
|
||||||
|
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
||||||
|
.eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
||||||
|
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
||||||
|
.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
||||||
|
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||||
|
|
||||||
|
Page<SysMessageTemplate> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||||
|
Page<SysMessageTemplate> resultPage = templateMapper.selectPage(page, lqw);
|
||||||
|
List<SysMessageTemplateVo> records = MapstructUtils.convert(resultPage.getRecords(), SysMessageTemplateVo.class);
|
||||||
|
Page<SysMessageTemplateVo> voPage = new Page<>(resultPage.getCurrent(), resultPage.getSize(), resultPage.getTotal());
|
||||||
|
voPage.setRecords(records);
|
||||||
|
return TableDataInfo.build(voPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysMessageTemplateVo> selectTemplateList(SysMessageTemplateBo bo) {
|
||||||
|
LambdaQueryWrapper<SysMessageTemplate> lqw = new LambdaQueryWrapper<>();
|
||||||
|
lqw.eq(StringUtils.isNotBlank(bo.getTemplateType()), SysMessageTemplate::getTemplateType, bo.getTemplateType())
|
||||||
|
.eq(StringUtils.isNotBlank(bo.getStatus()), SysMessageTemplate::getStatus, bo.getStatus())
|
||||||
|
.like(StringUtils.isNotBlank(bo.getTemplateName()), SysMessageTemplate::getTemplateName, bo.getTemplateName())
|
||||||
|
.like(StringUtils.isNotBlank(bo.getTemplateCode()), SysMessageTemplate::getTemplateCode, bo.getTemplateCode())
|
||||||
|
.orderByDesc(SysMessageTemplate::getCreateTime);
|
||||||
|
return MapstructUtils.convert(templateMapper.selectList(lqw), SysMessageTemplateVo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SysMessageTemplateVo selectTemplateById(Long id) {
|
||||||
|
return MapstructUtils.convert(templateMapper.selectById(id), SysMessageTemplateVo.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int insertTemplate(SysMessageTemplateBo bo) {
|
||||||
|
return templateMapper.insert(bo.toEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateTemplate(SysMessageTemplateBo bo) {
|
||||||
|
return templateMapper.updateById(bo.toEntity());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteTemplateByIds(Long[] ids) {
|
||||||
|
return templateMapper.deleteBatchIds(List.of(ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteTemplateById(Long id) {
|
||||||
|
return templateMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
@ -179,7 +179,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
for (SysDictType dictType : dictTypeList) {
|
for (SysDictType dictType : dictTypeList) {
|
||||||
dictType.setDictId(null);
|
dictType.setDictId(null);
|
||||||
dictType.setTenantId(tenantId);
|
dictType.setTenantId(tenantId);
|
||||||
dictType.setCreateDept(null);
|
// dictType.setCreateDept(null);
|
||||||
dictType.setCreateBy(null);
|
dictType.setCreateBy(null);
|
||||||
dictType.setCreateTime(null);
|
dictType.setCreateTime(null);
|
||||||
dictType.setUpdateBy(null);
|
dictType.setUpdateBy(null);
|
||||||
@ -188,7 +188,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
for (SysDictData dictData : dictDataList) {
|
for (SysDictData dictData : dictDataList) {
|
||||||
dictData.setDictCode(null);
|
dictData.setDictCode(null);
|
||||||
dictData.setTenantId(tenantId);
|
dictData.setTenantId(tenantId);
|
||||||
dictData.setCreateDept(null);
|
// dictData.setCreateDept(null);
|
||||||
dictData.setCreateBy(null);
|
dictData.setCreateBy(null);
|
||||||
dictData.setCreateTime(null);
|
dictData.setCreateTime(null);
|
||||||
dictData.setUpdateBy(null);
|
dictData.setUpdateBy(null);
|
||||||
@ -202,7 +202,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
for (SysConfig config : sysConfigList) {
|
for (SysConfig config : sysConfigList) {
|
||||||
config.setConfigId(null);
|
config.setConfigId(null);
|
||||||
config.setTenantId(tenantId);
|
config.setTenantId(tenantId);
|
||||||
config.setCreateDept(null);
|
// config.setCreateDept(null);
|
||||||
config.setCreateBy(null);
|
config.setCreateBy(null);
|
||||||
config.setCreateTime(null);
|
config.setCreateTime(null);
|
||||||
config.setUpdateBy(null);
|
config.setUpdateBy(null);
|
||||||
@ -448,7 +448,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
data.setTenantId(tenantId);
|
data.setTenantId(tenantId);
|
||||||
data.setCreateTime(null);
|
data.setCreateTime(null);
|
||||||
data.setUpdateTime(null);
|
data.setUpdateTime(null);
|
||||||
data.setCreateDept(null);
|
// data.setCreateDept(null);
|
||||||
data.setCreateBy(null);
|
data.setCreateBy(null);
|
||||||
data.setUpdateBy(null);
|
data.setUpdateBy(null);
|
||||||
set.add(tenantId);
|
set.add(tenantId);
|
||||||
@ -472,7 +472,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
data.setTenantId(tenantId);
|
data.setTenantId(tenantId);
|
||||||
data.setCreateTime(null);
|
data.setCreateTime(null);
|
||||||
data.setUpdateTime(null);
|
data.setUpdateTime(null);
|
||||||
data.setCreateDept(null);
|
// data.setCreateDept(null);
|
||||||
data.setCreateBy(null);
|
data.setCreateBy(null);
|
||||||
data.setUpdateBy(null);
|
data.setUpdateBy(null);
|
||||||
set.add(tenantId);
|
set.add(tenantId);
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package org.dromara.system.task;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
|
import org.dromara.system.domain.SysMessage;
|
||||||
|
//import org.dromara.system.domain.SysMessageUser;
|
||||||
|
import org.dromara.system.domain.SysMessageUser;
|
||||||
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
|
import org.dromara.system.mapper.SysMessageMapper;
|
||||||
|
//import org.dromara.system.mapper.SysMessageUserMapper
|
||||||
|
import org.dromara.system.mapper.SysMessageUserMapper;
|
||||||
|
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息定时任务
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MessageScheduledTask {
|
||||||
|
|
||||||
|
private final SysMessageMapper messageMapper;
|
||||||
|
private final SysMessageUserMapper messageUserMapper;
|
||||||
|
private final MessageWebSocketServer messageWebSocketServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每分钟执行一次,处理待发送的消息
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 */1 * * * ?")
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void processScheduledMessages() {
|
||||||
|
log.info("开始处理定时消息...");
|
||||||
|
try {
|
||||||
|
// 查询待发送的消息
|
||||||
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
|
// lqw.eq(SysMessage::getStatus, "0")
|
||||||
|
// .le(SysMessage::getScheduledTime, LocalDateTime.now())
|
||||||
|
// .isNotNull(SysMessage::getScheduledTime);
|
||||||
|
|
||||||
|
List<SysMessage> messages = messageMapper.selectList(lqw);
|
||||||
|
|
||||||
|
for (SysMessage message : messages) {
|
||||||
|
// 查询消息接收者
|
||||||
|
LambdaQueryWrapper<SysMessageUser> userLqw = new LambdaQueryWrapper<>();
|
||||||
|
userLqw.eq(SysMessageUser::getMessageId, message.getId());
|
||||||
|
List<SysMessageUser> messageUsers = messageUserMapper.selectList(userLqw);
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
SysMessageVo messageVo = MapstructUtils.convert(message, SysMessageVo.class);
|
||||||
|
for (SysMessageUser messageUser : messageUsers) {
|
||||||
|
try {
|
||||||
|
messageWebSocketServer.sendMessage(messageUser.getUserId(), String.valueOf(messageVo));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送消息失败,消息ID:{},用户ID:{}", message.getId(), messageUser.getUserId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新消息状态为已发送
|
||||||
|
// message.setStatus("1");
|
||||||
|
messageMapper.updateById(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("定时消息处理完成,共处理{}条消息", messages.size());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("处理定时消息时发生错误", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package org.dromara.system.websocket;
|
||||||
|
|
||||||
|
import jakarta.websocket.*;
|
||||||
|
import jakarta.websocket.server.ServerEndpoint;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
|
import org.dromara.common.websocket.holder.WebSocketSessionHolder;
|
||||||
|
import org.dromara.common.websocket.utils.WebSocketUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 站内信 WebSocket 服务
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@ServerEndpoint("/websocket/message")
|
||||||
|
public class MessageWebSocketServer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID和会话的映射关系
|
||||||
|
*/
|
||||||
|
private static final Map<Long, Session> SESSION_MAP = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接建立成功调用的方法
|
||||||
|
*/
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session) {
|
||||||
|
log.info("[WebSocket] 新的连接建立,sessionId: {}", session.getId());
|
||||||
|
try {
|
||||||
|
// 获取当前登录用户
|
||||||
|
LoginUser loginUser = (LoginUser) session.getUserProperties().get("loginUser");
|
||||||
|
if (loginUser != null) {
|
||||||
|
SESSION_MAP.put(loginUser.getUserId(), session);
|
||||||
|
log.info("[WebSocket] 用户 {} 连接成功", loginUser.getUserId());
|
||||||
|
} else {
|
||||||
|
log.warn("[WebSocket] 未获取到用户信息,关闭连接");
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[WebSocket] 连接建立失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连接关闭调用的方法
|
||||||
|
*/
|
||||||
|
@OnClose
|
||||||
|
public void onClose(Session session) {
|
||||||
|
log.info("[WebSocket] 连接关闭,sessionId: {}", session.getId());
|
||||||
|
// 从映射中移除会话
|
||||||
|
SESSION_MAP.values().removeIf(s -> s.getId().equals(session.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收到客户端消息后调用的方法
|
||||||
|
*/
|
||||||
|
@OnMessage
|
||||||
|
public void onMessage(String message, Session session) {
|
||||||
|
log.info("[WebSocket] 收到消息: {}", message);
|
||||||
|
// 这里可以处理客户端发送的消息
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发生错误时调用
|
||||||
|
*/
|
||||||
|
@OnError
|
||||||
|
public void onError(Session session, Throwable error) {
|
||||||
|
log.error("[WebSocket] 发生错误", error);
|
||||||
|
// 从映射中移除会话
|
||||||
|
SESSION_MAP.values().removeIf(s -> s.getId().equals(session.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息给指定用户
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
public void sendMessage(Long userId, String message) {
|
||||||
|
Session session = SESSION_MAP.get(userId);
|
||||||
|
if (session != null && session.isOpen()) {
|
||||||
|
try {
|
||||||
|
session.getBasicRemote().sendText(message);
|
||||||
|
log.info("[WebSocket] 消息发送成功,接收者: {}", userId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("[WebSocket] 消息发送失败", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("[WebSocket] 用户 {} 不在线或会话已关闭", userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 广播消息给所有在线用户
|
||||||
|
*
|
||||||
|
* @param message 消息内容
|
||||||
|
*/
|
||||||
|
public void broadcastMessage(String message) {
|
||||||
|
SESSION_MAP.forEach((userId, session) -> {
|
||||||
|
if (session.isOpen()) {
|
||||||
|
try {
|
||||||
|
session.getBasicRemote().sendText(message);
|
||||||
|
log.info("[WebSocket] 广播消息发送成功,接收者: {}", userId);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("[WebSocket] 广播消息发送失败,接收者: {}", userId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
java包使用 `.` 分割 resource 目录使用 `/` 分割
|
|
||||||
<br>
|
|
||||||
此文件目的 防止文件夹粘连找不到 `xml` 文件
|
|
@ -0,0 +1,32 @@
|
|||||||
|
<?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">
|
||||||
|
<mapper namespace="org.dromara.system.mapper.SysMessageMapper">
|
||||||
|
|
||||||
|
<resultMap type="org.dromara.system.domain.vo.SysMessageVo" id="SysMessageResult">
|
||||||
|
<id property="id" column="id" />
|
||||||
|
<result property="title" column="title" />
|
||||||
|
<result property="content" column="content" />
|
||||||
|
<result property="msgType" column="msg_type" />
|
||||||
|
<result property="subType" column="sub_type" />
|
||||||
|
<result property="senderId" column="sender_id" />
|
||||||
|
<result property="scheduledTime" column="scheduled_time"/>
|
||||||
|
<result property="status" column="status" />
|
||||||
|
<result property="createBy" column="create_by" />
|
||||||
|
<result property="createTime" column="create_time" />
|
||||||
|
<result property="updateBy" column="update_by" />
|
||||||
|
<result property="updateTime" column="update_time" />
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="selectPageUnreadMessages" resultMap="SysMessageResult">
|
||||||
|
SELECT m.*
|
||||||
|
FROM sys_message m
|
||||||
|
INNER JOIN sys_message_user mu ON m.id = mu.message_id
|
||||||
|
WHERE mu.user_id = #{userId}
|
||||||
|
AND mu.is_read = 0
|
||||||
|
AND m.status = '0'
|
||||||
|
ORDER BY m.create_time DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
@ -0,0 +1,33 @@
|
|||||||
|
<?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">
|
||||||
|
<mapper namespace="org.dromara.system.mapper.SysMessageUserMapper">
|
||||||
|
|
||||||
|
<resultMap type="org.dromara.system.domain.vo.SysMessageUserVo" id="SysMessageUserResult">
|
||||||
|
<id property="id" column="id" />
|
||||||
|
<result property="messageId" column="message_id" />
|
||||||
|
<result property="userId" column="user_id" />
|
||||||
|
<result property="isRead" column="is_read" />
|
||||||
|
<result property="readTime" column="read_time" />
|
||||||
|
<!-- <result property="createBy" column="create_by" />-->
|
||||||
|
<!-- <result property="createTime" column="create_time" />-->
|
||||||
|
<!-- <result property="updateBy" column="update_by" />-->
|
||||||
|
<!-- <result property="updateTime" column="update_time" />-->
|
||||||
|
<!-- <result property="tenantId" column="tenant_id" />-->
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<sql id="selectSysMessageUserVo">
|
||||||
|
select id, message_id, user_id, is_read, read_time, create_time, update_time
|
||||||
|
from sys_message_user
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<update id="updateReadStatus">
|
||||||
|
update sys_message_user
|
||||||
|
set is_read = #{isRead},
|
||||||
|
read_time = sysdate()
|
||||||
|
where message_id = #{messageId}
|
||||||
|
and user_id = #{userId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
@ -69,5 +69,19 @@
|
|||||||
select count(*) from sys_user where del_flag = '0' and user_id = #{userId}
|
select count(*) from sys_user where del_flag = '0' and user_id = #{userId}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectUserIdsByType" resultType="java.lang.Long">
|
||||||
|
select user_id
|
||||||
|
from sys_user
|
||||||
|
where user_type = #{userType}
|
||||||
|
and del_flag = '0'
|
||||||
|
and status = '0'
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectAllUserIds" resultType="java.lang.Long">
|
||||||
|
select user_id
|
||||||
|
from sys_user
|
||||||
|
where del_flag = '0'
|
||||||
|
and status = '0'
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
@ -220,7 +220,7 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
|
|||||||
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
|
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
|
||||||
flowCategory.setCategoryId(null);
|
flowCategory.setCategoryId(null);
|
||||||
flowCategory.setTenantId(tenantId);
|
flowCategory.setTenantId(tenantId);
|
||||||
flowCategory.setCreateDept(null);
|
// flowCategory.setCreateDept(null);
|
||||||
flowCategory.setCreateBy(null);
|
flowCategory.setCreateBy(null);
|
||||||
flowCategory.setCreateTime(null);
|
flowCategory.setCreateTime(null);
|
||||||
flowCategory.setUpdateBy(null);
|
flowCategory.setUpdateBy(null);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user