diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index f2e3a6360..7484e7f3d 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -11,6 +11,13 @@ spring.boot.admin.client:
username: @monitor.username@
password: @monitor.password@
+--- # 禁用RabbitMQ自动配置
+spring:
+ rabbitmq:
+ enabled: false
+ autoconfigure:
+ exclude: org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
+
--- # snail-job 配置
snail-job:
enabled: false
@@ -133,6 +140,30 @@ redisson:
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
+--- # RocketMQ 配置
+rocketmq:
+ # RocketMQ 服务器地址
+ name-server: 82.156.121.2:9876
+ # 生产者配置
+ producer:
+ # 生产者组名
+ group: wzj_group
+ # 发送消息超时时间
+ send-message-timeout: 30000
+ # 消息最大长度
+ max-message-size: 4194304
+ # 消息发送失败重试次数
+ retry-times-when-send-failed: 3
+ # 异步消息发送失败重试次数
+ retry-times-when-send-async-failed: 3
+ # 消费者配置
+ consumer:
+ # 拉取消息最大数量
+ pull-batch-size: 10
+ # 消费者组 (系统模块)
+ group: consumer_group_system
+ # 是否启动消费者
+ enabled: true
--- # mail 邮件发送
mail:
enabled: false
@@ -263,3 +294,17 @@ justauth:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
+
+# 腾讯云IM配置
+tencent:
+ im:
+ # 腾讯云 SDKAppId
+ sdkappid: 1600080789
+ # 密钥
+ secretkey: 311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091
+ # 签名过期时间(秒)
+ expire: 604800
+ # 管理员账号
+ admin: administrator
+ # API调用密钥
+ api-secret: 311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 888c73f77..f654d9b17 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -147,6 +147,7 @@ tenant:
- ums_account
- ums_account_change_record
- sys_message_template
+ - sys_message_user
- ums_fans
- ums_block
- oms_aftersale
diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/RabbitMQConsumer.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/RabbitMQConsumer.java
index 9c4d7d9a5..9ed9d08db 100644
--- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/RabbitMQConsumer.java
+++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/RabbitMQConsumer.java
@@ -14,6 +14,10 @@ import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+/**
+ * RabbitMQ消费者
+ * 已禁用,改用RocketMQ
+ */
@Slf4j
@Component
public class RabbitMQConsumer {
@@ -21,7 +25,7 @@ public class RabbitMQConsumer {
@Autowired
private MsgService msgService;
- @RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})
+ // @RabbitListener(queues = {RabbitMQConfig.QUEUE_SYS_MSG})
public void watchQueue(String payload, Message message) {
log.info(payload);
diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java
index 61d58ec07..89dad8ab8 100644
--- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java
+++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/domain/base/RabbitMQConfig.java
@@ -9,7 +9,11 @@ import org.springframework.context.annotation.Configuration;
-@Configuration
+/**
+ * RabbitMQ配置类
+ * 已禁用,改用RocketMQ
+ */
+// @Configuration
public class RabbitMQConfig {
/**
@@ -25,7 +29,7 @@ public class RabbitMQConfig {
public static final String QUEUE_SYS_MSG = "queue_sys_msg";
- @Bean(EXCHANGE_MSG)
+ // @Bean(EXCHANGE_MSG)
public Exchange exchange() {
return ExchangeBuilder // 构建交换机
.topicExchange(EXCHANGE_MSG) // 使用topic类型,参考:https://www.rabbitmq.com/getstarted.html
@@ -33,12 +37,12 @@ public class RabbitMQConfig {
.build();
}
- @Bean(QUEUE_SYS_MSG)
+ // @Bean(QUEUE_SYS_MSG)
public Queue queue() {
return new Queue(QUEUE_SYS_MSG);
}
- @Bean
+ // @Bean
public Binding binding(@Qualifier(EXCHANGE_MSG) Exchange exchange,
@Qualifier(QUEUE_SYS_MSG) Queue queue) {
diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java
index 4dfa5effa..a15f49563 100644
--- a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java
+++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java
@@ -1,12 +1,14 @@
package org.dromara.demo.service;
import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Service;
/**
* 导出下拉框Excel示例
*
* @author Emil.Zhang
*/
+@Service
public interface IExportExcelService {
/**
diff --git a/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/domain/po/Member.java b/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/domain/po/Member.java
index 0c7868b54..e18791057 100644
--- a/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/domain/po/Member.java
+++ b/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/domain/po/Member.java
@@ -3,8 +3,10 @@ package com.wzj.soopin.member.domain.po;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
+import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.model.BaseAudit;
import org.dromara.common.excel.annotation.Excel;
@@ -19,6 +21,8 @@ import java.time.LocalDateTime;
@Schema(description="会员信息对象")
@Data
@Builder
+@NoArgsConstructor
+@AllArgsConstructor
@TableName("ums_member")
public class Member extends BaseAudit {
@Schema(description = "会员id")
diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml
index dd960febd..23d05a29c 100644
--- a/ruoyi-modules/ruoyi-system/pom.xml
+++ b/ruoyi-modules/ruoyi-system/pom.xml
@@ -131,6 +131,19 @@
tomcat-embed-websocket
+
+
+ org.apache.rocketmq
+ rocketmq-spring-boot-starter
+ 2.2.3
+
+
+
+
+ org.springframework
+ spring-messaging
+
+
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java
index 196a8f4a7..43bc85443 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysMessageController.java
@@ -2,6 +2,7 @@ package org.dromara.system.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@@ -9,6 +10,7 @@ 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.utils.StringUtils;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.core.validate.QueryGroup;
@@ -27,8 +29,6 @@ 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.*;
@@ -58,7 +58,7 @@ public class SysMessageController extends BaseController {
/**
* 查询消息列表
*/
- @SaCheckPermission("system:message:list")
+// @SaCheckPermission("system:message:list")
@Tag(name = "查询消息列表")
@PostMapping("/list")
public R> list(@RequestBody SysMessageBo bo, @RequestBody Page page) {
@@ -73,7 +73,7 @@ public class SysMessageController extends BaseController {
*
* @param id 消息ID
*/
- @SaCheckPermission("system:message:query")
+// @SaCheckPermission("system:message:query")
@GetMapping("/{id}")
public R getInfo(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
return R.ok(messageService.selectMessageById(id));
@@ -82,52 +82,76 @@ public class SysMessageController extends BaseController {
/**
* 发送消息
*/
- @SaCheckPermission("system:message:send")
+// @SaCheckPermission("system:message:send")
@Log(title = "消息管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/send")
public R send(@Validated(AddGroup.class) @RequestBody SysMessageBo bo) {
- List users = userService.selectUserListByDept(null);
- List userIds;
+ // 设置发送者ID为当前登录用户ID
+ bo.setSenderId(getUserId());
- 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();
+ List userIdStrings;
+
+ // 获取第一个发送范围作为主要处理对象
+ String scope = bo.getSendScope() != null && !bo.getSendScope().isEmpty() ?
+ bo.getSendScope().get(0) : "";
+
+ // 如果是群发消息类型,则根据类型筛选用户
+ if ("all".equals(scope) || "expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
+ List users = userService.selectUserListByDept(null);
+ List userIds;
+
+ switch (scope) {
+ 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 = List.of();
+ }
+ userIdStrings = userIds.stream().map(String::valueOf).toList();
+ } else {
+ // 直接使用指定的接收者ID
+ if (bo.getUserIds() != null && !bo.getUserIds().isEmpty()) {
+ // 如果userIds不为空,使用它
+ userIdStrings = bo.getUserIds().stream().map(String::valueOf).toList();
+ } else if (bo.getSendScope() != null && !bo.getSendScope().isEmpty()) {
+ // 如果userIds为空但sendScope不为空,将sendScope中的值作为用户ID使用
+ userIdStrings = bo.getSendScope();
+ } else {
+ // 都为空,返回空列表
+ userIdStrings = List.of();
+ }
}
- return toAjax(messageService.sendMessageToUsers(bo, userIds));
+ return toAjax(messageService.sendMessageToUsers(bo, userIdStrings));
}
/**
* 标记消息为已读
*/
- @SaCheckPermission("system:message:mark")
+// @SaCheckPermission("system:message:mark")
@Log(title = "消息管理", businessType = BusinessType.UPDATE)
@PutMapping("/mark/{id}")
public R markAsRead(@NotNull(message = "消息ID不能为空") @PathVariable Long id) {
@@ -139,7 +163,7 @@ public class SysMessageController extends BaseController {
*
* @param ids 消息ID串
*/
- @SaCheckPermission("system:message:remove")
+// @SaCheckPermission("system:message:remove")
@Log(title = "消息管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R remove(@NotEmpty(message = "消息ID不能为空") @PathVariable Long[] ids) {
@@ -149,7 +173,7 @@ public class SysMessageController extends BaseController {
/**
* 获取未读消息列表
*/
- @SaCheckPermission("system:message:list")
+// @SaCheckPermission("system:message:list")
@Tag(name = "查询未读消息列表")
@PostMapping("/unread")
public R> unreadList(@RequestBody Page page) {
@@ -160,7 +184,7 @@ public class SysMessageController extends BaseController {
/**
* 获取已读消息列表
*/
- @SaCheckPermission("system:message:list")
+// @SaCheckPermission("system:message:list")
@Tag(name = "查询已读消息列表")
@PostMapping("/read")
public R> readList(@RequestBody Page page) {
@@ -172,12 +196,9 @@ public class SysMessageController extends BaseController {
* 获取用户列表
*/
// @SaCheckPermission("system:message:list")
-// @GetMapping("/user/list")
-// public R> getUserList() {
-// PageQuery pageQuery = new PageQuery();
-// pageQuery.setPageNum(1);
-// pageQuery.setPageSize(Integer.MAX_VALUE);
-// TableDataInfo users = userService.selectPageUserList(new SysUserBo(), pageQuery);
-// return R.ok(users);
-// }
+ @GetMapping("/user/list")
+ public R> getUserList(@RequestParam(required = false) String keyword) {
+ // 无论是否有关键词,都查询 ums_member 表中的用户信息
+ return R.ok(userService.selectMemberUsers(keyword));
+ }
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java
index e85ae3705..cbdd0d3eb 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMessageBo.java
@@ -3,6 +3,7 @@ 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.NotEmpty;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -45,7 +46,7 @@ public class SysMessageBo extends BaseAudit {
private String content;
/** 消息类型(AUTO自动/MANUAL手动) */
- @NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
+// @NotBlank(message = "消息类型不能为空", groups = { AddGroup.class, EditGroup.class })
@ExcelProperty(value = "消息类型")
private String msgType;
@@ -62,8 +63,8 @@ public class SysMessageBo extends BaseAudit {
private Date scheduledTime;
/** 发送范围(all:全部用户, userType:按用户类型, userIds:指定用户) */
- @NotBlank(message = "发送范围不能为空", groups = { AddGroup.class })
- private String sendScope;
+ @NotEmpty(message = "发送范围不能为空", groups = { AddGroup.class })
+ private List sendScope;
/** 接收用户ID列表 */
private List userIds;
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java
index 9cea99281..97cf2e934 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/event/MessageEvent.java
@@ -14,10 +14,47 @@ public class MessageEvent extends ApplicationEvent {
private final SysMessageVo message;
private final Long userId;
+ private final String userIdStr;
+ /**
+ * 使用 Long 类型用户 ID 创建消息事件
+ */
public MessageEvent(Object source, SysMessageVo message, Long userId) {
super(source);
this.message = message;
this.userId = userId;
+ this.userIdStr = userId != null ? String.valueOf(userId) : null;
+ }
+
+ /**
+ * 使用 String 类型用户 ID 创建消息事件
+ */
+ public MessageEvent(Object source, SysMessageVo message, String userIdStr) {
+ super(source);
+ this.message = message;
+ this.userIdStr = userIdStr;
+
+ // 尝试转换为 Long 类型
+ Long parsedUserId = null;
+ try {
+ if (userIdStr != null) {
+ parsedUserId = Long.parseLong(userIdStr);
+ }
+ } catch (NumberFormatException e) {
+ // 无法解析为 Long 类型,保持 userId 为 null
+ }
+ this.userId = parsedUserId;
+ }
+
+ /**
+ * 创建 MessageEvent 实例(支持 String 类型用户ID)
+ *
+ * @param source 事件源
+ * @param message 消息对象
+ * @param userIdStr 用户ID (String类型)
+ * @return MessageEvent 实例
+ */
+ public static MessageEvent createWithStringUserId(Object source, SysMessageVo message, String userIdStr) {
+ return new MessageEvent(source, message, userIdStr);
}
}
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java
index 0c38d1c0e..d5e5a49df 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/event/MessageEventListener.java
@@ -2,8 +2,14 @@ package org.dromara.system.event;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.system.config.RocketMQConfig;
+import org.dromara.system.consumer.MessageRocketMQConsumer;
import org.dromara.system.domain.event.MessageEvent;
+import org.dromara.system.service.IRocketMQService;
import org.dromara.system.websocket.MessageWebSocketServer;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@@ -15,10 +21,13 @@ import org.springframework.stereotype.Component;
*/
@Slf4j
@Component
-@RequiredArgsConstructor
public class MessageEventListener {
- private final MessageWebSocketServer messageWebSocketServer;
+ @Autowired
+ private IRocketMQService rocketMQService;
+
+ @Autowired
+ private MessageWebSocketServer messageWebSocketServer;
/**
* 处理消息事件
@@ -27,7 +36,37 @@ public class MessageEventListener {
@EventListener
public void handleMessageEvent(MessageEvent event) {
try {
- messageWebSocketServer.sendMessage(event.getUserId(), String.valueOf(event.getMessage()));
+ // 创建消息包装对象
+ MessageRocketMQConsumer.MessageWrapper wrapper = new MessageRocketMQConsumer.MessageWrapper();
+ wrapper.setUserId(event.getUserIdStr());
+ wrapper.setMessage(event.getMessage());
+
+ // 尝试通过RocketMQ发送消息
+ boolean sendSuccess = false;
+ try {
+ rocketMQService.sendMessage(
+ RocketMQConfig.TOPIC_SYS_MSG,
+ RocketMQConfig.TAG_SYS_MSG,
+ wrapper
+ );
+ sendSuccess = true;
+ log.info("消息事件已通过RocketMQ发送,userId: {}", event.getUserIdStr());
+ } catch (Exception e) {
+ log.error("通过RocketMQ发送消息失败,将尝试直接通过WebSocket发送", e);
+ }
+
+ // 如果RocketMQ发送失败,则尝试直接通过WebSocket发送
+ if (!sendSuccess && event.getUserId() != null) {
+ try {
+ messageWebSocketServer.sendMessage(
+ event.getUserId(),
+ JsonUtils.toJsonString(event.getMessage())
+ );
+ log.info("消息事件已直接通过WebSocket发送,userId: {}", event.getUserId());
+ } catch (Exception e) {
+ log.error("通过WebSocket发送消息失败", e);
+ }
+ }
} catch (Exception e) {
log.error("处理消息事件失败", e);
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java
index 0fb33c2e5..c8956ca11 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMessageService.java
@@ -34,22 +34,40 @@ public interface ISysMessageService extends IService {
Page selectReadMessagesPage(Long userId, Page page);
/**
- * 发送消息给指定用户
+ * 向用户发送消息
*
- * @param message 消息内容
- * @param userId 用户ID
+ * @param message 消息信息
+ * @param userId 用户ID (Long类型)
* @return 结果
*/
int sendMessageToUser(SysMessageBo message, Long userId);
/**
- * 发送消息给多个用户
+ * 向用户发送消息 (String类型用户ID)
*
- * @param message 消息内容
- * @param userIds 用户ID列表
+ * @param message 消息信息
+ * @param userId 用户ID (String类型)
* @return 结果
*/
- int sendMessageToUsers(SysMessageBo message, List userIds);
+ int sendMessageToUserByStringId(SysMessageBo message, String userId);
+
+ /**
+ * 向多个用户发送消息
+ *
+ * @param message 消息信息
+ * @param userIds 用户ID列表 (Long类型)
+ * @return 结果
+ */
+// int sendMessageToUsers(SysMessageBo message, List userIds);
+
+ /**
+ * 向多个用户发送消息
+ *
+ * @param message 消息信息
+ * @param userIds 用户ID列表 (String类型)
+ * @return 结果
+ */
+ int sendMessageToUsers(SysMessageBo message, List userIds);
/**
* 发送自动消息
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
index 1fe554547..475359f44 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
@@ -228,4 +228,27 @@ public interface ISysUserService {
* @return 结果
*/
List selectUserListByDept(Long deptId);
+
+ /**
+ * 根据条件查询用户列表
+ *
+ * @param user 用户信息
+ * @return 用户列表
+ */
+ List selectUserList(SysUserBo user);
+
+ /**
+ * 查询所有会员用户信息(ums_member表)
+ *
+ * @return 会员用户列表
+ */
+ List selectAllMemberUsers();
+
+ /**
+ * 根据关键字查询会员用户信息(ums_member表)
+ *
+ * @param keyword 关键字(用户名、昵称或手机号)
+ * @return 会员用户列表
+ */
+ List selectMemberUsers(String keyword);
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java
index 1578590cb..fda8bed01 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMessageServiceImpl.java
@@ -4,6 +4,7 @@ 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 lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
@@ -20,7 +21,9 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
/**
* 消息Service业务层处理
@@ -29,6 +32,7 @@ import java.util.List;
*/
@Service
@RequiredArgsConstructor
+@Slf4j
public class SysMessageServiceImpl extends ServiceImpl implements ISysMessageService {
private final SysMessageMapper messageMapper;
@@ -55,7 +59,7 @@ public class SysMessageServiceImpl extends ServiceImpl messagePage = messageMapper.selectPage(page, lqw);
Page voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
@@ -68,7 +72,7 @@ public class SysMessageServiceImpl extends ServiceImpl messagePage = messageMapper.selectPage(page, lqw);
Page voPage = new Page<>(messagePage.getCurrent(), messagePage.getSize(), messagePage.getTotal());
voPage.setRecords(MapstructUtils.convert(messagePage.getRecords(), SysMessageVo.class));
@@ -97,25 +101,40 @@ public class SysMessageServiceImpl extends ServiceImpl userIds) {
+ public int sendMessageToUsers(SysMessageBo message, List userIds) {
+ if (userIds == null || userIds.isEmpty()) {
+ return 0;
+ }
+
// 保存消息
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));
+ for (String userIdStr : userIds) {
+ if (StringUtils.isBlank(userIdStr)) {
+ continue;
+ }
+
+ try {
+ Long userId = Long.parseLong(userIdStr);
+ 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(MessageEvent.createWithStringUserId(this, messageVo, userIdStr));
+ }
+ } catch (NumberFormatException e) {
+ log.error("无法将String类型的用户ID转换为Long: {}", userIdStr);
}
}
+
return count;
}
@@ -123,7 +142,7 @@ public class SysMessageServiceImpl extends ServiceImpl userIds) {
message.setMsgType("AUTO");
- return sendMessageToUsers(message, userIds);
+ return sendMessageToUsers(message, userIds.stream().map(String::valueOf).collect(Collectors.toList()));
}
@Override
@@ -204,5 +223,20 @@ public class SysMessageServiceImpl extends ServiceImpl selectUserListByDept(Long deptId) {
- LambdaQueryWrapper lqw = Wrappers.lambdaQuery();
- lqw.eq(SysUser::getDeptId, deptId);
- lqw.orderByAsc(SysUser::getUserId);
- return baseMapper.selectVoList(lqw);
+ return baseMapper.selectUserList(new LambdaQueryWrapper()
+ .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId)
+ .eq(SysUser::getStatus, SystemConstants.NORMAL));
}
/**
@@ -720,4 +724,136 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
return selectListByIds(new ArrayList<>(userIds));
}
+ /**
+ * 根据条件查询用户列表
+ *
+ * @param user 用户信息
+ * @return 用户列表
+ */
+ @Override
+ public List selectUserList(SysUserBo user) {
+ LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
+ lqw.eq(SysUser::getStatus, SystemConstants.NORMAL);
+
+ // 模糊搜索昵称或手机号
+ if (StringUtils.isNotBlank(user.getNickName())) {
+ lqw.and(wrapper -> wrapper
+ .like(SysUser::getNickName, user.getNickName())
+ .or()
+ .like(StringUtils.isNotBlank(user.getPhonenumber()), SysUser::getPhonenumber, user.getPhonenumber()));
+ }
+
+ return baseMapper.selectUserList(lqw);
+ }
+
+ @Override
+ public List selectAllMemberUsers() {
+ try {
+ // 获取 Spring 上下文中的 MemberService bean
+ IMemberService memberService = SpringUtils.getBean(IMemberService.class);
+
+ if (memberService != null) {
+ // 查询所有会员信息
+ List members = memberService.list();
+
+ // 将 Member 转换为 SysUserVo
+ return members.stream().map(member -> {
+ SysUserVo userVo = new SysUserVo();
+ // 设置用户ID
+ userVo.setUserId(member.getId());
+ // 设置用户名
+ userVo.setUserName(member.getUserName());
+ // 设置昵称
+ userVo.setNickName(member.getNickname());
+ // 设置手机号,如果加密了就用隐藏版本
+ userVo.setPhonenumber(StringUtils.isNotBlank(member.getPhoneHidden()) ?
+ member.getPhoneHidden() : member.getPhoneEncrypted());
+ // 设置头像
+ if (StringUtils.isNotBlank(member.getAvatar())) {
+ try {
+ userVo.setAvatar(Long.parseLong(member.getAvatar()));
+ } catch (NumberFormatException e) {
+ log.warn("会员头像ID格式不正确: {}", member.getAvatar());
+ }
+ }
+ // 设置性别
+ if (member.getGender() != null) {
+ userVo.setSex(member.getGender().toString());
+ }
+ // 设置状态
+ userVo.setStatus(member.getStatus() == 1 ? "0" : "1"); // 转换状态值
+
+ return userVo;
+ }).collect(Collectors.toList());
+ }
+ } catch (Exception e) {
+ log.error("查询会员信息失败", e);
+ }
+
+ // 如果查询失败或会员服务不可用,返回空列表
+ return new ArrayList<>();
+ }
+
+ @Override
+ public List selectMemberUsers(String keyword) {
+ try {
+ // 获取 Spring 上下文中的 MemberService bean
+ IMemberService memberService = SpringUtils.getBean(IMemberService.class);
+
+ if (memberService != null) {
+ // 创建查询条件
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+
+ // 如果有关键词,添加模糊查询条件(昵称、用户名、手机号)
+ if (StringUtils.isNotBlank(keyword)) {
+ queryWrapper.like(Member::getNickname, keyword)
+ .or()
+ .like(Member::getUserName, keyword)
+ .or()
+ .like(Member::getPhoneEncrypted, keyword)
+ .or()
+ .like(Member::getPhoneHidden, keyword);
+ }
+
+ // 查询会员信息
+ List members = memberService.list(queryWrapper);
+
+ // 将 Member 转换为 SysUserVo
+ return members.stream().map(member -> {
+ SysUserVo userVo = new SysUserVo();
+ // 设置用户ID
+ userVo.setUserId(member.getId());
+ // 设置用户名
+ userVo.setUserName(member.getUserName());
+ // 设置昵称
+ userVo.setNickName(member.getNickname());
+ // 设置手机号,如果加密了就用隐藏版本
+ userVo.setPhonenumber(StringUtils.isNotBlank(member.getPhoneHidden()) ?
+ member.getPhoneHidden() : member.getPhoneEncrypted());
+ // 设置头像
+ if (StringUtils.isNotBlank(member.getAvatar())) {
+ try {
+ userVo.setAvatar(Long.parseLong(member.getAvatar()));
+ } catch (NumberFormatException e) {
+ log.warn("会员头像ID格式不正确: {}", member.getAvatar());
+ }
+ }
+ // 设置性别
+ if (member.getGender() != null) {
+ userVo.setSex(member.getGender().toString());
+ }
+ // 设置状态
+ userVo.setStatus(member.getStatus() == 1 ? "0" : "1"); // 转换状态值
+
+ return userVo;
+ }).collect(Collectors.toList());
+ }
+ } catch (Exception e) {
+ log.error("查询会员信息失败", e);
+ }
+
+ // 如果查询失败或会员服务不可用,返回空列表
+ return new ArrayList<>();
+ }
+
}