
1. 项目概述与需求分析1.1 毕设选题的核心价值这些年我带过不少毕业设计也评审过大量本科生的课题施工与库房管理系统这个名字看上去平平无奇但它在计算机毕业设计里属于典型的中段偏上选题——比纯图书管理、学生管理这类CRUD项目有含金量又比电商秒杀、分布式微服务这类项目更容易落地。原因在于它同时牵扯两条业务主线一条是施工项目全生命周期管理另一条是仓储物资的进销存流转。两条线之间还有强关联比如施工任务领用材料会直接扣减库房库存、材料采购计划会反哺施工进度这种业务耦合关系恰恰是毕设评分时最能体现建模能力和业务理解深度的地方。从技术角度看这个选题天然适合Spring Boot。施工和库房管理系统不需要像互联网高并发项目那样堆Redis集群、做消息队列削峰它的核心诉求是业务逻辑清晰、数据一致可靠、权限划分明确、报表统计直观。Spring Boot最擅长的就是这种单体应用分层架构快速迭代的场景。加上Spring Boot本身是当前Java后端就业市场的绝对主力用这个框架做毕设既好找工作面试时聊写论文时技术路线也有足够的深度可以展开。很多人误以为这种管理系统就是简单的前后端增删改查实际动手才知道真正的难点分布在几个容易被人忽视的角落多角色权限如何做到数据隔离、库存台账和实际出入库流水如何对账、施工任务审批流程怎么设计才能既灵活又可控。如果只是把CRUD写完就交差答辩时老师一问业务问题就会露馅。所以这篇博文我不打算讲那些烂大街的Spring Boot入门,而是聚焦施工库房这个具体场景从需求拆解、表结构设计、核心功能实现到答辩准备完整梳理一遍。1.2 功能性需求与非功能性需求拆解做毕设之前最忌讳的就是上来就建表、写代码。正确流程是先做需求清单哪怕只有一页纸也能让你少返工半个月。施工与库房管理系统业务角色大致可以分为四类系统管理员、工程项目经理、库房管理员、普通施工人员。不同角色看到的内容和能执行的操作严格区分。功能性需求可以拆成以下几个模块施工项目管理创建工程项目、维护项目基本信息名称、编号、地点、预算、开工/竣工日期、项目状态流转立项、在建、停工、完工、验收。施工任务与进度管理每个项目下可以拆分多个施工任务任务可以指派给施工班组或具体人员填报施工日志和进度百分比。库房基础信息管理仓库信息、物资分类建材、工具、五金、劳保用品等、物资规格型号、计量单位、安全库存上下限。物资入库管理采购入库、退料入库、盘点入库生成入库单并记录经手人、供应商、入库时间自动更新库存台账。物资出库管理施工领料出库、调拨出库、报废出库出库必须关联到具体的施工任务或项目做到每一件材料流向可追溯。库存预警与报表统计库存低于安全阈值自动提醒按项目/物资分类/时间维度统计领用量和金额。非功能性需求也不能忽略毕设评分里这一块经常被单独拿出来问。性能上这种项目并发量很低QPS撑死几十所以不需要做复杂优化但接口响应时间要控制在合理范围内。安全上用户密码不能明文存储至少用BCrypt加密接口要有统一的权限校验。可维护性上代码结构要符合MVC分层命名规范统一Swagger接口文档要配齐这些是答辩时展示工程素养的加分项。2. 技术选型与架构设计思路2.1 为什么是Spring Boot而不是其他框架如果倒退七八年学校里Java毕设的主流组合是SSHStruts2SpringHibernate或者SSMSpringSpringMVCMyBatis配置文件动辄几百行光搭环境就劝退一批人。现在做毕设选择Spring Boot本质上是用约定大于配置的思想把繁琐的配置工作直接砍掉。我常跟学生打比方SSM像是你买了一堆零件自己组装电脑Spring Boot则是买一台品牌整机接口、电源、驱动都帮你装好了你只需要插上自己那块显卡写业务代码就行。具体到这个项目Spring Boot的优势非常实际。第一内嵌Tomcat打一个jar包就能跑部署到服务器上一条java -jar命令搞定不像传统war包要装Tomcat、配置数据源第二starter机制让引入依赖变成一件极简的事spring-boot-starter-web、spring-boot-starter-security、mybatis-plus-boot-starter各自负责一块能力依赖冲突的概率大幅降低第三自动装配特性让框架层面的代码大量消失你可以把精力集中在真正的业务逻辑上。与Spring Boot搭配的生态选型我建议这样组合组件选型理由ORM框架MyBatis-Plus单表CRUD不用写SQL复杂统计用注解SQL比纯MyBatis省事数据库MySQL 8.0开源免费、生态成熟、安装方便足以承载毕设数据量认证授权Spring Security JWT官方主流方案权限模型清晰论文技术点好写接口文档Knife4j (Swagger增强)自动生成接口文档答辩演示接口时非常直观前端框架Vue 3 Element Plus与Spring Boot构成前后端分离技术栈时髦项目管理Maven依赖管理简单直接学校机房环境兼容性好这里要特别说明一下MyBatis-Plus的选择。早期我帮学生审代码发现很多人用了纯MyBatis写大量单表CRUD的XML一个用户表就写了几百行重复SQL完全是浪费时间。MyBatis-Plus的BaseMapper内置了insert、deleteById、selectById、updateById这些常用方法分页插件PageHelper也是一行代码接入。但同时要注意复杂报表查询不能依赖MyBatis-Plus自动生成的SQL该手写联表查询的地方必须手写否则会出现性能问题或统计结果不准确。2.2 系统整体架构设计架构上我推荐采用标准的前后端分离模式前端单独部署后端只提供RESTful API。前后端分离的好处是第一开发时前端和后端可以并行推进Mock数据就能让两边同时开工第二部署时前端打包成静态文件放在Nginx后端打jar包独立运行逻辑边界清晰第三论文里可以单独开辟一章讲前后端交互设计内容更充实。后端内部严格分层Controller层只做参数接收和响应封装不写业务逻辑Service层承载核心业务规则和事务控制Mapper层负责数据库交互entity包放数据库实体类dto包放接口传输对象vo包放视图展示对象。分层的好处是出了问题能快速定位答辩时老师问你某个功能代码在哪里你能很自然地分层回答显得思路清晰。模块划分上按照业务域拆包而不是按照技术层拆包。具体来说backend项目下的包结构大致如下com.example.construction ├── common // 公共模块统一返回体、异常处理、工具类 ├── config // 配置类MyBatis-Plus分页、Security配置、CORS配置 ├── controller // 控制器按业务模块分包 │ ├── project │ ├── task │ ├── warehouse │ ├── material │ └── report ├── service // 业务逻辑层 ├── mapper // 数据库访问层 ├── entity // 数据库实体类 └── dto/vo // 数据传输对象和视图对象这种结构的优势在于项目、任务、库房、物资共用的公共逻辑比如统一返回体Result、全局异常处理器GlobalExceptionHandler收敛到common包业务模块之间相对独立不会出现互相引用的混乱局面。我见过不少毕设代码Service层互相new来new去业务边界全糊在一起到后面改一个需求牵一发动全身这种代码就算运行成功答辩也不好看。安全架构上Spring Security负责认证和授权。认证逻辑用JWT无状态Token处理——用户登录成功后后端签发一个有效期为24小时的Token前端把Token存到localStorage每次请求在Authorization头里带上。授权层面通过自定义注解RequireRole(ADMIN)配合Spring Security的拦截器实现接口级权限控制。管理员、项目经理、库管员、施工人员四种角色分别访问不同的接口集合。2.3 数据库设计核心表与字段规划数据库设计是整个项目的地基这步没想清楚后面改起来非常痛。我见过太多毕设代码因为表结构设计不合理导致业务代码越写越别扭。施工与库房管理系统核心表至少有这些用户表、角色表、项目表、施工任务表、物资分类表、物资表、仓库表、库存表、入库单表、入库单明细表、出库单表、出库单明细表、项目领用记录表、操作日志表。把几张关键表的字段规划给大家过一遍。项目表(project)字段名类型说明idbigint主键雪花IDproject_codevarchar(50)项目编号唯一project_namevarchar(100)项目名称project_addressvarchar(200)项目地点budget_amountdecimal(14,2)项目预算manager_idbigint项目经理ID关联用户表start_datedate开工日期end_datedate计划竣工日期actual_end_datedate实际竣工日期statustinyint0立项 1在建 2停工 3完工 4验收create_timedatetime创建时间库存表(stock)字段名类型说明idbigint主键warehouse_idbigint仓库IDmaterial_idbigint物资IDquantitydecimal(14,3)当前库存数量safe_min_qtydecimal(14,3)安全库存下限safe_max_qtydecimal(14,3)安全库存上限update_timedatetime最后更新时间库存表设计有一个关键点必须加唯一约束UNIQUE(warehouse_id, material_id)否则同一仓库下同一物资会出现多行记录库存对账直接乱掉。这个细节很多新手会漏等数据一多才发现已经晚了。出库单明细表(out_stock_detail)字段名类型说明idbigint主键out_stock_idbigint出库单IDmaterial_idbigint物资IDquantitydecimal(14,3)出库数量unit_pricedecimal(14,2)出库单价total_pricedecimal(14,2)总金额task_idbigint关联施工任务ID材料去向这里有个非常容易忽视的设计决策库存台账和流水明细必须分开。库存表只存当前结余所有数量变化都操作流水表。这样做的好处是任何时候你可以从流水明细重算某个时间点的库存做审计对账时价值巨大论文里还可以写基于流水溯源的库存对账机制听起来就很加分。3. 核心功能模块设计与实现要点3.1 施工项目管理模块状态机设计施工项目的状态流转不是简单的字段修改它有明确的业务约束。立项的项目才能开工在建的项目才能领取物资停工的项目不能继续派发任务完工后不能再关联新的领料单。如果这些约束只靠前端按钮控制后端谁敢保证没人绕过前端直接调接口所以项目状态必须在后端用状态机来管理。我用一个枚举类来定义项目状态及允许的流转路径public enum ProjectStatus { CREATED(0, 立项), UNDER_CONSTRUCTION(1, 在建), SUSPENDED(2, 停工), COMPLETED(3, 完工), ACCEPTED(4, 验收); private final int code; private final String desc; // 状态流转合法性校验 public boolean canTransitTo(ProjectStatus target) { switch (this) { case CREATED: return target UNDER_CONSTRUCTION || target SUSPENDED; case UNDER_CONSTRUCTION: return target SUSPENDED || target COMPLETED; case SUSPENDED: return target UNDER_CONSTRUCTION || target COMPLETED; case COMPLETED: return target ACCEPTED; default: return false; } } }在Service层更新项目状态时先取出旧状态校验canTransitTo不合法就抛出业务异常。这个设计思路在论文里可以扩展为基于有限状态机的项目生命周期管理有理有据也让项目多了一个可深挖的亮点。施工任务模块的要点是任务与物资领用之间的关联。施工班组接受任务后需要领用对应材料系统里最合理的做法是施工任务中预设材料计划材料名称、规格、计划数量实际领料时以任务为单位发起出库申请出库数量不能超过剩余计划量。这样一来任务消耗了多少材料、进度完成到百分之多少都变成了可查的数据施工现场最头疼的材料不知道用到哪里去了问题就有了数据层面的抓手。3.2 库房管理模块一个仓库多物资的库存模型库房管理核心是库存台账的准确性。我推荐的库存模型是库存表流水表的双表结构任何数量变化都必须写流水。入库操作流程是创建入库单主表入库单号、供应商、经手人、入库日期、总金额。录入入库明细物资、数量、单价。事务内批量更新库存表quantity 入库数量。同时插入入库流水记录。出库操作则多一个业务校验步骤检查库存表当前数量是否足够不足则抛出库存不足物资XXX当前库存X申请出库Y。扣减库存前先校验出库数量是否大于0。事务内变更库存并写入出库流水且流水必须记录关联的施工任务ID。这里要强调查询库存和扣减库存必须放在同一个事务里并且要使用SELECT ... FOR UPDATE对库存行加锁防止并发环境下超卖。很多毕设代码因为表数据量小从没触发过并发问题到答辩演示时两个浏览器窗口同时抢最后一批材料库存直接变负数场面非常尴尬。所以这行代码一定要写Stock stock stockMapper.selectByWarehouseAndMaterialForUpdate(warehouseId, materialId);这个FOR UPDATE加的是行级悲观锁对这个场景来说简单可靠。虽然悲观锁并发性能有限但毕设系统本来并发就不高正确性优先。3.3 库存预警与统计报表的实现库存预警是库房系统里一个好看又好用的功能。实现方案不复杂分两个动作一是每次出入库事务结束后对比该物资当前库存和安全库存上下限如果低于下限或高于上限生成一条预警消息记录二是提供一个定时任务Scheduled注解每30分钟扫描一次把漏掉预警补上双保险。预警消息表(alert_message)字段需要物资ID、仓库ID、预警类型低于下限/高于上限、当前库存、阈值、状态未处理/已处理、创建时间。这样仓库管理员登录后能看到未处理的预警列表点击处理后标记状态形成闭环。我给别人的毕设建议里凡是有预警功能的项目一定要记得做处理闭环否则只报不处理业务逻辑很单薄答辩时也不好讲。统计报表模块用JDK 8的Stream分组聚合或者MyBatis写联表SQL来完成。举例来说按项目统计材料领用金额可以用一段SQLSELECT p.project_name, COUNT(DISTINCT od.id) AS out_order_count, SUM(od.total_price) AS total_amount FROM out_stock_detail od JOIN project p ON od.project_id p.id GROUP BY p.id, p.project_name ORDER BY total_amount DESC这种统计报表虽然不涉及大数据但写的时候要注意JOIN条件别多对多、小数精度用decimal别用float、日期范围用LocalDate别用字符串拼接。答辩时能现场演示任意时间段、任意项目的报表查询老师对项目的完整度印象会好很多。4. 开发实操从建项目到跑通核心接口4.1 项目初始化与关键配置用IDEA的Spring Initializr创建项目是最省事的路径。选Java 8或Java 11搭配Spring Boot 2.7.x即可没必要追Spring Boot 3.x因为3.x强制要求Java 17部分老学校的机房环境未必装了。另一个实际原因是网上Spring Boot 2.x的资料量碾压3.x你要是遇到问题搜解决方案的体验完全不同。依赖选择Spring Web、Spring Security、MyBatis-Plus、MySQL Driver、Lombok、Validation、Knife4j。注意MyBatis-Plus和Spring Boot版本要匹配3.5.3以上的MyBatis-Plus对Boot 2.7支持良好。核心配置文件application.yml写这么一段server: port: 8080 servlet: context-path: /api spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/construction_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: your_password mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: assign_id knife4j: enable: true setting: language: zh_cn注意几个参数serverTimezone必须设成Asia/Shanghai否则数据库时间会差8小时这个问题几乎每年答辩都会有人踩坑map-underscore-to-camel-case开启后数据库的project_code自动映射到实体类的projectCode省去一堆TableField注解。4.2 统一返回体与全局异常处理RESTful接口返回格式必须统一这是一个项目规范性的直接体现。我习惯定义一个Result类Data public class ResultT { private Integer code; private String message; private T data; private Long timestamp; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(success); result.setData(data); result.setTimestamp(System.currentTimeMillis()); return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.setCode(code); result.setMessage(message); result.setTimestamp(System.currentTimeMillis()); return result; } }配合全局异常处理器GlobalExceptionHandler使用RestControllerAdvice注解统一捕获两类异常一类是业务异常BusinessException自定义另一类是参数校验异常MethodArgumentNotValidException。这样Controller里不需要自己写try-catch代码清爽前端对接时也只需要按Result结构解析。这里有个实操建议业务异常一定要带上错误码。比如库存不足用1001、项目状态不合法用1002、权限不足用403。错误码的意义在于前端可以根据不同错误码做针对性交互而不只是弹一条提示——论文中描述这部分为基于错误码的异常分级处理机制也是一个可以展开的工程细节。4.3 核心接口实现领料出库全流程下面把施工任务领料出库这个最核心的接口完整走一遍。这个接口是施工和库房两个业务域的枢纽也是答辩时最可能被要求现场演示的功能。Controller层PostMapping(/out-stock/create) RequireRole(WAREHOUSE_KEEPER) public ResultLong createOutStockOrder(RequestBody Valid OutStockCreateDTO dto) { Long orderId outStockService.createOutStockOrder(dto); return Result.success(orderId); }Service层Transactional(rollbackFor Exception.class) public Long createOutStockOrder(OutStockCreateDTO dto) { // 1. 校验施工任务状态 ConstructionTask task taskMapper.selectById(dto.getTaskId()); if (task null || task.getStatus() ! TaskStatus.IN_PROGRESS.getCode()) { throw new BusinessException(1002, 施工任务不存在或不在进行中无法领料); } // 2. 创建出库单主表 OutStockOrder order new OutStockOrder(); order.setOrderNo(generateOrderNo(OC)); order.setTaskId(dto.getTaskId()); order.setProjectId(task.getProjectId()); order.setApplicantId(SecurityUtil.getCurrentUserId()); order.setTotalAmount(new BigDecimal(0)); order.setStatus(0); // 0草稿 1已出库 outStockOrderMapper.insert(order); // 3. 遍历明细校验库存并扣减 BigDecimal total BigDecimal.ZERO; for (OutStockDetailDTO item : dto.getItems()) { // 行级锁查询库存 Stock stock stockMapper.selectByWarehouseAndMaterialForUpdate( dto.getWarehouseId(), item.getMaterialId()); if (stock null || stock.getQuantity().compareTo(item.getQuantity()) 0) { throw new BusinessException(1001, 物资库存不足物资ID item.getMaterialId()); } // 计算金额 BigDecimal amount item.getQuantity().multiply(item.getUnitPrice()); total total.add(amount); // 插入明细 OutStockDetail detail new OutStockDetail(); detail.setOutStockId(order.getId()); detail.setMaterialId(item.getMaterialId()); detail.setQuantity(item.getQuantity()); detail.setUnitPrice(item.getUnitPrice()); detail.setTotalPrice(amount); detail.setTaskId(dto.getTaskId()); outStockDetailMapper.insert(detail); // 扣减库存 stock.setQuantity(stock.getQuantity().subtract(item.getQuantity())); stockMapper.updateById(stock); // 写流水 stockLogMapper.insert(buildStockLog(stock, item.getQuantity(), OUT, order.getId())); } // 4. 更新出库单总金额 order.setTotalAmount(total); outStockOrderMapper.updateById(order); return order.getId(); }这个接口覆盖了事务控制、状态校验、并发锁、库存扣减、流水记录、金额计算六个关键环节每一个都是答辩时可能追问的点。你也把这个接口的执行顺序理清楚给老师讲一遍比背十条Spring Boot面试题都管用。5. 常见问题与排查技巧实录5.1 权限拦截404和跨域问题的双簧坑前后端分离项目里最常见的两个问题就是跨域和权限拦404。跨域问题是因为前端页面在5173端口Vite默认后端在8080端口浏览器默认拦截不同源的请求。解决方法很简单在后端加一个CORS配置类允许指定前端地址访问。但要注意Spring Security开启后CORS配置必须在SecurityConfig里也放开否则前端请求过了浏览器这关到了后端会被Security拦截器直接拒绝表现就是明明后端接口能通前端就是拿不到数据。权限拦截404这个问题更隐蔽。有一次我帮学生排查发现未登录用户访问一个不存在的接口地址后端返回的是404但访问一个存在的接口地址且未登录返回的却是401。学生很困惑以为是接口丢了自己找半天。实际上是Spring Security的异常处理顺序问题——过滤链优先处理资源是否存在再处理认证是否通过。明白这个顺序排查起来就快了先确认URL是不是写错了再确认Token有没有生效。5.2 库存超卖与对账不平的排查思路库存超卖在毕设里几乎不会每次必现但一旦出现就是大问题。前面讲了用SELECT ... FOR UPDATE加悲观锁但如果锁加错了表或者不加在事务里一样白搭。快速排查思路分三步第一看Service层方法有没有Transactional注解第二看Thread.sleep测试并发时是否走的是同一个库存行第三看执行SQL日志里有没有FOR UPDATE关键字。这三步走完九成的并发扣减问题都能定位。对账不平的另一种常见情况是出入库单和库存增减不一致。比如用户下单后订单被删除但库存没有回补或者修改了订单数量库存在原基础上又扣了一次。排查技巧是写一段对账SQL把流水表按物资分组求和再和库存表结余对比偏差值一查就知道是哪笔流水出了问题。这个对账工具我强烈建议写进项目里既是保障工具又是论文里可以描述的系统自检能力。5.3 前端传日期格式和后端接收的时区错乱施工项目、出库单都有日期字段前端在Vue里用new Date()传给后端的日期到了后端经常会发现时间晚了8小时。这个问题的根源是后端没有配置Jackson的时区。在application.yml里补上spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: Asia/Shanghai同时实体类里用LocalDateTime接收日期不要用java.util.Date。LocalDateTime能自动处理时区而Date容易踩UTC的坑。这个坑在毕设答辩现场演示按时间范围查询出库记录时极容易暴露提前规避掉避免在台上手忙脚乱。5.4 FastJson与Jackson混用导致的序列化异常项目中别同时引入FastJson和Jackson我见过不止一个项目因为混用导致LocalDateTime序列化格式不一致前端解析日期时直接报错。统一用Jackson它是Spring Boot默认的消息转换器和框架融合度最高。如果你确实要用FastJSON的某些特性也要以全局配置的方式桥接而不是在业务代码里到处调JSON.toJSONString。做毕设宜简不宜繁保持技术栈的一致性本身就是一种专业性。5.5 上线部署时MySQL时区与SSL配置细节把项目打包成jar部署到服务器或者给老师演示时数据库连接串里两个参数最容易出问题。第一个是serverTimezone服务器时间如果不是Asia/Shanghai连接MySQL就会抛异常——不能忽略时区差异。第二个是allowPublicKeyRetrievaltrueMySQL 8默认使用caching_sha2_password认证首次连接时JDBC驱动拉取公钥需要这个参数放行不加上就会报Public Key Retrieval is not allowed。这两个配置对应到application.yml里基本上出问题的概率就降低到接近零了。6. 论文撰写与答辩准备建议6.1 论文结构规划让框架和工作量可视化毕设论文和项目代码是两回事。很多学生项目做得不错论文写成流水账分数反而不高。合理的结构应该是绪论写研究背景与意义从建筑行业信息化率偏低切入引出施工与库房管理的痛点。相关技术介绍Spring Boot、MyBatis-Plus、Vue、Spring Security、JWT每个技术写清楚是什么、为什么选它。需求分析功能性需求、非功能性需求、用例图、业务流程时序图。这部分最容易扩篇幅也最体现需求分析能力。系统设计总体架构、功能模块设计、数据库设计ER图、核心表设计、接口设计。系统实现分模块展示核心界面和核心接口代码配合界面截图和代码注释讲清楚每个模块是怎么实现的。系统测试功能测试用例表、性能测试结论、兼容性测试。这里我给的建议是数据库设计章节值得详细写每一张表都配一个表格说明字段含义工作量一下子就能撑起来而且这部分内容很实在导师看了也不会觉得水。系统实现章节不要贴大段完整代码截取核心方法片段再配上文字解释就够。6.2 答辩高频问题的应对话术答辩时老师最常问的问题我整理一个清单提前准备就不慌为什么用Spring Boot而不是SSM答Spring Boot通过自动装配和starter机制简化了项目搭建与配置内嵌Tomcat支持一键部署同时社区生态成熟适合快速开发这种业务密集型管理系统。库存扣减为什么用悲观锁答本系统并发量不大悲观锁实现简单、能严格保证数据一致性避免超卖如果需要更高并发可替换为乐观锁或Redis分布式锁但会增加复杂度不适合当前场景。项目状态流转怎么保证数据合法性答采用状态机设计模式定义了状态枚举和流转合法性校验规则非法流转会抛出业务异常数据库层还有status字段的CHECK约束兜底。如果用户并发领料怎么办答在事务中使用SELECT ... FOR UPDATE对库存行加锁确保同时只有一个请求扣减同一物资的库存其他请求等待锁释放后再校验库存。这个系统的核心业务闭环是什么答立项创建项目、项目下拆施工任务、任务领用材料生成出库单、出库自动扣减库存、库存流水记录材料流向、预警功能监控库存健康度。一个完整的材料管理闭环。6.3 演示环境的锋利细节现场演示环节我建议按这个顺序操作效果好且不容易翻车登录演示JWT认证→ 创建项目 → 添加施工任务 → 入库一批材料 → 任务领料出库 → 查看库存变化和流水 → 演示库存预警 → 展示统计报表 → 展示Swagger接口文档。整个过程可以设计成一个完整的故事有一个新项目要开工需要采购进场、分配任务、领料施工。老师跟着业务叙事走会觉得你的系统是个活的整体而不是一堆零散的页面。演示前还有几个小细节再三提醒提前把数据库里的演示数据清干净、再重新插入一套整洁的数据避免表格里出现测试123这种不专业的内容把浏览器缓存清掉确保首次加载正常准备一条数据线但先别插U盘防止老师现场要求拷贝代码时手忙脚乱。这些小细节看起来很琐碎但评审老师一天要听几十场答辩项目功能差不多的前提下谁的表现更从容、演示更流畅分往往就高一些。结尾一些真实体会这个项目带过好几届学生做我自己最大的体会是施工与库房管理系统表面上是管理信息系统的套路化选题但只要你把施工任务和库房库存之间的业务闭环真正跑通它的深度就会超出很多人的预期。相比于做一个花哨但空洞的商城这种有明确业务背景的系统反而更锻炼需求抽象和流程设计的能力。最后再分享一个实打实的小技巧项目开发过程中所有接口的请求参数和响应结果都用日志记录下来配合统一返回体这是你调试和答辩演示的底牌。遇到任何诡异问题先看日志八成问题都能当场定位。很多同学一遇到Bug就靠System.out.println乱打浪费几个小时不如养成立刻看日志的习惯。如果你想在这个基础上升级下一步可以做三件事一是把报表模块升级为图表可视化前端接入ECharts用折线图和饼图展示材料消耗趋势二是加入物资二维码标签扫码即可查看库存信息三是增加审批流引擎让领料单和采购单走多级审批。这三条任选其一项目的完整度和创新性就能再上一个台阶拿去参加校级的优秀毕设评选都有底气。