XuqmGroup-Server/im-service/src/main/java/com/xuqm/im/service/FriendRequestService.java
XuqmGroup 73060518f0 feat(im): 添加即时通讯SDK核心功能
- 实现IM API接口定义,包括消息、群组、好友、黑名单等功能
- 定义IM消息相关数据模型,包含聊天类型、消息类型、用户资料等
- 实现ImSDK单例类,提供登录、消息发送、群组管理、好友管理等核心功能
- 添加WebSocket连接管理,支持自动重连机制
- 实现历史消息查询、群组操作、用户资料管理等API调用
- 添加会话状态管理,支持置顶、静音、草稿等功能
- 集成文件上传结果,支持多媒体消息发送
- 实现连接状态监听和事件回调机制
2026-04-28 21:05:06 +08:00

244 行
10 KiB
Java

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

package com.xuqm.im.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.xuqm.common.exception.BusinessException;
import com.xuqm.im.cluster.ImClusterPublisher;
import com.xuqm.im.entity.ImFriendRequestEntity;
import com.xuqm.im.entity.ImMessageEntity;
import com.xuqm.im.repository.ImFriendRequestRepository;
import com.xuqm.im.repository.ImFriendRepository;
import com.xuqm.im.repository.ImMessageRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
@Service
public class FriendRequestService {
private final ImFriendRequestRepository requestRepository;
private final ImFriendRepository friendRepository;
private final ImMessageRepository messageRepository;
private final ImClusterPublisher clusterPublisher;
private final ObjectMapper objectMapper;
public FriendRequestService(ImFriendRequestRepository requestRepository,
ImFriendRepository friendRepository,
ImMessageRepository messageRepository,
ImClusterPublisher clusterPublisher,
ObjectMapper objectMapper) {
this.requestRepository = requestRepository;
this.friendRepository = friendRepository;
this.messageRepository = messageRepository;
this.clusterPublisher = clusterPublisher;
this.objectMapper = objectMapper;
}
@Transactional
public ImFriendRequestEntity send(String appId, String fromUserId, String toUserId, String remark) {
ImFriendRequestEntity saved = requestRepository.findByAppIdAndFromUserIdAndToUserId(appId, fromUserId, toUserId)
.orElseGet(() -> {
ImFriendRequestEntity entity = new ImFriendRequestEntity();
entity.setId(UUID.randomUUID().toString());
entity.setAppId(appId);
entity.setFromUserId(fromUserId);
entity.setToUserId(toUserId);
entity.setRemark(remark);
entity.setStatus(ImFriendRequestEntity.Status.PENDING.name());
entity.setCreatedAt(LocalDateTime.now());
return requestRepository.save(entity);
});
if (!ImFriendRequestEntity.Status.PENDING.name().equals(saved.getStatus())) {
return saved;
}
publishNotification(
saved,
saved.getFromUserId(),
saved.getToUserId(),
"FRIEND_REQUEST",
"好友申请",
buildDescription("好友申请", saved.getRemark())
);
return saved;
}
@Transactional
public ImFriendRequestEntity accept(String appId, String requestId, String operatorId) {
ImFriendRequestEntity request = getRequest(appId, requestId, operatorId);
request.setStatus(ImFriendRequestEntity.Status.ACCEPTED.name());
request.setReviewedAt(LocalDateTime.now());
requestRepository.save(request);
friendRepository
.findByAppIdAndUserIdAndFriendId(appId, request.getFromUserId(), request.getToUserId())
.orElseGet(() -> friendEntity(appId, request.getFromUserId(), request.getToUserId()));
friendRepository
.findByAppIdAndUserIdAndFriendId(appId, request.getToUserId(), request.getFromUserId())
.orElseGet(() -> friendEntity(appId, request.getToUserId(), request.getFromUserId()));
publishNotification(
request,
request.getToUserId(),
request.getFromUserId(),
"FRIEND_REQUEST_STATUS",
"好友申请已通过",
buildDescription("好友申请已通过", request.getRemark())
);
return request;
}
@Transactional
public ImFriendRequestEntity reject(String appId, String requestId, String operatorId) {
ImFriendRequestEntity request = getRequest(appId, requestId, operatorId);
request.setStatus(ImFriendRequestEntity.Status.REJECTED.name());
request.setReviewedAt(LocalDateTime.now());
ImFriendRequestEntity saved = requestRepository.save(request);
publishNotification(
saved,
saved.getToUserId(),
saved.getFromUserId(),
"FRIEND_REQUEST_STATUS",
"好友申请已拒绝",
buildDescription("好友申请已拒绝", saved.getRemark())
);
return saved;
}
@Transactional
public List<ImFriendRequestEntity> acceptBatch(String appId, List<String> requestIds, String operatorId) {
List<ImFriendRequestEntity> result = new java.util.ArrayList<>();
for (String requestId : unique(requestIds)) {
result.add(acceptInternal(appId, requestId, operatorId));
}
return result;
}
@Transactional
public List<ImFriendRequestEntity> rejectBatch(String appId, List<String> requestIds, String operatorId) {
List<ImFriendRequestEntity> result = new java.util.ArrayList<>();
for (String requestId : unique(requestIds)) {
result.add(rejectInternal(appId, requestId, operatorId));
}
return result;
}
public List<ImFriendRequestEntity> incoming(String appId, String userId) {
return requestRepository.findByAppIdAndToUserId(appId, userId).stream()
.filter(request -> ImFriendRequestEntity.Status.PENDING.name().equals(request.getStatus()))
.toList();
}
public List<ImFriendRequestEntity> outgoing(String appId, String userId) {
return requestRepository.findByAppIdAndFromUserId(appId, userId);
}
private ImFriendRequestEntity getRequest(String appId, String requestId, String operatorId) {
ImFriendRequestEntity request = requestRepository.findById(requestId)
.orElseThrow(() -> new BusinessException(404, "好友申请不存在"));
if (!request.getAppId().equals(appId) || !request.getToUserId().equals(operatorId)) {
throw new BusinessException(403, "无权操作");
}
return request;
}
private ImFriendRequestEntity acceptInternal(String appId, String requestId, String operatorId) {
ImFriendRequestEntity request = getRequest(appId, requestId, operatorId);
request.setStatus(ImFriendRequestEntity.Status.ACCEPTED.name());
request.setReviewedAt(LocalDateTime.now());
ImFriendRequestEntity saved = requestRepository.save(request);
friendRepository
.findByAppIdAndUserIdAndFriendId(appId, request.getFromUserId(), request.getToUserId())
.orElseGet(() -> friendEntity(appId, request.getFromUserId(), request.getToUserId()));
friendRepository
.findByAppIdAndUserIdAndFriendId(appId, request.getToUserId(), request.getFromUserId())
.orElseGet(() -> friendEntity(appId, request.getToUserId(), request.getFromUserId()));
publishNotification(
request,
request.getToUserId(),
request.getFromUserId(),
"FRIEND_REQUEST_STATUS",
"好友申请已通过",
buildDescription("好友申请已通过", request.getRemark())
);
return saved;
}
private ImFriendRequestEntity rejectInternal(String appId, String requestId, String operatorId) {
ImFriendRequestEntity request = getRequest(appId, requestId, operatorId);
request.setStatus(ImFriendRequestEntity.Status.REJECTED.name());
request.setReviewedAt(LocalDateTime.now());
ImFriendRequestEntity saved = requestRepository.save(request);
publishNotification(
saved,
saved.getToUserId(),
saved.getFromUserId(),
"FRIEND_REQUEST_STATUS",
"好友申请已拒绝",
buildDescription("好友申请已拒绝", saved.getRemark())
);
return saved;
}
private com.xuqm.im.entity.ImFriendEntity friendEntity(String appId, String userId, String friendId) {
com.xuqm.im.entity.ImFriendEntity entity = new com.xuqm.im.entity.ImFriendEntity();
entity.setAppId(appId);
entity.setUserId(userId);
entity.setFriendId(friendId);
return friendRepository.save(entity);
}
private List<String> unique(List<String> requestIds) {
return requestIds == null ? List.of() : new java.util.ArrayList<>(new java.util.LinkedHashSet<>(requestIds));
}
private void publishNotification(
ImFriendRequestEntity request,
String fromUserId,
String toUserId,
String type,
String title,
String content
) {
ImMessageEntity message = new ImMessageEntity();
message.setId(UUID.randomUUID().toString());
message.setAppId(request.getAppId());
message.setFromUserId(fromUserId);
message.setToId(toUserId);
message.setChatType(ImMessageEntity.ChatType.SINGLE);
message.setMsgType(ImMessageEntity.MsgType.NOTIFY);
message.setContent(buildNotificationContent(type, title, content, request));
message.setStatus(ImMessageEntity.MsgStatus.SENT);
message.setCreatedAt(LocalDateTime.now());
ImMessageEntity saved = messageRepository.save(message);
clusterPublisher.publish("/user/" + toUserId + "/queue/messages", saved);
}
private String buildNotificationContent(
String type,
String title,
String content,
ImFriendRequestEntity request
) {
ObjectNode node = objectMapper.createObjectNode();
node.put("type", type);
node.put("title", title);
node.put("content", content);
node.put("requestId", request.getId());
node.put("fromUserId", request.getFromUserId());
node.put("toUserId", request.getToUserId());
node.put("status", request.getStatus());
if (request.getRemark() != null) {
node.put("remark", request.getRemark());
}
return node.toString();
}
private String buildDescription(String prefix, String remark) {
if (remark == null || remark.isBlank()) {
return prefix;
}
return prefix + "" + remark;
}
}