【全栈进阶】Spring Boot 整合 WebSocket 实战:从实时告警到金融行情推送
一、 为什么要使用 WebSocket?
传统的 HTTP 协议是"一问一答"模式,只能由客户端发起。但在许多高性能场景下,我们需要服务器能"主动推"数据给客户端。
- 场景 A(实时告警):运维监控系统检测到服务器 CPU 过载,需要瞬间在管理员屏幕上弹出红框。
- 场景 B(金融行情):股票或数字货币交易平台,价格每秒波动几十次,用户需要无延迟看到跳动的数字。
二、 Spring Boot 快速上手
1. 添加依赖
在 pom.xml 中引入 Web 和 WebSocket 的 Starter:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 配置中心:注册 WebSocket
我们需要一个配置类来开启 WebSocket 支持,并注册 Endpoint。
java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册路径为 /ws/system 的处理器,并允许跨域
registry.addHandler(new SystemNotificationHandler(), "/ws/system")
.setAllowedOrigins("*");
}
}
3. 核心处理器:SystemNotificationHandler
这里负责处理连接的建立、消息的接收以及最重要的主动推送。
java
@Component
public class SystemNotificationHandler extends TextWebSocketHandler {
// 保存所有活跃的会话
private static final Set<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
System.out.println("新连接建立: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
// 接收客户端消息(如:心跳检测)
System.out.println("收到消息: " + message.getPayload());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
}
// 自定义方法:向所有在线用户广播告警
public static void broadcastAlert(String alertMsg) {
for (WebSocketSession session : sessions) {
if (session.isOpen()) {
try {
session.sendMessage(new TextMessage(alertMsg));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
三、 实战场景改版:金融行情实时推送
在金融交易系统中,我们通常会开启一个后台线程或定时任务,持续获取最新的行情数据,并推送给所有已连接的交易员。
java
@Component
public class StockPriceSimulator {
/**
* 模拟每隔 1 秒推送一次股票价格更新
*/
@Scheduled(fixedRate = 1000)
public void pushStockPrices() {
double price = 100 + Math.random() * 10;
String jsonPayload = String.format("{\"symbol\": \"AAPL\", \"price\": %.2f}", price);
// 调用 Handler 的广播方法
SystemNotificationHandler.broadcastAlert(jsonPayload);
}
}
四、 前端 JS 客户端实现
前端代码无需引入插件,直接使用 HTML5 标准 API 即可:
js
// 连接到服务端
const socket = new WebSocket("ws://localhost:8080/ws/system");
// 接收服务端推送的实时行情或系统告警
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log("收到推送:", data);
// 如果是告警,则显示通知弹窗
if(data.price > 105) {
showToast("价格预警:苹果股价已超过 $105!");
}
};
socket.onopen = () => console.log("连接已开启");
socket.onclose = () => console.log("连接已断开");
五、 总结与进阶建议
- 心跳机制 :为了防止网络波动或防火墙强制断开长连接,建议前端每 30 秒向后端发送一次
Ping包,后端回应Pong。 - 分布式部署 :如果你的应用有多个节点,必须引入 Redis Pub/Sub。当 A 节点触发广播时,通过 Redis 通知 B、C 节点,让它们也向各自连接的客户端推送。
- 安全性 :不要在 URL 中明文传输敏感信息,建议在
HandshakeInterceptor中拦截请求并校验 Token。
作者: [你的名字]