做了几次“某某实时监控系统”之后,你会发现这类项目看起来是个数据展示大屏,拆开看其实是 Java 全栈里最典型的练习题:前后端分离、接口设计、数据缓存、可视化图表、权限管理、打包部署,一套流程全走通,技术含金量并不比花哨的增删改查低。这篇文章我就拿“基于 Spring Boot 和 Vue 的新冠肺炎疫情实时监控系统”为例,把从需求拆解到前端大屏、再到服务器部署的完整过程写出来。适合正在准备毕业设计的人、想入门 Spring Boot + Vue 全栈开发的人,以及想把这种“监控看板”改造成其他业务数据中台的人参考。官方统计渠道的公开数据可以拉,但我不想把篇幅浪费在爬虫和合规讨论上,重点只讲技术实现。
1. 内容整体设计与思路拆解
做这类系统最忌讳一上来就写代码。先想清楚做给谁看、有哪些模块、将来怎么扩展,后面写起来会顺手很多。
1.1 为什么选 Spring Boot + Vue 这个组合
先说后端。Spring Boot 在 Java 生态里几乎已经成了工程项目的默认起点,内嵌 Tomcat、自动配置、依赖管理一步到位,你不需要像 SSM 时代那样写一堆 XML 配置。对于疫情监控这种以数据查询和展示为主的系统来说,Spring Boot 的 REST API 开发能力非常轻量,一个 @RestController 就能把数据抛给前端。
前端选 Vue 的理由更直接:它是渐进式框架,模板语法简单,组件化开发让“数据看板”这种多卡片多图表页面变得容易拆分和维护。配合 Element Plus 做后台管理界面,ECharts 做图表,整个前端的实现周期可以压缩得非常短。
这个组合还有一个实际好处:社区资料极多,踩坑很容易搜到答案。无论是刚接触框架还是已经工作几年的开发者,遇到问题基本都能在现有帖子里找到现成解法,项目进度不容易卡住。
1.2 功能模块怎么划分
疫情监控系统的业务不复杂,但天然分成“给普通用户看”和“给管理员维护”两个端,前后端分离之后需要对功能边界有明确切分。
公众端核心功能:
- 全国疫情数据看板:展示累计确诊、现存确诊、治愈、死亡、境外输入等核心指标。
- 趋势变化图表:用折线图展示一段时间内全国新增确诊、新增治愈的变化曲线。
- 地区分布地图:用中国地图展示各省累计确诊数,颜色深浅表示严重程度。
- 疫情资讯列表:展示官方发布的新闻、通告、防疫政策,支持分页。
- 数据更新时间提示:让用户知道当前数据是什么时候刷新的。
后台管理端核心功能:
- 管理员登录认证。
- 疫情核心指标的每日数据维护。
- 资讯的分类发布、编辑、删除。
- 用户账号管理。
模块化划分对前后端协作很重要。前端可以照着模块去建页面组件,后端的 Controller 也可以按模块拆类,不至于所有接口堆在一个类里。我见过不少毕设项目把新闻、统计数据、用户管理的接口全写在同一个 Controller 里,工程一旦扩大就非常痛苦。
1.3 几个关键技术选型的取舍
首先数据库用 MySQL,这个基本没有争议,数据量很小,不需要上 PostgreSQL 或者 Oracle。
ORM 框架我推荐 MyBatis Plus,而不是原生 MyBatis 或者 JPA。原因很简单:它的单表 CRUD 和分页插件能省掉非常多的重复代码,BaseMapper 里已经内置了 insert、updateById、selectPage 这些方法,疫情数据维护这类简单业务几乎不用写 XML。如果项目里需要联表查询或者复杂统计,MyBatis Plus 的 Wrapper 也够用,完全不阻塞开发。
缓存用 Redis 的原因是两个:疫情数据是低频更新的热点数据,同一个数据半小时内被请求成百上千次,每次都查数据库明显浪费;定时任务拉取数据时也需要一个临时存储作为中间态。如果你只是想先跑通功能,Redis 不是硬性要求,但生产环境下做一个监控系统,缓存是必不可少的一层。
实时推送用 WebSocket。数据看板如果做成前端轮询,每 5 秒请求一次接口,浪费资源而且不够“实时”。用 WebSocket 让服务端主动把最新数据推给所有在线的客户端,才是监控类系统的常规做法。
系统本身的监控用 Spring Boot Admin,这个很多人容易忽略。你在做一个“监控系统”,那谁来监控系统本身?Spring Boot Admin 可以提供健康检查、CPU 内存指标、日志级别动态调整等能力,部署到服务器上之后非常实用。
2. 核心细节解析与实操要点
框架选型定了,后面就是每一个环节的具体实现。这个章节我把后端的数据链路、数据库设计、接口设计、缓存推送和系统自监控全部展开,每一块都有我实际做过的细节。
2.1 疫情数据来源与定时任务设计
疫情监控系统的前提是“数据从哪里来”。正规做法是从官方公布的公开渠道获取,我当时的做法是通过定时任务定时拉取公开的健康码、行程卡之外的数据源。这里不讨论如何爬取网页,更推荐直接对接一些数据服务商提供的公开 JSON 接口,优点是数据稳定且字段已经处理过,省去解析 HTML 的麻烦。
但是“实时”不等于“不停地拉”。数据源接口本身有访问频率限制,我实测下来比较好的策略是每个整点和半点拉取一次,通过 @Scheduled 注解就能实现。
@Component public class DataSyncTask { @Autowired private EpidemicDataService epidemicDataService; // 每 30 分钟执行一次 @Scheduled(cron = "0 0/30 * * * ?") public void syncData() { try { // 从第三方接口拉取全国及各省数据 String response = restTemplate.getForObject(dataUrl, String.class); // 解析 JSON,写入数据库并进行汇总更新 epidemicDataService.syncEpidemicData(response); // 更新 Redis 缓存,让前端能够立刻感知到新数据 redisTemplate.delete("epidemic:overview"); } catch (Exception e) { // 数据源异常时保留旧数据,并记录错误日志 log.error("数据同步失败,使用上一次数据", e); } } }很多人在这一步会把逻辑做得很啰嗦,比如把同步任务做成一个复杂的调度系统。实际完全不需要,@Scheduled + 手动兜底就够了。
关键点在于数据源异常时的处理。曾经有一次第三方接口超时,我一开始没做异常兜底,结果前端大屏直接显示了昨天的旧数据,用户第一时间就发现了。后来我在 syncData 方法里做了 try-catch:数据同步失败就保留数据库里最新的一批数据,同时把错误信息写入日志配合告警。这样即使第三方接口挂了一天,页面数据也不会“断开”。
2.2 数据库设计和实体类规划
数据库表设计决定了后端的开发效率,我按业务模块拆成了三张核心表:
第一张是疫情统计数据表。字段包含日期、省份、累计确诊、现存确诊、治愈数、死亡数、新增确诊、新增治愈等。日期加上省份必须做成联合唯一索引,这样同一行数据不会重复插入。
第二张是疫情资讯表。字段包含标题、摘要、正文、来源、发布时间、分类。这个表不需要复杂设计,主键自增就可以了。
第三张是后台用户表。字段包含用户名、密码、角色、状态。密码一定不要存明文,用 BCrypt 加密后入库。
建表语句核心示例如下:
CREATE TABLE `epidemic_daily` ( `id` bigint NOT NULL AUTO_INCREMENT, `stat_date` date NOT NULL COMMENT '统计日期', `province` varchar(50) NOT NULL COMMENT '省份', `confirmed` int DEFAULT '0' COMMENT '累计确诊', `existing` int DEFAULT '0' COMMENT '现存确诊', `cured` int DEFAULT '0' COMMENT '治愈', `dead` int DEFAULT '0' COMMENT '死亡', `new_confirmed` int DEFAULT '0' COMMENT '新增确诊', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_stat_date_province` (`stat_date`, `province`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;表结构不要设计得太花哨,但是 create_time 和 update_time 建议保留。后面接定时任务和 WebSocket 推送的时候,你需要知道数据什么时候更新过,这两个字段能省去你很多排查问题的时间。
实体类的设计对应也比较直接。Java 端用 LocalDate 对应数据库的 date 类型,用 LocalDateTime 对应 datetime 类型。
2.3 后端接口设计与统一返回格式
接口设计遵循 RESTful 风格,并且所有接口返回统一的数据结构。这一点看起来简单,但很多人一开始都忽略,结果前端在解析数据时要针对每个接口单独做判空处理,非常散乱。
统一返回结构一般包括三个字段:code 表示业务状态码,msg 表示提示信息,data 是真正的业务数据。
public class Result<T> { private Integer code; private String msg; private T data; public static <T> Result<T> success(T data) { Result<T> result = new Result<>(); result.code = 200; result.msg = "success"; result.data = data; return result; } public static <T> Result<T> error(Integer code, String msg) { Result<T> result = new Result<>(); result.code = code; result.msg = msg; return result; } }核心接口清单如下:
| 接口路径 | 方法 | 功能说明 |
|---|---|---|
| /api/statistics/overview | GET | 获取全国累计数据概览 |
| /api/statistics/trend | GET | 获取近一个月新增确诊趋势 |
| /api/statistics/map | GET | 获取各省累计数据供地图渲染 |
| /api/news/list | GET | 分页获取疫情资讯 |
| /api/admin/login | POST | 管理员登录 |
| /api/admin/epidemic/save | POST | 后台维护每日数据 |
| /api/admin/news/save | POST | 后台发布资讯 |
Controller 层只做参数接收和结果包装,业务逻辑全部放到 Service 层。比如统计概览接口,Controller 里一行调用 service,如果 Redis 里有缓存就直接返回缓存,没有才查数据库,这正好承接前面缓存设计。
一次实际请求的流程可以串起来:前端调用 GET /api/statistics/overview,后端先查 Redis,key 是 epidemic:overview,如果命中直接返回;如果 miss,就从数据库汇总最新一条记录,重新写入 Redis 并设置 30 分钟过期时间。这样同一时间段内大量用户同时访问大屏,数据库压力基本上可以忽略。
2.4 Redis 缓存与 WebSocket 实时推送
缓存和推送是“实时监控”体验的关键,分开说。
Redis 缓存的设计不用太复杂,核心注意两点:第一,给缓存 key 设置合理的过期时间,新闻类数据可以高频刷新,统计数据 30 分钟左右就可以;第二,定时任务更新完数据后,要主动删除对应的缓存 key,否则用户一直看到的还是旧数据。
WebSocket 的引入则让前端不需要轮询就能拿到最新数据。Spring Boot 集成 WebSocket 的依赖很小:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>核心是一个 WebSocketConfigurer 配置类和一个业务 Handler。Handler 里 onOpen 记录会话,onMessage 接收前端传的订阅参数,业务定时任务执行完之后调用一个广播方法,把最新的统计数据推送给所有在线的会话。
这里有一个容易踩的问题:WebSocket 连接会因为服务器 Nginx 代理超时而被断开,尤其是当页面长时间不操作时。所以前端要写一个心跳机制,每隔一段时间发送 Ping,服务端收到后返回 Pong,一旦连接断了就自动重连。没有这个机制,看板页面第二天打开可能数据就不再刷新了。
2.5 系统自身的监控:Spring Boot Admin
做监控系统的同时一定不要忘了监控系统本身。Spring Boot Admin 可以实时查看服务的内存、线程、HTTP 请求量,我是在部署到服务器之后才加的,加了之后排查问题方便很多。
服务端是一个独立的 Spring Boot 应用,引入 spring-boot-admin-starter-server,主类加 @EnableAdminServer 注解。客户端就是业务系统本身,引入 spring-boot-admin-starter-client,配置文件中指定服务端地址,然后通过 HTTP 注册上去。
spring: boot: admin: client: url: http://localhost:9000 instance: name: epidemic-monitor management: endpoints: web: exposure: include: '*'需要留意的是管理端端口别跟业务端口混在一起,我用的是 9000 端口。部署后重启业务系统,登录 Admin 管理页就能看到健康状态、JVM 内存、在线线程等信息。如果服务器配置比较低,这些指标能在系统卡顿之前给你预警。
3. 实操过程与核心环节实现
这个部分从前后端初始化开始,把大屏图表、后台管理、权限控制和 Mock 联调逐步讲清楚。这些步骤我都实际跑过,难度不大,但容易在细节上卡住。
3.1 前端初始化与技术栈配置
前端我选 Vue 3 + Vite,而不是 Vue 2 + Vue CLI。如果你是第一次做项目,建议直接上 Vue 3,生态现在已经非常成熟,组件库和插件都是围绕 Vue 3 来发展的。
npm create vite@latest epidemic-frontend -- --template vue cd epidemic-frontend npm install npm install axios element-plus echarts vue-router piniaVue Router 使用路由懒加载来拆分页面,大屏页面和后台页面不会一次性打包进同一个 JS 文件。Pinia 替代 Vuex 管理全局状态,比如管理员登录后的用户信息。
项目的目录结构大致如下:
- src/api:所有接口请求方法的封装,按模块拆成 statistics.js、news.js、admin.js。
- src/router:路由配置文件,包含前端路由守卫。
- src/views:页面组件,大屏、后台、登录等都放这里。
- src/components:图表组件、通用卡片等。
- src/store:Pinia 的 store 文件。
- src/utils:axios 实例、权限指令等工具。
结构清晰是前端工程化的第一件事。组件命名统一用驼峰,文件命名统一用小写加横杠,不要在同一个项目里混用大驼峰和小驼峰风格。
3.2 Axios 封装与跨域处理
axios 不能直接在组件里到处 new,一定要统一封装。封装的核心功能有三个:设置 baseURL、统一请求头、响应拦截器统一处理后端返回的 Result。
import axios from 'axios'; const request = axios.create({ baseURL: '/api', timeout: 10000 }); request.interceptors.response.use( response => { const res = response.data; if (res.code !== 200) { // 业务错误统一提示 return Promise.reject(new Error(res.msg || '请求失败')); } return res; }, error => { // 网络错误或超时提示 return Promise.reject(error); } ); export default request;开发环境下的跨域问题由 Vite 的 proxy 解决,不需要后端开启 CORS。在 vite.config.js 里配置:
export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } });这里要注意 Vite 的代理只在开发环境生效。前端 npm run build 之后,dist 里的文件是纯静态资源,不管它,proxy 不再起作用,请求会直接发到当前域名下的 /api。所以生产环境要么用 Nginx 反向代理到后端服务,要么把前端产物放到后端服务的静态目录里,让 Spring Boot 自己托管。打包环节后面专门讲。
3.3 ECharts 大屏可视化核心实现
疫情数据看板是项目的门面,也是 ECharts 发挥主要价值的地方。我做了三个核心图表组件:全国趋势折线图、各省累计柱状图、中国地图分布图。
折线图组件的数据来自 /api/statistics/trend,返回近 30 天的日期和新增数字,直接配置 series 即可。地图分布这块要注意的是,新版 ECharts 已经不再默认内置中国地图 GeoJSON,需要单独引入 china.json,并从echarts的registerMap中注册。这个环节很多人踩坑,页面上一大片空白,控制台也没有明显报错,实际上就是地图文件没引入。
import * as echarts from 'echarts'; import china from '@/assets/china.json'; echarts.registerMap('china', china); // 地图配置核心项 myChart.setOption({ tooltip: {}, visualMap: { min: 0, max: 100000, text: ['高', '低'], inRange: { color: ['#e0f3f8', '#abd9e9', '#74add1', '#4575b4'] } }, series: [{ type: 'map', map: 'china', roam: true, label: { show: true }, itemStyle: { areaColor: '#f0f0f0' }, data: mapData }] });图表组件一定不要在 mounted 中直接调用 ECharts 的 setOption 就完了,需要处理窗口大小变化时 resize 事件,同时在组件销毁前移除事件监听,否则切换到后台页面再回来时图表会错乱或者报内存相关的警告。
3.4 后台管理的路由、权限与 Mock 联调
后台管理部分涉及登录和权限控制。页面级权限通过 Vue Router 的前置守卫来实现:未登录用户访问后台路由时,强制跳转到登录页。这已经算是比较基础了。
按钮级别的权限控制我用了一个自定义指令。后端登录接口返回管理员角色和权限列表后,前端把权限标识存到 Pinia,自定义指令在元素挂载前校验权限,无权限的按钮直接移除。这个设计在模板里写起来非常干净:
<button v-permission="'admin:news:delete'">删除</button>再补充一个 Mock 联调的问题。热搜词里很多人问 Mock 是怎么体现的,我实际项目中的做法是在前端还没等到后端接口时,在 src/mock 目录放置静态 JSON 数据,接口封装层直接返回这些 JSON,让前端开发和数据可视化工作先行。后端接口完成后,把原来的 import 静态数据改成 axios 请求真实接口即可。Mock 是开发阶段的联调工具,不是正式接口的替代品,上线之前一定要清干净。
4. 常见问题与排查技巧实录
这个部分整理的是我在实际操作中真正遇到并解决的问题。我把现象、原因和解决办法都写出来,方便你在复现的时候快速对照。
4.1 跨域请求被拦截
前后端分离联调时最常见的错误就是 CORS。现象是浏览器控制台出现类似 “Access-Control-Allow-Origin” 的错误,接口数据加载不出来。
处理方法有两种:开发环境用 Vite 代理,上面已经写过;如果坚持要让后端开跨域,则要写一个配置类实现 WebMvcConfigurer。但是需要注意 Spring Boot 版本差异,2.4 之前的版本用 addCorsMappings 可以直接配置,2.6 之后因为引入新的跨域处理机制,默认情况下允许跨域的源不能是 allowedOrigins 的通配符,需要改成 allowedOriginPatterns,否则配置了也不生效。
4.2 前端拿到的时间格式不是想要的样子
后端返回 LocalDateTime 时,默认序列化结果是 ISO 格式的字符串,前端直接在表格里显示会非常难读。解决办法是在配置文件中统一制定格式:
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8需要注意的是 SimpleDateFormat 只能格式化 java.util.Date,如果实体类使用的是 LocalDateTime,则需要引入 jackson-datatype-jsr310 模块,或者直接给字段添加 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 注解。否则你会发现配置文件设置了格式,接口返回还是 ISO 格式。
4.3 ECharts 地图显示空白
这个问题我上面提到过,但值得单独强调。现象:图表区域空白,没有省份名称也没有地图轮廓。
原因几乎都是缺少 GeoJSON 数据并且没有 registerMap。解决方法是下载 china.json 放入 src/assets 目录,在组件初始化时注册地图。还有一个小细节,项目打包后 GeoJSON 文件路径可能出问题,不要用相对路径,统一用 import 引入,打包时 Vite 会正确处理资源路径。
4.4 WebSocket 连接不稳定
部署到服务器之后发现看板页面经常出现数据“不更新”的情况,刷新页面又好了。排查后发现是 Nginx 默认的 proxy_read_timeout 设为 60 秒,而 WebSocket 是长连接,超过 60 秒没有数据交互就被服务端断开了。
解决方案双层处理:前端在 onclose 事件里延迟执行重连逻辑,心跳 Ping 设置为 30 秒一次;Nginx 的代理配置里增加 Upgrade 和 Connection 头,提升 proxy_read_timeout 到 300 秒。两边都做了之后,连接就非常稳定了。
4.5 第三方数据源接口延迟或失败
定时任务去第三方接口拉数据时,偶尔会遇到网络抖动或者对方接口升级,导致同步失败。这个问题直接决定了监控大屏的可用性。我的处理是“三级兜底”:本地有一份备份数据文件;数据库里始终保留最新一次成功同步的数据;同步失败时日志告警并保持旧数据不变。这样即使第三方接口挂了 24 小时,页面上仍然展示最近一次有效数据,只是更新时间不再变动。
我做了一个简单的排查速查表,方便你对照:
| 问题现象 | 可能原因 | 处理方法 |
|---|---|---|
| 接口报跨域错误 | CORS 配置不对或没有走代理 | 开发环境用 Vite proxy,生产用 Nginx |
| 数据请求 404 | 前端 baseURL 与后端 context-path 不一致 | 统一上下文路径并检查代理路径 |
| 大屏图表无数据 | 后端接口返回空数组,前端未做空值处理 | 接口层做默认值,前端判空渲染 |
| 地图区域颜色不显示 | GeoJSON 未注册或数据格式不匹配 | registerMap 注册后检查 series.data 字段名 |
| WebSocket 自动断开 | 代理超时或没有心跳 | 前端心跳 + Nginx 升级协议配置 |
| 定时任务重复执行数据翻倍 | cron 表达式写错,或应用部署了多个实例 | 校验 cron,多实例下加分布式锁 |
| LocalDateTime 格式错误 | 未配置 Jackson 时间序列化 | yml 统一 date-format 或字段加 @JsonFormat |
5. 部署与联调实战
前端的开发和生产环境是不同的场景,这一节把从本地联调到打包部署的完整流程写出来,让你直接用同样的步骤复现。
5.1 开发环境准备
如果你用的是 IntelliJ IDEA 社区版,有一点需要提前知道:社区版免费,但不带 Spring Initializr 集成面板。很多新手在这个地方直接卡住,以为社区版不能做 Spring Boot 项目,其实不是,解决办法有两个。
第一种是到 start.spring.io 网页上选择依赖并且生成项目压缩包,然后下载,在 IDEA 中直接打开解压后的目录,完全没问题。第二种是直接建一个 Maven 项目,在 pom.xml 里手动引入 spring-boot-starter-parent 和需要的依赖,Maven 会自动拉取。我在社区版上用一个多模块项目做过完整开发,体验上没有任何障碍。
后端通常需要 JDK 8 或者 JDK 11、Maven 3.6+、MySQL 5.7+、Redis。注意 pom.xml 里 Spring Boot 的版本一般用 2.6.x 或 2.7.x,别追求最新,2.x 系列的社区资料和兼容性稳定;如果你选择 Spring Boot 3,JDK 必须换到 17,依赖可能有些 API 变化,尤其是 javax 改成 jakarta 这一块,新手容易踩坑。
5.2 前后端联调的关键注意点
联调阶段最常见的问题是字段名不一致。前端定义的是newConfirmed,后端返回的是new_confirmed,页面就会显示 undefined。最佳实践是:后端统一使用 camelCase 风格输出,数据库表字段才用 snake_case,实体类上加 MyBatis Plus 的驼峰映射配置即可自动转换。
联调时建议打开浏览器开发者工具的 Network 面板,直接查看接口请求和返回。Vue 项目的网络请求若被代理,显示的是/api/statistics/overview,你可以在面板里看到代理后真正请求的地址,这样能快速判断是前端路径错了还是后端接口报错了。
5.3 两种部署方式:合并打包与前后端分离部署
部署方式有两种,我都使用过。
第一种方式,把前端打包后的 dist 目录复制到后端项目的src/main/resources/static目录里,然后直接使用 Maven 打包成一个可执行的 jar 包,启动后通过同一个端口访问页面和接口。这种方式的优点是部署简单,只需要跑一个 Java 进程,不需要额外安装 Nginx。缺点是前后端代码物理上耦在一起,以后前端更新要重新打整个 jar 包。它非常适合毕业设计演示和内部测试场景。
第二种方式,前后端分离部署。前端静态文件交给 Nginx 托管,后端只是一个纯 API 服务。Nginx 负责拦截/api前缀的请求并反向代理到后端的 8080 端口,静态页面直接由 Nginx 直接返回。这种方式更接近实际生产环境,但配置成本高一些。
如果你选了 Spring Boot 3,要注意 Java 17 版本的 server 部署,Tomcat 内嵌版本和 javax 到 jakarta 的包名变化。不过日常演示场景,Spring Boot 2.x 仍然是部署最稳妥的选择。
5.4 服务器部署流程参考
部署到 Linux 服务器的操作流程大致如下:
- 在服务器安装 JDK、MySQL、Redis,修改 MySQL 初始密码并创建数据库。
- 在服务器执行初始化脚本,建表。
- 后端项目在本地执行
mvn clean package -DskipTests打包,把 target 下的 jar 包上传到服务器。 - 前端在本地执行
npm run build,把 dist 目录也上传到服务器。 - 单进程方式就直接运行 jar,分离部署就先配置 Nginx 静态目录和反向代理再启动服务。
启动后检查接口和数据同步是否正常:
curl http://localhost:8080/api/statistics/overview如果接口返回了统计数据,并且定时任务日志里没有报错,整个系统就算跑起来了。
写在最后
做这个项目之前,我本来以为它只是一个“拿现成 API 数据展示”的简单系统,真正做完之后才发现里面牵扯的环节非常多:从数据源同步、数据库建模、统一接口设计、Redis 缓存,到 WebSocket 实时推送、ECharts 地图可视化、权限控制和最后的生产部署,几乎每一个模块都有值得记录的坑。最让我收获大的其实不是某个具体功能,而是把前端和后端之间的“契约”想清楚:字段名、返回结构、异常处理、时间格式,这些约定越早统一,联调阶段越省心。
另外有一点个人建议:如果你打算把这个项目作为毕业设计或者个人作品展示,不妨在核心架构不变的前提下,把“疫情数据”这个主题替换成更通用的“实时数据监控”,比如设备状态监控、空气质量监控、交通流量监控等,技术栈完全不需要改动,只需要调整数据源和前端展示文案。这样项目的展示价值和实际意义都会更广,面试时也更容易讲清楚设计思路。
最后分享一个实际操作中的习惯:每写一批接口,就用 Postman 把请求和响应保存下来,写一个简单的接口文档。这个习惯在多人和团队协作时效果极其明显,关键时候真的能救命。