修改回调整合分发模式
This commit is contained in:
parent
5e239c99a4
commit
83ed8e4150
@ -87,33 +87,12 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int sendMessageToUser(SysMessageBo message, Long userId) {
|
public int sendMessageToUser(SysMessageBo message, Long userId) {
|
||||||
|
|
||||||
|
|
||||||
|
//加一个约定
|
||||||
// 保存消息
|
// 保存消息
|
||||||
SysMessage entity = message.toEntity();
|
SysMessage entity = message.toEntity();
|
||||||
Date scheduledTime = entity.getScheduledTime();
|
Date scheduledTime = entity.getScheduledTime();
|
||||||
// if (scheduledTime != null && scheduledTime.after(new Date())) {
|
|
||||||
// entity.setStatus("0"); // 未发送
|
|
||||||
// messageMapper.insert(entity);
|
|
||||||
// // 注册SnailJob单次任务
|
|
||||||
// SnailJobApiUtil.createSingleJob(entity.getId(), scheduledTime);
|
|
||||||
// // 检查消息与用户关联是否已存在
|
|
||||||
// LambdaQueryWrapper<SysMessageUser> queryWrapper = new LambdaQueryWrapper<>();
|
|
||||||
// queryWrapper.eq(SysMessageUser::getMessageId, entity.getId())
|
|
||||||
// .eq(SysMessageUser::getUserId, userId);
|
|
||||||
// int count = Math.toIntExact(messageUserMapper.selectCount(queryWrapper));
|
|
||||||
// int rows = 0;
|
|
||||||
// if (count == 0) {
|
|
||||||
// SysMessageUser messageUser = new SysMessageUser();
|
|
||||||
// messageUser.setMessageId(entity.getId());
|
|
||||||
// messageUser.setUserId(userId);
|
|
||||||
// messageUser.setIsRead(false);
|
|
||||||
// rows = messageUserMapper.insert(messageUser);
|
|
||||||
// } else {
|
|
||||||
// log.info("消息与用户关联已存在,跳过创建: messageId={}, userId={}", entity.getId(), userId);
|
|
||||||
// rows = 1;
|
|
||||||
// }
|
|
||||||
// // 定时消息不发布事件
|
|
||||||
// return rows;
|
|
||||||
// } else {
|
|
||||||
entity.setStatus("1"); // 已发送
|
entity.setStatus("1"); // 已发送
|
||||||
messageMapper.insert(entity);
|
messageMapper.insert(entity);
|
||||||
// 检查消息与用户关联是否已存在
|
// 检查消息与用户关联是否已存在
|
||||||
|
@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequestMapping("/ums/fans/")
|
@RequestMapping("/ums/fans/")
|
||||||
@ -103,6 +104,42 @@ public class FansController {
|
|||||||
// 1. IM回调格式
|
// 1. IM回调格式
|
||||||
if (callbackData != null && callbackData.containsKey("CallbackCommand")) {
|
if (callbackData != null && callbackData.containsKey("CallbackCommand")) {
|
||||||
log.info("收到IM关注回调: {}", callbackData);
|
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;
|
||||||
|
}
|
||||||
|
handleImFollow(fromId, java.util.Arrays.asList(toId));
|
||||||
|
log.info("IM回调处理成功: fromId={}, vloggerId={}", fromId, toId);
|
||||||
|
} else {
|
||||||
|
log.warn("IM回调Pair参数不完整: {}", pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 返回IM平台要求的应答
|
||||||
|
Map<String, Object> 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");
|
String fromAccount = (String) callbackData.get("From_Account");
|
||||||
List<Map<String, String>> followList = (List<Map<String, String>>) callbackData.get("FollowList");
|
List<Map<String, String>> followList = (List<Map<String, String>>) callbackData.get("FollowList");
|
||||||
if (fromAccount != null && followList != null) {
|
if (fromAccount != null && followList != null) {
|
||||||
@ -156,6 +193,47 @@ public class FansController {
|
|||||||
// 1. 判断是否为IM回调格式
|
// 1. 判断是否为IM回调格式
|
||||||
if (callbackData != null && callbackData.containsKey("CallbackCommand")) {
|
if (callbackData != null && callbackData.containsKey("CallbackCommand")) {
|
||||||
log.info("收到IM取消关注回调: {}", callbackData);
|
log.info("收到IM取消关注回调: {}", callbackData);
|
||||||
|
|
||||||
|
// 1.1 兼容腾讯IM的 PairList 回调格式
|
||||||
|
Object pairListObj = callbackData.get("PairList");
|
||||||
|
log.info("PairList 类型: {}, 内容: {}", pairListObj != null ? pairListObj.getClass() : "null", pairListObj);
|
||||||
|
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.doCancel(fromId, toId);
|
||||||
|
log.info("IM取消关注回调处理成功: fromId={}, toId={}", fromId, toId);
|
||||||
|
} else {
|
||||||
|
log.warn("IM取消关注回调Pair参数不完整: {}", pair);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("PairList元素不是Map: {}", pairObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 返回IM平台要求的应答
|
||||||
|
Map<String, Object> resp = new HashMap<>();
|
||||||
|
resp.put("ActionStatus", "OK");
|
||||||
|
resp.put("ErrorCode", 0);
|
||||||
|
resp.put("ErrorInfo", "");
|
||||||
|
return resp;
|
||||||
|
} else {
|
||||||
|
log.warn("PairList 不是 List 类型: {}", pairListObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.2 兼容原有 To_Account 逻辑
|
||||||
String fromAccount = (String) callbackData.get("From_Account");
|
String fromAccount = (String) callbackData.get("From_Account");
|
||||||
List<String> toAccounts = null;
|
List<String> toAccounts = null;
|
||||||
// 兼容腾讯IM的 To_Account 可能是 List<String> 或 List<Map<String, String>>
|
// 兼容腾讯IM的 To_Account 可能是 List<String> 或 List<Map<String, String>>
|
||||||
|
@ -0,0 +1,261 @@
|
|||||||
|
package com.wzj.soopin.member.controller;
|
||||||
|
|
||||||
|
import com.wzj.soopin.member.domain.po.Member;
|
||||||
|
import com.wzj.soopin.member.service.IMemberService;
|
||||||
|
import com.wzj.soopin.member.service.IFansService;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.dromara.common.core.constant.CacheConstants;
|
||||||
|
import org.dromara.common.redis.utils.RedisUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.wzj.soopin.member.service.IMemberBlockService;
|
||||||
|
import org.dromara.common.core.domain.R;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/callback/api")
|
||||||
|
public class ImCallbackController {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ImCallbackController.class);
|
||||||
|
// private static final String CALLBACK_TOKEN = "your_auth_token"; //
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMemberService memberService;
|
||||||
|
@Autowired
|
||||||
|
private IFansService fansService;
|
||||||
|
@Autowired
|
||||||
|
private FansController fansController;
|
||||||
|
@Autowired
|
||||||
|
private IMemberBlockService memberBlockService;
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public R handleCallback(
|
||||||
|
@RequestParam(value = "Sign", required = false) String sign,
|
||||||
|
@RequestParam(value = "RequestTime", required = false) String requestTime,
|
||||||
|
@RequestParam(value = "CallbackCommand", required = false) String callbackCommand,
|
||||||
|
@RequestBody Map<String, Object> requestBody) {
|
||||||
|
|
||||||
|
// // 1. 签名验证
|
||||||
|
// if (!verifySignature(CALLBACK_TOKEN, sign, requestTime)) {
|
||||||
|
// return Map.of("ActionStatus", "FAIL", "ErrorCode", 1001);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 2. 快速响应
|
||||||
|
R response = R.ok();
|
||||||
|
|
||||||
|
// 3. 分发业务逻辑
|
||||||
|
if (StringUtils.isBlank(callbackCommand)) {
|
||||||
|
return R.fail(1002, "缺少CallbackCommand");
|
||||||
|
}
|
||||||
|
switch (callbackCommand) {
|
||||||
|
case "Sns.CallbackFriendAdd":
|
||||||
|
// 关注,直接调用 FansController 的 follow
|
||||||
|
fansController.follow(requestBody, null, null);
|
||||||
|
break;
|
||||||
|
case "Sns.CallbackFriendDelete":
|
||||||
|
// 取关,直接调用 FansController 的 cancel
|
||||||
|
fansController.cancel(requestBody, null, null);
|
||||||
|
break;
|
||||||
|
case "Profile.CallbackPortraitSet":
|
||||||
|
// 资料修改
|
||||||
|
handleProfileCallbackPortraitSet(requestBody);
|
||||||
|
break;
|
||||||
|
case "Sns.CallbackBlackListAdd":
|
||||||
|
handleImAddBlock(requestBody);
|
||||||
|
break;
|
||||||
|
case "Sns.CallbackBlackListDelete":
|
||||||
|
handleImCancelBlock(requestBody);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.info("收到未知事件类型: {}, 参数: {}", callbackCommand, requestBody);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理IM关注事件
|
||||||
|
private void handleImFollow(Map<String, Object>requestBody) {
|
||||||
|
Object pairListObj = requestBody.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 = Long.valueOf(fromAccountObj.toString());
|
||||||
|
Long toId = Long.valueOf(toAccountObj.toString());
|
||||||
|
fansService.doFollow(fromId, toId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理IM取关事件
|
||||||
|
private void handleImCancel(Map<String, Object> requestBody) {
|
||||||
|
Object pairListObj = requestBody.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 = Long.valueOf(fromAccountObj.toString());
|
||||||
|
Long toId = Long.valueOf(toAccountObj.toString());
|
||||||
|
fansService.doCancel(fromId, toId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理IM黑名单添加事件
|
||||||
|
private void handleImAddBlock(Map<String, Object> requestBody) {
|
||||||
|
Object pairListObj = requestBody.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) {
|
||||||
|
try {
|
||||||
|
Long myId = Long.valueOf(fromAccountObj.toString());
|
||||||
|
Long vloggerId = Long.valueOf(toAccountObj.toString());
|
||||||
|
// 1. 判断两个id不能为空
|
||||||
|
if (myId == null || vloggerId == null) {
|
||||||
|
log.warn("黑名单回调参数id为空: myId={}, vloggerId={}", myId, vloggerId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 2. 是否已经存在关注关系
|
||||||
|
boolean flow = fansService.queryDoIFollowVloger(myId, vloggerId);
|
||||||
|
if (flow) {
|
||||||
|
// 删除关注
|
||||||
|
fansService.doCancel(myId, vloggerId);
|
||||||
|
// 博主的粉丝-1,我的关注-1
|
||||||
|
RedisUtils.decrAtomicValue(CacheConstants.MEMBER_FANS + ":" + vloggerId);
|
||||||
|
RedisUtils.decrAtomicValue(CacheConstants.MEMBER_FOLLOW + ":" + myId);
|
||||||
|
}
|
||||||
|
// 3. 检查是否已在黑名单中
|
||||||
|
boolean hasblock = memberBlockService.hasBlocked(myId, vloggerId);
|
||||||
|
if (hasblock) {
|
||||||
|
log.info("用户{}已拉黑{}", myId, vloggerId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 4. 拉黑
|
||||||
|
memberBlockService.addBlock(myId, vloggerId);
|
||||||
|
log.info("用户{}成功拉黑{}", myId, vloggerId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("黑名单回调参数转换失败: {}", pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理IM取消拉黑事件
|
||||||
|
private void handleImCancelBlock(Map<String, Object> requestBody) {
|
||||||
|
Object pairListObj = requestBody.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) {
|
||||||
|
try {
|
||||||
|
Long myId = Long.valueOf(fromAccountObj.toString());
|
||||||
|
Long vloggerId = Long.valueOf(toAccountObj.toString());
|
||||||
|
if (myId == null || vloggerId == null) {
|
||||||
|
log.warn("取消拉黑回调参数id为空: myId={}, vloggerId={}", myId, vloggerId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memberBlockService.removeBlock(myId, vloggerId);
|
||||||
|
log.info("用户{}已取消拉黑{}", myId, vloggerId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("取消拉黑回调参数转换失败: {}", pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 签名校验方法
|
||||||
|
private boolean verifySignature(String token, String sign, String requestTime) {
|
||||||
|
if (sign == null || requestTime == null) return false;
|
||||||
|
long now = System.currentTimeMillis() / 1000;
|
||||||
|
if (Math.abs(now - Long.parseLong(requestTime)) > 60) return false;
|
||||||
|
String localSign = DigestUtils.sha256Hex(token + requestTime);
|
||||||
|
return localSign.equals(sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 资料修改回调处理逻辑
|
||||||
|
private void handleProfileCallbackPortraitSet(Map<String, Object> callbackData) {
|
||||||
|
log.info("收到IM用户资料更新回调: {}", callbackData);
|
||||||
|
String fromAccount = (String) callbackData.get("From_Account");
|
||||||
|
List<Map<String, Object>> profileItems = (List<Map<String, Object>>) callbackData.get("ProfileItem");
|
||||||
|
if (fromAccount != null && profileItems != null) {
|
||||||
|
Long userId = null;
|
||||||
|
try {
|
||||||
|
userId = Long.valueOf(fromAccount.replace("UserID_", ""));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("用户ID转换失败: {}", fromAccount);
|
||||||
|
}
|
||||||
|
if (userId != null) {
|
||||||
|
Member memberToUpdate = memberService.getById(userId);
|
||||||
|
if (memberToUpdate != null) {
|
||||||
|
for (Map<String, Object> item : profileItems) {
|
||||||
|
String tag = (String) item.get("Tag");
|
||||||
|
Object value = item.get("Value");
|
||||||
|
updateMemberProfile(memberToUpdate, tag, value);
|
||||||
|
}
|
||||||
|
memberService.updateById(memberToUpdate);
|
||||||
|
log.info("IM用户资料更新回调处理成功: userId={}, profileItems={}", userId, profileItems);
|
||||||
|
} else {
|
||||||
|
log.warn("IM用户资料更新回调中用户不存在: userId={}", userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("IM用户资料更新回调参数不完整: {}", callbackData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只更新 nickname/gender 字段
|
||||||
|
private void updateMemberProfile(Member member, String tag, Object value) {
|
||||||
|
if (tag == null || value == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (tag) {
|
||||||
|
case "Tag_Profile_IM_Nick":
|
||||||
|
member.setNickname(value.toString());
|
||||||
|
break;
|
||||||
|
case "Tag_Profile_IM_Gender":
|
||||||
|
if ("Gender_Type_Male".equals(value)) {
|
||||||
|
member.setGender(1);
|
||||||
|
} else if ("Gender_Type_Female".equals(value)) {
|
||||||
|
member.setGender(2);
|
||||||
|
} else {
|
||||||
|
member.setGender(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log.debug("未处理的用户资料字段: tag={}, value={}", tag, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user