ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringBoot+Vue+MyBatis+MySQL:企业级垃圾分类管理系统全流程解析

SpringBoot+Vue+MyBatis+MySQL:企业级垃圾分类管理系统全流程解析 搞定这套企业级城市垃圾分类管理系统前后端分离、SpringBootVueMyBatisMySQL 一套全流程代码拿过去就能跑。说句实在话这套东西不是那种 demo 级别的玩具项目是真正能在环卫集团、街道办、物业公司场景里落地的管理系统。整个系统围绕垃圾分类投放点管理、居民积分激励、督导员巡检、车辆收运调度、可视化数据大屏这些核心业务展开从用户端到管理端从数据录入到报表分析逻辑是完整闭环的。如果你正打算做类似的政府治理类项目、市政信息化项目或者毕业设计想找个既有业务深度又有技术亮点的题目这套源码是很值得参考的。项目本身有几个非常硬核的点值得先摆出来第一权限管理是完整的 RBAC 模型不是那种写死角色的东西菜单、按钮、接口三级权限都做了第二积分体系不是摆设它跟垃圾分类的四大分类可回收物、有害垃圾、厨余垃圾、其他垃圾深度挂钩投放正确与否会直接影响积分加减这里面是有智能评判逻辑的第三报表模块接入了 ECharts投放趋势、分类准确率、车辆轨迹分析都有图表支撑不是拿个表格糊弄事。第四MyBatis 这一层用了大量动态 SQL 应对复杂条件查询分页用的 PageHelper整体性能在几十万条数据量级下是验证过的。这篇博文不是给你讲一遍项目能干什么而是带着你把整系统的架构逻辑理顺把关键的实现代码讲透把部署时容易踩的坑全部标记出来。内容覆盖从 SpringBoot 后端的核心设计到 Vue 前端的路由权限控制再到 MySQL 的索引调优、以及常见的报错场景。无论你是想把源码直接部署上线还是想把架构设计抽出来用在别的项目上这篇文章都能给你实际的帮助。1. 项目整体设计与业务架构拆解1.1 这套系统到底解决了什么业务问题先别急着看代码得先把业务逻辑盘明白。城市垃圾分类管理表面上看是扔垃圾这个动作实际上监管链条很长居民分类投放是否正确需要评判督导员是否到岗履职需要记录收运车辆是否按线路清运需要追踪各区各街道的分类覆盖率、准确率需要量化评估各投放点的垃圾桶满溢状态需要实时感知。这些数据如果靠人工报表去汇总不仅时效性差而且没法支撑月底的绩效考核。这套管理系统就是把投放、督导、收运、考核四个环节全部线上化。居民端或者督导员代录做投放登记系统根据垃圾种类与投放点类别自动判断是否匹配匹配给积分不匹配走整改记录督导员端巡检打卡、上报问题、打印整改通知单管理后台做投放点管理、车辆排班、路线规划、积分规则配置、月度报表生成。数据全部沉淀到 MySQL支撑大屏展示和精细化运营决策。这里面的核心设计理念是信息化不是把纸质台账变成 Excel而是把业务逻辑变成代码规则。比如分类正确与否这个判断系统里是通过投放记录表中的 waste_type 字段与投放点规定的 category_type 字段比对实现的督导员是否履职是通过上岗签到时间与投放高峰时段的轮班表关联计算实现的。这些规则都是可以直接在配置表里调整的所以系统在不同城市的落地适应性也很强。1.2 为什么选 SpringBoot Vue MyBatis MySQL 这套技术组合这套技术栈放到今天仍然是后端管理系统领域最稳的组合没有之一。有人可能会说怎么不用微服务怎么不搞个 Redis 缓存、ES 搜索当然可以加但一个城市垃圾分类管理系统尤其是区县级部署的场景实际并发量并不高一个区可能就几万个投放点真正的高峰并发也就是早晚投放时段QPS 撑死不过几百。用微服务拆分纯属给自己找运维麻烦一台服务器能跑完的事拆五个服务反而要处理分布式事务、服务注册发现、链路追踪这些额外复杂度。SpringBoot 的定位是快速构建生产级应用内嵌 Tomcat打成一个 Jar 直接部署这对基层信息化项目的交付非常友好——现场环境往往就是一个 Windows 服务器或者一台 Linux 虚拟机不需要搞复杂的中间件集群。Vue 做管理后台是标配组件化开发效率高配合 Element UI 库能快速做出观感合格的界面。MyBatis 这一层的优势是灵活复杂查询用 XML 里的动态 SQL 来写跟业务报表的复杂 WHERE 条件配合很默契比 JPA 那种全自动映射好调优得多。MySQL 更不用说了开源免费运维简单数据量在百万级以内完全撑得住。说句实在经验这个组合还有一个隐性的好处招人容易。SpringBootVue 是 Java 全栈开发者的基本盘无论是后续维护还是二次开发找个熟手成本都不高。技术选型不只是性能问题还是团队可持续性问题这个在我做过的十几个政企项目里体会太深了。1.3 系统目录结构与核心模块总览拿到源码之后先别急着跑起来花半个小时把目录结构过一遍比你瞎改半天代码有用得多。这套项目是标准的前后端分离结构后端是 Maven 多环境工程前端是 Vue CLI 工程两者完全解耦通过 RESTful API 通信。后端的 Java 包结构是按业务模块划分的不是按技术层划分的这个值得学习。每个业务域比如 point、vehicle、inspection下有 controller、service、mapper 三层。这样做的好处是当你要修改某个业务功能时所有相关代码都在同一个包路径下不用在 controller 包、service 包、mapper 包三个地方来回切换。我见过不少项目按技术层分包结果改一个需求要同时打开五个包目录找文件完全是浪费时间。前端 Vue 工程里views 目录按角色分模块router 目录里配置动态路由storeVuex里管理用户状态和权限令牌api 目录里统一封装了所有 axios 请求。这套前端的权限控制做得很细后端接口有 PreAuthorize 注解前端路由有 meta.roles 字段限制按钮等级权限用自定义指令 v-permission 控制三层防线确保越权访问进不来。核心功能模块清单大致如下模块名称核心功能涉及关键表系统管理用户、角色、菜单、部门管理sys_user、sys_role、sys_menu投放点管理分类点位信息维护、设备绑定drop_site、device_info投放记录居民扫码投放、垃圾分类判定drop_record、waste_type积分管理积分规则配置、积分流水查询point_rule、point_log督导巡检督导员排班、到岗记录、问题上报inspector_schedule、inspection_task车辆收运车辆信息、排班路线、收运记录vehicle_info、collect_route、collect_record报表大屏投放趋势、分类率统计、地图分布视图/聚合查询通知公告政策宣导、站点公告推送notice_info预留站内信扩展这八个模块正好覆盖了垃圾分类管理从投放源头到收运末端的完整闭环前后端代码量加起来差不多有 4 万行麻雀虽小五脏俱全。2. SpringBoot 后端核心设计与关键实现2.1 分层架构设计思路与职责边界后端这块代码分层是一个比较标准的 DDD 轻量落地方式Controller 层只负责参数接收和结果封装Service 层承载业务规则和事务控制Mapper 层只跟数据库打交道。这套分层的核心逻辑就是保持单向依赖上层不能反向依赖下层。Controller 层我建议不要放任何业务逻辑。很多小项目写久了就随手在 Controller 里直接调用 Mapper代码确实能跑但后续就没法维护了。比如积分发放这个动作如果直接在 Controller 里掉了几条 SQL当业务改成投放正确得 5 分连续一周正确额外奖励 20 分时你得把 Controller 翻个底朝天。但在这套系统里积分计算逻辑封装在 PointService.calculateAndAward 方法里Controller 只需要调 service 层的一个方法新加奖励规则只是改 service 内部实现对其他层完全透明。Service 层是这套代码里最有含金量的地方。比如投放记录处理这个操作它要同时做四件事写入投放主记录、更新分类正确率统计、发放积分并写积分流水、检查垃圾桶满溢状态决定是否需要通知收运。这四个动作绑定在同一个事务里任何一个失败都会回滚。这就是典型的跨聚合事务Spring 的 Transactional 注解就可以搞定。当然后续如果并发量上去了这种强一致性的事务可以拆成消息队列来做最终一致性那是后话。Mapper 层全部用 MyBatis 的 XML 文件实现没有用注解 SQL。这个选择有两个原因一是复杂的多表关联查询用注解写会堆成一长串完全没法看二是 XML 文件支持动态 SQL 的 、 、 标签跟报表筛选这种条件可选的复杂查询契合度极高。举个例子查询投放记录列表时可能按时间范围过滤可能按投放点过滤也可能按分类结果过滤这些条件组合是随意的。用动态 SQL 就可以拼出自动去掉多余 AND、WHERE的查询用 Java 代码来拼 SQL 字符串就是灾难现场。2.2 RBAC 权限模型与 JWT 鉴权流程权限这块是判断一个管理系统是否企业级的分水岭。这套系统用的是标准的 RBAC 模型底层的表结构设计完全支持用户-角色-权限三层关系而且扩展了菜单权限和按钮权限两种粒度。后端启动时Spring Security 的过滤器链会拦截所有 /api/** 请求。用户登录成功后后端签发一个 JWT TokenToken 里不放密码等敏感信息只放用户 ID、登录名、过期时间。前端拿到 Token 后存到 localStorage并在 axios 的请求拦截器里统一加上 Authorization 请求头。后端每次收到请求先解析 Token 合法性然后从 Redis 或数据库加载该用户的权限列表到 Spring SecurityContext。代码里你看到的 PreAuthorize(hasAuthority(drop:record:add)) 这类注解就是接口级权限的控制点。实际项目中我建议你建一张权限标识字典比如drop:record:add表示投放记录新增权限这样在给角色分配权限的时候直接按模块:操作的规则勾选就行不用面对一堆没有规律的接口 URL。前端这边的权限控制我多说一句。路由配置里不是一次性注册了全部路由而是根据用户登录后返回的角色信息动态把符合权限的路由 addRoute 到路由表里。这样做的效果是普通居民账号连系统管理这个菜单都看不到而不是点进去才提示无权限。这个细节很影响用户体验很多系统就是这个没做好导致用户能看见菜单但点不开体验很差。2.3 垃圾分类判定规则与积分引擎实现垃圾分类判定是整个系统的业务核心代码里实现这个逻辑的是 WasteClassifyService 这个类。它做的事情本质上就是一个规则匹配投放记录中的 waste_type 枚举值是否与投放点规定的分类类型匹配。但这里有个容易被忽视的细节同一个垃圾袋里可能是混合垃圾比如一个塑料袋其他垃圾里面装着剩饭厨余垃圾。系统是怎么处理的我看到源码里做的是主导类别识别策略——督导员在投放点现场观察判断如果无法判断就打开袋子检查主要成分。这个业务规则在前端表单里体现为一个 radioselcet督导员可以选择正确、错误、待复查三种状态。一旦判定错误系统会自动扣减积分并记录违规原因同一投放点累计三次错误会对居民推送宣传教育任务。这套扣分-预警-教育-复查的流程比单纯扣分更能体现治理理念。积分引擎这一块我估计很多人在看代码的时候会迷糊因为它不是简单的加几分逻辑而是规则引擎的思路。核心表是 point_rule里面配置了规则编码、积分值、适用范围、有效期。规则编码比如 CORRECT_DROP_POINT、MAX_STREAK_BONUS、INSPECTOR_CHECKIN_BONUS 等等。PointCalculator 收到事件投放、签到、巡检上报后根据事件类型去 point_rule 表里找到对应规则计算积分并写入 point_log 流水表。流水表是冗余存储的设计哪怕积分规则将来改了历史流水永远不变这对后续对账审计非常关键。2.4 MyBatis 动态 SQL 与分页查询实战MyBatis 在这个项目里用得最出彩的地方就是报表查询。拿投放趋势分析这个接口举例前端传过来的查询条件是时间范围必传、区/街道可选、投放点名称可选、分类类型可选、结果状态可选。如果用 Java 代码拼 SQL七七八八的条件拼接会让你想砸键盘。但用 MyBatis 的 标签加 判断整个 SQL 看起来干净利落。分页这块项目用的是 PageHelper 插件原理是在 MyBatis 执行器执行前拦截 SQL自动拼接 LIMIT 语句同时执行一条 COUNT 查询拿到总数。实际使用中有一个坑必须注意PageHelper 的 page 参数是线程私有的只对下一个查询生效。如果你在 Service 方法里先执行了一个查询B再去执行分页查询A那么分页语句会错误地作用到查询B上。解决方法是把分页查询放在 Service 方法里的最后一个查询语句或者直接调用 PageHelper.startPage 之后就立即执行目标查询。再补充一个性能优化经验。投放记录这个表在项目上线三个月后就会积累到几十万条数据如果你的列表查询还需要关联积分流水表统计每个人的累计积分一个子查询可能就把接口拖到三秒开外。源码里的处理方式是把统计逻辑拆成定时任务每天夜里把昨天每个用户的投放次数、正确率、总积分汇总到 report_user_daily 这张统计表里。查询的时候直接查汇总表不实时计算。这是典型的用空间换时间思路报表统计类系统都应该这么设计。3. Vue 前端工程实现与体验优化3.1 前端工程结构、路由守卫与菜单权限控制前端这部分工程是 Vue CLI 初始化的标准结构Vue 2.6 Element UI Vuex Vue Router Axios这套搭配成熟稳定改动成本也低。如果你手里已经有 Vue 3 的项目经验把这个结构迁过去也不难核心业务组件基本可以平移。路由这块我重点说说权限控制的闭环逻辑。src/router/index.js 里定义的是公共路由login、404 等业务路由全部放在 asyncRoutes 数组里每个路由项的 meta 字段标记了所需角色。用户登录成功后前端拿到用户角色标识然后调用一个工具函数 filterAsyncRoutes递归遍历 asyncRoutes把当前角色没有权限的路由剔除掉再用 router.addRoutes 动态挂载。这个工具函数在 vue-element-admin 项目里是个非常经典的复用片段代码逻辑足够清晰并且支持路由嵌套层级。这还没完路由只控制了页面级访问页面里的按钮操作权限是另一层控制。项目里自定义了一个 v-permission 指令用法是 v-permission[drop:record:add]。指令内部会读取当前用户的权限数组如果没有对应权限就把 DOM 节点移除掉。这个机制的效果很直观没有删除权限的用户界面上压根不会出现删除按钮而不是点了才提示无权这种权限控制的体验差异是非常明显的。3.2 Axios 统一封装、Token 刷新与异常处理前端的网络层源码里做了一个非常实用的 axios 封装文件 request.js。它统一配置了 baseURL、超时时间 15 秒、请求拦截器和响应拦截器。请求拦截器里从 Vuex 读取 Token加在请求头 Authorization 字段响应拦截器里统一处理 HTTP 状态码和后端业务状态码。这个统一封装的价值在于后端返回的业务数据格式约定为 { code: 200, msg: 操作成功, data: {...} }。如果 code 不是 200前端就弹出对应错误提示如果 HTTP 状态是 401就清空本地 Token 并跳转登录页如果是 500就提示系统内部错误而不是把一堆英文堆栈信息甩给用户。我见过太多项目因为没做拦截器系统报错的时候用户看到一整页的 Java NullPointerException这在国内政企项目里是极其不专业的表现。Token 过期处理是前端最容易忽略的一个问题。这套源码的做法是在响应拦截器里判断 401 后执行静默刷新逻辑先调用 refreshToken 接口换取新 Token然后递归重发刚才失败的请求。这个逻辑虽然代码量不多但实际能落地的项目很少绝大部分系统都是登录过期后直接踢去登录页用户填到一半的表单直接丢失非常影响体验。3.3 ECharts 数据可视化大屏与投放点分布地图数据大屏是这套系统整个界面的颜值担当。管理后台首页加载的就是一套完整的垃圾分类监管驾驶舱左侧栏是投放量日报、月报趋势折线图中间部分是各街道分类正确率环形图右侧栏是实时收运车辆动态列表、满溢警报滚动消息。所有图表都是 ECharts 生态环境下制作其中地图分布是通过 ECharts 的 geo 坐标系配合散点图实现的——注意它并没有接入百度地图或高德 SDK因为纯 ECharts 的 geo 地图不需要申请密钥部署时不依赖外网这对内网环境部署的政企项目是一个很实用的取舍。这里给想改前端样式的朋友提个建议不要动 ECharts 默认的主题而是去看数据接口返回的字段名。这些图表的数据接口都遵循相同的响应格式比如趋势图接口返回 xAxis 数组和 series 数组饼图接口返回 categories 和 values。如果你想把折线图改成柱状图只需要换一个图表组件把数据 mapping 换一下不需要动后端接口。这套图表和数据源解耦的思路值得你在二次开发时沿用。3.4 表单校验、上传组件与其他实用细节表单处理方面Element UI 自带的 el-form 校验规则已经足够源码里用到了简单的必填校验和自定义校验函数。比如投放点编号的格式校验是字母数字横杠的组合督导员工号要校验是否为 11 位数字。这些自定义校验规则写在校验文件 validate.js 中可以在多个表单里复用。一个建议把常见的身份证号、手机号、金额校验这些规则全部抽象成公共函数不要散落在各个组件里。批量导入投放点数据用的是 el-upload 组件上传 Excel 文件后端用 EasyExcel 解析。这个功能看似小但影响面很大——手工录入几百个投放点账号的工作量会让人崩溃而 Excel 模板导入五分钟就解决问题。前端这边要注意上传组件的 action 地址和 headers 头带上 Token提交成功后刷新列表数据。前端在移动端适配上也做了响应式处理头部导航栏在窄屏下会折叠为侧边栏表格列数通过屏幕宽度判断做降级展示。因为垃圾分类管理场景里督导员在外面巡检时是用手机访问的这个适配虽然是够用就好但也说明了原作者考虑到了移动办公场景这是很多后台管理系统不具备的细节意识。4. MySQL 数据库设计、索引优化与执行计划分析4.1 核心表结构设计与关联关系解读数据库是这个系统的地基也是我建议你最先阅读源码的部分。整个库大概二十几张表命名规范统一主键全部采用自增 ID每张表都包含 create_time、update_time 字段逻辑删除用 deleted 字段0 正常1 删除。这个设计虽然没有 UUID 那样的分布式标识能力但在单库部署的场景下简单实用利于排序和索引效率。核心业务表的结构关系我挑几个重点说一下。drop_record 投放记录表是最核心的事实表字段包括 resident_id、drop_site_id、waste_type、judge_result、point_amount、device_no、drop_time。point_log 积分流水表跟 drop_record 是 1:N 的关系一条投放记录可以产生多条积分流水比如基础积分加连续投放奖励每条流水都带着规则编码方便追溯是哪条积分规则产生的。另外还有一张 inspection_task 督导任务表它跟 drop_site 是多对一的关系一个投放点可以有多个督导任务记录。这张表里记录了督导员上报的问题描述、现场照片地址、处理状态。车辆收运模块中collect_record 收运记录表通过 route_id 关联收运路线再通过 vehicle_id 关联车辆。这些业务表的关联链路加起来可以支撑从某个垃圾袋是谁投的一直追溯到哪辆车运到了哪个处理厂的完整数据链这在审计和纠纷处理中非常有价值。4.2 索引优化实战从全表扫描到毫秒级响应我对这套系统的数据库部分做过一次完整的索引体检因为上线反馈说投放记录列表越查越慢。打开慢查询日志发现drop_record 表的列表查询触发了全表扫描数据量到 30 万行时一次查询要 1.8 秒。这个问题的根源是 WHERE 条件是 drop_time BETWEEN ? AND ? AND judge_result ?但表上只有主键索引MySQL 只能全表过滤。解决方案是在 drop_record 表上加复合索引 idx_drop_time_result (drop_time, judge_result)。索引字段的顺序有讲究等值条件judge_result应该放前面范围条件drop_time放后面还是放前面实际上对于 range 查询把等值条件放前面能更精确地缩小范围。加完索引之后同样的查询从 1.8 秒降到 0.05 秒这就是百万行以内数据量级索引优化的典型效果。积分流水表 point_log 还有一个高频查询模式是按 user_id 查最近 N 条记录适合建立 (user_id, create_time) 复合索引。报表查询里按日聚合的汇总表 report_user_daily 则建议建立 (stat_date, region_id) 复合索引因为报表页的筛选维度正好是日期区域。这里有一个索引优化的黄金法则索引不是越多越好而是覆盖最高频查询模式。如果你发现一张表有十几个索引但查询还是很慢八成是索引建错了方向而不是建少了。每多一个索引InnoDB 写入时就要多维护一棵 B 树插入和更新的性能会随之下降。所以加索引之前先打开 MySQL 的慢查询日志找出 TOP 10 慢 SQL针对性建索引而不是凭感觉。4.3 数据库事务隔离级别与并发控制要点投放在早晚高峰期会产生并发写入这种场景下事务隔离级别的选择很重要。源码里 Spring 配置的默认隔离级别是 MySQL 的 REPEATABLE READ可重复读这是 MySQL InnoDB 引擎的默认级别配合 MVCC 机制能够保证同一个事务内多次读取结果一致。积分发放的并发场景比较典型居民投放垃圾后督导员扫码录入积分请求请求可能同时在多个设备上发起。如果不对发放动作做控制用户一次投放可能被扣两次积分。源码的处理思路是对同一投放记录的唯一性做约束drop_record 表设计了一个唯一索引 uk_record_no (record_no)record_no 由设备编码时间戳随机数生成。这样即使请求被重复提交第二次插入会触发唯一键冲突异常不会被计入积分。这种基于数据库约束的幂等方案比在应用层加分布式锁要简单可靠得多——不是所有场景都需要引入 Redis很多时候数据库的唯一索引就是最好的并发控制工具。不过要提醒一个 MySQL 特有的坑如果要使用 SELECT FOR UPDATE 做行锁控制务必确认 where 条件是索引字段或者锁定的行是存在的否则 InnoDB 会退化成锁全表。这个在低并发系统里不常见但一旦并发上来容易莫名其妙地出现死锁。排查死锁的手法是通过 SHOW ENGINE INNODB STATUS 查看最近的死锁信息重点看 LATEST DETECTED DEADLOCK 段它能打印出具体的 SQL 语句和持有锁的会话。4.4 定时任务与数据归档策略系统里有两个定时任务值得研究它们都基于 Spring 自带的 Scheduled 实现没有引入 Quartz减少不必要的依赖。一个是每天凌晨 2 点执行的数据汇总任务把前一天所有投放记录、积分变动、收运记录聚合到日报汇总表另一个是每周一凌晨执行的周报统计任务计算各街道的分类正确率趋势、车辆满载率等管理指标。数据归档这块是很多项目上线后才开始后悔的事。投放记录表的数据增长是线性的一个城市一天就是几万条。如果不做归档一年后主表就有几百万行查询和备份都会遇到麻烦。这套系统源码里预留了按年度分表的思路把历史数据迁移到 drop_record_2024 这样的归档表里业务查询只访问当年数据。如果数据量再大还可以进一步考虑按月分表。一个经验分表方案要提前设计别等数据库报警了再动刀那时候迁移成本很高。5. 项目部署实操与常见问题排查5.1 从源码到上线环境准备与快速部署指南拿到源码的第一件事是在本地把环境跑通。后端需要 JDK 1.8、Maven 3.6推荐 3.6.3用更高版本要注意依赖冲突、MySQL 5.7推荐 5.7.44不要用 MySQL 8.0 以下版本用到的一些认证插件项目里配置了 useSSLfalse 来规避 SSL 连接问题。前端需要 Node.js 14建议用 16 LTS 版本npm 安装依赖的时候如果报错 node-sass 编译失败直接切换成 dart-sass 即可解决。启动顺序有讲究。先导入数据库脚本 sql/init.sql 到 MySQL它会创建数据库、全部表结构和初始化数据包括管理员账号和菜单权限数据这一步不用手工建库脚本里已经写了 CREATE DATABASE 语句。然后启动后端修改 application-dev.yml 里的数据库连接密码执行 mvn spring-boot:run后端默认端口是 8080可自行切换。最后进入前端目录先改 .env.development 里的 VUE_APP_BASE_API 为 http://localhost:8080/api然后 npm installnpm run serve前端默认跑在 9527 端口。前后端联调的时候最容易遇到的就是跨域问题。项目的解决方案是在后端加了一个 WebMvcConfigurer 的配置类实现 addCorsMappings 方法允许所有来源跨域。这个方法简单粗暴但有效。另外一个常用方案是用 Nginx 做反向代理实现前后端同域部署。后端生产环境推荐打成 Jar 用 nohup java -jar 运行前端执行 npm run build 后把 dist 静态文件交给 Nginx 托管。5.2 高频报错场景与解决方案速查这套系统在我实际部署验证过程中遇到过不少经典问题我把它们整理成一个排查速查表希望能帮你少走弯路错误现象可能原因解决方式前端请求全部 404后端未启动或路径前缀配置不对检查后端打印日志确认 /api 前缀与后端 ContextPath 匹配登录后 Token 失效JWT 有效期过短(默认 24h 可调)修改 jwt.expiration 配置检查服务器与客户端时间差列表数据慢缺少联合索引见 4.2 节在 where 高频字段建复合索引积分重复发放缺乏幂等控制检查唯一索引 uk_record_no 是否生效观察请求日志是否重复提交图片上传失败前端上传路径未配对后端存储目录检查 upload.path 配置确保目录存在且有写权限MySQL 连接报 SSL 错误连接串未禁用 SSLurl 中加 useSSLfalseserverTimezoneAsia/Shanghainpm install 卡在 idealTree网络原因或 node 版本不兼容切换 npm 官方源或镜像源用 nvm 切换 node 版本页面白屏但不报错Vue 路由 history 模式下刷新 404Nginx 配置 try_files $uri $uri/ /index.html定时任务不执行Scheduled 默认单线程阻塞排查任务耗时是否超长改用 Async 注解或线程池配置5.3 性能调优三件套连接池、缓存与 SQL 日志排查生产环境调优时最有性价比的三个操作我挨个说。第一是数据库连接池参数调整。项目用的 HikariCP 连接池Spring Boot 默认默认最大连接数是 10当业务高峰期并发请求超过连接池上限时新请求会等待空闲连接表现为接口响应延迟拉长。建议根据机器配置调整 maximum-pool-size 到 20-50minimum-idle 一般保持和 maximum-pool-size 一致即可避免频繁创建连接的开销。第二个是缓存层。这个系统没有引入 Redis但部分热点数据用了本地缓存 Caffeine——比如投放点分类规则配置这个数据几乎不变但被高频读取每次查数据库显然浪费。源码里用 Cacheable 注解实现了方法级缓存命中率极高。如果未来要引入 Redis建议优先缓存的是菜单权限数据、积分规则配置、投放点列表。这三类数据是读多写少的典型命中一次数据库就可以服务几千次查询。第三个是排查慢 SQL 的操作方法。在 application-dev.yml 里打开 MyBatis 的 SQL 日志打印观察每次请求的 SQL 执行时间。日志里如果发现执行时间超过 500ms 的语句立刻把 SQL 拿出来跑一遍 EXPLAIN看有没有走索引、有没有 filesort、有没有临时表。这套排查流程我在优化报表接口时反复使用只要梳理出 TOP 5 慢查询并逐一优化系统整体响应时间能提升 50% 以上。5.4 关于源码二次开发的三点经验建议最后聊点实际的。如果你打算基于这套源码做二次开发或者毕业设计改造我有几条个人经验分享。第一不要先改代码先跑通主线流程——用管理员账号登录创建角色、创建用户、录入投放点、模拟一次投放记录、查看积分流水和报表把整个闭环走一遍你才对系统有了整体感知此时再改代码就不会改了一处坏三处。第二新增业务模块时沿用原有的分包规范。后端在 business 包下新建子包前端在 views 下新建目录路由在 asyncRoutes 里添加配置菜单在 sys_menu 表里插入记录。只要遵循这个后端建包-前端建目录-路由注册-菜单入库的四步流程新模块的接入成本会非常低。第三不要把微信扫码登录、小程序端这类功能当后续扩展的幻想这部分改动量不是加个接口能解决的。如果真要做更合理的路径是保留系统的核心 API 不动作单独开一个新的小程序工程作为独立客户端来调这些 API。系统的后管功能是通用底座更换端入口不会影响中间层逻辑关键技术底座足够稳延展性也够好。我在实际带着团队做这类市政信息化项目时最深的一点体会是代码能跑只是起点真正考验一个系统的是它在真实业务场景中能不能撑住长年累月的数据流转和权限管控。这套垃圾分类管理系统之所以值得参考不在于技术用得多新多炫而在于它的架构分层、权限模型、业务闭环、性能优化这些维度全是经过真实运营考验的实用方案。你拿过去部署也好、改造也罢只要抓住业务规则配置化、统计查询离线化、权限控制三层化这三个核心设计思想就完全能把它延伸成你自己的东西去服务更多类似的城市治理场景。
返回列表