ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SSM+Vue空气污染预警系统毕业设计:从AQI算法到ECharts可视化完整实现

SSM+Vue空气污染预警系统毕业设计:从AQI算法到ECharts可视化完整实现 又是一年毕设季后台已经有好几个同学在问“空气污染预警系统”这个题目怎么做。说实话这个题在SSM Vue这套组合里属于非常典型的“数据采集—计算—展示—预警”闭环业务链路完整、可视化效果好、又贴合环保热点老师看到题目和演示都会觉得有实际价值。这篇就把我实际做完这套系统之后沉淀下来的东西整理出来从需求拆解、数据库设计、AQI算法到前端Vue工程、ECharts图表、联调部署最后补充一批毕设现场最容易踩的坑和答辩准备建议。无论你现在是刚立项还没动工还是代码已经写了半截卡在跨域和图表上这篇都能给你一份可以直接对着做的路线。1. 项目整体设计预警系统的需求边界与技术选型1.1 功能模块拆解空气污染预警到底要做什么空气污染预警系统说白了就是把监测站采集到的PM2.5、PM10、SO2、NO2、CO、O3这些污染物浓度数据存进MySQL后端用算法计算AQI空气质量指数前端把结果用表格、曲线图、地图展示出来同时当某个站点的污染物浓度超过阈值时自动生成预警记录并推送到页面。我第一次接到这个需求的时候第一反应是“这不就是个CRUD项目吗”。但你真正动手拆分就会发现问题没那么简单它至少包含四个业务闭环。首先是数据接入与管理。监测站是数据源头每个站有名称、所属区域、经纬度信息污染物数据是按时间积累的一天内一个站可以采集24条甚至更多记录。系统里必须有站点管理功能支持对监测站的新增、修改、停用、删除同时要能手动录入或批量导入监测数据。这块是后端的重头戏涉及两张核心表的设计。其次是空气指数计算。污染物浓度原始值和人们感知的空气质量不是一个东西需要根据《环境空气质量指数AQI技术规定》把六项污染物浓度换算成各自的IAQI分指数再取最大值作为该站点的AQI值并划分等级。这部分是系统里最有“技术含量”的地方也是答辩时老师最爱追问的部分我会在2.2节详细展开。第三是查询与可视化。普通用户进来最关心的就是“今天空气怎么样”“我所在区域能不能户外运动”。所以首页要展示当前各站点的AQI排行、等级颜色、首要污染物站点详情页要有近24小时或近7天的污染物变化趋势。可视化的核心工具就是ECharts绘制折线图、柱状图、站点地图打点。第四是预警功能。预先给PM2.5、PM10、O3等污染物设定告警阈值比如PM2.5浓度超过150μg/m³就触发重度污染预警。系统做定时扫描发现超标则自动生成预警记录前端通过轮询或WebSocket把最新预警弹出来。管理员还需要一个预警管理页面处理或确认预警记录处置情况。建议的模块清单是登录注册、实时空气质量展示、历史数据查询、地图站点分布、预警规则配置、预警记录管理、用户管理、站点管理、数据管理。千万别贪多把这条闭环做扎实比堆一堆半成品功能要强得多。1.2 技术选型SSM Vue 为什么是毕设的稳妥组合先聊后端。SSM是Spring、SpringMVC、MyBatis三个框架的组合在Spring Boot出现之前是Java Web的绝对主流现在很多学校的Java课程和毕业设计模板依然用这套组合。它好在哪儿一个是职责边界非常清晰Spring管对象和事务SpringMVC管请求路由和参数绑定MyBatis管SQL和结果映射。你写完一个接口很容易跟老师讲清楚“请求怎么进来的、业务逻辑在哪做的、SQL是怎么执行的”。相比Spring Boot那种一揽子自动配置的风格SSM更接近框架底层原理对答辩展示有利。有人会问2026年了还上SSM是不是太老了我的看法是如果你的毕设任务书明确写了SSM那就别纠结这套组合成熟稳定、资料极其丰富遇到任何问题都能搜到解法。如果任务书没限定我会建议用Spring Boot因为开发效率高很多但从“论文好写、原理好讲”的角度SSM反而更占便宜——你可以浓墨重彩地写IOC容器、AOP事务、SpringMVC的HandlerMapping流程这些在Spring Boot里被自动配置盖住了反而不好写。前端选Vue的理由很简单组件化开发、响应式数据绑定、生态成熟。Element Plus或Element UI能快速搞定后台管理的表格、表单、弹窗省下大量写CSS的时间这对时间紧张的毕设来说太关键了。版本上我建议2026年做毕设直接上Vue 3 Vite Element Plus Pinia这套组合是当前主流而且Vite的启动速度比Webpack快一个量级开发体验好很多。如果你拿到的学校模板是Vue 2 Element UI也不是不能用但我更推荐自己搭Vue 3工程然后按2.3节的思路集成进模板。下面这个表是我当时做选型对比时列的供你参考对比维度SSM Vue 前后端分离单体JSPServletSpring Boot VueThymeleaf前后端分离程度完全分离接口交互页面耦合基本无分离可以分离但老式用法仍耦合框架学习价值高贴近底层低偏陈旧中封装度高开发效率中需要自己写较多配置低高论文可写深度高有大量原理可分析低中答辩友好度高低中图表组件我选了ECharts没有选AntV或Highcharts。原因是ECharts对中文支持好、地图支持完善、示例多毕业设计里做空气质量趋势图、站点污染等级地图几乎就是官方示例的改造学习成本很低。1.3 论文与程序的配合先搭框架还是先写代码毕业设计的交付物是“论文 程序”这两者不是先写代码后凑论文的关系而是应该从一开始就互相咬合。我的建议是先定系统模块图和数据库表设计再写代码最后用系统截图和核心代码回填论文。这样论文里的系统设计部分和实际程序不会“两张皮”答辩时也不会出现老师问你某个功能你却说“还没做”的尴尬。论文结构可以参考经典的七章式第一章绪论写背景、国内外研究现状第二章相关技术介绍写SSM、Vue、MySQL、ECharts第三章需求分析画用例图、流程图第四章系统设计写架构图、功能模块图、数据库ER图第五章系统实现放核心代码和运行截图第六章系统测试放功能测试和性能测试记录第七章总结与展望。这里有个细节容易被忽略论文里放的每张截图、每个数据都要和程序实际运行结果一致。我见过不止一个人先写论文再补程序结果论文里写“系统支持24小时实时数据采集”程序里根本没有定时任务被老师一句话问穿。你应该在程序完全跑通之后再整理截图宁可晚点写也不能瞎写。同时代码注释一定要认真写关键类、关键方法的注释直接可以搬进论文的核心代码分析部分一举两得。2. 后端实现数据库、AQI算法与SSM分层开发2.1 数据库表设计从监测站到预警记录数据库是整个系统的地基表结构设计得好不好直接决定后面写代码顺不顺手。按照“一站一数据、一数据一预警”的脉络我设计了四张核心表外加用户表和基础字典表。用户表t_user字段id、username、password、role、real_name、create_time。角色用字符串区分“admin”和“user”不做复杂的RBAC权限模型。注意密码在毕设里用MD5或BCrypt加密存储别用明文虽然是小项目但这是评审老师会看的一个专业细节。监测站点表t_station字段id、station_no、station_name、region、longitude、latitude、status、remark。经纬度用decimal(10,6)存精度足够到米级。status字段控制站点是否启用做下拉筛选时很方便。污染物数据表t_air_data字段id、station_id、pm25、pm10、so2、no2、co、o3、aqi、level、primary_pollutant、collect_time。浓度值我用decimal(10,2)因为污染物浓度在绝大多数情况下保留两位小数就够了。aqi和level字段是该条记录的“计算结果”特意冗余存下来避免每次查询都要实时计算。这是数据仓库里的“空间换时间”思路在做范围查询和趋势统计时能省大量计算。预警记录表t_warning字段id、station_id、pollutant_type、warning_level、content、handled、handle_user、handle_time、create_time。这里有个设计点是我后来才补的除了存预警触发时的污染物type和level还应该冗余一个content字段把“某站点PM2.5浓度达到XXX属于重度污染”这行提示文字直接存下来前端展示时就不用再去拼接了。索引方面t_air_data表最核心的查询是按站点和时间段查一定要建联合索引(station_id, collect_time)t_warning表按handled状态查询较多建普通索引(handled)。字段类型上主键用BIGINT自增时间统一DATETIME不要用timestamp或者字符串否则后续做区间查询和排序会出现各种怪问题。数据量其实不用太担心。一天24小时、10个站点也就是240条记录一个月7200条MySQL完全扛得住。重点是把采集时间标注清楚为后面画趋势图做准备。如果你希望演示时数据好看可以写一个存储过程或Java程序批量生成近30天的模拟监测数据注意让数据体现出“白天高、夜间低”“冬季偏高”这样的周期性。2.2 AQI指数计算预警规则的核心算法AQI计算是整个系统最能体现专业度的地方也是答辩老师可能问得最细的环节。它不是一个简单的平均值公式而是分段线性插值计算。完整算法逻辑是这样的对于每一项污染物都有一张“浓度限值表”把浓度区间和对应IAQI区间对应起来。比如PM2.5当浓度在0-35μg/m³时IAQI是0-50浓度在35-75μg/m³时IAQI是50-100浓度在75-115μg/m³时IAQI是100-150后面每一档对应不同区间。某个浓度值落在哪个档就用下面这个公式算IAQI_p (IAQI_Hi - IAQI_Lo) / (BP_Hi - BP_Lo) * (C_p - BP_Lo) IAQI_Lo其中C_p是实测浓度BP_Hi和BP_Lo是该浓度对应区间的上限和下限IAQI_Hi和IAQI_Lo是分指数区间的上限和下限。最后AQI取六项污染物IAQI的最大值最大的那一项就是首要污染物。等级划分是0-50优绿色、51-100良黄色、101-150轻度污染橙色、151-200中度污染红色、201-300重度污染紫色、大于300严重污染褐红色。我给一个可复制的Java工具类核心代码你在Service层直接调就行public class AqiUtil { // PM2.5的浓度限值区间{浓度下限, 浓度上限, IAQI下限, IAQI上限} private static final double[][] PM25_TABLE { {0, 35, 0, 50}, {35, 75, 50, 100}, {75, 115, 100, 150}, {115, 150, 150, 200}, {150, 250, 200, 300}, {250, 500, 300, 500} }; public static double calcIAQI(double concentration, double[][] table) { for (double[] range : table) { if (concentration range[0] concentration range[1]) { return (range[3] - range[2]) / (range[1] - range[0]) * (concentration - range[0]) range[2]; } } return -1; // 超出上限可视为严重 } public static int calcAQI(double pm25, double pm10, double so2, double no2, double co, double o3) { double max 0; max Math.max(max, calcIAQI(pm25, PM25_TABLE)); // 其余污染物用对应限值表逻辑相同 return (int) Math.round(max); } }如果为了简化只用一个污染物的IAQI代替AQI也不是不行但你的论文里一定要写清楚是“简化处理”。我个人建议还是把六项都实现出来代码就多几十行但论文里可以写“系统严格参照HJ 633-2012标准计算AQI”这个含金量完全不一样。关于预警规则的实现不建议把阈值写死在代码里而是在库里建一张warning_config表存pollutant_type、threshold、warning_level。定时任务每个整点跑一次扫描过去一小时的数据凡是浓度超过当天阈值的记录都生成预警。MyBatis的Mapper里一句select语句批量查出超标的站点和数值Service里循环写入预警表再配合一个状态字段防止重复告警。重点说明一点预警级别的颜色体系一定跟前端联动好红橙黄绿这些颜色对应关系在前后端要一致否则做演示的时候会出现“页面显示严重污染但颜色是绿的”这种笑话。2.3 SSM三层联动Mapper、Service、Controller的落地方式SSM的分层方式说起来简单但第一次接触的同学很容易在Mapper这一层卡住。我习惯的写法是Mapper接口负责定义方法Mapper XML里写SQLService层做业务编排和事务管理Controller只负责接收参数和返回结果。一个典型的“查询某站点近7天AQI趋势”接口完整调用链是这样的。Controller层用RestController和RequestMapping(/api/station)定义RESTful接口。接收参数用RequestParam或RequestBody返回统一封装的Result对象包含code、message、data三个字段。这段代码看起来有点啰嗦但统一响应格式对前端axios封装至关重要RestController RequestMapping(/api/station) public class StationController { Autowired private StationService stationService; GetMapping(/trend) public Result trend(RequestParam Long stationId, RequestParam(required false) Integer days) { ListMapString, Object data stationService.getAqiTrend(stationId, days null ? 7 : days); return Result.success(data); } }Service层里接口定义方法实现类加Service注解需要多条SQL协作的方法加Transactional。注意一个细节MyBatis的Mapper绑定时Mapper接口的namespace必须是XML文件里的完整接口路径方法名必须跟XML中id完全一致。我曾经因为方法重载导致参数类型不匹配卡了好几个小时才找到原因。还有一个常见坑是MyBatis的驼峰映射数据库字段是collect_timeJava属性是collectTime如果不配置map-underscore-to-camel-case或在XML里写resultMap查询结果就是一片null。Mapper XML里有两个占位符需要区分清楚#{}是预编译参数生成PreparedStatement占位符安全且能防SQL注入${}是字符串拼接仅用于动态表名或排序字段等特殊场景。建议非特殊场景一律用#{}。分页我用的PageHelper一行PageHelper.startPage(pageNum, pageSize)就搞定能省不少事。数据返回前端之前还有一个环节值得打磨日期格式。LocalDateTime如果不做全局配置返回给前端的是类似“2026-03-17T10:30:00”的字符串虽然也能解析但不利于展示。可以在Jackson配置里统一格式为“yyyy-MM-dd HH:mm:ss”这样一个值对象直接JSON序列化就能被前端表格列正常展示。3. 前端工程化Vue 项目结构与数据可视化3.1 Vue 工程搭建Vite、Element Plus 与项目目录前端工程我推荐用Vite搭建命令就一条npm create vitelatest air-front -- --template vue装完之后进入项目安装核心依赖cd air-front npm install npm install vue-router4 pinia axios element-plus element-plus/icons-vue echarts如果网络慢先改npm镜像再装不然卡在node_modules上很崩溃。这里有个经验把package.json里依赖先写好再npm install比一条条安装更稳妥版本不容易乱。项目目录我建议按功能拆而不是按文件类型堆src/api存放所有后端接口调用按模块拆文件station.js、airdata.js、warning.js、user.jssrc/assets静态资源src/components可复用组件LineChart.vue、StationMap.vue、WarningBanner.vuesrc/router路由配置含路由守卫src/storePinia状态管理存用户信息和站点列表src/utilsrequest.jsaxios封装、auth.jstoken存取src/views页面级组件Login.vue、Home.vue、Station.vue、History.vue、Warning.vue、Admin.vueElement Plus的引入方式有两种全量引入简单但包体积大按需引入要用unplugin-auto-import配置稍麻烦。毕设场景我建议全量引入省下的那些性能和体积对项目实际上没有意义稳定性优先。App.vue里放一个全局的router-viewNavBar和SideBar通过布局组件复用。Vite端口默认5173如果和本机其他项目冲突在vite.config.js里配server.port。这里建议把开发服务器端口固定一下比如5173方便后面写文档和演示。还有一点Vite官方脚手架默认对外暴露局域网访问如果开了防火墙手机调试连不上可以先在局域网内测试一下移动端展示效果虽然这个系统主要是PC端用但老师很可能用平板外接投影演示页面宽度自适应还是要注意的。3.2 Axios 封装与跨域处理每个请求都写一遍axios.get然后单独处理错误代码会非常啰嗦。我的做法是封装一个request.js实例统一设置baseURL、超时时间并用拦截器处理token注入和响应错误。核心代码如下import axios from axios import { ElMessage } from element-plus import router from ../router const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] token } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message) return Promise.reject(new Error(res.message)) } return res }, error { if (error.response error.response.status 401) { localStorage.removeItem(token) router.push(/login) } ElMessage.error(error.message || 请求失败) return Promise.reject(error) } ) export default request跨域问题在开发环境有两个解法后端加CrossOrigin或者前端用Vite的proxy代理。建议优先用proxy因为CrossOrigin虽然简单但涉及cookie跨域、CORS预检请求等额外细节而且生产环境还得再处理一次。Vite里配置代理只需要在vite.config.js加一段server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }这样前端请求地址写/api/station/list开发服务器会把请求转发到后端8080端口。生产部署时把dist包放到后端同域位置或者让Nginx做同样的反向代理跨域就完全不用操心了。这里再强调一下前后端分离项目有“两个源”localhost:5173和localhost:8080浏览器会觉得它们是不同的源只有代理或CORS能解决。3.3 ECharts 可视化趋势图、柱状图与站点地图ECharts是前端可视化的主力。我封装了一个LineChart.vue组件接收一个options prop在mounted里初始化图表并在watch里监听数据变化调用setOptiontemplate div refchartRef stylewidth: 100%; height: 400px/div /template script setup import * as echarts from echarts import { ref, onMounted, watch } from vue const props defineProps({ options: { type: Object, required: true } }) const chartRef ref(null) let chart null onMounted(() { chart echarts.init(chartRef.value) chart.setOption(props.options) }) watch(() props.options, (val) { chart.setOption(val) }, { deep: true }) /script趋势图是核心展示AQI随时间的变化。X轴放时间、Y轴放AQI值用折线图或者面积图同时在折线图上用markLine画一条预警阈值的参考线一眼就能看出哪些时段超了。柱状图可以按污染物浓度展示六个污染物各一根柱子适合对比同一站点不同污染物浓度。饼图可以用来统计预警等级占比比如近一个月“良占多少、轻度污染占多少”。地图部分是很多同学会卡的坑ECharts 5官方包不再内置中国地图GeoJSON需要自己下载china.json文件并注册地图。做法是在项目里放一个geo目录然后用import chinaJson from ../geo/china.json echarts.registerMap(china, chinaJson)站点在地图上的展示用scatter或者effectScatter系列每个站点一个坐标点把经纬度从后端拉出来散点颜色根据AQI等级动态计算。你可以给不同等级设计不同的颜色映射函数优是绿色、良是黄色、轻度污染是橙色、中度污染是红色这样地图上整个区域的污染态势一目了然演示效果非常好。需要注意地图组件加载时候选分辨率的问题window.resize时最好调用chart.resize()否则缩放浏览器后图表会变形。3.4 预警功能的前端交互轮询、路由守卫与权限控制预警展现是“最后一公里”交互做得好不好直接影响老师对系统的第一印象。我的做法是在首页顶部放一个警告横幅组件实时展示最新的未处理预警。实现方式不复杂组件挂载后用一个setInterval定时器每30秒请求一次/api/warning/latest接口如果后端返回的预警记录和当前展示的不同就用ElMessage.warning弹出提示并更新横幅文字。定时轮询虽然不优雅但比WebSocket简单可靠得多。如果你想让项目看上去更有技术含量也可以引入WebSocket后端用Spring的WebSocket推送预警实时消息前端new WebSocket来处理。不过我对毕设的建议是先轮询跑通如果时间和精力充足再加WebSocket不要一上来就上通信协议复杂度会指数上升。路由守卫这块基于Vue Router的beforeEach钩子实现登录拦截和权限控制router.beforeEach((to, from, next) { const token localStorage.getItem(token) const role localStorage.getItem(role) if (to.path /login) return next() if (!token) return next(/login) if (to.path.startsWith(/admin) role ! admin) { ElMessage.error(无权限访问) return next(/) } next() })普通用户只能看首页、站点查询、历史趋势管理员才能进入后台管理页面做站点CRUD、用户管理、预警规则配置。这里有一个小技巧菜单栏的入口根据角色动态render比如Vue的v-if里判断role管理员的“系统管理”菜单对普通用户隐藏。演示的时候分别登录两个账号给老师看区别权限控制的印象分会很足。Vue的v-model在表单交互中会高频使用。比如站点的筛选条件一个el-select绑定stationId一个el-date-picker绑定dateRange数据一变前端立刻重新调用接口更新图表。这个响应式特性体现了Vue的核心价值论文的“前端实现”部分一定要写一段关于数据双向绑定和组件化的分析。4. 联调部署与踩坑实录毕业设计中最常见的问题4.1 环境配置清单与端口规划做毕设最怕的其实是环境问题代码写对了跑不起来比写不出来更让人崩溃。我整理一份可以直接照抄的环境清单后端环境JDK 1.8或11Maven 3.6以上IDEA建议2021.1以上版本Tomcat 8.5或9如果用Spring Boot则内嵌TomcatMySQL 5.7或8.0数据库连接驱动用mysql-connector-java 8.0.x注意8.x驱动需要配置serverTimezoneAsia/Shanghai避免时区报错Redis可加可不加预警系统对缓存依赖不大毕设加上Redis会让论文多了“缓存设计”一章但也会多出管理成本根据自己时间决定。前端环境Node.js建议16.20以上20也兼容ViteVite 5以上。Vue 3 Vite组合运行时过新或过旧都会报古怪错误比如Node版本过高导致OpenSSL错误解决办法是在启动命令里加NODE_OPTIONS--openssl-legacy-provider或者用nvm切换到16.x。端口规划建议固定后端8080、前端5173、MySQL 3306。端口写进项目文档和答辩演示PPT方便老师照着访问。其它偶发情况比如8080被占用在Windows下用netstat -ano | findstr 8080查出PID再结束任务在Mac/Linux下用lsof -i :8080搞定。4.2 常见错误与排查速查表我把整个开发过程中碰到的典型问题整理成一个速查表每个都是实际踩过的坑直接对标解决方案现象可能的根因解决方案前端请求接口报CORS错误前后端跨域未配置Vite proxy代理或后端CrossOrigin接口404URL路径不一致、未加RequestMapping前缀检查controller路径和axios地址接口500SQL异常、空指针、参数缺失查看后端日志断点定位MyBatis报BindingExceptionnamespace或方法id不匹配核对Mapper接口与XML数据库连接失败MySQL版本驱动不匹配、时区未配置换驱动版本加serverTimezoneLocalDateTime序列化报错Jackson不支持Java8时间类型引入jackson-datatype-jsr310中文乱码数据库字符集不是utf8mb4建库建表指定utf8mb4npm install超时默认registry访问慢设置registry为npmmirrorecharts地图空白没注册GeoJSON或路径错误下载jsonregisterMapVue警告“Failed to resolve component”组件名注册错误或未引入检查import和components注册打包后dist打开接口404baseURL是相对路径/没有服务器改用后端同域部署或Nginx代理排查问题的通用思路是先看后端Tomcat日志和浏览器F12控制台。后端异常会打印堆栈前端404会在Network面板显示响应两个面板一对比问题基本就定位了。遇到报错不要急着改代码先把完整错误信息贴到编辑器里读一遍很多时候根因就在第一行。把这一条养成习惯调试速度会快很多。4.3 答辩演示与项目交付建议答辩演示是毕业设计的临门一脚我的建议是准备两条演示线路一条是“正常流程线”一条是“预警触发线”。正常流程线从登录开始普通用户进首页看今天各站点的AQI和等级分布点开站点看趋势图然后切换到历史查询页查询某段时间的污染物曲线再退出用管理员账号登录进系统管理做站点新增、数据录入演示一下表格分页和查询。这一条线要让老师看到系统能跑、功能齐全、界面美观。预警触发线专门演示预警闭环。为了演示效果可以提前在后端写一个临时的数据修改接口或者直接改预警阈值把PM2.5阈值改成比当前数据低的值然后刷新页面30秒内预警横幅弹出预警记录表里多一条记录。老师看到这一套它会觉得系统的“预警”不是摆设而是真正联动的。演示时先把预警规则配置好再触发数据顺序错了容易当场翻车。交付材料建议包含五个部分项目源码注释完整、有README、数据库初始化SQL脚本包含建库建表和模拟数据、设计文档或论文、演示视频录屏、保证清晰不卡、答辩PPT。README里务必要写清楚环境版本、启动步骤、默认账号密码老师拿到项目后能顺利跑起来这是加分项。有条件的话把项目传到Git仓库并保留提交记录答辩时一句“完整代码已托管在Git仓库共X次提交”就能体现工程素养。一些小复盘与收尾建议这个项目做完我最大的体会是“预警系统”听起来是个很高大上的东西落到代码层面其实就是一张张表、一个个接口和一套定时扫描逻辑。毕业设计不需要追求面面俱到把数据链路走通、把页面做得好看、把论文里的图表画清楚就已经能拿到很不错的分数。有几个细节值得你再花一点时间打磨全局异常处理里加一个ControllerAdvice统一兜底未知异常比让Tomcat吐出一大段报错信息体面得多所有接口返回时间字段统一格式化避免前端显示“2026-03-17T10:30:00”这种生硬格式预警规则阈值不建议写死在常量类里放到数据库表中不仅便于操作论文“系统可配置性”这部分也有素材可以展开写。代码注释、包名规范、分层清楚这些工程习惯比多写两个页面更能博得老师好感。最后想说的是做完这套系统之后你自然会发现前端Vue的响应式原理、SSM的Bean管理、SQL优化这些知识点打通了这才是毕设最大的收获。后续如果还想扩展可以在现有基础上接一套真实天气数据API、把MySQL换成时序数据库、加上移动端适配页面或者把权重整合指数、健康建议这些功能补上项目深度和完整性都会更进一步。先把当前这条链路跑通后面想怎么折腾都来得及。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进