WebSocket 实战:用 Spring Boot 构建实时聊天系统

James Park | 2026-08-26T23:03:08 | Java, Spring Boot, Frontend

基于 Spring Boot + STOMP + SockJS 构建实时聊天系统,涵盖消息广播、私聊、在线状态和消息持久化。

# WebSocket 实战:用 Spring Boot 构建实时聊天系统 ## WebSocket 配置 ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws") .setAllowedOrigins("https://example.com") .withSockJS(); // 降级支持 } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic", "/queue"); registry.setApplicationDestinationPrefixes("/app"); registry.setUserDestinationPrefix("/user"); } } ``` ## 消息控制器 ```java @Controller public class ChatController { @Autowired private SimpMessagingTemplate messagingTemplate; // 群发消息 @MessageMapping("/chat.send") @SendTo("/topic/public") public ChatMessage sendMessage(ChatMessage message) { message.setTimestamp(LocalDateTime.now()); chatMessageRepository.save(message); // 持久化 return message; } // 私聊 @MessageMapping("/chat.private") public void sendPrivateMessage(PrivateMessage message) { message.setTimestamp(LocalDateTime.now()); chatMessageRepository.save(message); messagingTemplate.convertAndSendToUser( message.getRecipient(), "/queue/messages", message ); } // 用户上线 @MessageMapping("/chat.join") @SendTo("/topic/public") public ChatMessage userJoin(ChatMessage message) { message.setType(MessageType.JOIN); onlineUsers.add(message.getSender()); return message; } } ``` ## 前端连接 ```javascript const socket = new SockJS('/ws'); const stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { console.log('连接成功: ' + frame); // 订阅公共频道 stompClient.subscribe('/topic/public', function (message) { const msg = JSON.parse(message.body); displayMessage(msg); }); // 订阅私人消息 stompClient.subscribe('/user/queue/messages', function (message) { const msg = JSON.parse(message.body); displayPrivateMessage(msg); }); // 发送上线通知 stompClient.send('/app/chat.join', {}, JSON.stringify({ sender: username, type: 'JOIN' }) ); }); // 发送消息 function sendMessage(content) { stompClient.send('/app/chat.send', {}, JSON.stringify({ sender: username, content: content }) ); } ``` ## 在线状态管理 ```java @Component public class WebSocketEventListener { @EventListener public void handleConnect(SessionConnectedEvent event) { // 用户连接 } @EventListener public void handleDisconnect(SessionDisconnectEvent event) { StompHeaderAccessor accessor = StompHeaderAccessor.wrap(event.getMessage()); String username = (String) accessor.getSessionAttributes().get("username"); if (username != null) { onlineUsers.remove(username); messagingTemplate.convertAndSend("/topic/public", new ChatMessage(username, MessageType.LEAVE)); } } } ``` ## 注意事项 1. 生产环境使用外部消息代理(RabbitMQ/Redis)替代 SimpleBroker 2. 添加 JWT 认证到 WebSocket 握手阶段 3. 实现消息已读/未读状态 4. 大规模场景考虑 WebSocket 集群(Sticky Session + Redis PubSub)

← Back to Blog