本文目录导读:

我来为您提供一个完整的Java数据大屏实现案例,使用Spring Boot + ECharts + WebSocket实现实时数据展示。
项目结构
data-screen/
├── pom.xml
├── src/main/java/com/example/datascreen/
│ ├── DataScreenApplication.java
│ ├── controller/
│ │ └── DataController.java
│ ├── service/
│ │ ├── DataService.java
│ │ └── RealTimeDataService.java
│ ├── config/
│ │ ├── WebSocketConfig.java
│ │ └── CorsConfig.java
│ └── model/
│ └── DataModel.java
└── src/main/resources/
├── application.yml
└── static/
├── index.html
├── css/style.css
└── js/
├── echarts.min.js
└── dashboard.js
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>data-screen</artifactId>
<version>1.0.0</version>
<name>data-screen</name>
<description>数据大屏展示系统</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<!-- 数据库连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
应用主类
package com.example.datascreen;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class DataScreenApplication {
public static void main(String[] args) {
SpringApplication.run(DataScreenApplication.class, args);
}
}
数据模型
package com.example.datascreen.model;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
@Data
public class DataModel {
// 实时数据
private Integer totalSales; // 总销售额
private Integer totalOrders; // 总订单数
private Integer activeUsers; // 活跃用户数
private Integer conversionRate; // 转化率
// 图表数据
private List<Map<String, Object>> trendData; // 趋势数据
private List<Map<String, Object>> categoryData; // 分类数据
private List<Map<String, Object>> regionData; // 地区数据
private List<Map<String, Object>> realtimeData; // 实时数据
// 排名数据
private List<Map<String, Object>> productRanking; // 产品排名
private List<Map<String, Object>> sellerRanking; // 商家排名
// 时间戳
private LocalDateTime updateTime;
// 饼图数据
private List<Map<String, Object>> channelData; // 渠道数据
private List<Map<String, Object>> ageDistribution; // 年龄分布
}
数据服务
package com.example.datascreen.service;
import com.alibaba.fastjson.JSON;
import com.example.datascreen.model.DataModel;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
@Service
public class DataService {
private DataModel dataModel;
private final Map<String, Object> dataCache = new HashMap<>();
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
@PostConstruct
public void init() {
dataModel = new DataModel();
}
/**
* 获取大屏数据
*/
public Map<String, Object> getDashboardData() {
Map<String, Object> result = new HashMap<>();
// 生成模拟数据
result.put("totalSales", ThreadLocalRandom.current().nextInt(800, 1200));
result.put("totalOrders", ThreadLocalRandom.current().nextInt(5000, 8000));
result.put("activeUsers", ThreadLocalRandom.current().nextInt(10000, 15000));
result.put("conversionRate", ThreadLocalRandom.current().nextDouble(2.5, 5.0) / 100);
// 趋势图数据
result.put("trendData", generateTrendData());
// 分类数据
result.put("categoryData", generateCategoryData());
// 地区数据
result.put("regionData", generateRegionData());
// 产品排名
result.put("productRanking", generateProductRanking());
// 渠道数据
result.put("channelData", generateChannelData());
// 时间
result.put("updateTime", LocalDateTime.now().format(formatter));
return result;
}
/**
* 生成趋势数据(最近7天)
*/
private List<Map<String, Object>> generateTrendData() {
List<Map<String, Object>> list = new ArrayList<>();
String[] dates = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
int[] values = {120, 200, 150, 80, 70, 110, 130};
int[] values2 = {80, 150, 100, 60, 50, 90, 100};
for (int i = 0; i < dates.length; i++) {
Map<String, Object> map = new HashMap<>();
map.put("name", dates[i]);
map.put("value", values[i]);
map.put("value2", values2[i]);
list.add(map);
}
return list;
}
/**
* 生成分类数据
*/
private List<Map<String, Object>> generateCategoryData() {
List<Map<String, Object>> list = new ArrayList<>();
String[] categories = {"电子产品", "服装", "食品", "家居", "美妆", "图书"};
String[] colors = {"#5470c6", "#91cc75", "#fac858", "#ee6666", "#73c0de", "#3ba272"};
for (int i = 0; i < categories.length; i++) {
Map<String, Object> map = new HashMap<>();
map.put("name", categories[i]);
map.put("value", ThreadLocalRandom.current().nextInt(100, 500));
map.put("color", colors[i]);
list.add(map);
}
return list;
}
/**
* 生成地区数据
*/
private List<Map<String, Object>> generateRegionData() {
List<Map<String, Object>> list = new ArrayList<>();
String[] regions = {"北京", "上海", "广州", "深圳", "杭州", "成都", "武汉"};
int[][] coordinates = {
{116.46, 39.92}, {121.48, 31.22}, {113.23, 23.16},
{114.07, 22.62}, {120.19, 30.26}, {104.06, 30.67}, {114.29, 30.59}
};
for (int i = 0; i < regions.length; i++) {
Map<String, Object> map = new HashMap<>();
map.put("name", regions[i]);
map.put("value", ThreadLocalRandom.current().nextInt(50, 200));
map.put("coordinate", coordinates[i]);
list.add(map);
}
return list;
}
/**
* 生成产品排名
*/
private List<Map<String, Object>> generateProductRanking() {
List<Map<String, Object>> list = new ArrayList<>();
String[] products = {"iPhone 15", "华为Mate60", "小米14", "OPPO Find X7",
"三星S24", "荣耀Magic6", "vivo X100", "一加12"};
for (int i = 0; i < products.length; i++) {
Map<String, Object> map = new HashMap<>();
map.put("name", products[i]);
map.put("value", ThreadLocalRandom.current().nextInt(1000, 5000));
list.add(map);
}
// 按销量排序
list.sort((a, b) -> ((Integer) b.get("value")).compareTo((Integer) a.get("value")));
return list;
}
/**
* 生成渠道数据
*/
private List<Map<String, Object>> generateChannelData() {
List<Map<String, Object>> list = new ArrayList<>();
String[] channels = {"线上商城", "实体店", "直播带货", "社交电商", "跨境电商"};
for (int i = 0; i < channels.length; i++) {
Map<String, Object> map = new HashMap<>();
map.put("name", channels[i]);
map.put("value", ThreadLocalRandom.current().nextInt(20, 100));
list.add(map);
}
return list;
}
/**
* 实时数据推送(WebSocket)
*/
public String getRealtimeData() {
Map<String, Object> data = getDashboardData();
return JSON.toJSONString(data);
}
}
WebSocket配置
package com.example.datascreen.config;
import com.example.datascreen.service.DataService;
import com.alibaba.fastjson.JSON;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.config.annotation.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private DataService dataService;
private static final CopyOnWriteArrayList<WebSocketSession> sessions =
new CopyOnWriteArrayList<>();
private static final Map<String, WebSocketSession> sessionMap = new ConcurrentHashMap<>();
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new TextWebSocketHandler() {
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
sessionMap.put(session.getId(), session);
System.out.println("连接建立: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
// 处理客户端发送的消息
String payload = message.getPayload();
System.out.println("收到消息: " + payload);
// 发送响应
session.sendMessage(new TextMessage(
JSON.toJSONString(dataService.getDashboardData())));
}
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus status) {
sessions.remove(session);
sessionMap.remove(session.getId());
System.out.println("连接关闭: " + session.getId());
}
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) {
sessions.remove(session);
sessionMap.remove(session.getId());
}
}, "/websocket").setAllowedOrigins("*");
}
/**
* 定时推送数据(每5秒)
*/
@Scheduled(fixedRate = 5000)
public void sendRealtimeData() {
if (sessions.isEmpty()) return;
String data = dataService.getRealtimeData();
TextMessage message = new TextMessage(data);
for (WebSocketSession session : sessions) {
try {
if (session.isOpen()) {
synchronized (session) {
session.sendMessage(message);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
控制器
package com.example.datascreen.controller;
import com.example.datascreen.service.DataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping("/api/data")
@CrossOrigin
public class DataController {
@Autowired
private DataService dataService;
/**
* 获取大屏数据
*/
@GetMapping("/dashboard")
public Map<String, Object> getDashboardData() {
return dataService.getDashboardData();
}
/**
* 获取实时数据
*/
@GetMapping("/realtime")
public Map<String, Object> getRealtimeData() {
return dataService.getDashboardData();
}
/**
* 获取统计数据
*/
@GetMapping("/statistics")
public Map<String, Object> getStatistics() {
return dataService.getDashboardData();
}
}
application.yml
server:
port: 8080
spring:
application:
name: data-screen
datasource:
url: jdbc:mysql://localhost:3306/data_screen?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 自定义配置
data:
screen:
# 刷新频率(毫秒)
refresh-rate: 5000
前端大屏页面
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">大数据可视化大屏</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #091828;
color: #fff;
font-family: "Microsoft YaHei", sans-serif;
min-height: 100vh;
overflow: hidden;
}
.dashboard {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: 70px 1fr 1fr;
gap: 10px;
padding: 20px;
height: 100vh;
background: linear-gradient(180deg, #0a1929 0%, #091828 100%);
}
/* 大屏标题 */
.header {
grid-column: 1 / -1;
text-align: center;
padding: 15px;
background: linear-gradient(90deg, transparent, rgba(0, 150, 255, 0.3), transparent);
box-shadow: 0 4px 20px rgba(0, 150, 255, 0.2);
}
.header h1 {
font-size: 32px;
background: linear-gradient(90deg, #ff6b6b, #ffd93d);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 30px rgba(255, 107, 107, 0.3);
}
/* 图表容器 */
.chart-container {
background: rgba(0, 20, 40, 0.6);
border: 1px solid #1a3a5c;
border-radius: 8px;
padding: 15px;
box-shadow: 0 0 20px rgba(0, 100, 200, 0.1);
}
.chart-container .title {
font-size: 16px;
margin-bottom: 10px;
color: #00d4ff;
border-left: 3px solid #00d4ff;
padding-left: 10px;
}
/* 数字卡片 */
.stat-cards {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.stat-card {
background: rgba(0, 20, 40, 0.8);
border: 1px solid #1a3a5c;
border-radius: 8px;
padding: 15px;
text-align: center;
transition: all 0.3s;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 20px rgba(0, 150, 255, 0.3);
}
.stat-card .value {
font-size: 28px;
font-weight: bold;
background: linear-gradient(90deg, #00d4ff, #0066ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.stat-card .label {
font-size: 14px;
color: #8ab4f8;
margin-top: 5px;
}
/* 地图容器 */
#mapChart {
grid-column: 2;
grid-row: 2 / 4;
}
/* 滚动消息 */
.scroll-message {
position: fixed;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
color: #00d4ff;
font-size: 12px;
animation: scroll 10s linear infinite;
}
@keyframes scroll {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
/* 动画效果 */
@keyframes glowing {
0% { box-shadow: 0 0 5px rgba(0, 150, 255, 0.5); }
50% { box-shadow: 0 0 20px rgba(0, 150, 255, 0.8); }
100% { box-shadow: 0 0 5px rgba(0, 150, 255, 0.5); }
}
.glowing {
animation: glowing 2s infinite;
}
/* 自适应 */
@media (max-width: 768px) {
.dashboard {
grid-template-columns: 1fr;
gap: 5px;
}
.stat-cards {
grid-template-columns: repeat(2, 1fr);
}
#mapChart {
grid-column: 1;
grid-row: auto;
}
}
</style>
</head>
<body>
<div class="dashboard">
<!-- 头部标题 -->
<div class="header">
<h1>📊 电商大数据可视化大屏</h1>
</div>
<!-- 顶部统计卡片 -->
<div class="stat-cards">
<div class="stat-card">
<div class="value" id="totalSales">0</div>
<div class="label">总销售额(万)</div>
</div>
<div class="stat-card">
<div class="value" id="totalOrders">0</div>
<div class="label">总订单数</div>
</div>
<div class="stat-card">
<div class="value" id="activeUsers">0</div>
<div class="label">活跃用户</div>
</div>
<div class="stat-card">
<div class="value" id="conversionRate">0%</div>
<div class="label">转化率</div>
</div>
</div>
<!-- 左侧图表 -->
<div class="chart-container">
<div class="title">销售趋势</div>
<div id="trendChart" style="width: 100%; height: 90%;"></div>
</div>
<!-- 中间图表 -->
<div class="chart-container" id="mapChart">
<div class="title">销售地区分布</div>
<div id="regionMap" style="width: 100%; height: 90%;"></div>
</div>
<!-- 右侧图表 -->
<div class="chart-container">
<div class="title">销售渠道分析</div>
<div id="channelChart" style="width: 100%; height: 90%;"></div>
</div>
<!-- 左下角图表 -->
<div class="chart-container">
<div class="title">商品分类</div>
<div id="categoryChart" style="width: 100%; height: 90%;"></div>
</div>
<!-- 右下角图表 -->
<div class="chart-container">
<div class="title">产品销量排名</div>
<div id="rankingChart" style="width: 100%; height: 90%;"></div>
</div>
<div class="scroll-message">数据更新时间:<span id="updateTime"></span> | 数据每5秒自动刷新</div>
</div>
<script src="/js/dashboard.js"></script>
</body>
</html>
前端JavaScript
// dashboard.js
$(document).ready(function() {
// 初始化所有图表
initCharts();
// 连接WebSocket
connectWebSocket();
// 定时刷新数据
setInterval(updateData, 5000);
});
// 图表实例
let trendChart, regionMap, channelChart, categoryChart, rankingChart;
function initCharts() {
// 趋势图
trendChart = echarts.init(document.getElementById('trendChart'));
trendChart.setOption({
tooltip: { trigger: 'axis' },
legend: { data: ['销售额', '订单量'], textStyle: { color: '#fff' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
data: [],
axisLine: { lineStyle: { color: '#1a3a5c' } },
axisLabel: { color: '#fff' }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#1a3a5c' } },
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1a3a5c' } }
},
series: [
{
name: '销售额',
type: 'line',
smooth: true,
data: [],
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1,
[{ offset: 0, color: 'rgba(0, 212, 255, 0.3)' },
{ offset: 1, color: 'rgba(0, 212, 255, 0)' }])
}
},
{
name: '订单量',
type: 'line',
smooth: true,
data: [],
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1,
[{ offset: 0, color: 'rgba(255, 107, 107, 0.3)' },
{ offset: 1, color: 'rgba(255, 107, 107, 0)' }])
}
}
]
});
// 地区地图
regionMap = echarts.init(document.getElementById('regionMap'));
regionMap.setOption({
tooltip: { trigger: 'item', formatter: '{b}: {c}' },
visualMap: {
min: 0,
max: 200,
text: ['高', '低'],
calculable: true,
inRange: { color: ['#50a3ba', '#eac736', '#d94e5d'] }
},
series: [{
type: 'map',
map: 'china',
roam: true,
label: { show: true },
data: []
}]
});
// 渠道分析(饼图)
channelChart = echarts.init(document.getElementById('channelChart'));
channelChart.setOption({
tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d}%)' },
legend: { orient: 'vertical', right: 10, textStyle: { color: '#fff' } },
series: [{
name: '销售渠道',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: { borderRadius: 10, borderColor: '#fff', borderWidth: 2 },
label: { show: false, position: 'center' },
emphasis: {
label: { show: true, fontSize: 20, fontWeight: 'bold' }
},
data: []
}]
});
// 商品分类(柱状图)
categoryChart = echarts.init(document.getElementById('categoryChart'));
categoryChart.setOption({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: {
type: 'category',
data: [],
axisLabel: { color: '#fff', rotate: 30 },
axisLine: { lineStyle: { color: '#1a3a5c' } }
},
yAxis: {
type: 'value',
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1a3a5c' } }
},
series: [{
name: '销售额',
type: 'bar',
data: [],
itemStyle: {
borderRadius: [5, 5, 0, 0],
color: new echarts.graphic.LinearGradient(0, 0, 0, 1,
[{ offset: 0, color: '#00d4ff' },
{ offset: 1, color: '#0066ff' }])
}
}]
});
// 产品排名(横向柱状图)
rankingChart = echarts.init(document.getElementById('rankingChart'));
rankingChart.setOption({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '10%', bottom: '3%', containLabel: true },
xAxis: {
type: 'value',
axisLabel: { color: '#fff' },
splitLine: { lineStyle: { color: '#1a3a5c' } }
},
yAxis: {
type: 'category',
data: [],
axisLabel: { color: '#fff' },
axisLine: { lineStyle: { color: '#1a3a5c' } }
},
series: [{
name: '销量',
type: 'bar',
data: [],
itemStyle: {
borderRadius: [0, 5, 5, 0],
color: new echarts.graphic.LinearGradient(0, 0, 1, 0,
[{ offset: 0, color: '#ff6b6b' },
{ offset: 1, color: '#ffd93d' }])
}
}]
});
}
function updateData() {
$.ajax({
url: '/api/data/dashboard',
type: 'GET',
dataType: 'json',
success: function(data) {
renderData(data);
},
error: function() {
console.log('请求数据失败');
}
});
}
function renderData(data) {
if (!data) return;
// 更新统计卡片
animateNumber($('#totalSales'), 0, data.totalSales, 1000);
animateNumber($('#totalOrders'), 0, data.totalOrders, 1000);
animateNumber($('#activeUsers'), 0, data.activeUsers, 1000);
let rate = (data.conversionRate * 100).toFixed(2);
$('#conversionRate').text(rate + '%');
// 更新时间
$('#updateTime').text(data.updateTime);
// 更新图表
updateCharts(data);
}
function updateCharts(data) {
// 更新趋势图
if (data.trendData) {
trendChart.setOption({
xAxis: { data: data.trendData.map(item => item.name) },
series: [
{ data: data.trendData.map(item => item.value) },
{ data: data.trendData.map(item => item.value2) }
]
});
}
// 更新地区地图
if (data.regionData) {
regionMap.setOption({
series: [{
data: data.regionData.map(item => ({
name: item.name,
value: item.value
}))
}]
});
}
// 更新渠道饼图
if (data.channelData) {
channelChart.setOption({
series: [{ data: data.channelData }]
});
}
// 更新商品分类
if (data.categoryData) {
categoryChart.setOption({
xAxis: { data: data.categoryData.map(item => item.name) },
series: [{ data: data.categoryData.map(item => item.value) }]
});
}
// 更新产品排名
if (data.productRanking) {
rankingChart.setOption({
yAxis: { data: data.productRanking.map(item => item.name) },
series: [{ data: data.productRanking.map(item => item.value) }]
});
}
}
// 数字动画
function animateNumber($element, start, end, duration) {
let current = start;
let step = (end - start) / (duration / 50);
let timer = setInterval(function() {
current += step;
if (current >= end) {
current = end;
clearInterval(timer);
}
$element.text(Math.round(current).toLocaleString());
}, 50);
}
// WebSocket连接
function connectWebSocket() {
const socket = new WebSocket('ws://' + window.location.host + '/websocket');
socket.onopen = function() {
console.log('WebSocket连接成功');
};
socket.onmessage = function(event) {
let data = JSON.parse(event.data);
renderData(data);
};
socket.onclose = function() {
console.log('WebSocket连接关闭');
// 断线重连
setTimeout(connectWebSocket, 5000);
};
socket.onerror = function(error) {
console.log('WebSocket错误:', error);
};
}
运行与部署
打包运行
# 打包 mvn clean package -DskipTests # 运行 java -jar target/data-screen-1.0.0.jar
访问地址
http://localhost:8080
功能特点
- 实时数据展示:通过WebSocket实现数据的实时推送
- 多种图表类型:折线图、柱状图、饼图、地图等
- 动态数字效果:数字变化的动态展示
- 响应式设计:适配不同屏幕尺寸
- 自动刷新:定时获取最新数据
- 美观的UI设计:科技感十足的大屏样式
扩展建议
- 数据库集成:使用MySQL存储真实业务数据
- 多数据源:支持Kafka、Flink等实时数据源
- 权限控制:添加用户认证和权限管理
- 告警功能:添加数据异常预警
- 更多图表:添加雷达图、仪表盘等更多可视化组件
- 数据导出:支持数据报表导出功能
- 多屏幕适配:支持多屏拼接显示
这个数据大屏案例可以直接运行,适合学习大数据可视化和WebSocket实时通信开发,您可以根据实际需求修改数据和样式。