Spring WebSocket
1. WebSocket基础
连接建立流程:
Client Server
| |
|------ HTTP Upgrade ------>| // 发起升级请求
| |
|<---- 101 Switching -------| // 服务器同意升级
| |
|<===== WebSocket =========>| // 建立全双工连接
2. Spring WebSocket核心组件
- WebSocketHandler
@Component
public class MessageWebSocketHandler extends TextWebSocketHandler {
// 连接建立时
@Override
public void afterConnectionEstablished(WebSocketSession session) {
String userId = getUserId(session);
sessions.put(userId, session);
}
// 处理消息
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
// 处理接收到的消息
}
// 连接关闭时
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(getUserId(session));
}
}
- WebSocketConfigurer
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/ws")
.addInterceptors(handshakeInterceptor)
.setAllowedOrigins("*");
}
}
3. 会话管理
- Session存储
public class MessageWebSocketHandler {
// 使用线程安全的Map存储会话
private final Map<String, WebSocketSession> sessions =
new ConcurrentHashMap<>();
// 发送消息
public void sendMessage(String userId, String message) {
WebSocketSession session = sessions.get(userId);
if (session != null && session.isOpen()) {
session.sendMessage(new TextMessage(message));
}
}
}
- 心跳检测
@Configuration
public class WebSocketConfig {
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container =
new ServletServerContainerFactoryBean();
// 设置消息大小限制
container.setMaxTextMessageBufferSize(8192);
// 设置心跳超时时间
container.setMaxSessionIdleTimeout(60000L);
return container;
}
}
4. 消息类型
- TextMessage
// 发送文本消息
session.sendMessage(new TextMessage("Hello"));
// 接收文本消息
@Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) {
String payload = message.getPayload();
}
- BinaryMessage
// 发送二进制消息
byte[] bytes = ...;
session.sendMessage(new BinaryMessage(bytes));
// 接收二进制消息
@Override
protected void handleBinaryMessage(WebSocketSession session,
BinaryMessage message) {
byte[] payload = message.getPayload().array();
}
5. 安全处理
- 握手拦截
public class WebSocketInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(...) {
// 验证token
String token = request.getHeaders().get("token").get(0);
if (!isValidToken(token)) {
return false; // 拒绝连接
}
return true;
}
}
- 异常处理
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) {
log.error("WebSocket传输错误", exception);
if (session.isOpen()) {
session.close();
}
}
6. STOMP支持
Spring也支持STOMP协议:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic"); // 广播消息前缀
config.setApplicationDestinationPrefixes("/app"); // 应用前缀
}
}
7. 最佳实践
- 错误处理
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
log.error("发送消息失败", e);
sessions.remove(userId);
}
- 消息序列化
// 发送JSON消息
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(messageObject);
session.sendMessage(new TextMessage(json));
- 连接状态检查
public void sendMessage(String userId, String message) {
WebSocketSession session = sessions.get(userId);
if (session != null && session.isOpen()) {
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
log.error("发送失败", e);
closeSession(session);
}
}
}
这些是Spring WebSocket的主要知识点,在实际应用中要根据具体需求选择合适的实现方式。