修改回调整合分发模式
This commit is contained in:
parent
5e239c99a4
commit
83ed8e4150
@ -87,33 +87,12 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int sendMessageToUser(SysMessageBo message, Long userId) {
|
||||
|
||||
|
||||
//加一个约定
|
||||
// 保存消息
|
||||
SysMessage entity = message.toEntity();
|
||||
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"); // 已发送
|
||||
messageMapper.insert(entity);
|
||||
// 检查消息与用户关联是否已存在
|
||||
|
@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
@Slf4j
|
||||
@RequestMapping("/ums/fans/")
|
||||
@ -103,6 +104,42 @@ public class FansController {
|
||||
// 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;
|
||||
}
|
||||
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");
|
||||
List<Map<String, String>> followList = (List<Map<String, String>>) callbackData.get("FollowList");
|
||||
if (fromAccount != null && followList != null) {
|
||||
@ -156,6 +193,47 @@ public class FansController {
|
||||
// 1. 判断是否为IM回调格式
|
||||
if (callbackData != null && callbackData.containsKey("CallbackCommand")) {
|
||||
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");
|
||||
List<String> toAccounts = null;
|
||||
// 兼容腾讯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