基于 Vue3 + WebSocket + Spring Boot 的实时聊天系统实现
前言
在当今互联网时代,实时聊天功能已经成为许多Web应用不可或缺的一部分。本文将详细介绍如何使用Vue3和Spring Boot构建一个功能完善、界面优雅的实时聊天系统。这个系统不仅包含基本的聊天功能,还实现了房间管理、用户状态同步、消息持久化等高级特性。
核心特性
- 🚀 实时消息推送
- 🎨 优雅的UI设计
- 🔒 安全的WebSocket连接
- 📦 消息持久化存储
- 👥 房间在线人数实时统计
- ⏰ 房间过期自动清理
- 💡 智能的重连机制
- 🎯 分类管理系统
技术栈
- 前端:Vue 3 + Element Plus
- 后端:Spring Boot
- 通信:WebSocket
- 数据库:MongoDB
- 构建工具:Vite
系统架构
1. WebSocket通信架构
Client (Vue3) <---> WebSocket Server (Spring Boot) <---> Database (MongoDB)
↑ ↑ ↑
| | |
实时UI更新 消息广播&状态管理 消息持久化
2. 核心功能模块
- 房间管理模块
- 消息处理模块
- 用户会话管理
- 实时状态同步
- 数据持久化层
详细实现
1. 后端实现
1.1 WebSocket处理器
@Component
public class ChatWebSocketHandler extends TextWebSocketHandler {
@Autowired
private ChatService chatService;
@Override
public void afterConnectionEstablished(WebSocketSession session) {
// 处理新连接
String roomId = getQueryParam(session, "roomId");
String userId = getQueryParam(session, "userId");
// 添加到房间管理器
ChatRoomManager.addSession(roomId, userId, session);
// 发送历史消息
List<ChatMessageDTO> history = messageService.getHistory(roomId, 50);
for (ChatMessageDTO dto : history) {
session.sendMessage(new TextMessage(objectMapper.writeValueAsString(dto)));
}
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage text) {
// 处理接收到的消息
ChatMessage raw = objectMapper.readValue(payload, ChatMessage.class);
ChatMessageDTO dto = messageService.saveAndConvert(raw);
broadcastToRoom(roomId, new TextMessage(json));
}
}
1.2 房间管理器
public class ChatRoomManager {
private static final Map<String, Set<WebSocketSession>> roomSessions = new ConcurrentHashMap<>();
private static final Map<String, AtomicLong> messageCounters = new ConcurrentHashMap<>();
public static void addSession(String roomId, String userId, WebSocketSession session) {
roomSessions.computeIfAbsent(roomId, k -> new ConcurrentHashSet<>()).add(session);
}
public static void broadcastToRoom(String roomId, TextMessage message) {
roomSessions.get(roomId).forEach(session -> {
try {
session.sendMessage(message);
} catch (IOException e) {
// 处理异常
}
});
}
}
2. 前端实现
2.1 Vue组件结构
<template>
<div class="public-discussion">
<!-- 头部区域 -->
<div class="discussion-header">
<h1>公共讨论区</h1>
<div class="header-actions">
<el-button type="success" @click="showCreateRoomDialog">
创建房间
</el-button>
</div>
</div>
<!-- 聊天区域 -->
<div class="chat-container" v-if="selectedRoom">
<div class="chat-messages">
<div v-for="message in messages"
:key="message.id"
:class="{ 'message-self': message.userId === currentUserId }">
<div class="message-content">{{ message.content }}</div>
</div>
</div>
<!-- 输入区域 -->
<div class="chat-input">
<el-input v-model="newMessage"
@keyup.enter="sendMessage"
placeholder="输入消息..."/>
</div>
</div>
</div>
</template>
<script setup>
const ws = ref(null);
const messages = ref([]);
// WebSocket连接管理
const connectWebSocket = (roomId) => {
const token = store.state.token;
const userId = store.state.id;
ws.value = new WebSocket(`${wsUrl}/ws/chat?roomId=${roomId}&token=${token}&userId=${userId}`);
ws.value.onmessage = (event) => {
const data = JSON.parse(event.data);
messages.value.push(data);
};
// 心跳检测
startHeartbeat();
};
// 发送消息
const sendMessage = () => {
if (!newMessage.value.trim()) return;
const message = {
roomId: selectedRoom.value.id,
content: newMessage.value,
timestamp: new Date().toISOString()
};
ws.value.send(JSON.stringify(message));
newMessage.value = '';
};
</script>
3. 高级特性实现
3.1 心跳检测
为了保持WebSocket连接的稳定性,实现了心跳机制:
const startHeartbeat = () => {
heartbeatInterval = setInterval(() => {
if (ws.value?.readyState === WebSocket.OPEN) {
ws.value.send(JSON.stringify({ type: 'heartbeat' }));
}
}, 30000); // 每30秒发送一次心跳
};
3.2 自动重连机制
const reconnect = () => {
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
setTimeout(() => {
connectWebSocket(selectedRoom.value.id);
reconnectAttempts++;
}, RECONNECT_INTERVAL * Math.pow(2, reconnectAttempts));
}
};
3.3 消息持久化
@Service
public class ChatMessageService {
@Autowired
private ChatMessageRepository messageRepo;
public ChatMessageDTO saveAndConvert(ChatMessage message) {
// 保存消息到数据库
ChatMessage saved = messageRepo.save(message);
// 转换为DTO并返回
return convertToDTO(saved);
}
public List<ChatMessageDTO> getHistory(String roomId, int limit) {
return messageRepo.findByRoomIdOrderByTimestampDesc(roomId, PageRequest.of(0, limit))
.stream()
.map(this::convertToDTO)
.collect(Collectors.toList());
}
}
性能优化
1. 前端优化
- 虚拟滚动列表
- 消息分页加载
- 防抖和节流处理
- WebSocket重连机制
2. 后端优化
- 线程池管理
- 消息队列处理
- 数据库索引优化
- 连接池管理
安全性考虑
- Token验证
String token = getQueryParam(session, "token");
if (!tokenService.validateToken(token)) {
session.close(CloseStatus.NOT_ACCEPTABLE);
return;
}
- 消息过滤
- 频率限制
- XSS防护
部署说明
1. 环境要求
- JDK 17+
- MongoDB 8.0+
2. 配置说明
spring:
data:
mongodb:
host: 127.0.0.1
database: ******
port: *****
connection-pool-size: 50 # 配置 MongoDB 连接池大小
max-wait-time: 2000ms # 设置最大等待时间(单位:毫秒)
扩展功能
- 图片消息支持
- 语音消息
- 在线状态显示
- 消息撤回
- @功能
- 表情包支持
总结
本文详细介绍了如何使用Vue3和Spring Boot构建一个功能完善的实时聊天系统。通过WebSocket实现了实时通信,结合Vue3的响应式特性,实现了流畅的用户体验。系统的设计考虑了性能、安全性和可扩展性,是一个完整的实时通信解决方案。
源码获取
完整源码已开源,欢迎访问:项目地址
关于作者
白帽工坊安全团队
版权声明
本文版权归白帽工坊所有,转载请注明出处。