This commit is contained in:
zzy
2026-05-24 00:24:56 +08:00
commit 29eb268180
131 changed files with 25500 additions and 0 deletions

View File

@@ -0,0 +1,195 @@
package com.example.websocket;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.example.entity.ChatMessage;
import com.example.service.ChatMessageService;
import jakarta.annotation.Resource;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/ws/chat/{userId}/{userType}")
@Component
public class ChatWebSocket {
private static final Logger log = LoggerFactory.getLogger(ChatWebSocket.class);
// 静态变量,用来记录当前在线连接数
private static int onlineCount = 0;
// 用户ID和WebSocket的映射关系
private static Map<String, ChatWebSocket> clients = new ConcurrentHashMap<>();
// 与某个客户端的连接会话,用于发送数据
private Session session;
// 当前连接用户ID
private Integer userId;
// 当前连接用户类型
private String userType;
// 注入Service因为@ServerEndpoint不支持直接注入需要通过静态变量
private static ChatMessageService chatMessageService;
private static final ObjectMapper objectMapper = new ObjectMapper();
@Resource
public void setChatMessageService(ChatMessageService chatMessageService) {
ChatWebSocket.chatMessageService = chatMessageService;
}
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") Integer userId, @PathParam("userType") String userType) {
this.session = session;
this.userId = userId;
this.userType = userType;
// 将当前WebSocket对象加入到Map中
String key = userId + ":" + userType;
clients.put(key, this);
addOnlineCount();
log.info("有新连接加入,当前在线人数为:{}", getOnlineCount());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
// 从Map中移除
String key = userId + ":" + userType;
clients.remove(key);
subOnlineCount();
log.info("有一连接关闭,当前在线人数为:{}", getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到来自用户{}:{}的消息:{}", userId, userType, message);
try {
// 解析消息
ChatMessage chatMessage = objectMapper.readValue(message, ChatMessage.class);
// 直接设置发送者信息不再通过TokenUtils获取
chatMessage.setSenderId(userId);
chatMessage.setSenderType(userType);
chatMessage.setSendTime(new Date());
chatMessage.setIsRead(false);
// 保存临时ID用于前端识别消息
String tempId = null;
try {
// 从消息中提取tempId字段
Map<String, Object> messageMap = objectMapper.readValue(message, Map.class);
if (messageMap.containsKey("tempId")) {
tempId = messageMap.get("tempId").toString();
}
} catch (Exception e) {
log.warn("提取tempId失败", e);
}
// 保存消息到数据库
try {
// 检查发送者和接收者是否有关联关系并保存消息
chatMessageService.directSaveMessage(chatMessage);
// 将保存后的消息转为Map以便添加tempId
Map<String, Object> responseMap = objectMapper.convertValue(chatMessage, Map.class);
if (tempId != null) {
responseMap.put("tempId", tempId);
}
String responseJson = objectMapper.writeValueAsString(responseMap);
// 转发消息给接收者
String receiverKey = chatMessage.getReceiverId() + ":" + chatMessage.getReceiverType();
ChatWebSocket receiverSocket = clients.get(receiverKey);
if (receiverSocket != null) {
// 接收者在线,发送消息
receiverSocket.sendMessage(responseJson);
}
// 同时也返回给发送者
sendMessage(responseJson);
} catch (Exception e) {
log.error("处理消息时发生错误", e);
// 发送错误消息给客户端
ChatMessage errorMessage = new ChatMessage();
errorMessage.setSenderId(0);
errorMessage.setSenderType("system");
errorMessage.setReceiverId(userId);
errorMessage.setReceiverType(userType);
errorMessage.setContent("发送消息失败:" + e.getMessage());
errorMessage.setSendTime(new Date());
// 将错误消息转为Map以便添加tempId
Map<String, Object> errorMap = objectMapper.convertValue(errorMessage, Map.class);
if (tempId != null) {
errorMap.put("tempId", tempId);
}
sendMessage(objectMapper.writeValueAsString(errorMap));
}
} catch (Exception e) {
log.error("处理消息时发生错误", e);
}
}
/**
* 发生错误时调用
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误", error);
}
/**
* 发送消息
*/
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("发送消息失败", e);
}
}
/**
* 服务端主动推送消息
*/
public static void sendMessage(Integer userId, String userType, String message) {
String key = userId + ":" + userType;
ChatWebSocket socket = clients.get(key);
if (socket != null) {
socket.sendMessage(message);
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
ChatWebSocket.onlineCount++;
}
public static synchronized void subOnlineCount() {
ChatWebSocket.onlineCount--;
}
}