SpringBoot+Vue抗疫物资管理系统:从数据库设计到权限控制实战
我做了几个学期的毕设指导也帮人排查过不少类似的系统可以这么说抗疫物资管理系统这类题目是Java Web方向里性价比最高的选题之一。有完整业务闭环入库、出库、库存、申领、统计有前后端分离技术栈又贴合实际场景答辩时故事也好讲。不过正因为做的人多想拿高分关键是别停留在“能跑就行”而是要把几个核心模块的设计逻辑真正讲清楚。这篇文章就围绕 SpringBoot Vue 的抗疫物资管理平台从需求拆解、数据库设计、权限模型、核心接口实现到前端联调和部署的完整链路把我的实操经验和踩坑记录都放出来。不管是正在做毕设还是想拿这个项目练手看完应该能少走不少弯路。1. 项目定位与功能拆解先搞明白“抗疫物资管理系统”到底在管什么1.1 核心需求解析这类系统解决的三个核心问题很多人一开始拿到这个题目的反应是“做一个物资增删改查”这个理解太浅了。如果只是CRUD那跟课程设计没什么区别。抗疫物资管理系统之所以有区别度是因为它背后有真实的管理痛点。第一个痛点是信息同步慢。物资的库存数量、申领审批进度、分发记录如果靠表格和微信群来回传就会产生一个经典的“信息孤岛”问题库房说口罩还有五千个一线却说已经断供两天了。系统要解决的就是让这些数据在一个平台里实时流动。第二个痛点是审批流程不透明。物资不是谁申请就能谁拿走通常有“部门申请—负责人审批—库房出库”这样一套流程。如果在线下走纸质单既难追溯也不好统计所以要系统支撑流程状态跟踪。第三个痛点是数据汇总难。管理者要回答“这个月防护服消耗了多少”“哪些物资临近过期”“哪个部门的申领占比最高”这些问题没有结构化数据只能拍脑袋。所以系统必须包含统计报表模块。我见过不少同学把大量精力花在花哨的页面效果上结果库存一致性和权限控制这两个核心维度没做好答辩被老师追问几句就露馅了。记住这类系统的灵魂是数据准确和流程严谨而不是视觉效果。1.2 功能模块标准划分一套可直接参考的系统功能清单基于上面的需求我建议把系统分成七个功能域。这套划分方式不仅适用于抗疫物资场景换成“实验室耗材管理系统”“办公用品管理系统”也完全成立。用户与权限管理登录、登出、密码修改用户分角色常见的是系统管理员、仓库管理员、部门用户或普通员工三种采用不同的操作权限。物资档案管理物资的基础信息包括物资编码、名称、分类口罩、防护服、消毒液、医疗器械等、规格型号、计量单位、保质期信息等。入库管理入库单创建与审核。要注意的是入库操作会直接影响库存总量所以必须记录来源采购、调拨、捐赠和批次信息。出库管理申领管理部门填写申领单管理员审批后出库。这里涉及库存扣减和批次扣减策略是整个系统业务逻辑最重的模块。库存管理与预警实时库存查询、库存流水、库存预警下限阈值、临期提醒。统计报表收发存汇总、部门消耗排行、分类占比等图表通常用图表库展示。系统管理操作日志、数据字典管理。可以看到这套模块拆分的逻辑是从“基础数据”到“业务流转”再到“数据决策辅助”层次分明也符合标准的企业级应用形态。1.3 技术选型和版本规划为什么是 SpringBoot Vue 这个组合技术栈的选择直接决定了项目开发效率和答辩观感。SpringBoot Vue 至今仍是Java Web毕设的主流选择我大概总结一下原因。后端用 SpringBoot内置Tomcat不需要单独部署WAR包Starter体系简化了配置只需要引入依赖即可快速整合MyBatis、MySQL、Redis等组件自带Actuator、统一异常处理等能力写起来省心而且企业里真正用的也是这套有较高的实用价值。前端用 Vue Element UI或者 Vue 3 Element Plus生态成熟组件库丰富。表格、表单弹窗、树形控件都能直接拿来用开发效率非常高而且国内社区资料多遇到问题搜索就能解决。数据库用 MySQLSQL脚本直接附上方便评审老师直接跑起来看效果。身份认证用 JWT 做无状态登录避免传统 Session 在前后端分离架构下的跨域问题。如果你还想加分可以加一层 Redis 缓存热点数据比如库存数量和用户权限信息再配合定时任务做库存预警扫描。这些点不一定都写完但设计思路一定要有答辩的时候提出来会显得考虑周全。2. 数据库设计详解五张核心表的结构与关键字段分析2.1 数据库整体设计思路从业务流转到表结构数据库设计是整个系统能不能落地的基础。很多人建表凭感觉字段随意加直接导致后期开发时逻辑混乱。我的习惯是先画业务流转图从“人、物资、单据”三个核心概念出发来抽象表结构。在抗疫物资管理系统中核心参与方有三类用户、物资、出入库单据。围绕这三个概念我设计了以下主要表用户表sys_user存放用户账号、密码加密存储、姓名、联系电话、所属部门、角色标识。物资分类表material_category虽然只有一个字段值差异但还是建议独立成表方便扩展分类层级。物资信息表material_info存放物资名称、编码、规格、单位、库存数量、预警阈值、有效期等。入库记录表stock_in_record每一条数据对应一次入库动作记录物资编码、来源、入库数量、经办人、入库时间。出库记录表stock_out_record记录申领部门、物资编码、出库数量、领取人、审批人、出库时间、用途。这里我特别想提醒一点库存数量不要只存在物资信息表的库存字段里还要有出入库流水表。因为一旦出现数据对不上流水表才能作为追溯的依据。这也是为什么说“有审计能力的CRUD”才是管理系统而不是单纯改一个数字。2.2 字段级设计细节哪些字段决定成败很多项目字段设计看似合理但实际开发时才发现缺这少那。我根据自己的开发经验把几个重要的表列出来给出推荐字段结构。用户表sys_user字段名类型说明idbigint主键自增usernamevarchar(50)登录账号唯一passwordvarchar(100)加密后的密码BCryptnicknamevarchar(50)显示名称role_idbigint关联角色表的iddept_idbigint所属部门statustinyint1启用 0禁用create_timedatetime创建时间密码一定要加密。直接用明文存的话答辩时老师看到会非常减分。BCrypt 是 Spring Security 自带的加密方式生成一串带盐的哈希值安全性比简单的 MD5 高得多。物资信息表material_info字段名类型说明idbigint主键material_codevarchar(50)物资编码如 YY-001material_namevarchar(100)物资名称category_idbigint分类idspecvarchar(100)规格型号unitvarchar(20)单位个/箱/瓶stock_quantityint当前库存数量warning_quantityint库存预警下限expire_datedate保质期statustinyint1在库 0停用remarkvarchar(255)备注这里的 stock_quantity 可以设计成冗余字段每次入出库事务性更新也可以用视图动态计算。我更推荐存一个实时的库存数字用于列表展示同时通过流水表保证可追溯性。两种方案配合最终一致性的纠错机制既快又稳。出入库记录表stock_in_record / stock_out_record核心字段包括单据编号bill_no、关联物资 id、单据数量、操作人 id、审核人 id、单据状态、备注、创建时间。这种单据类表一定要保留“创建人”和“审核人”两个字段因为审批流后面要用。2.3 SQL脚本的编写注意事项索引、外键与初始化数据SQL脚本是这个项目里最容易被忽略却又很关键的部分。因为评审老师拿到项目后第一步就是导入SQL跑起来。脚本写得不规范或者初始化数据不够合理直接影响第一印象。我建议以下几点必须注意建表语句加 IF NOT EXISTS避免重复执行时报错。字符集统一用 utf8mb4否则后期插入表情符号或其他特殊字符容易乱码。关键关联字段建索引material_id、user_id、create_time。查询统计的时候索引非常管用。外键约束建议在表设计里体现但实际导入时如果担心数据插入顺序问题可以使用逻辑外键不加物理约束靠代码保证两者皆可但必须在文档里说清楚理由。初始化数据要完整超级管理员账号admin、仓库管理员账号operator、几个部门测试账号各角色的密码用同一套BCrypt加密值还要有至少10种物资和对应的分类数据这样前端首页和统计图表才不会空荡荡。3. 后端核心模块实现从登录鉴权到出入库的完整业务逻辑3.1 登录鉴权与权限控制JWT Spring Security 的正确打开方式登录认证是前后端分离项目的第一个技术门槛也是毕设答辩最常被问的部分。我用 JWTJson Web Token 结合 Spring Security 的实现方案这里把整体思路讲一下。流程是这样的用户提交账号密码后端校验通过后生成一个 JWT 令牌返回前端。前端把令牌存在本地存储或内存中之后每次请求在请求头里带上Authorization: Bearer token字段。后端配置一个过滤器在请求进入Controller之前拦截校验token的有效性并解析出用户角色用于权限判断。这种方案最大的好处是服务器不需要存储会话状态。传统 Session 方案要在服务端保存用户状态前后端分离时还得解决 Cookie 跨域的问题。而 JWT 是无状态的天然适合这种架构。在实际编码中有几个关键点值得注意密钥要放在配置文件中不要写死在代码里。token 要设置合理的过期时间我建议2小时并刷新机制否则用户用着用着就掉线。Spring Security 的过滤器链需要排除登录接口、验证码接口等少数公开路径其余接口都要过认证。密码用BCryptPasswordEncoder加密校验时调用matches()方法。权限模型我设计的是基于角色的访问控制超级管理员拥有全部权限仓库管理员可以操作出入库和查看库存部门用户只能申领物资和查看本部门记录。颗粒度不用做到按钮级但菜单级和操作级一定要有区分。3.2 物资入库功能实现事务处理与批次记录的常见坑物资入库的页面逻辑很简单但后端这里一定要谨慎因为入库不是一个单纯的 INSERT。它实际上是由两个步骤组成的插入入库记录 增加库存数量。这两个操作必须在一个事务里完成否则就容易出现记录有了但库存没涨或者库存涨了但记录缺失的脏数据问题。我在代码里通常这样实现Transactional(rollbackFor Exception.class) public void stockIn(StockInDTO dto) { // 1. 校验物资信息不允许对已停用的物资进行入库 // 2. 生成入库单号例如 IN 时间戳 随机数 // 3. 插入入库记录 // 4. 同步更新物资库存表数量 }注意Transactional注解的rollbackFor要设置成Exception.class因为默认它只在遇到运行时异常时才回滚如果直接抛受检异常事务不会回滚这个细节很多新手会踩到。入库单号生成也有讲究。不能只靠数据库自增id来标记单据因为对外沟通时“第500条记录”远不如“单据号IN20250114001”来得清晰。我习惯用前缀 日期 序列号的格式一眼就能看出是哪一天的单据。另外我建议入库单设计“草稿—提交—审核”三个状态。如果毕设时间不够可以砍到两个状态待审核和已入库。不然眼前的下拉菜单会多一个状态前端组件不算复杂但后端逻辑会相对多一些。这个取舍根据个人时间和精力决定。3.3 申领出库功能实现库存扣减时机与幂等性出库申领是业务上最容易出错的地方。一个完整的出库流程是部门用户填写申领单选物资、填数量、填用途。系统校验申领数量不能大于现有库存。提交后单子进入待审批状态库存数量暂时不变这叫“预占”或者“冻结”也可以看需求。管理员审批通过后才真正扣减库存。如果审批拒绝单据状态变为已驳回库存不受影响。确定哪种方案取决于一个需求细节要不要支持“多人同时申领同一批物资导致库存超卖”如果要严谨控制就必须在审批通过时使用数据库行级锁例如查询时加FOR UPDATE或者使用乐观锁版本号。如果只是毕设演示最简单的方式是在提交申领时校验一次库存审批通过时再校验一次双重校验就能挡住90%的问题。SQL层面的悲观锁操作可以参考SELECT * FROM material_info WHERE id #{materialId} FOR UPDATE这行SQL的意义在于事务 A 在审批通过时锁住这行物资数据直到更新完库存并提交事务 B 才能读取。这样就避免了两笔出库同时读到“还有10个库存”然后各自扣减8个导致库存变成-6的情况。出库单的状态流转也比较清晰待审核、已通过、已驳回、已完成。要注意每次状态更新都要记录操作人和时间这就是前面说的审计能力。3.4 库存预警与统计报表定时任务 SQL聚合的技巧库存预警是这个系统里比较能体现工程能力的部分建议单独拎出来展示。实现方式有两种定时扫描用 Spring Boot 的Scheduled注解写一个定时任务每天凌晨扫描所有库存数量小于预警阈值的物资生成预警记录。即时判断在每次出库扣减库存后立刻判断剩余库存是否低于阈值是就标记该物资为预警状态。两种方式可以同时用实际开发中也常这么干。预警记录可以放在单独的预警表里也可以只给物资表加个状态字段配合前端黄色/红色高亮展示即可。定时任务的时间建议做成可配置的值写在 application.yml 里而不是写死这样适配性更好。统计报表用的核心是 SQL 聚合查询。比如按分类统计库存量就是GROUP BY category_id然后SUM(stock_quantity)按部门统计申领次数就是GROUP BY apply_department然后COUNT(*)。后端封装好查询接口返回数据结构给前端图表组件直接渲染。图表库用 ECharts 比较多柱状图、饼图、折线图都支持得很好。3.5 接口文档与统一返回结构降低前端联调难度的关键接口文档是这个项目里不可缺失的交付物。很多同学不重视接口设计导致前端开发时反复沟通耗时。我的建议是定义一套统一的返回结构{ code: 200, message: 操作成功, data: { } }所有接口都返回这个格式前端只需要针对code做统一判断即可。错误码建议划分为200成功、400参数错误、401未认证、403无权限、500系统错误。这样前端对异常的识别非常直观。接口文档方面如果时间充足可以用 SwaggerKnife4j自动生成在线调试方便答辩演示也加分。如果来不及也可以在项目里附带一份Markdown格式的接口列表标明每个接口的URL、请求方式、请求参数、返回示例。重点是逻辑清晰不遗漏。4. 前端工程开发与前后端联调要点4.1 Vue 项目结构和路由设计按模块划分而非按页面划分前端工程我建议用 Vue CLI或 Vite创建统一用 Vue 2 Element UI 或者 Vue 3 Element Plus 都可以只要保持整体风格一致就行。这里说一下项目目录结构的分隔逻辑这个直接影响后期的可维护性。src/ api/ // 按模块划分的接口请求封装模块 assets/ // 静态资源 components/ // 公共组件上传组件、富文本、弹窗等 layout/ // 页面布局框架侧边栏、顶栏 router/ // 路由配置 store/ // 全局状态管理Vuex 或 Pinia views/ // 页面api 目录里我喜欢每个模块建一个文件比如login.js、material.js、stock.js。里面把该模块下的所有接口请求都封装成函数方便页面调用也方便统一处理 token 注入。路由设计上用前端路由守卫拦截未登录用户。在router.beforeEach里判断本地是否有 token没有就跳转到登录页有就放行。同时根据用户角色动态生成可以访问的菜单项。这个点如果做了答辩的时候会很加分因为“权限控制”在前后端都有体现。4.2 Axios 封装与请求拦截器token注入、错误码统一处理前端和后端的联通依赖 HTTP 请求。我强烈建议用 Axios 封装一层好处是统一处理很多冗余操作。// axios.js const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) // 请求拦截器注入token service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) // 响应拦截器统一处理错误码 service.interceptors.response.use( response { const res response.data if (res.code ! 200) { // 统一提示错误信息 Message.error(res.message) if (res.code 401) { // 跳转登录页 router.push(/login) } return Promise.reject(new Error(res.message)) } return res.data }, error { Message.error(网络异常请稍后重试) return Promise.reject(error) } )这个封装的价值在于登录过期、服务端错误、网络异常这些情况在每一个接口里不用都重复处理统一拦截即可。前端开发时只需要关心业务数据不需要关心鉴权细节。4.3 典型页面实现物资列表筛选、入库弹窗表单、出库审批操作拿库存列表这个页面举例它是最典型的表格搜索分页操作按钮组合页面。后端接口设计时要注意返回的数据结构。分页参数我推荐这样传输pageNum和pageSize返回结构为{ records: [], total: 160 }Vue 页面里用el-table展示数据el-pagination绑定分页搜索区放几个el-input和el-select搜索按钮触发重新查询。库存列表页除了展示当前数量还可以加一个“出入库记录”的按钮点击弹窗展示该物资的历史流水。这个功能做起来不难但非常实用也展示了你对业务的理解。入库表单可以用抽屉el-drawer或弹窗el-dialog结构上是动态表单选择物资 - 填数量 - 填来源 - 提交。前端在提交前做一次正整数校验避免把0或负数发到后端。4.4 前端部署与后端发布本地跑通还是服务器部署毕设阶段最低要求是本地能跑通。但不代表你可以不写部署说明。很多同学把项目发给评审老师后老师因为环境问题跑不起来直接影响最后评分。前端生产构建跑npm run build生成 dist 目录。后端打 jar 包跑mvn clean package或mvn spring-boot:run。如果想在一台服务器上同时部署前端静态资源和后端接口可以用 Nginx 做反向代理把/路径指向 dist 目录把/api路径代理到后端地址。这个方案不需要额外处理 CORS因为同源了。Nginx 配置关键点server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; # 前端 dist 目录 index index.html; try_files $uri $uri/ /index.html; # 路由模式为 history 时必须有 } location /api/ { proxy_pass http://localhost:8080/; # 后端地址 } }注意try_files这一行Vue 路由如果用的是 history 模式刷新二级页面时会 404加上它才能回退到 index.html。5. 常见报错与排查经验几年间踩过的高频问题清单5.1 后端常见异常与解决思路开发过程中后端报错其实很集中。我把最高频的几类整理一下先帮大家判断方向数据库连接失败大概率是 MySQL 服务没启动或者账号密码、URL 配置错误。注意 MySQL 8 的驱动应使用com.mysql.cj.jdbc.Driver并且 URL 中要带serverTimezoneAsia/Shanghai否则报时区错误。时区问题在配置里加上就没了别在代码里绕。Spring Security 拦截了所有请求导致 401两种可能一是过滤器链配置里没有放行登录接口二是前端请求头没有正确携带 token。排查时先看请求头里有没有Authorization字段再看 SecurityConfig 里的permitAll路径配置是否正确。MyBatis 查询字段映射为 null这是字段命名不一致导致的。数据库字段用下划线material_name实体类属性用驼峰materialName需要在配置里开启驼峰转换mybatis-plus: configuration: map-underscore-to-camel-case: true前端跨域报错如果前后端分开启动不同端口需要在后端配置跨域过滤器或者前端用代理解决。一般不推荐直接把 CORS 全部放开至少限制一下允许来源虽然是毕设项目但写习惯了以后工作也用得上。5.2 前端高频问题与调整技巧前端报错最经典的问题是页面白屏和路由跳转失效。页面白屏先打开浏览器控制台看报错最常见的有三种请求接口失败导致数据未定义、组件引入路径错误、Element UI 样式没引入。其中“数据未定义”最常见比如接口返回的字段名和你页面里用的字段名不一致数据绑定到不存在的属性上控制台就会报 undefined。还有一个容易忽略的问题菜单权限和路由不匹配。如果前端只是把菜单隐藏了但路由还能直接访问那么用户手输 URL 照样能进入管理页面。更合适的做法是后端在返回用户信息时带上权限标识前端做动态路由注册或者至少在后端接口层面二次校验。表格时间格式显示成时间戳或者显示不完整也很常见。后端返回的时间字段加上JsonFormat(pattern yyyy-MM-dd HH:mm:ss)注解即可前端也可以再通过dayjs格式化一次双保险。5.3 环境配置类问题JDK、Maven 依赖、Node 版本环境问题虽然不“高级”但非常影响开发效率。我建议在交付文档里直接写清楚JDK 版本统一用 1.8 或 11不要用高版本却配了旧依赖。Maven 如果下载依赖太慢配置阿里云镜像。Node 版本注意兼容性Vue 2 项目建议 Node 1416Vue 3 Vite 建议 Node 16 以上。数据库导入脚本后记得核对一下表是否完整字段是否一致特别是如果做过表结构改动脚本要和实体类保持一致。这些问题都不难但第一次遇到会比较懵。把环境版本固定下来大部分问题都能避免。5.4 常见问题速查表快速定位直接解决问题表现可能原因解决方案控制台报 401 且不弹窗前端未携带 token 或 token 过期检查请求拦截器清除本地缓存重新登录数据库中文乱码连接字符集未指定URL 加characterEncodingutf8表结构用 utf8mb4首次启动时接口返回 500初始化数据不完整或字段缺失核对 SQL 脚本检查实体类和数据库字段对应关系前端安装依赖报错提示 node-sass 不兼容Node 版本和 node-sass 不匹配替换为 sassdart-sass或降低 Node 版本refresh 后页面 404前端路由为 history 模式Nginx 配置 try_files 回退到 index.html打包后接口地址变了环境变量文件未正确读取修改.env.production里的VUE_APP_BASE_API为后端真实地址这张表我是按真实场景整理的基本覆盖了毕设从开发到部署全过程中最容易卡住的环节。6. 接口文档设计规范从接口命名到字段约束的完整作品6.1 接口文档应该包含哪些内容很多同学把接口文档理解成“在代码里加个注释”这是不够的。一个合格的接口文档至少要包含以下信息接口名称比如“物资入库接口”。请求URL与请求方式明确是 POST/api/material/stock-in。请求参数参数名、类型、是否必填、具体含义。返回结果返回结构示例每个字段的含义。错误码该接口可能返回的特殊错误码及含义。这些信息里最容易忽略的是返回结果的字段说明。前端开发时最纠结的往往是接口返回的数据结构不够稳定后端文档写清了前端和字段对齐就很顺。6.2 统一响应结构的约定与错误码规划我在 3.5 节已经提到了统一返回结构这里再补充一下错误码规划的建议。错误码按区间划分更清晰1000 ~ 1999通用错误参数校验失败、操作失败2000 ~ 2999认证授权错误token过期、无权限3000 ~ 3999业务错误库存不足、物资不存在、单据状态异常比如库存不足的提示如果后端返回 3001前端就能在拦截器里针对性地做处理。这套规划虽然是毕设但养成的习惯和真实企业规范是一致的。6.3 前后端接口联调实战记录一份物资出库单的完整请求链路我拿“部门用户创建出库申请单管理员审批通过库存扣减”这条主链路完整串一次前后端交互过程方便大家落实。第一步部门用户登录。前端调用POST /api/auth/login参数为{ username: dept_user, password: 123456 }。后端返回结构{ code: 200, message: 登录成功, data: { token: eyJhbGciOiJIUzI1NiIs..., userInfo: { id: 3, username: dept_user, nickname: 后勤保障部-张三, role: USER } } }第二步前端带上 token 调用POST /api/stock-out/apply提交参数{ materialId: 5, applyQuantity: 200, reason: 一线保障需要补充医用口罩 }后端校验库存当前库存 1500申请 200充足生成单号为 OUT20250114002 的单据状态为“待审批”返回申请成功。第三步管理员账号登录系统在待审批列表看到这张单子。点击“通过”前端调用POST /api/stock-out/approve参数为{ id: 2, approveResult: PASS, approveRemark: 同意 }。第四步后端在事务里执行更新单据状态为“已通过”同时执行UPDATE material_info SET stock_quantity stock_quantity - 200 WHERE id 5。然后返回最新库存数量 1300 给前端。第五步前端刷新后物资列表里的库存显示更新为 1300该单据状态变为“已通过”。这一条链路走通整个系统的核心业务就通了。入库流程就是反向操作把出库时的“扣减库存”改成“增加库存”其他逻辑类似。7. 项目亮点的包装答辩时如何把“会做”讲成“做得好”7.1 技术亮点怎么体现三层校验、事务控制、审计日志很多同学答辩的问题是“只会演示不会讲设计”。老师问“你这个项目有什么亮点”答“页面好看”“功能齐全”是远远不够的。我建议准备几个拿得出手的技术细节数据校验分三层前端表单校验负责体验比如非空、正整数后端 DTO 注解校验负责接口健壮性比如NotNull、Min业务层校验负责业务规则比如库存是否充足。三层校验的逻辑讲清楚老师一听就觉得你有工程意识。事务控制入库、出库这些涉及库存变动的操作务必在事务里完成并且讲清楚为什么要加FOR UPDATE锁以及什么情况下会出现并发超卖。这个问题几乎是每年必问。审计日志所有关键单据记录了“谁在什么时间做了什么操作”。这个设计思路能体现你对管理系统的理解不只是在写增删改查。预警机制定时任务 阈值判断把被动查询变成主动提醒这种思路本身就是系统设计的加分项。7.2 演示过程中容易翻车的四个细节根据我的经验有几个环节是演示时最容易出问题也是老师最容易盯上的。第一登录态过期。如果演示时间比较长登录可能中途过期点击操作时突然跳回登录页。建议演示前把 token 过期时间临时调长或者重新登录一次避免尴尬。第二数据不一致。演示时如果先前的操作已经改了库存临时又去点一个旧页面的数据展示的库存可能对不上。演示前最好先把数据库数据恢复成初始状态也就是重新导入一次 SQL 脚本让数据“干净”地展示。第三网络异常。本地开发时接口地址如果是localhost演示环境换了一台机器接口就全挂了。建议提前把接口地址改成相对路径或可配置项避免移植机器后连环报错。第四不知道演示脚本。很多人演示时想到哪里点哪里一会儿点这个菜单一会儿点那个菜单老师看完一脸茫然。我建议提前准备一个简单的演示脚本按“角色登录 → 建物资 → 入库 → 申领 → 审批 → 看报表 → 看预警”这条主线串起来逻辑清晰故事完整。7.3 让项目“多一点工程味”的三个小动作如果时间和精力允许我建议在项目里加一两个小功能让整体的工程完整感明显提升同时这些功能的代码量并不高。操作日志Spring AOP 切面记录用户操作包括操作人、操作方法、参数、耗时、执行结果。这个小功能把系统从“能用”拉到了“规范”。数据字典把物资分类、审批状态、单位等常量抽成数据字典表代码里不写死状态值前端下拉选项从接口获取。优点是好维护、代码干净但会增加一定的开发量。如果时间不够可以用枚举类替代同样达到效果。软删除删除物资、删除单据时不是物理删除而是逻辑删除即加一个deleted字段标记。这个细节虽然简单但体现的是数据安全观念很能加分。8. 写在最后我的个人体会与复盘做这类系统我的个人体会是不要为了堆功能而堆功能而要围绕一条核心业务线把代码写干净、流程打通、边界理顺。很多同学喜欢一开始就追求“什么都能做”结果每个模块都是半成品。反过来你把“申领物资”这条主线做扎实让登录、角色、入库、出库、库存、统计首尾呼应整个系统的完整度立刻就出来了。再分享一个小技巧写代码之前先花两小时把后端接口文档写完再让前端照着文档开发后端照着文档实现。这个习惯能在开发阶段减少大量沟通成本。我后来自己带项目、带毕设凡是这么做的基本都开发得比较顺利。如果你正在动手做这个项目遇到解决不了的问题可以按文章里的排查表先对照一下。还是没思路的话把报错信息和日志贴出来比一句“报错了”更有利于定位问题。如果你已经做完了再回头看看自己的表结构设计里有没有流水表权限模型里有没有灰度漏洞这些细节往往决定了你的毕设是“合格的”还是“优秀的”。