
简介一套基于SpringBoot与ECharts的新闻可视化分析平台完整源码及数据库适合正在学习Spring Boot后端开发、ECharts数据可视化或需要完成课程设计、毕业设计的开发者。项目将新闻数据的采集、存储、查询与可视化展示串联起来通过柱状图、折线图等图表直观呈现新闻趋势、热门话题热度变化与类别分布有助于理解前后端接口设计及数据联动流程。压缩包共69个文件、约1.68MB主要包含Java后端源码、前端页面与js/css文件、SQL与CSV新闻数据、Maven构建脚本和Markdown说明文档同时附有界面截图与效果预览图目录结构清晰便于按模块对照学习。目前已有37人下载学习。借助源码中的新闻实体类、Service业务层、Controller请求处理以及ECharts图表配置可快速掌握从数据库设计到可视化展示的完整链路压缩包内的附赠内容与备份文件也为二次开发和调试提供了有价值的参考。1. 这个 SpringBootEcharts 平台到底解决了什么问题每天几万条新闻涌进来光看标题列表你根本看不出哪个领域在升温、哪个来源在刷屏、热度曲线是往上走还是往下走。这个基于 SpringBootEchart 的新闻可视化分析平台就是把「数据落库 → 聚合统计 → 接口输出 → 图表展示」整条链路做通的一个完整工程MySQL 存新闻数据SpringBoot 负责把查询结果组装成图表要的 JSON前端 Echarts 负责渲染成趋势折线、分类占比和来源 Top 榜。项目自带数据库建表脚本和业务源码跑起来就是一套能直接演示的新闻数据分析环境。适合三类人拿 SpringBoot 做课设或毕设、想要一个不是玩具项目的完整参照的学生想在公司内部搭一套资讯/新闻数据展示看板的小团队以及想彻底搞懂 SpringBoot 后端如何对齐 Echarts 数据格式的前后端开发。下面从架构到部署把每个环节和踩过的坑一次讲透。2. 技术选型与数据链路为什么是这个组合数据怎么流到图表2.1 选型理由SpringBoot 管接口Echarts 管渲染MySQL 管聚合先说 SpringBoot。它在这类项目里几乎是默认选项不是因为玄学而是因为它把过去 Spring 项目里最繁琐的配置全收了内嵌 Tomcat、自动配置数据源、starter 一键引入 MyBatis 或 JPA你写一个RestController加一个Mapper就能把数据库表暴露成 HTTP 接口。对于新闻可视化这个场景后端要做的事情其实很薄——接收请求、查库、聚合、返回 JSONSpringBoot 在这条链路里的心智负担是最低的。再说 Echarts。它之所以被选中而不是 Highcharts 或 D3核心原因是 Echarts 是「JSON 配置驱动」的你给一个option对象里面写上xAxis、series、tooltip它就画图。图表类型是line、bar还是pie只是series.type一个字段的事。这意味着后端的聚合结果基本可以 1:1 映射到图表的data字段上省掉了 D3 那种手写 SVG 的复杂度。最后是 MySQL。新闻数据本质上是结构化数据标题、来源、分类、发布时间、热度值天然适合关系型存储。更重要的是图表要的「分类数量趋势」「来源 Top 10」都可以用 SQL 的GROUP BY直接算出来不需要把全表数据拉到内存里再算。这几层选型合起来就是一句话让数据库做聚合让 SpringBoot 做搬运让 Echarts 做展示。2.2 完整数据链路从 MySQL 表到浏览器图表的七个环节我一般会把这个项目的数据流拆成这样排查问题的时候按这个链路逐层查层级对应文件/组件职责数据存储sql/news_info.sql原始新闻表聚合统计news_category_daily表按日期分类预聚合ORM 映射NewsStatsMapper.java/Mapper.xml执行聚合 SQL业务组装NewsStatsService.java把查询结果拼成图表 JSON接口暴露NewsStatsController.javaRestController输出前端请求static/index.html中的fetch拉取接口数据图表渲染EchartssetOption()画图这里有一个很多新手会犯的错试图把全量新闻数据返回给前端让前端 JS 去算分组和总和。千万别这么干。图表接口返回的应该已经是「图表可以直接用的数据」而不是原始数据。前端只负责把data[0]塞进series[0].data不该做任何聚合计算。2.3 SpringBoot 基础配置application.yml 里的关键参数拿到源码包后第一步不是急着跑而是先把application.yml里的数据源改成本地环境。下面是这份资源里典型的配置我加了逐项说明server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/news_analysis?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8allowPublicKeyRetrievaltrue username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true这里几个参数是血泪经验换来的。serverTimezoneAsia/Shanghai不写的话MySQL 8 和 JDBC 驱动之间会出现 8 小时时差查询出来的publish_time会比你数据库里实际值早 8 个小时图表上的时间轴会整体偏移。characterEncodingutf8不写中文新闻标题在返回 JSON 时会出现乱码。allowPublicKeyRetrievaltrue是 MySQL 8.x 连接时的常见报错点后面避坑章节专门讲。还有一个注意点如果源码包里的spring-boot-starter-parent是 3.x 版本它要求 JDK 17本地 JDK 8 会直接启动失败。我看到很多人在这个位置翻车解决方案两个要么把 JDK 换到 17要么把pom.xml里 SpringBoot 版本降到 2.7.x。后面避坑章节细说。3. 数据库设计与数据准备报表结构要提前想好3.1 新闻表和聚合统计表怎么建这份资源里通常会准备两张核心表一张存原始新闻数据一张存按日期和分类聚合后的统计结果。原始表负责「存事实」统计表负责「给图表提速」。news_info表结构如下CREATE TABLE news_info ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL COMMENT 新闻标题, source VARCHAR(100) COMMENT 来源站点, category VARCHAR(50) COMMENT 新闻分类科技/财经/体育/娱乐等, publish_time DATETIME COMMENT 发布时间, heat INT DEFAULT 0 COMMENT 热度值用于排序和均值计算, content TEXT COMMENT 正文摘要, KEY idx_category_time (category, publish_time), KEY idx_source (source) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;注意两个细节一是category和publish_time建了联合索引因为后面所有报表查询基本都带WHERE category ? AND publish_time BETWEEN ? AND ?没有这个索引数据量大了之后查询会非常慢二是字符集用utf8mb4而不是utf8因为新闻标题里可能出现 emoji 或特殊符号utf8存不了四个字节的字符。统计表news_category_daily的设计是这份资源里比较关键的地方CREATE TABLE news_category_daily ( id INT AUTO_INCREMENT PRIMARY KEY, stat_date DATE NOT NULL COMMENT 统计日期, category VARCHAR(50) NOT NULL COMMENT 新闻分类, news_count INT DEFAULT 0 COMMENT 当日该分类新闻数, avg_heat INT DEFAULT 0 COMMENT 当日该分类平均热度, UNIQUE KEY uk_date_cat (stat_date, category) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这个表解决什么问题假设你想看「最近 30 天科技类新闻的数量趋势」没有这张表就要对news_info做GROUP BY DATE(publish_time), category数据量到了几十万级别时接口响应会明显变慢。有了预聚合表接口只需要SELECT * FROM news_category_daily WHERE category科技 ORDER BY stat_date毫秒级返回。这是数据可视化项目里非常标准的「空间换时间」做法。3.2 数据导入源码包里的 SQL 与模拟数据脚本源码包里的sql/目录一般包含完整的建表和预置数据脚本。导入方式很简单mysql -uroot -proot news_analysis sql/news_info.sql mysql -uroot -proot news_analysis sql/news_category_daily.sql如果你拿到的是带数据的版本运行完这两条命令后库里就有现成的可查询数据直接启动 SpringBoot 就能看到图表。但如果没有预置数据或者你想自己生成一批规模更大的数据来压测我一般会写一个 Python 脚本造模拟数据因为手写 SQL 插入几百条太累而且造数据要模拟出「分布特征」才有图表效果import random import pymysql from datetime import datetime, timedelta conn pymysql.connect(host127.0.0.1, userroot, passwordroot, databasenews_analysis, charsetutf8mb4) cursor conn.cursor() categories [科技, 财经, 体育, 娱乐, 国际] sources [新浪新闻, 腾讯新闻, 网易新闻, 今日头条, 澎湃新闻] start_date datetime(2024, 1, 1) for i in range(5000): publish_time start_date timedelta( daysrandom.randint(0, 90), hoursrandom.randint(0, 23), minutesrandom.randint(0, 59) ) category random.choice(categories) source random.choice(sources) heat random.randint(0, 10000) title f[{category}] 模拟新闻标题 {i} cursor.execute( INSERT INTO news_info (title, source, category, publish_time, heat) VALUES (%s, %s, %s, %s, %s), (title, source, category, publish_time, heat) ) conn.commit() cursor.close() conn.close()脚本里的random.randint分布决定图表形态热度完全均匀随机时折线图是平的没有趋势感。想要好看的趋势可以在heat生成逻辑里加一个基于publish_time日期的正弦波动模拟工作日高峰、周末低谷这样画出来的折线才有真实项目的感觉。数据量 5000 条足够演示想压测可以改成 50000。3.3 聚合查询GROUP BY 是图表的燃料统计表不会自己填数据要么用定时任务要么手动跑聚合 SQL。把news_info聚合成news_category_daily的核心 SQL 是这样的INSERT INTO news_category_daily (stat_date, category, news_count, avg_heat) SELECT DATE(publish_time) AS stat_date, category, COUNT(*) AS news_count, ROUND(AVG(heat)) AS avg_heat FROM news_info WHERE publish_time DATE_SUB(CURDATE(), INTERVAL 90 DAY) GROUP BY DATE(publish_time), category ON DUPLICATE KEY UPDATE news_count VALUES(news_count), avg_heat VALUES(avg_heat);注意末尾的ON DUPLICATE KEY UPDATE很重要因为uk_date_cat唯一键的存在重复跑这条 SQL 不会插入重复数据而是更新已有统计值。这样不管是每天定时跑还是手动重复执行结果都是稳定的。实际资源里这段逻辑可能会放在 SpringBoot 的启动ApplicationRunner里或者用Scheduled定时触发后面章节会展示代码。4. SpringBoot 接口层把查询结果组装成 Echarts 要的 JSON4.1 接口返回结构先约定后编码做可视化项目的第一条铁律就是先定 JSON 结构再写后端代码最后才碰前端。如果前后端各写各的字段名对不上是最常见的翻车现场。这份资源里接口返回结构一般是下面这样的规范格式按data字段传对象、code和message走统一响应{ code: 0, message: success, data: { dates: [2024-01-01, 2024-01-02, 2024-01-03], series: [ { name: 科技, data: [12, 18, 25] }, { name: 财经, data: [8, 10, 15] } ] } }为什么dates和series分开而不是塞成对象数组因为 Echarts 的折线图xAxis.data需要的是日期数组series需要的是并列的多条线数据。后端按这个结构返回前端只需要chart.setOption({ xAxis: { data: res.data.dates }, series: res.data.series })一行代码都不用加工。如果返回成[{date:2024-01-01, category:科技, count:12}]这种行式结构前端就要自己遍历重组既慢又容易错。4.2 Controller 到 Mapper 的完整实现后端代码一般拆成三层。Controller 层只做请求接收和响应包装不写业务逻辑。下面是核心代码我按这份资源的常见实现方式给出RestController RequestMapping(/api/news) public class NewsStatsController { Autowired private NewsStatsService newsStatsService; // 分类数量趋势/api/news/trend?category科技days30 GetMapping(/trend) public MapString, Object trend(RequestParam(required false) String category, RequestParam(defaultValue 30) Integer days) { ListMapString, Object rows newsStatsService.getDailyStats(category, days); return buildTrendResponse(rows); } // 来源 Top 榜/api/news/topSources?limit10 GetMapping(/topSources) public MapString, Object topSources(RequestParam(defaultValue 10) Integer limit) { ListMapString, Object rows newsStatsService.getTopSources(limit); return buildPieResponse(rows); } private MapString, Object buildTrendResponse(ListMapString, Object rows) { ListString dates new ArrayList(); MapString, ListInteger seriesMap new LinkedHashMap(); for (MapString, Object row : rows) { String date String.valueOf(row.get(stat_date)); String cat String.valueOf(row.get(category)); Integer count ((Number) row.get(news_count)).intValue(); dates.add(date); seriesMap.computeIfAbsent(cat, k - new ArrayList()).add(count); } ListMapString, Object series new ArrayList(); seriesMap.forEach((k, v) - { MapString, Object s new HashMap(); s.put(name, k); s.put(data, v); series.add(s); }); MapString, Object result new HashMap(); result.put(dates, dates); result.put(series, series); return result; } }这里有两个细节值得注意。第一seriesMap用LinkedHashMap而不是HashMap是为了保证分类顺序稳定否则前端图例顺序每次请求都会变。第二stat_date从 MyBatis 查出来可能是java.sql.Date直接String.valueOf会得到2024-01-01这种标准格式但如果数据库驱动返回的是Timestamp就会带00:00:00后缀所以稳妥的做法是在 SQL 里用DATE_FORMAT(stat_date, %Y-%m-%d)转好字符串再返回。Service 层和 Mapper 层对应如下Service public class NewsStatsService { Autowired private NewsStatsMapper newsStatsMapper; public ListMapString, Object getDailyStats(String category, Integer days) { return newsStatsMapper.selectDailyStats(category, days); } public ListMapString, Object getTopSources(Integer limit) { return newsStatsMapper.selectTopSources(limit); } }!-- NewsStatsMapper.xml -- select idselectDailyStats resultTypemap SELECT DATE_FORMAT(stat_date, %Y-%m-%d) AS stat_date, category, news_count, avg_heat FROM news_category_daily where if testcategory ! null and category ! AND category #{category} /if /where AND stat_date DATE_SUB(CURDATE(), INTERVAL #{days} DAY) ORDER BY stat_date /select select idselectTopSources resultTypemap SELECT source, COUNT(*) AS news_count FROM news_info GROUP BY source ORDER BY news_count DESC LIMIT #{limit} /selectMapper 接口里对应写两个方法声明Mapper注解标上MyBatis 会自动扫描到NewsStatsMapper.xml里的同名 SQL。where标签是动态 SQL 的关键category参数为空时自动去掉该条件实现「不传 category 就查全部分类趋势」的效果。4.3 定时任务统计表自动更新聚合统计表不会自己长数据这份资源里一般会在 SpringBoot 启动时自动跑一次初始化同时注册一个每日定时任务。代码通常在启动类或独立组件里Component public class DailyStatsTask { Autowired private JdbcTemplate jdbcTemplate; // 每天凌晨 1 点执行一次统计聚合 Scheduled(cron 0 0 1 * * ?) public void aggregateDailyStats() { String sql INSERT INTO news_category_daily (stat_date, category, news_count, avg_heat) SELECT DATE(publish_time), category, COUNT(*), ROUND(AVG(heat)) FROM news_info WHERE publish_time DATE_SUB(CURDATE(), INTERVAL 1 DAY) GROUP BY DATE(publish_time), category ON DUPLICATE KEY UPDATE news_count VALUES(news_count), avg_heat VALUES(avg_heat); jdbcTemplate.execute(sql); } }注意Scheduled需要主启动类上加了EnableScheduling才会生效这是新手最容易漏的。cron 表达式0 0 1 * * ?的意思是「每天 1 点 0 分 0 秒执行」?是秒位占位符表示不指定。如果不加EnableScheduling这个定时任务会静默失效统计表永远停留在初始数据图表时间轴不再增长。5. 前端 Echarts 可视化从接口 JSON 到图表渲染的完整实践5.1 页面初始化与 Ajax 拉取前端部分在这份资源里一般就是一个static/index.html引入 Echarts 的 JS 文件后开始渲染。用 CDN 还是本地文件看你的环境内网部署建议把echarts.min.js下载到static/js/目录下避免外网依赖。页面中画趋势折线图的核心逻辑如下const chart echarts.init(document.getElementById(trendChart)); fetch(/api/news/trend?days30) .then(res res.json()) .then(data { if (data.code ! 0) { console.error(接口异常:, data.message); return; } const { dates, series } data.data; chart.setOption({ tooltip: { trigger: axis }, legend: { data: series.map(s s.name) }, grid: { left: 10%, right: 5%, top: 15%, bottom: 15% }, xAxis: { type: category, data: dates }, yAxis: { type: value, name: 新闻数量 }, series: series.map(s ({ name: s.name, type: line, smooth: true, data: s.data })) }); }) .catch(err console.error(请求失败:, err));这里要注意一个常见的白屏原因echarts.init的容器trendChart在 JS 执行时必须已经存在于 DOM 中。如果你把script标签写在了div idtrendChart前面document.getElementById返回nullEcharts 会在控制台报Cant get dom width or height之类的错。正确做法是把脚本放在页面末尾或者用window.onload或DOMContentLoaded包裹。5.2 饼图、柱状图与可视化大屏适配除了趋势折线这份资源里典型还有「来源占比饼图」和「分类数量柱状图」。饼图的 option 片段const pieChart echarts.init(document.getElementById(sourcePie)); fetch(/api/news/topSources?limit10) .then(res res.json()) .then(data { if (data.code ! 0) return; const { names, values } data.data; pieChart.setOption({ tooltip: { trigger: item, formatter: {b}: {c} ({d}%) }, legend: { orient: vertical, left: right }, series: [{ type: pie, radius: [30%, 65%], data: names.map((name, i) ({ name, value: values[i] })) }] }); });radius: [30%, 65%]表示这是一个环形图而不是实心饼图内径 30%、外径 65%视觉效果更现代。formatter: {b}: {c} ({d}%)中{d}是 Echarts 内置的占比变量会在 tooltip 里自动显示百分比。如果你要做可视化大屏所有图表容器都要考虑自适应。我的习惯是加一个窗口监听让所有图表实例统一 resizewindow.addEventListener(resize, () { chart.resize(); pieChart.resize(); });大屏套件的常见布局是用grid或flex把页面切成 3 列上面放趋势图、左下放词云、右下放 Top 榜。字体大小和图表高度用vw/vh单位而不是px避免在不同分辨率下布局错乱。5.3 echart axis.type 与参数调校category 还是 timeEcharts 折线图xAxis.type有两个选择category和time。这个选择决定了日期数据的解析方式也是很多人被坑的地方。如果xAxis.type: categoryxAxis.data里的每个值都会被当作「类目」原样显示在横轴上不解析、不排序。如果xAxis.type: timeEcharts 会把data里的值当作时间戳或日期字符串来解析自动排序并计算坐标刻度。两种方式的适用场景完全不同场景推荐 type原因日期是字符串且格式统一2024-01-01category原样展示显示规则可控日期是时间戳或 ISO 字符串time自动解析适合非均匀时间间隔想控制横轴显示密度每 3 天标一个刻度categoryaxisLabel.intervaltime轴刻度不可控我在实际项目里更倾向于用category因为后端 SQL 已经在DATE_FORMAT里统一了日期格式前端拿到的不存在解析歧义。用time轴反而容易出现「日期字符串被解析成 UTC 时间导致横轴偏移 8 小时」的莫名其妙的显示问题那是我踩过的最莫名其妙的一个坑。5.4 柱状图与折线图组合双 Y 轴场景新闻数据里经常要同时对比「数量」和「平均热度」两者量级不同数量一般是几十到几百热度可能是几千到几万放在同一个 Y 轴里数量那根线会被压扁成一条直线。解决方案是用双 Y 轴series: [ { name: 新闻数量, type: bar, yAxisIndex: 0, data: countData }, { name: 平均热度, type: line, yAxisIndex: 1, data: heatData } ]对应的yAxis要写成数组两个对象分别设置name: 数量和name: 热度。这个配置在 Echarts 里叫「多轴联动」不算难但新手经常忘了加yAxisIndex导致两根线挤在一个轴上图表形态完全失真。6. 避坑与常见问题排查本地跑通这个平台的五处关键细节6.1 现象SpringBoot 启动直接失败报UnsupportedClassVersionError原因源码包的pom.xml里 SpringBoot 版本是 3.x它编译时目标 JDK 是 17而你本地 JDK 是 8 或 11字节码版本不兼容JVM 在加载主类时直接抛异常。解决两个方案选一个。方案一把本地 JDK 换到 17JAVA_HOME指过去后重新mvn clean package。方案二把pom.xml里的spring-boot-starter-parent版本降到2.7.18同时确认java.version标签改成1.8然后mvn clean再启动。我一般推荐方案一因为 SpringBoot 3.x 的jakarta.*命名空间和 2.x 的javax.*差异较大降版本可能伴随其他依赖兼容问题。6.2 现象接口查询报Public Key Retrieval is not allowed原因MySQL 8.x 默认使用caching_sha2_password认证插件JDBC 驱动第一次连接时需要向服务器请求公钥来加密密码传输但连接串里没有允许这个行为于是驱动抛异常拒绝连接。解决在application.yml的 JDBC URL 末尾加allowPublicKeyRetrievaltrue完整的连接串是url: jdbc:mysql://localhost:3306/news_analysis?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingutf8useSSLfalse也要保留本地开发环境没有配置 SSL 证书驱动默认尝试加密连接会额外报 SSL 警告。6.3 现象前端图表白屏F12 控制台报echarts is not defined原因echarts.min.js没引入成功。最常见的两种一是script srcjs/echarts.min.js路径写错浏览器 404二是脚本放在了 DOM 之前导致echarts.init传入的容器不存在。解决先用浏览器 F12 的 Network 面板确认echarts.min.js请求状态是 200。然后确认init的执行时机——把页面脚本统一放到/body前面或者用window.onload包裹。这里我用一个习惯杜绝此坑所有 Echarts 初始化代码都包进一个initCharts()函数在window.onload里统一调用既保证 DOM 就绪还能在函数里统一加console.log验证。6.4 现象折线图横轴日期全部挤成一团且显示的是数字而不是日期原因xAxis.type被设成了time而后端返回的日期字符串2024-01-01中带横杠Echarts 把它解析成时间戳后由于默认刻度算法不合适标签挤在一起有时候还会显示成毫秒时间戳数字。解决优先用category轴并显式设置xAxis.data这样日期是什么就显示什么。如果一定要用time轴给xAxis.axisLabel加formatter: (value) echarts.format.formatTime(value, {yyyy}-{MM}-{dd})强制把时间戳格式化成日期字符串。6.5 现象图表存在闪烁或动画卡顿页面滚动时明显原因这是两个问题叠加。一是setOption被频繁调用比如页面里有刷新定时器Echarts 每次都做全量 diff开销大二是图表容器在滚动或尺寸变化时被不断重绘。前端圈里管这叫「图表翻车现场」不致命但很影响观感。解决setOption时传入第二个参数true强制覆盖而不是合并chart.setOption(option, true);用于刷新场景时在 fetch 新的数据前先chart.clear()再setOption避免旧图形残留。定时刷新加一个防抖比如每 5 秒拉一次数据时用setInterval但只在数据有变化时才setOption不然每次刷新都是全量重绘。这五条是本地跑这个平台最容易卡的五个位置前两条属于环境类后三条属于代码类。按「配置 → 依赖 → 数据 → 渲染」的顺序排查绝大多数问题能在 10 分钟内定位。7. 部署与进阶用法打包、启动和日常维护技巧7.1 打 jar 包与启动后端打标准 SpringBoot jar 包执行mvn clean package -DskipTests java -jar target/news-visualization-0.0.1-SNAPSHOT.jar如果想换端口而不改配置启动时加参数java -jar target/news-visualization-0.0.1-SNAPSHOT.jar --server.port8081这个参数优先级高于application.yml线上临时改端口时不用重新打包也算是有后悔药可吃。前端index.html里的接口请求路径如果写的是绝对路径带端口改完要同步如果写的是相对路径/api/news/trend那后端换端口完全不影响页面访问。7.2 进阶前端工程化整合与词云扩展如果你的前端不是单个 HTML而是 Vue 或 React 工程最省事的做法是执行npm run build后把dist目录里的index.html、js、css全部拷贝到 SpringBoot 的static/目录下然后后端接口保持RestController不动。这是「Vue 打包放进 SpringBoot」的标准姿势注意dist/index.html里的资源引用如果是绝对路径/js/xxx.js要改成相对路径否则后端根路径改变时资源会 404。功能扩展方向上除了折线、柱状、饼图这份资源还可以加两个高价值图表词云和地图。词云用 Echarts 扩展插件echarts-wordcloud只需要后端多提供一个「高频关键词」接口前端把它渲染成词云图视觉冲击力比普通柱状图强得多适合大屏展示。7.3 数据维护的日常工作这个平台跑起来之后我一般的日常巡检顺序是先看news_category_daily表最新日期是不是今天再看定时任务日志有没有执行成功最后打开页面确认图表时间轴在增长。定时任务失败最常见的迹象就是图表停在昨天或更早的日期上这个时候查日志比调前端代码有效得多——先确认数据端没问题再考虑是不是接口或渲染层的问题。从那以后我每次在本地跑这类 SpringBootEcharts 项目都强制先做一遍三步检查SQL 字段名和后端返回的 key 有没有对齐、Echarts 的xAxis.data和series.data长度是否一致、连接串的时区和编码参数有没有漏。这三处全对了再打开浏览器能省掉至少一半的图表白屏和乱码时间。希望帮到你。本文还有配套的精品资源点击获取