在数据可视化场景中,数据大屏需要实时展示动态数据(如实时销售额、在线人数、设备状态),传统轮询方式效率低、延迟高,而 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 项目

  1. 访问Spring Initializr,选择:
    • 依赖:Spring Web、Spring WebSocket;
    • 打包方式:Jar;
    • JDK 版本:8+;
  1. 下载项目并导入 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. 后端运行

  1. 配置application.yml(可选,默认端口 8080):

server:

port: 8080 # 前端WebSocket连接需与该端口一致

logging:

level:

com.example.websocket: INFO # 日志级别

  1. 启动 Spring Boot 应用(main 方法启动),控制台输出以下日志表示启动成功:

Started WebSocketDashboardApplication in 2.3 seconds (JVM running for 2.8)

2. 前端运行

  1. 将前端 HTML 文件(dashboard.html)放入src/main/resources/static目录(Spring Boot 静态资源目录);
  1. 浏览器访问 http://localhost:8080/dashboard.html,即可打开数据大屏页面;
  1. 观察页面效果:
    • 页面加载后自动建立 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”;
  • 解决方法
    1. 检查后端应用是否启动,端口是否正确(前端连接端口与后端server.port一致);
    1. 确认后端 WebSocket 路径是否正确(代码中为/ws/dashboard,前端连接路径需匹配);
    1. 关闭浏览器跨域限制(开发环境),或后端配置正确的跨域域名;
    1. 避免使用 HTTPS 协议(WebSocket 对应 WSS,需单独配置)。

2. 数据推送不实时

  • 错误现象:后端已推送数据,但前端未更新;
  • 解决方法
    1. 检查后端SESSIONS连接池是否包含当前客户端(日志打印在线数);
    1. 确认前端onmessage回调是否正确解析 JSON 数据(避免数据格式错误);
    1. 排查网络延迟,可在后端日志打印推送时间,前端打印接收时间。

3. 前端图表不更新

  • 错误现象:数据已接收,但 ECharts 图表未变化;
  • 解决方法
    1. 检查图表初始化是否成功(echarts.init是否绑定正确的 DOM 元素);
    1. 确认setOption方法是否调用,且数据格式与图表配置一致(如趋势图数据为数组);
    1. 窗口大小变化时调用resize()方法,避免图表被遮挡。

4. 后端定时任务不执行

  • 错误现象:控制台未打印定时推送日志;
  • 解决方法
    1. 确认类上添加了@EnableScheduling注解(开启定时任务支持);
    1. 检查 cron 表达式是否正确(本文0/5 * * * * ?表示每隔 5 秒);
    1. 避免定时任务方法为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 大屏” 的完整方案,实现了数据实时推送功能,核心亮点如下:

  1. 技术栈简单:基于 Spring Boot 原生 WebSocket,无需额外中间件,开发成本低;
  1. 代码精简:后端核心逻辑仅 3 个类,前端纯 HTML+JS,无需复杂框架;
  1. 实时性高:WebSocket 全双工通信,推送延迟低,支持每秒级更新;
  1. 稳定性强:包含自动重连、心跳检测、连接限制等生产级优化;
  1. 扩展性好:支持多大屏差异化推送、消息队列集成、更多可视化图表。

该方案适用于各类数据大屏场景(如运营监控、生产调度、实时报表),无论你是后端开发还是前端开发者,都能通过本文的代码快速落地实时数据大屏功能。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐