每日总结
package com.mentalhealth.service;
import com.mentalhealth.dto.WebSocketMessage;
import com.mentalhealth.entity.ConsultationSession;
import com.mentalhealth.entity.Message;
import com.mentalhealth.entity.MessageType;
import com.mentalhealth.entity.User;
import com.mentalhealth.entity.Consultant;
import com.mentalhealth.repository.ConsultationSessionRepository;
import com.mentalhealth.repository.UserRepository;
import com.mentalhealth.repository.ConsultantRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
@Slf4j
@RequiredArgsConstructor
public class ConsultationWebSocketHandler extends TextWebSocketHandler {
private final MessageService messageService;
private final ConsultationSessionRepository sessionRepository;
private final UserRepository userRepository;
private final ConsultantRepository consultantRepository;
private final ObjectMapper objectMapper;
private final Map<Long, WebSocketSession> userSessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Long userId = getUserIdFromSession(session);
if (userId != null) {
userSessions.put(userId, session);
log.info("用户 {} WebSocket连接建立", userId);
// 发送连接成功消息
sendToUser(userId, createWebSocketMessage(
WebSocketMessage.MessageType.CHAT,
"WebSocket连接成功",
null,
userId,
null
));
} else {
log.warn("WebSocket连接建立但无法识别用户,关闭连接");
session.close(CloseStatus.NOT_ACCEPTABLE);
}
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage) throws Exception {
Long currentUserId = getUserIdFromSession(session);
if (currentUserId == null) {
log.warn("收到消息但无法识别发送用户,关闭连接");
session.close(CloseStatus.NOT_ACCEPTABLE);
return;
}
try {
String payload = textMessage.getPayload();
log.debug("收到用户 {} 的消息: {}", currentUserId, payload);
WebSocketMessage message = objectMapper.readValue(payload, WebSocketMessage.class);
message.setFromUserId(currentUserId); // 确保发送者ID正确
switch (message.getType()) {
case CHAT:
handleChatMessage(message);
break;
case JOIN:
handleJoinSession(message);
break;
case TYPING:
handleTypingIndicator(message);
break;
case READ_RECEIPT:
handleReadReceipt(message);
break;
case LEAVE:
handleLeaveSession(message);
break;
default:
log.warn("用户 {} 发送了未知的消息类型: {}", currentUserId, message.getType());
}
} catch (Exception e) {
log.error("处理用户 {} 的消息失败", currentUserId, e);
sendToUser(currentUserId, createWebSocketMessage(
WebSocketMessage.MessageType.CHAT,
"消息处理失败: " + e.getMessage(),
null,
currentUserId,
null
));
}
}
private void handleChatMessage(WebSocketMessage message) {
try {
// 保存消息到数据库
Message savedMessage = messageService.sendMessage(
message.getFromUserId(),
message.getToUserId(),
message.getContent(),
MessageType.TEXT // 修正:直接使用 MessageType.TEXT
);
// 发送给接收方
sendToUser(message.getToUserId(), createWebSocketMessage(
WebSocketMessage.MessageType.CHAT,
savedMessage.getContent(),
savedMessage.getSenderId(),
savedMessage.getReceiverId(),
message.getSessionId()
));
log.info("用户 {} 发送消息给用户 {}", message.getFromUserId(), message.getToUserId());
} catch (Exception e) {
log.error("处理聊天消息失败", e);
}
}
private void handleJoinSession(WebSocketMessage message) {
try {
ConsultationSession session = sessionRepository.findById(message.getSessionId())
.orElseThrow(() -> new RuntimeException("咨询会话不存在"));
// 更新会话状态
session.setStatus(ConsultationSession.SessionStatus.IN_PROGRESS);
session.setActualStartTime(java.time.LocalDateTime.now());
sessionRepository.save(session);
// 获取用户和咨询师信息
User user = userRepository.findById(session.getUserId())
.orElseThrow(() -> new RuntimeException("用户不存在"));
Consultant consultant = consultantRepository.findById(session.getConsultantId())
.orElseThrow(() -> new RuntimeException("咨询师不存在"));
// 通知双方用户
sendToUser(session.getUserId(), createWebSocketMessage(
WebSocketMessage.MessageType.JOIN,
"咨询会话已开始",
session.getUserId(),
consultant.getUser().getId(),
message.getSessionId()
));
sendToUser(consultant.getUser().getId(), createWebSocketMessage(
WebSocketMessage.MessageType.JOIN,
"咨询会话已开始",
consultant.getUser().getId(),
session.getUserId(),
message.getSessionId()
));
log.info("用户 {} 加入咨询会话 {}", message.getFromUserId(), message.getSessionId());
} catch (Exception e) {
log.error("处理加入会话失败", e);
}
}
private void handleLeaveSession(WebSocketMessage message) {
try {
ConsultationSession session = sessionRepository.findById(message.getSessionId())
.orElseThrow(() -> new RuntimeException("咨询会话不存在"));
// 更新会话状态为已完成
session.setStatus(ConsultationSession.SessionStatus.COMPLETED);
session.setEndTime(java.time.LocalDateTime.now());
sessionRepository.save(session);
log.info("用户 {} 离开咨询会话 {}", message.getFromUserId(), message.getSessionId());
} catch (Exception e) {
log.error("处理离开会话失败", e);
}
}
private void handleTypingIndicator(WebSocketMessage message) {
sendToUser(message.getToUserId(), createWebSocketMessage(
WebSocketMessage.MessageType.TYPING,
"对方正在输入...",
message.getFromUserId(),
message.getToUserId(),
message.getSessionId()
));
}
private void handleReadReceipt(WebSocketMessage message) {
log.info("用户 {} 已读消息", message.getFromUserId());
}
private void sendToUser(Long userId, WebSocketMessage message) {
WebSocketSession session = userSessions.get(userId);
if (session != null && session.isOpen()) {
try {
String messageJson = objectMapper.writeValueAsString(message);
session.sendMessage(new TextMessage(messageJson));
log.debug("发送消息给用户 {}: {}", userId, message.getType());
} catch (IOException e) {
log.error("发送消息给用户 {} 失败", userId, e);
userSessions.remove(userId);
}
} else {
log.warn("用户 {} 的WebSocket连接不存在或已关闭", userId);
}
}
private WebSocketMessage createWebSocketMessage(WebSocketMessage.MessageType type,
String content, Long fromUserId, Long toUserId, Long sessionId) {
WebSocketMessage message = new WebSocketMessage();
message.setType(type);
message.setContent(content);
message.setFromUserId(fromUserId);
message.setToUserId(toUserId);
message.setSessionId(sessionId);
message.setTimestamp(java.time.LocalDateTime.now().toString());
return message;
}
private Long getUserIdFromSession(WebSocketSession session) {
Map<String, Object> attributes = session.getAttributes();
if (attributes.containsKey("userId")) {
Object userIdObj = attributes.get("userId");
if (userIdObj instanceof Long) {
return (Long) userIdObj;
} else if (userIdObj instanceof String) {
try {
return Long.parseLong((String) userIdObj);
} catch (NumberFormatException e) {
log.error("用户ID格式错误: {}", userIdObj);
}
}
}
log.warn("无法从WebSocket会话中获取用户ID");
return null;
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
log.error("WebSocket传输错误", exception);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
Long userId = getUserIdFromSession(session);
if (userId != null) {
userSessions.remove(userId);
log.info("用户 {} WebSocket连接关闭,状态: {}", userId, closeStatus);
}
}
/**
* 广播消息给所有在线用户
*/
public void broadcastToAll(WebSocketMessage message) {
for (Map.Entry<Long, WebSocketSession> entry : userSessions.entrySet()) {
sendToUser(entry.getKey(), message);
}
}
/**
* 检查用户是否在线
*/
public boolean isUserOnline(Long userId) {
WebSocketSession session = userSessions.get(userId);
return session != null && session.isOpen();
}
/**
* 获取在线用户数量
*/
public int getOnlineUserCount() {
return userSessions.size();
}
}


浙公网安备 33010602011771号