Java 实操:WebSocket 实时推送数据到数据大屏(附前后端代码)
本文介绍如何使用Java(SpringBoot)和WebSocket实现数据大屏实时更新系统。通过WebSocket全双工通信替代传统轮询方式,显著降低延迟和服务器压力。内容包括:1)核心原理与SpringBoot集成方案;2)后端实现(配置类、处理器、定时推送);3)前端大屏页面(数字卡片+ECharts图表);4)生产环境优化建议(心跳检测、安全验证等);5)常见问题解决方案。该方案代码精简高
在数据可视化场景中,数据大屏需要实时展示动态数据(如实时销售额、在线人数、设备状态),传统轮询方式效率低、延迟高,而 WebSocket 通过全双工通信实现服务器主动推送数据,是数据大屏实时更新的最优方案。本文将手把手教你用 Java(Spring Boot)搭建 WebSocket 服务端,配合前端页面实现数据实时推送,代码精简高效,新手也能快速上手。
一、核心原理与技术选型
1. 核心逻辑
WebSocket 实现数据大屏实时更新的核心流程:
2. 技术选型说明
|
技术 / 框架 |
版本要求 |
作用描述 |
|
Java |
8+ |
核心开发语言 |
|
Spring Boot |
2.3.x-2.7.x(稳定版) |
快速开发框架,集成 WebSocket |
|
Spring WebSocket |
内置(Spring Boot 依赖) |
WebSocket 服务端核心组件 |
|
Vue.js 3(可选) |
3.0+ |
前端大屏页面开发(简化 DOM 操作) |
|
ECharts |
5.0+ |
数据可视化图表(折线图 / 柱状图 / 数字卡片) |
|
Maven |
3.6+ |
依赖管理工具 |
3. 核心优势
- 实时性强:WebSocket 连接建立后,服务端可主动推送数据,延迟低至毫秒级;
- 效率高:避免轮询的无效请求,减少服务器压力和网络带宽占用;
- 开发简单:Spring Boot 对 WebSocket 提供原生支持,无需复杂配置;
- 兼容性好:支持主流浏览器(Chrome、Firefox、Edge)和数据大屏展示设备。
二、环境搭建与项目初始化
1. 创建 Spring Boot 项目
-
- 依赖:Spring Web、Spring WebSocket;
-
- 打包方式:Jar;
-
- JDK 版本:8+;
- 下载项目并导入 IDE(IDEA/Eclipse)。
2. 依赖配置(pom.xml)
Spring Boot 已内置 WebSocket 依赖,无需额外添加,核心依赖如下:
<!-- Spring Web(基础Web支持) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring WebSocket(核心依赖,内置无需额外导入) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 工具类依赖(可选,用于模拟数据) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
三、Java 后端实现(WebSocket 服务端)
步骤 1:WebSocket 配置类(开启 WebSocket 支持)
创建配置类,注册 WebSocket 处理器和拦截器,开启 WebSocket 功能:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
/**
* WebSocket配置类
*/
@Configuration
@EnableWebSocket // 开启WebSocket支持
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册WebSocket处理器,映射路径为/ws/dashboard,允许跨域
registry.addHandler(webSocketHandler(), "/ws/dashboard")
.setAllowedOrigins("*"); // 开发环境允许所有跨域,生产环境需指定具体域名
}
// 注入WebSocket处理器(核心业务逻辑)
@Bean
public WebSocketHandler webSocketHandler() {
return new DashboardWebSocketHandler();
}
}
步骤 2:WebSocket 处理器(核心业务逻辑)
实现 WebSocket 连接管理、数据推送逻辑,维护客户端连接池,支持广播推送(推送给所有大屏):
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 数据大屏WebSocket处理器
*/
@Component
@Slf4j
public class DashboardWebSocketHandler extends TextWebSocketHandler {
// 线程安全的客户端连接池(存储所有在线大屏的WebSocketSession)
private static final List<WebSocketSession> SESSIONS = new CopyOnWriteArrayList<>();
/**
* 客户端连接建立成功时触发
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
SESSIONS.add(session);
log.info("新的大屏客户端连接成功,当前在线数:{}", SESSIONS.size());
// 连接成功后,推送初始数据
session.sendMessage(new TextMessage(buildInitData()));
}
/**
* 客户端连接关闭时触发
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
SESSIONS.remove(session);
log.info("大屏客户端连接关闭,当前在线数:{}", SESSIONS.size());
}
/**
* 广播推送数据(推送给所有在线大屏)
* @param data 要推送的JSON格式数据
*/
public void broadcastData(String data) {
if (SESSIONS.isEmpty()) {
log.warn("暂无在线大屏客户端,推送数据失败");
return;
}
// 遍历所有连接,推送数据
for (WebSocketSession session : SESSIONS) {
if (session.isOpen()) { // 确保连接处于打开状态
try {
session.sendMessage(new TextMessage(data));
} catch (IOException e) {
log.error("推送数据到大屏失败", e);
}
}
}
}
/**
* 构建初始数据(连接成功时推送)
*/
private String buildInitData() {
// 实际场景从数据库/缓存获取,此处模拟数据(JSON格式)
return "{" +
"\"onlineUserCount\": 1289," +
"\"totalSales\": 896520.50," +
"\"orderCount\": 368," +
"\"deviceOnlineRate\": 92.3" +
"}";
}
}
步骤 3:定时推送数据(模拟实时数据更新)
创建定时任务,每隔 5 秒生成模拟数据并推送给所有大屏(实际场景可替换为监听数据源变化触发推送):
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
/**
* 定时推送数据任务(模拟实时数据更新)
*/
@Component
@EnableScheduling // 开启定时任务支持
public class DataPushTask {
@Autowired
private DashboardWebSocketHandler webSocketHandler;
private final Random random = new Random();
// 基础数据(用于模拟波动)
private int baseOnlineUser = 1200;
private BigDecimal baseTotalSales = new BigDecimal("890000.00");
private int baseOrderCount = 350;
private double baseDeviceRate = 90.0;
/**
* 每隔5秒推送一次实时数据(cron表达式:秒 分 时 日 月 周)
*/
@Scheduled(cron = "0/5 * * * * ?")
public void pushRealTimeData() {
// 模拟数据波动(±5%范围内)
int onlineUser = baseOnlineUser + random.nextInt(200) - 100;
BigDecimal totalSales = baseTotalSales.add(new BigDecimal(random.nextDouble() * 10000 - 5000))
.setScale(2, RoundingMode.HALF_UP);
int orderCount = baseOrderCount + random.nextInt(50) - 20;
double deviceRate = Math.round((baseDeviceRate + random.nextDouble() * 5 - 2.5) * 10) / 10.0;
// 构建JSON数据
JSONObject data = new JSONObject();
data.put("onlineUserCount", onlineUser);
data.put("totalSales", totalSales);
data.put("orderCount", orderCount);
data.put("deviceOnlineRate", deviceRate);
// 广播推送数据
webSocketHandler.broadcastData(data.toJSONString());
log.info("已推送实时数据:{}", data.toJSONString());
}
}
步骤 4:手动触发推送接口(可选,用于主动更新)
提供 HTTP 接口,支持手动触发数据推送(如后台操作后主动更新大屏):
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 手动触发数据推送接口
*/
@RestController
@RequestMapping("/dashboard")
public class DashboardController {
@Autowired
private DashboardWebSocketHandler webSocketHandler;
/**
* 手动推送最新数据(GET请求,方便测试)
*/
@GetMapping("/push")
public String pushDataManually() {
// 模拟最新数据(实际场景从数据库查询)
String latestData = "{" +
"\"onlineUserCount\": " + (1200 + new Random().nextInt(200)) + "," +
"\"totalSales\": " + (890000 + new Random().nextInt(10000)) + ".99," +
"\"orderCount\": " + (350 + new Random().nextInt(50)) + "," +
"\"deviceOnlineRate\": " + String.format("%.1f", 90 + new Random().nextDouble() * 5) +
"}";
webSocketHandler.broadcastData(latestData);
return "数据推送成功:" + latestData;
}
}
四、前端数据大屏实现(HTML+ECharts)
创建简洁的数据大屏页面,通过 WebSocket 连接后端,接收实时数据并更新图表(无需框架,纯 HTML+JS 即可运行):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>实时数据大屏</title>
<!-- 引入ECharts可视化库 -->
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #0f172a;
color: #fff;
font-family: "Microsoft YaHei", sans-serif;
padding: 20px;
}
.dashboard-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 20px;
height: calc(100vh - 40px);
}
.panel {
background-color: rgba(30, 41, 59, 0.8);
border-radius: 8px;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.panel-title {
font-size: 18px;
margin-bottom: 15px;
color: #60a5fa;
display: flex;
align-items: center;
}
.panel-title i {
margin-right: 8px;
color: #34d399;
}
.number-card {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: calc(100% - 40px);
}
.number-value {
font-size: 48px;
font-weight: bold;
margin-bottom: 10px;
color: #fff;
}
.number-unit {
font-size: 16px;
color: #94a3b8;
}
/* 适配不同屏幕 */
@media (max-width: 1200px) {
.dashboard-container {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.dashboard-container {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="dashboard-container">
<!-- 在线用户数 -->
<div class="panel">
<div class="panel-title"><i>👥</i> 实时在线用户数</div>
<div class="number-card">
<div class="number-value" id="onlineUserCount">0</div>
<div class="number-unit">人</div>
</div>
</div>
<!-- 累计销售额 -->
<div class="panel">
<div class="panel-title"><i>💰</i> 累计销售额(元)</div>
<div class="number-card">
<div class="number-value" id="totalSales">0.00</div>
<div class="number-unit">元</div>
</div>
</div>
<!-- 今日订单数 -->
<div class="panel">
<div class="panel-title"><i>📦</i> 今日订单数</div>
<div class="number-card">
<div class="number-value" id="orderCount">0</div>
<div class="number-unit">单</div>
</div>
</div>
<!-- 设备在线率 -->
<div class="panel">
<div class="panel-title"><i>📶</i> 设备在线率</div>
<div class="number-card">
<div class="number-value" id="deviceOnlineRate">0.0%</div>
<div class="number-unit">正常运行</div>
</div>
</div>
<!-- 销售额趋势图 -->
<div class="panel" style="grid-column: span 2;">
<div class="panel-title"><i>📈</i> 销售额实时趋势</div>
<div id="salesTrendChart" style="width: 100%; height: calc(100% - 40px);"></div>
</div>
<!-- 数据概览饼图 -->
<div class="panel">
<div class="panel-title"><i>📊</i> 订单来源分布</div>
<div id="orderSourceChart" style="width: 100%; height: calc(100% - 40px);"></div>
</div>
</div>
<script>

// 初始化ECharts图表
const salesTrendChart = echarts.init(document.getElementById('salesTrendChart'));
const orderSourceChart = echarts.init(document.getElementById('orderSourceChart'));
// 趋势图初始配置
const trendOption = {
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
data: [], // 时间轴数据(动态添加)
axisLine: { lineStyle: { color: '#94a3b8' } },
axisLabel: { color: '#e2e8f0' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#94a3b8' } },
axisLabel: { color: '#e2e8f0', formatter: '{value} 元' },
splitLine: { lineStyle: { color: 'rgba(148, 163, 184, 0.2)' } }
},
series: [{
name: '销售额',
type: 'line',
data: [], // 销售额数据(动态添加)
smooth: true,
lineStyle: { color: '#34d399', width: 3 },
itemStyle: { color: '#34d399', borderRadius: 5 },
areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(52, 211, 153, 0.3)' },
{ offset: 1, color: 'rgba(52, 211, 153, 0)' }
])}
}]
};
// 饼图初始配置
const pieOption = {
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
legend: {
bottom: 0,
textStyle: { color: '#e2e8f0' }
},
series: [{
name: '订单来源',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '40%'],
avoidLabelOverlap: false,
label: { show: false, position: 'center' },
emphasis: { label: { show: true, fontSize: 16, fontWeight: 'bold' } },
labelLine: { show: false },
data: [
{ value: 0, name: '移动端' },
{ value: 0, name: 'PC端' },
{ value: 0, name: '小程序' },
{ value: 0, name: '其他' }
],
itemStyle: {
color: ['#60a5fa', '#34d399', '#fbbf24', '#f87171']
}
}]
};
salesTrendChart.setOption(trendOption);
orderSourceChart.setOption(pieOption);
// WebSocket连接与数据处理
let webSocket;
// 初始化WebSocket连接
function initWebSocket() {
// 判断浏览器是否支持WebSocket
if ('WebSocket' in window) {
// 连接后端WebSocket服务(注意协议为ws,端口与后端一致)
webSocket = new WebSocket('ws://' + window.location.host + '/ws/dashboard');
// 连接成功回调
webSocket.onopen = function() {
console.log('WebSocket连接成功,开始接收实时数据...');
};
// 接收数据回调(核心:处理后端推送的数据)
webSocket.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('接收实时数据:', data);
// 更新数字卡片
updateNumberCards(data);
// 更新趋势图
updateTrendChart(data.totalSales);
// 更新饼图(模拟订单来源分布)
updatePieChart();
};
// 连接关闭回调
webSocket.onclose = function() {
console.log('WebSocket连接关闭,正在重连...');
// 自动重连(避免网络中断)
setTimeout(initWebSocket, 3000);
};
// 连接错误回调
webSocket.onerror = function(error) {
console.error('WebSocket连接错误:', error);
};
} else {
alert('您的浏览器不支持WebSocket,无法查看实时数据!');
}
}
// 更新数字卡片数据
function updateNumberCards(data) {
document.getElementById('onlineUserCount').innerText = data.onlineUserCount;
document.getElementById('totalSales').innerText = data.totalSales;
document.getElementById('orderCount').innerText = data.orderCount;
document.getElementById('deviceOnlineRate').innerText = data.deviceOnlineRate + '%';
// 添加数字变化动画
const numberElements = document.querySelectorAll('.number-value');
numberElements.forEach(el => {
el.style.transition = 'all 0.5s ease';
el.style.transform = 'scale(1.1)';
setTimeout(() => el.style.transform = 'scale(1)', 300);
});
}
// 存储趋势图数据(最多显示10个数据点)
const trendData = {
times: [],
sales: []
};
// 更新销售额趋势图
function updateTrendChart(sales) {
// 获取当前时间(精确到分钟)
const now = new Date();
const timeStr = now.getHours().toString().padStart(2, '0') + ':' +
now.getMinutes().toString().padStart(2, '0');
// 添加新数据点
trendData.times.push(timeStr);
trendData.sales.push(parseFloat(sales));
// 限制数据点数量(超过10个则删除最早的)
if (trendData.times.length > 10) {
trendData.times.shift();
trendData.sales.shift();
}
// 更新图表数据
salesTrendChart.setOption({
xAxis: { data: trendData.times },
series: [{ data: trendData.sales }]
});
}
// 模拟更新订单来源饼图
function updatePieChart() {
const orderCount = parseInt(document.getElementById('orderCount').innerText);
// 模拟各来源订单数(按比例分配)
const mobile = Math.floor(orderCount * 0.5); // 移动端50%
const pc = Math.floor(orderCount * 0.3); // PC端30%
const applet = Math.floor(orderCount * 0.15); // 小程序15%
const other = orderCount - mobile - pc - applet; // 其他5%
orderSourceChart.setOption({
series: [{
data: [
{ value: mobile, name: '移动端' },
{ value: pc, name: 'PC端' },
{ value: applet, name: '小程序' },
{ value: other, name: '其他' }
]
}]
});
}
// 页面加载完成后初始化WebSocket
window.onload = function() {
initWebSocket();
// 窗口大小变化时,调整图表尺寸
window.addEventListener('resize', function() {
salesTrendChart.resize();
orderSourceChart.resize();
});
};
</script>
</body>
</html>
五、运行与测试步骤
1. 后端运行
- 配置application.yml(可选,默认端口 8080):
server:
port: 8080 # 前端WebSocket连接需与该端口一致
logging:
level:
com.example.websocket: INFO # 日志级别
- 启动 Spring Boot 应用(main 方法启动),控制台输出以下日志表示启动成功:
Started WebSocketDashboardApplication in 2.3 seconds (JVM running for 2.8)
2. 前端运行
- 将前端 HTML 文件(dashboard.html)放入src/main/resources/static目录(Spring Boot 静态资源目录);
- 浏览器访问 http://localhost:8080/dashboard.html,即可打开数据大屏页面;
- 观察页面效果:
-
- 页面加载后自动建立 WebSocket 连接,显示初始数据;
-
- 每隔 5 秒自动更新实时数据(数字卡片、趋势图、饼图);
-
- 数字变化时有动画效果,趋势图动态添加数据点;
-
- 关闭页面再重新打开,可自动重连 WebSocket。
3. 手动触发推送测试
访问 HTTP 接口 http://localhost:8080/dashboard/push,可手动触发数据推送,大屏页面会立即更新数据。
六、关键优化与生产环境配置
1. 连接稳定性优化
- 自动重连:前端实现 WebSocket 断开后自动重连(已在代码中实现);
- 心跳检测:后端定时向客户端发送心跳包,检测无效连接并清理:
// 在WebSocketHandler中添加心跳检测
@Scheduled(cron = "0/30 * * * * ?") // 每30秒发送一次心跳
public void sendHeartbeat() {
for (WebSocketSession session : SESSIONS) {
if (session.isOpen()) {
try {
session.sendMessage(new TextMessage("{\"type\":\"heartbeat\"}"));
} catch (IOException e) {
log.error("发送心跳包失败,移除无效连接", e);
SESSIONS.remove(session);
}
}
}
}
- 跨域配置:生产环境避免setAllowedOrigins("*"),指定具体域名:
registry.addHandler(webSocketHandler(), "/ws/dashboard")
.setAllowedOrigins("http://dashboard.example.com"); // 生产环境域名
2. 性能优化
- 连接池限制:限制最大并发连接数(避免恶意连接占用资源):
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
if (SESSIONS.size() >= 100) { // 限制最大100个并发连接
session.close(CloseStatus.POLICY_VIOLATION.withReason("连接数已达上限"));
return;
}
SESSIONS.add(session);
// ...
}
- 数据压缩:对推送的 JSON 数据进行压缩,减少网络传输量;
- 批量推送:高频更新场景(如每秒更新),可合并多次数据推送,降低频率。
3. 安全配置
- 身份验证:WebSocket 连接时携带 token,后端验证身份(避免非法访问):
// 前端连接时携带token:new WebSocket('ws://localhost:8080/ws/dashboard?token=xxx')
// 后端在WebSocketHandler中验证token
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String token = session.getUri().getQuery().split("=")[1];
if (!validateToken(token)) { // 验证token有效性
session.close(CloseStatus.POLICY_VIOLATION.withReason("身份验证失败"));
return;
}
// ...
}
- 数据加密:敏感数据推送时,采用 WSS(WebSocket Secure,协议为 wss://)加密传输。
七、避坑指南(新手必看)
1. WebSocket 连接失败
- 错误现象:浏览器控制台提示 “WebSocket connection failed”;
- 解决方法:
-
- 检查后端应用是否启动,端口是否正确(前端连接端口与后端server.port一致);
-
- 确认后端 WebSocket 路径是否正确(代码中为/ws/dashboard,前端连接路径需匹配);
-
- 关闭浏览器跨域限制(开发环境),或后端配置正确的跨域域名;
-
- 避免使用 HTTPS 协议(WebSocket 对应 WSS,需单独配置)。
2. 数据推送不实时
- 错误现象:后端已推送数据,但前端未更新;
- 解决方法:
-
- 检查后端SESSIONS连接池是否包含当前客户端(日志打印在线数);
-
- 确认前端onmessage回调是否正确解析 JSON 数据(避免数据格式错误);
-
- 排查网络延迟,可在后端日志打印推送时间,前端打印接收时间。
3. 前端图表不更新
- 错误现象:数据已接收,但 ECharts 图表未变化;
- 解决方法:
-
- 检查图表初始化是否成功(echarts.init是否绑定正确的 DOM 元素);
-
- 确认setOption方法是否调用,且数据格式与图表配置一致(如趋势图数据为数组);
-
- 窗口大小变化时调用resize()方法,避免图表被遮挡。
4. 后端定时任务不执行
- 错误现象:控制台未打印定时推送日志;
- 解决方法:
-
- 确认类上添加了@EnableScheduling注解(开启定时任务支持);
-
- 检查 cron 表达式是否正确(本文0/5 * * * * ?表示每隔 5 秒);
-
- 避免定时任务方法为private(需为public或默认访问权限)。
八、进阶扩展(按需优化)
1. 多大屏差异化推送
支持根据大屏 ID 推送不同数据(如按区域、按业务线区分):
// 1. 后端维护连接与大屏ID的映射
private static final Map<String, WebSocketSession> SESSION_MAP = new ConcurrentHashMap<>();
// 2. 前端连接时携带大屏ID:new WebSocket('ws://localhost:8080/ws/dashboard?screenId=1001')
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String screenId = session.getUri().getQuery().split("=")[1];
SESSION_MAP.put(screenId, session);
// ...
}
// 3. 定向推送数据到指定大屏
public void pushDataToScreen(String screenId, String data) {
WebSocketSession session = SESSION_MAP.get(screenId);
if (session != null && session.isOpen()) {
try {
session.sendMessage(new TextMessage(data));
} catch (IOException e) {
log.error("定向推送数据失败", e);
}
}
}
2. 集成消息队列(如 RabbitMQ)
实际场景中,数据可能来自消息队列(如订单创建后发送消息),后端监听消息队列并推送数据:
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class RabbitMQListener {
@Autowired
private DashboardWebSocketHandler webSocketHandler;
// 监听订单创建消息队列
@RabbitListener(queues = "order.create.queue")
public void onOrderCreated(String orderData) {
log.info("接收到订单创建消息:{}", orderData);
// 解析订单数据,提取销售额、订单数等信息
JSONObject data = JSON.parseObject(orderData);
String pushData = buildPushData(data);
// 推送数据到大屏
webSocketHandler.broadcastData(pushData);
}
private String buildPushData(JSONObject orderData) {
// 构建推送数据逻辑
return "{}";
}
}
3. 大屏页面美化与更多图表
- 增加数据预警功能(如销售额低于阈值时数字标红);
- 集成更多 ECharts 图表(如地图、雷达图);
- 使用 CSS 动画和渐变效果,提升大屏视觉体验。
九、总结
本文通过 “Java 后端 WebSocket 服务端 + 前端 ECharts 大屏” 的完整方案,实现了数据实时推送功能,核心亮点如下:
- 技术栈简单:基于 Spring Boot 原生 WebSocket,无需额外中间件,开发成本低;
- 代码精简:后端核心逻辑仅 3 个类,前端纯 HTML+JS,无需复杂框架;
- 实时性高:WebSocket 全双工通信,推送延迟低,支持每秒级更新;
- 稳定性强:包含自动重连、心跳检测、连接限制等生产级优化;
- 扩展性好:支持多大屏差异化推送、消息队列集成、更多可视化图表。
该方案适用于各类数据大屏场景(如运营监控、生产调度、实时报表),无论你是后端开发还是前端开发者,都能通过本文的代码快速落地实时数据大屏功能。
更多推荐
所有评论(0)