修改消息通过腾讯im发送bug加模糊查询
This commit is contained in:
parent
3a66394bbe
commit
297b0332da
@ -298,13 +298,8 @@ justauth:
|
|||||||
# 腾讯云IM配置
|
# 腾讯云IM配置
|
||||||
tencent:
|
tencent:
|
||||||
im:
|
im:
|
||||||
# 腾讯云 SDKAppId
|
enabled: true # 启用腾讯云IM
|
||||||
sdkappid: 1600080789
|
sdk-app-id: 1600080789 # 你的腾讯云 SDKAppID
|
||||||
# 密钥
|
secret-key: "311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091" # 你的密钥
|
||||||
secretkey: 311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091
|
administrator: "administrator" # 管理员账号
|
||||||
# 签名过期时间(秒)
|
expire-time: 604800 # UserSig 过期时间(7天,单位:秒)
|
||||||
expire: 604800
|
|
||||||
# 管理员账号
|
|
||||||
admin: administrator
|
|
||||||
# API调用密钥
|
|
||||||
api-secret: 311b5309d714a20f7f5b54360ee21b1e24ec208ebcd25ce8f47d24753bccc091
|
|
||||||
|
@ -113,7 +113,7 @@ public class LogAspect {
|
|||||||
// 设置消耗时间
|
// 设置消耗时间
|
||||||
StopWatch stopWatch = KEY_CACHE.get();
|
StopWatch stopWatch = KEY_CACHE.get();
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
operLog.setCostTime(stopWatch.getDuration().toMillis());
|
operLog.setCostTime(stopWatch.getTime());
|
||||||
// 发布事件保存数据库
|
// 发布事件保存数据库
|
||||||
SpringUtils.context().publishEvent(operLog);
|
SpringUtils.context().publishEvent(operLog);
|
||||||
} catch (Exception exp) {
|
} catch (Exception exp) {
|
||||||
|
@ -67,7 +67,7 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
StopWatch stopWatch = KEY_CACHE.get();
|
StopWatch stopWatch = KEY_CACHE.get();
|
||||||
if (ObjectUtil.isNotNull(stopWatch)) {
|
if (ObjectUtil.isNotNull(stopWatch)) {
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getDuration().toMillis());
|
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
|
||||||
KEY_CACHE.remove();
|
KEY_CACHE.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,10 @@ import org.apache.rocketmq.spring.core.RocketMQListener;
|
|||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
import org.dromara.system.config.RocketMQConfig;
|
import org.dromara.system.config.RocketMQConfig;
|
||||||
import org.dromara.system.domain.SysMessageUser;
|
|
||||||
import org.dromara.system.domain.vo.SysMessageVo;
|
import org.dromara.system.domain.vo.SysMessageVo;
|
||||||
import org.dromara.system.mapper.SysMessageUserMapper;
|
|
||||||
import org.dromara.system.websocket.MessageWebSocketServer;
|
import org.dromara.system.websocket.MessageWebSocketServer;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RocketMQ消息消费者
|
* RocketMQ消息消费者
|
||||||
*
|
*
|
||||||
@ -32,7 +28,6 @@ import java.util.Date;
|
|||||||
public class MessageRocketMQConsumer implements RocketMQListener<String> {
|
public class MessageRocketMQConsumer implements RocketMQListener<String> {
|
||||||
|
|
||||||
private final MessageWebSocketServer messageWebSocketServer;
|
private final MessageWebSocketServer messageWebSocketServer;
|
||||||
private final SysMessageUserMapper messageUserMapper;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
@ -53,18 +48,6 @@ public class MessageRocketMQConsumer implements RocketMQListener<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (userIdLong != null) {
|
if (userIdLong != null) {
|
||||||
// 保存消息用户关联记录
|
|
||||||
try {
|
|
||||||
SysMessageUser messageUser = new SysMessageUser();
|
|
||||||
messageUser.setMessageId(wrapper.getMessage().getId());
|
|
||||||
messageUser.setUserId(userIdLong);
|
|
||||||
messageUser.setIsRead(false);
|
|
||||||
messageUserMapper.insert(messageUser);
|
|
||||||
log.info("消息用户关联记录保存成功,messageId: {}, userId: {}", wrapper.getMessage().getId(), userIdLong);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("保存消息用户关联记录失败", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送WebSocket消息
|
// 发送WebSocket消息
|
||||||
messageWebSocketServer.sendMessage(userIdLong, JsonUtils.toJsonString(wrapper.getMessage()));
|
messageWebSocketServer.sendMessage(userIdLong, JsonUtils.toJsonString(wrapper.getMessage()));
|
||||||
log.info("通过WebSocket发送消息成功,userId: {}", userIdLong);
|
log.info("通过WebSocket发送消息成功,userId: {}", userIdLong);
|
||||||
|
@ -2,6 +2,8 @@ package org.dromara.system.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.wzj.soopin.member.domain.po.Member;
|
||||||
|
import com.wzj.soopin.member.mapper.MemberMapper;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
@ -31,6 +33,9 @@ import org.dromara.system.domain.vo.SysUserVo;
|
|||||||
import org.dromara.system.service.ISysMessageService;
|
import org.dromara.system.service.ISysMessageService;
|
||||||
import org.dromara.system.service.ISysMessageTemplateService;
|
import org.dromara.system.service.ISysMessageTemplateService;
|
||||||
import org.dromara.system.service.ISysUserService;
|
import org.dromara.system.service.ISysUserService;
|
||||||
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@ -51,6 +56,7 @@ public class SysMessageController extends BaseController {
|
|||||||
private final ISysMessageService messageService;
|
private final ISysMessageService messageService;
|
||||||
private final ISysUserService userService;
|
private final ISysUserService userService;
|
||||||
private final ISysMessageTemplateService templateService;
|
private final ISysMessageTemplateService templateService;
|
||||||
|
private final MemberMapper umsMemberMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前用户ID
|
* 获取当前用户ID
|
||||||
@ -107,12 +113,12 @@ public class SysMessageController extends BaseController {
|
|||||||
return R.fail("未找到指定的消息模板");
|
return R.fail("未找到指定的消息模板");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证消息内容是否为空
|
// 验证消息内容是否为空
|
||||||
if (StringUtils.isBlank(bo.getContent())) {
|
if (StringUtils.isBlank(bo.getContent())) {
|
||||||
return R.fail("消息内容不能为空");
|
return R.fail("消息内容不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证发送范围是否为空
|
// 验证发送范围是否为空
|
||||||
List<String> sendScope = bo.getSendScope();
|
List<String> sendScope = bo.getSendScope();
|
||||||
if (sendScope == null || sendScope.isEmpty()) {
|
if (sendScope == null || sendScope.isEmpty()) {
|
||||||
@ -129,37 +135,35 @@ public class SysMessageController extends BaseController {
|
|||||||
if (sendScope == null || sendScope.isEmpty()) {
|
if (sendScope == null || sendScope.isEmpty()) {
|
||||||
return R.fail("发送范围不能为空");
|
return R.fail("发送范围不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
String scope = sendScope.get(0); // 获取第一个范围值
|
String scope = sendScope.get(0); // 获取第一个范围值
|
||||||
|
|
||||||
switch (logmess) {
|
switch (logmess) {
|
||||||
case 1: // 指定角色
|
case 1: // 指定角色
|
||||||
// 当logmess=1时,sendScope接收的是角色ID或特殊标识
|
// 当logmess=1时,sendScope接收的是角色ID或特殊标识
|
||||||
if ("all".equals(scope) || "expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
|
if ("all".equals(scope)) {
|
||||||
|
// 全部会员用户(查ums_member表)
|
||||||
|
List<Member> members = umsMemberMapper.selectList(
|
||||||
|
new QueryWrapper<Member>().eq("status", 1)
|
||||||
|
);
|
||||||
|
userIdStrings = members.stream().map(m -> String.valueOf(m.getId())).toList();
|
||||||
|
} else if ("expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
|
||||||
List<SysUserVo> users = userService.selectUserListByDept(null);
|
List<SysUserVo> users = userService.selectUserListByDept(null);
|
||||||
List<Long> userIds;
|
List<Long> userIds;
|
||||||
|
|
||||||
switch (scope) {
|
switch (scope) {
|
||||||
case "all":
|
|
||||||
// 全部用户
|
|
||||||
userIds = users.stream().map(SysUserVo::getUserId).toList();
|
|
||||||
break;
|
|
||||||
case "expert":
|
case "expert":
|
||||||
// 达人
|
|
||||||
userIds = users.stream()
|
userIds = users.stream()
|
||||||
.filter(user -> "expert".equals(user.getUserType()))
|
.filter(user -> "expert".equals(user.getUserType()))
|
||||||
.map(SysUserVo::getUserId)
|
.map(SysUserVo::getUserId)
|
||||||
.toList();
|
.toList();
|
||||||
break;
|
break;
|
||||||
case "merchant":
|
case "merchant":
|
||||||
// 商户
|
|
||||||
userIds = users.stream()
|
userIds = users.stream()
|
||||||
.filter(user -> "merchant".equals(user.getUserType()))
|
.filter(user -> "merchant".equals(user.getUserType()))
|
||||||
.map(SysUserVo::getUserId)
|
.map(SysUserVo::getUserId)
|
||||||
.toList();
|
.toList();
|
||||||
break;
|
break;
|
||||||
case "user":
|
case "user":
|
||||||
// 普通用户
|
|
||||||
userIds = users.stream()
|
userIds = users.stream()
|
||||||
.filter(user -> "user".equals(user.getUserType()))
|
.filter(user -> "user".equals(user.getUserType()))
|
||||||
.map(SysUserVo::getUserId)
|
.map(SysUserVo::getUserId)
|
||||||
@ -220,14 +224,14 @@ public class SysMessageController extends BaseController {
|
|||||||
if (sendScope == null || sendScope.isEmpty()) {
|
if (sendScope == null || sendScope.isEmpty()) {
|
||||||
return R.fail("发送范围不能为空");
|
return R.fail("发送范围不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
String scope = sendScope.get(0); // 获取第一个范围值
|
String scope = sendScope.get(0); // 获取第一个范围值
|
||||||
|
|
||||||
// 如果是群发消息类型,则根据类型筛选用户
|
// 如果是群发消息类型,则根据类型筛选用户
|
||||||
if ("all".equals(scope) || "expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
|
if ("all".equals(scope) || "expert".equals(scope) || "merchant".equals(scope) || "user".equals(scope)) {
|
||||||
List<SysUserVo> users = userService.selectUserListByDept(null);
|
List<SysUserVo> users = userService.selectUserListByDept(null);
|
||||||
List<Long> userIds;
|
List<Long> userIds;
|
||||||
|
|
||||||
switch (scope) {
|
switch (scope) {
|
||||||
case "all":
|
case "all":
|
||||||
// 全部用户
|
// 全部用户
|
||||||
|
@ -14,6 +14,8 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
|
|||||||
import org.dromara.system.domain.SysMessage;
|
import org.dromara.system.domain.SysMessage;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -85,16 +87,25 @@ public class SysMessageBo extends BaseAudit {
|
|||||||
/** 备注 */
|
/** 备注 */
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
/** 创建时间-起始 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
|
||||||
|
private LocalDateTime startTime;
|
||||||
|
/** 创建时间-结束 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
|
||||||
|
private LocalDateTime sendTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为查询条件
|
* 转换为查询条件
|
||||||
*/
|
*/
|
||||||
public LambdaQueryWrapper<SysMessage> toWrapper() {
|
public LambdaQueryWrapper<SysMessage> toWrapper() {
|
||||||
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<SysMessage> lqw = new LambdaQueryWrapper<>();
|
||||||
lqw.like(StringUtils.isNotBlank(this.getTitle()), SysMessage::getTitle, this.getTitle())
|
lqw.like(StringUtils.isNotBlank(this.getTitle()), SysMessage::getTitle, this.getTitle())
|
||||||
|
.like(StringUtils.isNotBlank(this.getContent()), SysMessage::getContent, this.getContent())
|
||||||
.eq(StringUtils.isNotBlank(this.getMsgType()), SysMessage::getMsgType, this.getMsgType())
|
.eq(StringUtils.isNotBlank(this.getMsgType()), SysMessage::getMsgType, this.getMsgType())
|
||||||
.eq(StringUtils.isNotBlank(this.getSubType()), SysMessage::getSubType, this.getSubType())
|
.eq(StringUtils.isNotBlank(this.getSubType()), SysMessage::getSubType, this.getSubType())
|
||||||
.eq(this.getSenderId() != null, SysMessage::getSenderId, this.getSenderId())
|
.eq(this.getSenderId() != null, SysMessage::getSenderId, this.getSenderId())
|
||||||
// .eq(StringUtils.isNotBlank(this.getStatus()), SysMessage::getStatus, this.getStatus())
|
.ge(this.getStartTime() != null, SysMessage::getCreateTime, this.getStartTime())
|
||||||
|
.le(this.getSendTime() != null, SysMessage::getCreateTime, this.getSendTime())
|
||||||
.orderByDesc(SysMessage::getCreateTime);
|
.orderByDesc(SysMessage::getCreateTime);
|
||||||
return lqw;
|
return lqw;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.dromara.system.event;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
import org.dromara.system.config.RocketMQConfig;
|
import org.dromara.system.config.RocketMQConfig;
|
||||||
import org.dromara.system.consumer.MessageRocketMQConsumer;
|
import org.dromara.system.consumer.MessageRocketMQConsumer;
|
||||||
@ -61,7 +62,7 @@ public class MessageEventListener {
|
|||||||
// 消息发送者可能是系统或管理员,这里使用固定的管理员账号作为发送者
|
// 消息发送者可能是系统或管理员,这里使用固定的管理员账号作为发送者
|
||||||
String fromUserId = "administrator";
|
String fromUserId = "administrator";
|
||||||
String toUserId = userId; // 接收者是事件中的用户ID
|
String toUserId = userId; // 接收者是事件中的用户ID
|
||||||
String content = JsonUtils.toJsonString(event.getMessage()); // 消息内容序列化为JSON
|
String content = event.getMessage().getContent(); // 只取content字段
|
||||||
|
|
||||||
// 处理消息变量替换(如果有)
|
// 处理消息变量替换(如果有)
|
||||||
Map<String, String> variables = new HashMap<>();
|
Map<String, String> variables = new HashMap<>();
|
||||||
@ -127,7 +128,7 @@ public class MessageEventListener {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 默认为单用户推送
|
// 默认为单用户推送
|
||||||
tencentIMSendSuccess = tencentIMService.sendMessageToTencentIM(fromUserId, toUserId, content);
|
tencentIMSendSuccess = tencentIMService.sendMessageToTencentIM(fromUserId, toUserId, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tencentIMSendSuccess) {
|
if (tencentIMSendSuccess) {
|
||||||
@ -141,6 +142,7 @@ public class MessageEventListener {
|
|||||||
|
|
||||||
// 无论腾讯IM是否发送成功,都继续尝试通过RocketMQ发送消息
|
// 无论腾讯IM是否发送成功,都继续尝试通过RocketMQ发送消息
|
||||||
// 这样可以确保消息至少通过一种方式发送出去
|
// 这样可以确保消息至少通过一种方式发送出去
|
||||||
|
/*
|
||||||
boolean rocketMQSendSuccess = false;
|
boolean rocketMQSendSuccess = false;
|
||||||
try {
|
try {
|
||||||
rocketMQService.sendMessage(
|
rocketMQService.sendMessage(
|
||||||
@ -153,6 +155,8 @@ public class MessageEventListener {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("通过RocketMQ发送消息失败,将尝试直接通过WebSocket发送", e);
|
log.error("通过RocketMQ发送消息失败,将尝试直接通过WebSocket发送", e);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
boolean rocketMQSendSuccess = false; // 直接设为false,表示不走MQ
|
||||||
|
|
||||||
// 如果前两种方式都失败,则尝试直接通过WebSocket发送
|
// 如果前两种方式都失败,则尝试直接通过WebSocket发送
|
||||||
if (!tencentIMSendSuccess && !rocketMQSendSuccess && event.getUserId() != null) {
|
if (!tencentIMSendSuccess && !rocketMQSendSuccess && event.getUserId() != null) {
|
||||||
|
@ -22,7 +22,10 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,6 +131,11 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
|
|
||||||
// 批量创建消息用户关联
|
// 批量创建消息用户关联
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
|
// 先过滤有效的用户ID
|
||||||
|
List<Long> validUserIds = new ArrayList<>();
|
||||||
|
Map<Long, String> userIdStrMap = new HashMap<>();
|
||||||
|
|
||||||
for (String userIdStr : userIds) {
|
for (String userIdStr : userIds) {
|
||||||
if (StringUtils.isBlank(userIdStr)) {
|
if (StringUtils.isBlank(userIdStr)) {
|
||||||
continue;
|
continue;
|
||||||
@ -135,37 +143,61 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Long userId = Long.parseLong(userIdStr);
|
Long userId = Long.parseLong(userIdStr);
|
||||||
|
validUserIds.add(userId);
|
||||||
// 检查消息与用户关联是否已存在
|
userIdStrMap.put(userId, userIdStr);
|
||||||
LambdaQueryWrapper<SysMessageUser> queryWrapper = new LambdaQueryWrapper<>();
|
} catch (NumberFormatException e) {
|
||||||
queryWrapper.eq(SysMessageUser::getMessageId, entity.getId())
|
log.error("无法将String类型的用户ID转换为Long: {}", userIdStr);
|
||||||
.eq(SysMessageUser::getUserId, userId);
|
}
|
||||||
int existCount = Math.toIntExact(messageUserMapper.selectCount(queryWrapper));
|
}
|
||||||
|
|
||||||
// 只有当关联不存在时才创建
|
// 一次性查询所有已存在的关联记录
|
||||||
if (existCount == 0) {
|
if (!validUserIds.isEmpty()) {
|
||||||
SysMessageUser messageUser = new SysMessageUser();
|
LambdaQueryWrapper<SysMessageUser> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
messageUser.setMessageId(entity.getId());
|
queryWrapper.eq(SysMessageUser::getMessageId, entity.getId())
|
||||||
messageUser.setUserId(userId);
|
.in(SysMessageUser::getUserId, validUserIds);
|
||||||
messageUser.setIsRead(false);
|
List<SysMessageUser> existingRecords = messageUserMapper.selectList(queryWrapper);
|
||||||
int rows = messageUserMapper.insert(messageUser);
|
|
||||||
if (rows > 0) {
|
// 创建已存在用户ID的集合
|
||||||
count++;
|
Set<Long> existingUserIds = existingRecords.stream()
|
||||||
|
.map(SysMessageUser::getUserId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
log.info("已存在的消息关联记录数: {}", existingUserIds.size());
|
||||||
|
|
||||||
|
// 对不存在关联的用户批量插入
|
||||||
|
for (Long userId : validUserIds) {
|
||||||
|
if (!existingUserIds.contains(userId)) {
|
||||||
|
try {
|
||||||
|
SysMessageUser messageUser = new SysMessageUser();
|
||||||
|
messageUser.setMessageId(entity.getId());
|
||||||
|
messageUser.setUserId(userId);
|
||||||
|
messageUser.setIsRead(false);
|
||||||
|
int rows = messageUserMapper.insert(messageUser);
|
||||||
|
if (rows > 0) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建消息用户关联失败: messageId={}, userId={}, error={}",
|
||||||
|
entity.getId(), userId, e.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.info("消息与用户关联已存在,跳过创建: messageId={}, userId={}", entity.getId(), userId);
|
log.info("消息与用户关联已存在,跳过创建: messageId={}, userId={}", entity.getId(), userId);
|
||||||
// 已存在也计入成功数量
|
// 已存在也计入成功数量
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无论关联是否新建,都发送事件通知
|
|
||||||
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
|
||||||
eventPublisher.publishEvent(MessageEvent.createWithStringUserId(this, messageVo, userIdStr));
|
|
||||||
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
log.error("无法将String类型的用户ID转换为Long: {}", userIdStr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 最后只发送一次批量事件通知
|
||||||
|
if (count > 0) {
|
||||||
|
SysMessageVo messageVo = MapstructUtils.convert(entity, SysMessageVo.class);
|
||||||
|
// 为所有有效用户ID组装一个逗号分隔的字符串
|
||||||
|
String batchUserIds = validUserIds.stream()
|
||||||
|
.map(String::valueOf)
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
// 发布一个批量事件,在MessageEvent和MessageEventListener中进行处理
|
||||||
|
eventPublisher.publishEvent(MessageEvent.createWithStringUserId(this, messageVo, batchUserIds));
|
||||||
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.dromara.system.service.impl;
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.system.service.ITencentIMService;
|
import org.dromara.system.service.ITencentIMService;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -8,9 +9,17 @@ import org.springframework.http.*;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.util.Base64;
|
||||||
|
import com.wzj.soopin.member.util.TLSSigAPIv2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 腾讯IM服务实现类
|
* 腾讯IM服务实现类
|
||||||
@ -21,20 +30,30 @@ import java.util.regex.Pattern;
|
|||||||
@Service("systemTencentIMService")
|
@Service("systemTencentIMService")
|
||||||
public class TencentIMServiceImpl implements ITencentIMService {
|
public class TencentIMServiceImpl implements ITencentIMService {
|
||||||
|
|
||||||
@Value("${tencent.im.sdkappid}")
|
@Value("${tencent.im.sdk-app-id}")
|
||||||
private long sdkAppId;
|
private long sdkAppId;
|
||||||
|
|
||||||
@Value("${tencent.im.secretkey}")
|
@Value("${tencent.im.secret-key}")
|
||||||
private String secretKey;
|
private String secretKey;
|
||||||
|
|
||||||
@Value("${tencent.im.admin}")
|
@Value("${tencent.im.administrator}")
|
||||||
private String adminAccount;
|
private String adminAccount;
|
||||||
|
|
||||||
|
@Value("${tencent.im.expire-time:180}")
|
||||||
|
private int expireTime;
|
||||||
|
|
||||||
private final RestTemplate restTemplate = new RestTemplate();
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
// 变量替换的正则表达式模式
|
// 变量替换的正则表达式模式
|
||||||
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$(\\w+)");
|
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$(\\w+)");
|
||||||
|
|
||||||
|
private TLSSigAPIv2 tlsSigApi;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void initTlsSigApi() {
|
||||||
|
this.tlsSigApi = new TLSSigAPIv2(sdkAppId, secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成用户签名
|
* 生成用户签名
|
||||||
*
|
*
|
||||||
@ -42,28 +61,84 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
* @return 用户签名
|
* @return 用户签名
|
||||||
*/
|
*/
|
||||||
private String generateUserSig(String userId) {
|
private String generateUserSig(String userId) {
|
||||||
// 注意: 这里需要实现腾讯云IM SDK的TLSSigAPIv2签名生成
|
// 直接调用官方TLSSigAPIv2生成
|
||||||
// 参考腾讯云文档: https://cloud.tencent.com/document/product/269/32688
|
return tlsSigApi.genUserSig("administrator", expireTime);
|
||||||
// 实现方法:
|
}
|
||||||
// 1. 导入腾讯云IM SDK依赖
|
|
||||||
// 2. 使用sdkAppId和secretKey生成签名
|
/**
|
||||||
// 示例代码:
|
* 生成 tls 票据
|
||||||
// TLSSigAPIv2 tlsSigApi = new TLSSigAPIv2(sdkAppId, secretKey);
|
*
|
||||||
// return tlsSigApi.genUserSig(userId, 86400); // 有效期设为1天(86400秒)
|
* @param sdkappid 应用的 appid
|
||||||
|
* @param userId 用户id
|
||||||
log.info("生成用户签名: {}", userId);
|
* @param expire 有效期 (时间戳 单位秒)
|
||||||
|
* @param priKeyContent 私钥文件内容
|
||||||
// 当前为模拟实现,实际项目中请替换为真实签名生成逻辑
|
* @return 通过 base64 编码的 tls 票据
|
||||||
|
*/
|
||||||
|
private String genTLSSignature(long sdkappid, String userId, long expire, String priKeyContent) {
|
||||||
try {
|
try {
|
||||||
// 临时返回一个固定值用于测试
|
JSONObject sigDoc = new JSONObject();
|
||||||
// 注意:这是临时方案,正式环境必须替换为正确实现
|
sigDoc.put("TLS.ver", "2.0");
|
||||||
return "eJyrVgrxDXFSsrS0MDA2MzY1NTawNDAzsTQ1sTCyMDI2NdRRKs9ILUpVsjKoLEgsKk7NswlPzYnIsagoyIgrsYl3Lg5IALITi5BkS1JzSlOLbMJKi32DKtNCglONDSNNXfMqk3wN0myrvVUYGBgYGZiaGBoamCgZ6hlYGOUb6Rmaq1QHAAD--wJe";
|
sigDoc.put("TLS.identifier", userId);
|
||||||
|
sigDoc.put("TLS.sdkappid", sdkappid);
|
||||||
|
sigDoc.put("TLS.expire", expire);
|
||||||
|
sigDoc.put("TLS.time", System.currentTimeMillis() / 1000);
|
||||||
|
|
||||||
|
String base64UserBuf = null;
|
||||||
|
if (null != userId) {
|
||||||
|
base64UserBuf = base64EncodeUrl(userId.getBytes(StandardCharsets.UTF_8));
|
||||||
|
sigDoc.put("TLS.userbuf", base64UserBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
String sig = hmacSHA256(sdkappid, userId, expire, priKeyContent, base64UserBuf);
|
||||||
|
if (sig.length() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
sigDoc.put("TLS.sig", sig);
|
||||||
|
Deflater compressor = new Deflater();
|
||||||
|
compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
compressor.finish();
|
||||||
|
byte[] compressedBytes = new byte[2048];
|
||||||
|
int compressedBytesLength = compressor.deflate(compressedBytes);
|
||||||
|
compressor.end();
|
||||||
|
return base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("生成用户签名异常", e);
|
log.error("生成tls票据异常", e);
|
||||||
return null;
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 HMAC-SHA256 生成签名
|
||||||
|
*/
|
||||||
|
private String hmacSHA256(long sdkappid, String userId, long expire, String priKeyContent, String base64UserBuf) {
|
||||||
|
try {
|
||||||
|
String contentToBeSigned = "TLS.identifier:" + "administrator" + "\n"
|
||||||
|
+ "TLS.sdkappid:" + sdkappid + "\n"
|
||||||
|
+ "TLS.time:" + System.currentTimeMillis() / 1000 + "\n"
|
||||||
|
+ "TLS.expire:" + expire + "\n";
|
||||||
|
if (null != base64UserBuf) {
|
||||||
|
contentToBeSigned += "TLS.userbuf:" + base64UserBuf + "\n";
|
||||||
|
}
|
||||||
|
byte[] byteKey = priKeyContent.getBytes(StandardCharsets.UTF_8);
|
||||||
|
Mac hmac = Mac.getInstance("HmacSHA256");
|
||||||
|
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
|
||||||
|
hmac.init(keySpec);
|
||||||
|
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return base64EncodeUrl(byteSig);
|
||||||
|
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组使用 base64 编码(URL 安全)
|
||||||
|
*/
|
||||||
|
private String base64EncodeUrl(byte[] data) {
|
||||||
|
byte[] encodedBytes = Base64.getEncoder().encode(data);
|
||||||
|
String encodedStr = new String(encodedBytes);
|
||||||
|
return encodedStr.replace('+', '*').replace('/', '-').replace('=', '_');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成管理员签名
|
* 生成管理员签名
|
||||||
*
|
*
|
||||||
@ -92,17 +167,17 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
Map<String, Object> requestBody = new HashMap<>();
|
Map<String, Object> requestBody = new HashMap<>();
|
||||||
requestBody.put("UserID", userId);
|
requestBody.put("UserID", userId);
|
||||||
requestBody.put("Nick", userId);
|
requestBody.put("Nick", userId);
|
||||||
|
|
||||||
// 设置请求头
|
// 设置请求头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
log.info("创建腾讯IM账号结果: {}", response.getBody());
|
log.info("创建腾讯IM账号结果: {}", response.getBody());
|
||||||
|
|
||||||
// 生成并返回用户签名
|
// 生成并返回用户签名
|
||||||
return generateUserSig(userId);
|
return generateUserSig(userId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -146,13 +221,13 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
// 设置请求头
|
// 设置请求头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
log.info("发送消息到腾讯IM结果: {}", response.getBody());
|
log.info("发送消息到腾讯IM结果: {}", response.getBody());
|
||||||
|
|
||||||
// 解析响应判断是否成功
|
// 解析响应判断是否成功
|
||||||
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
return "OK".equals(responseJson.getString("ActionStatus"));
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
@ -161,7 +236,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pushToAll(String title, String desc, boolean offlinePush, String ext) {
|
public boolean pushToAll(String title, String desc, boolean offlinePush, String ext) {
|
||||||
try {
|
try {
|
||||||
@ -181,12 +256,12 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
Map<String, Object> msgContent = new HashMap<>();
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
msgContent.put("Title", title);
|
msgContent.put("Title", title);
|
||||||
msgContent.put("Desc", desc);
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
// 构建消息体
|
// 构建消息体
|
||||||
Map<String, Object> msgBody = new HashMap<>();
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
msgBody.put("MsgType", "TIMCustomElem");
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
msgBody.put("MsgContent", msgContent);
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
// 如果有扩展字段,添加到消息内容中
|
// 如果有扩展字段,添加到消息内容中
|
||||||
if (ext != null && !ext.isEmpty()) {
|
if (ext != null && !ext.isEmpty()) {
|
||||||
msgContent.put("Ext", ext);
|
msgContent.put("Ext", ext);
|
||||||
@ -197,7 +272,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
requestBody.put("From_Account", adminAccount);
|
requestBody.put("From_Account", adminAccount);
|
||||||
requestBody.put("MsgRandom", Integer.parseInt(random));
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
requestBody.put("MsgBody", new Object[]{msgBody});
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
|
||||||
// 设置离线推送信息
|
// 设置离线推送信息
|
||||||
if (offlinePush) {
|
if (offlinePush) {
|
||||||
Map<String, Object> offlinePushInfo = new HashMap<>();
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
@ -211,13 +286,13 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
// 设置请求头
|
// 设置请求头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
log.info("全员推送消息结果: {}", response.getBody());
|
log.info("全员推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
// 解析响应判断是否成功
|
// 解析响应判断是否成功
|
||||||
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
return "OK".equals(responseJson.getString("ActionStatus"));
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
@ -226,7 +301,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pushByAttributes(String title, String desc, Map<String, Object> attributes, boolean offlinePush, String ext) {
|
public boolean pushByAttributes(String title, String desc, Map<String, Object> attributes, boolean offlinePush, String ext) {
|
||||||
try {
|
try {
|
||||||
@ -246,12 +321,12 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
Map<String, Object> msgContent = new HashMap<>();
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
msgContent.put("Title", title);
|
msgContent.put("Title", title);
|
||||||
msgContent.put("Desc", desc);
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
// 构建消息体
|
// 构建消息体
|
||||||
Map<String, Object> msgBody = new HashMap<>();
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
msgBody.put("MsgType", "TIMCustomElem");
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
msgBody.put("MsgContent", msgContent);
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
// 如果有扩展字段,添加到消息内容中
|
// 如果有扩展字段,添加到消息内容中
|
||||||
if (ext != null && !ext.isEmpty()) {
|
if (ext != null && !ext.isEmpty()) {
|
||||||
msgContent.put("Ext", ext);
|
msgContent.put("Ext", ext);
|
||||||
@ -264,7 +339,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
requestBody.put("MsgBody", new Object[]{msgBody});
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
requestBody.put("AttrNames", attributes.keySet().toArray(new String[0]));
|
requestBody.put("AttrNames", attributes.keySet().toArray(new String[0]));
|
||||||
requestBody.put("AttrValues", attributes.values().toArray());
|
requestBody.put("AttrValues", attributes.values().toArray());
|
||||||
|
|
||||||
// 设置离线推送信息
|
// 设置离线推送信息
|
||||||
if (offlinePush) {
|
if (offlinePush) {
|
||||||
Map<String, Object> offlinePushInfo = new HashMap<>();
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
@ -278,13 +353,13 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
// 设置请求头
|
// 设置请求头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
log.info("属性推送消息结果: {}", response.getBody());
|
log.info("属性推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
// 解析响应判断是否成功
|
// 解析响应判断是否成功
|
||||||
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
return "OK".equals(responseJson.getString("ActionStatus"));
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
@ -293,7 +368,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pushByTags(String title, String desc, List<String> tags, boolean offlinePush, String ext) {
|
public boolean pushByTags(String title, String desc, List<String> tags, boolean offlinePush, String ext) {
|
||||||
try {
|
try {
|
||||||
@ -313,12 +388,12 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
Map<String, Object> msgContent = new HashMap<>();
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
msgContent.put("Title", title);
|
msgContent.put("Title", title);
|
||||||
msgContent.put("Desc", desc);
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
// 构建消息体
|
// 构建消息体
|
||||||
Map<String, Object> msgBody = new HashMap<>();
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
msgBody.put("MsgType", "TIMCustomElem");
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
msgBody.put("MsgContent", msgContent);
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
// 如果有扩展字段,添加到消息内容中
|
// 如果有扩展字段,添加到消息内容中
|
||||||
if (ext != null && !ext.isEmpty()) {
|
if (ext != null && !ext.isEmpty()) {
|
||||||
msgContent.put("Ext", ext);
|
msgContent.put("Ext", ext);
|
||||||
@ -330,7 +405,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
requestBody.put("MsgRandom", Integer.parseInt(random));
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
requestBody.put("MsgBody", new Object[]{msgBody});
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
requestBody.put("TagList", tags);
|
requestBody.put("TagList", tags);
|
||||||
|
|
||||||
// 设置离线推送信息
|
// 设置离线推送信息
|
||||||
if (offlinePush) {
|
if (offlinePush) {
|
||||||
Map<String, Object> offlinePushInfo = new HashMap<>();
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
@ -344,13 +419,13 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
// 设置请求头
|
// 设置请求头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
log.info("标签推送消息结果: {}", response.getBody());
|
log.info("标签推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
// 解析响应判断是否成功
|
// 解析响应判断是否成功
|
||||||
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
return "OK".equals(responseJson.getString("ActionStatus"));
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
@ -359,7 +434,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean pushToUsers(String title, String desc, List<String> userIds, boolean offlinePush, String ext) {
|
public boolean pushToUsers(String title, String desc, List<String> userIds, boolean offlinePush, String ext) {
|
||||||
try {
|
try {
|
||||||
@ -379,12 +454,12 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
Map<String, Object> msgContent = new HashMap<>();
|
Map<String, Object> msgContent = new HashMap<>();
|
||||||
msgContent.put("Title", title);
|
msgContent.put("Title", title);
|
||||||
msgContent.put("Desc", desc);
|
msgContent.put("Desc", desc);
|
||||||
|
|
||||||
// 构建消息体
|
// 构建消息体
|
||||||
Map<String, Object> msgBody = new HashMap<>();
|
Map<String, Object> msgBody = new HashMap<>();
|
||||||
msgBody.put("MsgType", "TIMCustomElem");
|
msgBody.put("MsgType", "TIMCustomElem");
|
||||||
msgBody.put("MsgContent", msgContent);
|
msgBody.put("MsgContent", msgContent);
|
||||||
|
|
||||||
// 如果有扩展字段,添加到消息内容中
|
// 如果有扩展字段,添加到消息内容中
|
||||||
if (ext != null && !ext.isEmpty()) {
|
if (ext != null && !ext.isEmpty()) {
|
||||||
msgContent.put("Ext", ext);
|
msgContent.put("Ext", ext);
|
||||||
@ -396,7 +471,7 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
requestBody.put("To_Account", userIds);
|
requestBody.put("To_Account", userIds);
|
||||||
requestBody.put("MsgRandom", Integer.parseInt(random));
|
requestBody.put("MsgRandom", Integer.parseInt(random));
|
||||||
requestBody.put("MsgBody", new Object[]{msgBody});
|
requestBody.put("MsgBody", new Object[]{msgBody});
|
||||||
|
|
||||||
// 设置离线推送信息
|
// 设置离线推送信息
|
||||||
if (offlinePush) {
|
if (offlinePush) {
|
||||||
Map<String, Object> offlinePushInfo = new HashMap<>();
|
Map<String, Object> offlinePushInfo = new HashMap<>();
|
||||||
@ -410,13 +485,13 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
// 设置请求头
|
// 设置请求头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
|
||||||
|
|
||||||
log.info("指定用户推送消息结果: {}", response.getBody());
|
log.info("指定用户推送消息结果: {}", response.getBody());
|
||||||
|
|
||||||
// 解析响应判断是否成功
|
// 解析响应判断是否成功
|
||||||
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
JSONObject responseJson = JSONObject.parseObject(response.getBody());
|
||||||
return "OK".equals(responseJson.getString("ActionStatus"));
|
return "OK".equals(responseJson.getString("ActionStatus"));
|
||||||
@ -425,23 +500,23 @@ public class TencentIMServiceImpl implements ITencentIMService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String processMessageVariables(String content, Map<String, String> variables) {
|
public String processMessageVariables(String content, Map<String, String> variables) {
|
||||||
if (content == null || variables == null || variables.isEmpty()) {
|
if (content == null || variables == null || variables.isEmpty()) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matcher matcher = VARIABLE_PATTERN.matcher(content);
|
Matcher matcher = VARIABLE_PATTERN.matcher(content);
|
||||||
StringBuffer sb = new StringBuffer();
|
StringBuffer sb = new StringBuffer();
|
||||||
|
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String variableName = matcher.group(1);
|
String variableName = matcher.group(1);
|
||||||
String replacement = variables.getOrDefault(variableName, "$" + variableName);
|
String replacement = variables.getOrDefault(variableName, "$" + variableName);
|
||||||
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
||||||
}
|
}
|
||||||
|
|
||||||
matcher.appendTail(sb);
|
matcher.appendTail(sb);
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user