diff --git a/pom.xml b/pom.xml
index a9e017390..c8dd1f8a5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -409,11 +409,6 @@
ruoyi-common-mq
${revision}
-
- org.springframework.boot
- spring-boot-starter-amqp
- 2.5.4
-
org.dromara
diff --git a/ruoyi-admin/src/main/java/org/dromara/app/AppDictController.java b/ruoyi-admin/src/main/java/org/dromara/app/AppDictController.java
new file mode 100644
index 000000000..0d6b6af02
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/app/AppDictController.java
@@ -0,0 +1,45 @@
+package org.dromara.app;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.wzj.soopin.member.convert.FeedbackConvert;
+import com.wzj.soopin.member.domain.bo.FeedbackBO;
+import com.wzj.soopin.member.service.IFeedbackService;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.service.ISysDictDataService;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Slf4j
+@Api(tags = "VlogController 短视频相关业务功能的接口")
+@RequestMapping("/app/sys/dict")
+@RestController
+@AllArgsConstructor
+public class AppDictController {
+ private final ISysDictDataService dictDataService;
+ private final ISysDictTypeService dictTypeService;
+
+ /**
+ * 根据字典类型查询字典数据信息
+ *
+ * @param dictType 字典类型
+ */
+ @GetMapping(value = "/type/{dictType}")
+ public R> dictType(@PathVariable String dictType) {
+ List data = dictTypeService.selectDictDataByType(dictType);
+ if (ObjectUtil.isNull(data)) {
+ data = new ArrayList<>();
+ }
+ return R.ok(data);
+ }
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/app/AppFeedbackController.java b/ruoyi-admin/src/main/java/org/dromara/app/AppFeedbackController.java
new file mode 100644
index 000000000..f82244c90
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/app/AppFeedbackController.java
@@ -0,0 +1,51 @@
+package org.dromara.app;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.wzj.soopin.content.domain.bo.*;
+import com.wzj.soopin.content.domain.po.Vlog;
+import com.wzj.soopin.content.domain.vo.IndexVlogVO;
+import com.wzj.soopin.content.service.VlogService;
+import com.wzj.soopin.content.service.VlogUploadService;
+import com.wzj.soopin.content.utils.QcCloud;
+import com.wzj.soopin.content.utils.RedisOperator;
+import com.wzj.soopin.member.convert.FeedbackConvert;
+import com.wzj.soopin.member.domain.bo.FeedbackBO;
+import com.wzj.soopin.member.service.IFeedbackService;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.wzj.soopin.content.domain.base.BaseInfoProperties.*;
+
+
+@Slf4j
+@Api(tags = "VlogController 短视频相关业务功能的接口")
+@RequestMapping("/app/feedback")
+@RestController
+@AllArgsConstructor
+public class AppFeedbackController {
+ private final IFeedbackService service;
+ private final FeedbackConvert convert;
+
+ @Tag(name = "修改意见反馈备注信息")
+ @Log(title = "新增意见反馈", businessType = BusinessType.UPDATE)
+ @PostMapping("/add")
+ public R add(@RequestBody FeedbackBO feedback) {
+ return R.ok(service.save(convert.toPo(feedback)));
+ }
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/app/AppVlogController.java b/ruoyi-admin/src/main/java/org/dromara/app/AppVlogController.java
index 962de1bd6..716f8f66a 100644
--- a/ruoyi-admin/src/main/java/org/dromara/app/AppVlogController.java
+++ b/ruoyi-admin/src/main/java/org/dromara/app/AppVlogController.java
@@ -18,11 +18,16 @@ import org.apache.commons.lang3.StringUtils;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.mq.domain.MQMessage;
+import org.dromara.common.mq.enums.MQMessageType;
+import org.dromara.common.mq.enums.MessageActionEnum;
+import org.dromara.common.mq.utils.MqUtil;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -150,15 +155,14 @@ public class AppVlogController {
@PostMapping("like")
- public R like(@RequestBody Map params) {
+ public R like(@RequestBody VlogBO vlogBO) {
LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) {
throw new ServiceException("用户未登录");
}
String userId = String.valueOf(loginUser.getUserId());
- String vlogId = params.get("vlogId");
-
+ String vlogId = vlogBO.getId();
//获取vlog
@@ -188,6 +192,22 @@ public class AppVlogController {
vlogService.flushCounts(vlogId, counts);
}
}
+ if (userId != null && vlog.getMemberId() != null && !userId.equals(vlog.getMemberId())) {
+ // 新版:使用模板类型编号和参数
+ Map params = new HashMap<>();
+ params.put("userId", userId);
+ params.put("nickname", loginUser.getNickname());
+ params.put("action", MessageActionEnum.INTERACTION_LIKE.name());
+ params.put("toUserId",vlog.getMemberId());
+ MQMessage message = MQMessage.builder()
+ .messageType(MQMessageType.IM.name())
+ .data(params)
+ .source("member")
+ .build();
+ // 关注消息
+ MqUtil.sendIMMessage(message);
+
+ }
return R.ok();
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
index 42c2467b7..536bf0934 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
@@ -57,4 +57,6 @@ public interface CacheConstants {
String CHAT="CHAT:";
+ String IM_MSG_RECEIVE="im:msg:receive:";
+
}
diff --git a/ruoyi-common/ruoyi-common-mq/pom.xml b/ruoyi-common/ruoyi-common-mq/pom.xml
index cd5f7ba10..97f1eb7d5 100644
--- a/ruoyi-common/ruoyi-common-mq/pom.xml
+++ b/ruoyi-common/ruoyi-common-mq/pom.xml
@@ -32,7 +32,7 @@
org.apache.rocketmq
rocketmq-spring-boot-starter
- 2.2.3
+ 2.3.1
diff --git a/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/domain/MQMessage.java b/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/domain/MQMessage.java
index 3a47e8a0d..519c1cf9f 100644
--- a/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/domain/MQMessage.java
+++ b/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/domain/MQMessage.java
@@ -11,6 +11,7 @@ import java.time.LocalDateTime;
@Data
@Builder(toBuilder = true)
@AllArgsConstructor
+@NoArgsConstructor
public class MQMessage {
/**
* 消息ID
diff --git a/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MQMessageType.java b/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MQMessageType.java
new file mode 100644
index 000000000..48a7969f6
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MQMessageType.java
@@ -0,0 +1,7 @@
+package org.dromara.common.mq.enums;
+
+public enum MQMessageType {
+ IM,
+ VLOG,
+ COMMENT;
+}
diff --git a/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MessageActionEnum.java b/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MessageActionEnum.java
index 005ff2b19..62a2b14cf 100644
--- a/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MessageActionEnum.java
+++ b/ruoyi-common/ruoyi-common-mq/src/main/java/org/dromara/common/mq/enums/MessageActionEnum.java
@@ -2,39 +2,37 @@ package org.dromara.common.mq.enums;
public enum MessageActionEnum {
- NEW_FOUCS(1,"新的关注"), //新的关注
- SYSTEM_NOTIFY(2, "系统->通知"), // 系统->通知
- SYSTEM_REPORT(3, "系统->举报下架(视频,视频评论) 视频评论"), // 系统->举报下架(视频,视频评论) 视频评论
- SYSTEM_CHECK(4, "系统->审核结果(复审,驳回 ,通过)"), // 系统->审核结果(复审,驳回 ,通过)
- SYSTEM_PUSH(5, "系统->推广类的"), //系统->推广类的
- INTERACTION_COMMENT(6, "互动->评论"), //互动->评论
- INTERACTION_AT(7, "互动->视频评论中的@"), //互动->视频评论中的@
- INTERACTION_LIKE(8, "互动->点赞"), //互动->点赞
- INTERACTION_REPLY(9, "互动->评论回复"), //互动->评论回复
- ORDER_RECHARGE(10, "订单->充值 online"), //订单->充值 online
- ORDER_PAY(11, "订单->订单交易成功通知 online"), //订单->订单交易成功通知 online
- ORDER_REFUND(12, "订单->退款结果通知"), //订单->退款结果通知
- GROUP_NOTIFY_CHECK(13, "群通知->进群申请 online"), //群通知->进群申请 online
- GROUP_NOTIFY_ACCEPT(14, "群通知->进群审核审核通过 online"), // 群通知->进群审核审核通过 online
- GROUP_NOTIFY_FAIL(15, "群通知->进群审核审核拒绝 online"), // 群通知->进群审核审核拒绝 online
- GROUP_NOTIFY_LEAVE_UP(16, "群通知->群升级为达人群通知"), // 群通知->群升级为达人群通知
- GROUP_NOTIFY_LEAVE_DOWN(17, "群通知->群降级为普通群通知"); // 群通知->群降级为普通群通知
+ NEW_FOUCS(1,"newFocus"), //新的关注
+ SYSTEM_NOTIFY(2, "system"), // 系统->通知
+ SYSTEM_REPORT(3, "system"), // 系统->举报下架(视频,视频评论) 视频评论
+ SYSTEM_CHECK(4, "system"), // 系统->审核结果(复审,驳回 ,通过)
+ SYSTEM_PUSH(5, "system"), //系统->推广类的
+ INTERACTION_COMMENT(6, "interaction"), //互动->评论
+ INTERACTION_AT(7, "interaction"), //互动->视频评论中的@
+ INTERACTION_LIKE(8, "interaction"), //互动->点赞
+ INTERACTION_REPLY(9, "interaction"), //互动->评论回复
+ ORDER_RECHARGE(10, "order"), //订单->充值 online
+ ORDER_PAY(11, "order"), //订单->订单交易成功通知 online
+ ORDER_REFUND(12, "order"), //订单->退款结果通知
+ GROUP_NOTIFY_CHECK(13, "groupNotify"), //群通知->进群申请 online
+ GROUP_NOTIFY_ACCEPT(14, "groupNotify"), // 群通知->进群审核审核通过 online
+ GROUP_NOTIFY_FAIL(15, "groupNotify"), // 群通知->进群审核审核拒绝 online
+ GROUP_NOTIFY_LEAVE_UP(16, "groupNotify"), // 群通知->群升级为达人群通知
+ GROUP_NOTIFY_LEAVE_DOWN(17, "groupNotify"); // 群通知->群降级为普通群通知
private int code;
private String account;
- private String desc;
- MessageActionEnum(int code, String desc) {
+ MessageActionEnum(int code, String account) {
this.code = code;
- this.desc = desc;
+ this.account = account;
}
public int getCode() {
return code;
}
-
- public String getDesc() {
- return desc;
+ public String getAccount() {
+ return account;
}
public static MessageActionEnum getByCode(int code) {
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/consumer/MessageRocketMQConsumer.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/consumer/MessageRocketMQConsumer.java
index cde201d26..cbfa1f133 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/consumer/MessageRocketMQConsumer.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/consumer/MessageRocketMQConsumer.java
@@ -1,16 +1,14 @@
package com.wzj.soopin.im.consumer;
+import com.wzj.soopin.im.service.IMQMessageHandleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
-
-import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
-//import org.dromara.system.config.RocketMQConfig;
-import com.wzj.soopin.im.domain.vo.SysMessageVo;
import org.dromara.common.mq.config.RocketMQConfig;
-import org.dromara.system.websocket.MessageWebSocketServer;
+import org.dromara.common.mq.domain.MQMessage;
import org.springframework.stereotype.Component;
/**
@@ -24,66 +22,45 @@ import org.springframework.stereotype.Component;
@RocketMQMessageListener(
topic = RocketMQConfig.TOPIC_IM_MSG,
consumerGroup = RocketMQConfig.CONSUMER_GROUP_SYS_MSG,
- selectorExpression = RocketMQConfig.TAG_SYS_MSG
+ selectorExpression = "*"
+// ackMode = AckMode.MANUAL
)
-public class MessageRocketMQConsumer implements RocketMQListener {
+public class MessageRocketMQConsumer implements RocketMQListener {
- private final MessageWebSocketServer messageWebSocketServer;
+ private final IMQMessageHandleService messageHandleService;
@Override
- public void onMessage(String message) {
- try {
- log.info("接收到RocketMQ消息: {}", message);
- // 解析消息格式,格式为: {"userId": "123", "message": {...}}
- MessageWrapper wrapper = JsonUtils.parseObject(message, MessageWrapper.class);
- if (wrapper != null && wrapper.getUserId() != null && wrapper.getMessage() != null) {
- // 将String类型的userId转换为Long类型
- Long userIdLong = null;
- try {
- if (StringUtils.isNotBlank(wrapper.getUserId())) {
- userIdLong = Long.parseLong(wrapper.getUserId());
- }
- } catch (NumberFormatException e) {
- log.error("用户ID转换失败: {}", wrapper.getUserId(), e);
- return;
- }
+ public void onMessage(MessageExt messageExt) { // 参数为MessageExt
+ String message = new String(messageExt.getBody());
+ log.info("接收到RocketMQ消息: {}, msgId: {}", message, messageExt.getMsgId());
- if (userIdLong != null) {
- // 发送WebSocket消息
- messageWebSocketServer.sendMessage(userIdLong, JsonUtils.toJsonString(wrapper.getMessage()));
- log.info("通过WebSocket发送消息成功,userId: {}", userIdLong);
+ try {
+ MQMessage mqMessage = JsonUtils.parseObject(message, MQMessage.class);
+ if (mqMessage != null) {
+ boolean result = messageHandleService.handleMessage(mqMessage);
+ if (result) {
+ // 消息处理成功,手动确认
+// messageExt.acknowledge(); // 2.3.1版本支持该方法
+ log.info("消息确认成功, msgId: {}", messageExt.getMsgId());
} else {
- log.warn("用户ID为空或无效: {}", wrapper.getUserId());
+ // 业务失败,抛出异常触发重试
+ throw new RuntimeException("业务处理失败,将重试");
}
} else {
- log.warn("消息格式不正确: {}", message);
+ log.warn("消息格式错误,直接确认避免重试: {}", message);
+// messageExt.acknowledge(); // 格式错误无需重试
}
} catch (Exception e) {
- log.error("处理RocketMQ消息失败", e);
+ log.error("消息处理异常, msgId: {}", messageExt.getMsgId(), e);
+ // 达到最大重试次数后确认消息
+ if (messageExt.getReconsumeTimes() >= 3) {
+ log.error("达到最大重试次数,确认消息进入死信队列, msgId: {}", messageExt.getMsgId());
+// messageExt.acknowledge();
+ } else {
+ // 未达重试上限,抛出异常触发重试
+ throw new RuntimeException("消息处理异常,将重试", e);
+ }
}
}
- /**
- * 消息包装类
- */
- public static class MessageWrapper {
- private String userId;
- private SysMessageVo message;
-
- public String getUserId() {
- return userId;
- }
-
- public void setUserId(String userId) {
- this.userId = userId;
- }
-
- public SysMessageVo getMessage() {
- return message;
- }
-
- public void setMessage(SysMessageVo message) {
- this.message = message;
- }
- }
}
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/domain/SysMessageTemplate.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/domain/SysMessageTemplate.java
index 077d69b84..466e625c7 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/domain/SysMessageTemplate.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/domain/SysMessageTemplate.java
@@ -64,4 +64,9 @@ public class SysMessageTemplate extends BaseAudit {
* 备注
*/
private String description;
+
+ /**
+ * 模板参数
+ */
+ private String params;
}
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/event/MessageEventListener.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/event/MessageEventListener.java
index fb23706c9..a1b0f174c 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/event/MessageEventListener.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/event/MessageEventListener.java
@@ -52,9 +52,9 @@ public class MessageEventListener {
String userId = event.getUserIdStr();
// 创建消息包装对象
- MessageRocketMQConsumer.MessageWrapper wrapper = new MessageRocketMQConsumer.MessageWrapper();
- wrapper.setUserId(userId);
- wrapper.setMessage(event.getMessage());
+// MessageRocketMQConsumer.MessageWrapper wrapper = new MessageRocketMQConsumer.MessageWrapper();
+// wrapper.setUserId(userId);
+// wrapper.setMessage(event.getMessage());
// 首先尝试发送消息到腾讯IM
boolean tencentIMSendSuccess = false;
@@ -129,35 +129,18 @@ public class MessageEventListener {
}
} else {
// 默认为单用户推送
- TencentIMServiceImpl.TencentIMResult imResult = tencentIMService.sendMessageToTencentIM(fromUserId, toUserId, content,ext);
- tencentIMSendSuccess = imResult.isSuccess();
- if (tencentIMSendSuccess) {
- log.info("腾讯IM推送成功,userId={}, response={}", toUserId, imResult.getRawResponse());
- } else {
- log.warn("腾讯IM推送失败,userId={}, errorCode={}, errorInfo={}, response={}",
- toUserId, imResult.getErrorCode(), imResult.getErrorInfo(), imResult.getRawResponse());
- }
+ tencentIMSendSuccess = tencentIMService.sendMessageToTencentIM(fromUserId, toUserId, content,ext);
+
+ }
+ if (tencentIMSendSuccess) {
+ log.info("腾讯IM推送成功,userId={}", toUserId);
+ } else {
+ log.warn("腾讯IM推送失败,userId={}", toUserId);
}
} catch (Exception e) {
log.error("发送消息到腾讯IM异常,将尝试通过其他方式发送", e);
}
- // 无论腾讯IM是否发送成功,都继续尝试通过RocketMQ发送消息
- // 这样可以确保消息至少通过一种方式发送出去
- /*
- boolean rocketMQSendSuccess = false;
- try {
- rocketMQService.sendMessage(
- RocketMQConfig.TOPIC_SYS_MSG,
- RocketMQConfig.TAG_SYS_MSG,
- wrapper
- );
- rocketMQSendSuccess = true;
- log.info("消息事件已通过RocketMQ发送,userId: {}", userId);
- } catch (Exception e) {
- log.error("通过RocketMQ发送消息失败,将尝试直接通过WebSocket发送", e);
- }
- */
boolean rocketMQSendSuccess = false; // 直接设为false,表示不走MQ
// 如果前两种方式都失败,则尝试直接通过WebSocket发送
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/IMQMessageHandleService.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/IMQMessageHandleService.java
new file mode 100644
index 000000000..118edd1d2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/IMQMessageHandleService.java
@@ -0,0 +1,7 @@
+package com.wzj.soopin.im.service;
+
+import org.dromara.common.mq.domain.MQMessage;
+
+public interface IMQMessageHandleService {
+ boolean handleMessage(MQMessage message);
+}
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ISysMessageTemplateService.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ISysMessageTemplateService.java
index 37f65341a..a38d5e32e 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ISysMessageTemplateService.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ISysMessageTemplateService.java
@@ -66,4 +66,12 @@ public interface ISysMessageTemplateService extends IService
*/
List selectTemplateListByName(String name);
SysMessageTemplate selectByTemplateType(String templateType) ;
+
+ /**
+ * 根据action获取消息模板
+ * @param action
+ * @return
+ */
+ SysMessageTemplate getTemplateByAction(Integer action) ;
+
}
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ITencentIMService.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ITencentIMService.java
index b7c1fda87..144e79e54 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ITencentIMService.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/ITencentIMService.java
@@ -19,7 +19,7 @@ public interface ITencentIMService {
* @param content 消息内容
* @return 是否发送成功
*/
- TencentIMServiceImpl.TencentIMResult sendMessageToTencentIM(String fromUserId, String toUserId, String content, String cloudCustomData);
+ boolean sendMessageToTencentIM(String fromUserId, String toUserId, String content, String cloudCustomData);
/**
* 推送消息给全体用户
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/MQMessageHandleServiceImpl.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/MQMessageHandleServiceImpl.java
new file mode 100644
index 000000000..2e3b7e420
--- /dev/null
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/MQMessageHandleServiceImpl.java
@@ -0,0 +1,165 @@
+package com.wzj.soopin.im.service.impl;
+
+import cn.hutool.json.JSONObject;
+import com.wzj.soopin.im.consumer.MessageRocketMQConsumer;
+import com.wzj.soopin.im.domain.SysMessageTemplate;
+import com.wzj.soopin.im.service.IMQMessageHandleService;
+import com.wzj.soopin.im.service.ISysMessageTemplateService;
+import com.wzj.soopin.im.service.ITencentIMService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mq.domain.MQMessage;
+import org.dromara.common.mq.enums.MessageActionEnum;
+import org.dromara.common.redis.redis.RedisCache;
+import org.dromara.system.websocket.MessageWebSocketServer;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class MQMessageHandleServiceImpl implements IMQMessageHandleService {
+ // 变量替换的正则表达式模式
+ private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{\\w+}");
+ private final RedisCache redisCache;
+ private final ISysMessageTemplateService templateService;
+ private final ITencentIMService tencentIMService;
+ private final MessageWebSocketServer messageWebSocketServer;
+
+ public boolean handleMessage(MQMessage message) {
+ // 消息幂等性检查
+ String messageId = message.getMessageId();
+ // 检查消息是否已处理
+ if (redisCache.getCacheObject(CacheConstants.IM_MSG_RECEIVE + messageId) != null) {
+ log.info("消息已处理,忽略重复消息:{}", messageId);
+ return true;
+ }
+ //创建im消息
+ //根据消息类型获取消息模板
+ Map params = (Map) message.getData();
+ String action = (String) params.get("action");
+ //根据action获取消息模板
+ MessageActionEnum actionEnum = MessageActionEnum.valueOf(action);
+
+ SysMessageTemplate template = templateService.getTemplateByAction(actionEnum.getCode());
+
+ if (template == null) {
+ log.error("根据action获取消息模板失败,action:{}", action);
+ return true;
+ }
+
+ // 首先尝试发送消息到腾讯IM
+ boolean tencentIMSendSuccess = false;
+ try {
+ // 消息发送者可能是系统或管理员,这里使用action对应的账号发送
+ String fromUserId = actionEnum.getAccount();
+ String toUserId = ""; // 接收者是事件中的用户ID
+ String content = template.getContent(); // 只取content字段
+
+ // 处理消息变量替换(如果有)
+ // 从消息中提取标题和描述
+ String title = template.getTitle();
+ String desc = template.getContent();
+ // 扩展字段,可以在APP端获取
+ String ext = template.getExt();
+ // 处理变量替换
+ if (params.size() > 0) {
+ title = processMessageVariables(title, params);
+ desc = processMessageVariables(desc, params);
+ content = processMessageVariables(content, params);
+ ext = processMessageVariables(ext, params);
+ toUserId = String.valueOf(params.get("toUserId"));
+ }
+
+ String pushType = null;
+ // 根据消息类型决定推送方式
+ String templateParams = template.getParams();
+ if (templateParams != null) {
+ JSONObject param = new JSONObject(templateParams);
+ // 从消息参数中提取接收者
+ if (param != null && param.containsKey("pushType")) {
+ pushType = String.valueOf(param.get("pushType"));
+ }
+ }
+
+ if (pushType != null) {
+ switch (pushType) {
+ case "ALL":
+ // 全员推送
+ tencentIMSendSuccess = tencentIMService.pushToAll(title, desc, true, ext);
+ break;
+ case "ATTRIBUTE":
+ // 属性推送
+ Map attributes = new HashMap<>();
+ // 从消息参数中提取属性条件
+ if (params != null && params.containsKey("attributes")) {
+ Object attrObj = params.get("attributes");
+ if (attrObj instanceof Map) {
+ attributes = (Map) attrObj;
+ }
+ }
+ tencentIMSendSuccess = tencentIMService.pushByAttributes(title, desc, attributes, true, ext);
+ break;
+ case "TAG":
+ // 标签推送
+ if (params != null && params.containsKey("tags")) {
+ Object tagsObj = params.get("tags");
+ if (tagsObj instanceof String[]) {
+ tencentIMSendSuccess = tencentIMService.pushByTags(title, desc,
+ Arrays.asList((String[]) tagsObj), true, ext);
+ }
+ }
+ break;
+ case "USER":
+ default:
+ // 单用户推送(默认)
+ tencentIMSendSuccess = tencentIMService.pushToUsers(title, desc,
+ Collections.singletonList(toUserId), true, ext);
+ break;
+ }
+ } else {
+ // 默认为单用户推送
+ tencentIMSendSuccess = tencentIMService.sendMessageToTencentIM(fromUserId, toUserId, content, ext);
+ }
+ if (tencentIMSendSuccess) {
+ log.info("腾讯IM推送成功,userId={}", toUserId);
+ } else {
+ log.error("腾讯IM推送失败,userId={}", toUserId);
+ }
+ // 如果前两种方式都失败,则尝试直接通过WebSocket发送
+ if (!tencentIMSendSuccess) {
+ try {
+ messageWebSocketServer.sendMessage(
+ Long.parseLong(toUserId),
+ JsonUtils.toJsonString(message)
+ );
+ log.info("消息事件已直接通过WebSocket发送,userId: {}", toUserId);
+ } catch (Exception e) {
+ log.error("通过WebSocket发送消息失败", e);
+ }
+ }
+ } catch (Exception e) {
+ log.error("发送消息到腾讯IM异常,将尝试通过其他方式发送", e);
+ }
+ return true;
+ }
+
+ public String processMessageVariables(String content, Map variables) {
+ if (content == null || variables == null || variables.isEmpty()) {
+ return content;
+ }
+ for (String key : variables.keySet()) {
+ content = content.replaceAll("\\$\\{" + key + "\\}", variables.get(key).toString());
+ }
+ return content;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/SysMessageTemplateServiceImpl.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/SysMessageTemplateServiceImpl.java
index cf98d70ac..f5105e27a 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/SysMessageTemplateServiceImpl.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/SysMessageTemplateServiceImpl.java
@@ -78,4 +78,10 @@ public class SysMessageTemplateServiceImpl extends ServiceImpl lqw = new LambdaQueryWrapper<>();
+ lqw.eq(SysMessageTemplate::getAction, action).eq(SysMessageTemplate::getStatus, 0);
+ return templateMapper.selectOne(lqw);
+ }
}
diff --git a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/TencentIMServiceImpl.java b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/TencentIMServiceImpl.java
index 36f96e25f..8c511fd11 100644
--- a/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/TencentIMServiceImpl.java
+++ b/ruoyi-modules/ruoyi-im/src/main/java/com/wzj/soopin/im/service/impl/TencentIMServiceImpl.java
@@ -171,7 +171,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
}
@Override
- public TencentIMResult sendMessageToTencentIM(String fromUserId, String toUserId, String msgBody,String cloudCustomData) {
+ public boolean sendMessageToTencentIM(String fromUserId, String toUserId, String msgBody,String cloudCustomData) {
TencentIMResult result = new TencentIMResult();
try {
String userSig = generateAdminUserSig();
@@ -206,10 +206,9 @@ public class TencentIMServiceImpl implements ITencentIMService {
result.setSuccess("OK".equals(result.getActionStatus()) && result.getErrorCode() == 0);
} catch (Exception e) {
log.error("发送消息到腾讯IM异常", e);
- result.setSuccess(false);
- result.setErrorInfo(e.getMessage());
+ return false;
}
- return result;
+ return true;
}
@Override
diff --git a/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/controller/FansController.java b/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/controller/FansController.java
index 38163a1d4..2c51086df 100644
--- a/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/controller/FansController.java
+++ b/ruoyi-modules/ruoyi-member/src/main/java/com/wzj/soopin/member/controller/FansController.java
@@ -22,6 +22,9 @@ import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mq.domain.MQMessage;
+import org.dromara.common.mq.enums.MessageActionEnum;
+import org.dromara.common.mq.utils.MqUtil;
import org.dromara.common.redis.utils.RedisUtils;
import org.springframework.web.bind.annotation.*;
@@ -88,201 +91,7 @@ public class FansController {
return R.ok(service.removeById(id));
}
- // 提取IM关注处理逻辑为私有方法
- private void handleImFollow(Long myId, List vloggerIds) {
- if (myId != null && vloggerIds != null) {
- for (Long vloggerId : vloggerIds) {
- service.doFollow(myId, vloggerId);
- }
- }
- }
- @PostMapping("follow")
- public Object follow(@RequestBody(required = false) Map callbackData,
- @RequestParam(required = false) Long myId,
- @RequestParam(required = false) Long vloggerId) {
- // 1. IM回调格式
- if (callbackData != null && callbackData.containsKey("CallbackCommand")) {
- log.info("收到IM关注回调: {}", callbackData);
-
- // 1.1 兼容腾讯IM的 PairList 回调格式
- Object pairListObj = callbackData.get("PairList");
- if (pairListObj instanceof List) {
- List> pairList = (List>) pairListObj;
- for (Object pairObj : pairList) {
- if (pairObj instanceof Map) {
- Map, ?> pair = (Map, ?>) pairObj;
- Object fromAccountObj = pair.get("From_Account");
- Object toAccountObj = pair.get("To_Account");
- if (fromAccountObj != null && toAccountObj != null) {
- Long fromId = null;
- Long toId = null;
- try {
- fromId = Long.valueOf(fromAccountObj.toString());
- toId = Long.valueOf(toAccountObj.toString());
- } catch (Exception e) {
- log.warn("IM回调Pair参数转换失败: {}", pair);
- continue;
- }
- service.doFollow(fromId, toId);
- log.info("IM回调处理成功: fromId={}, vloggerId={}", fromId, toId);
- } else {
- log.warn("IM回调Pair参数不完整: {}", pair);
- }
- }
- }
- // 返回IM平台要求的应答
- Map resp = new HashMap<>();
- resp.put("ActionStatus", "OK");
- resp.put("ErrorCode", 0);
- resp.put("ErrorInfo", "");
- return resp;
- }
-
- // 1.2 兼容原有 FollowList 格式
- String fromAccount = (String) callbackData.get("From_Account");
- List