
简介这是一套面向Java初学者与毕业设计/课程设计学生的SpringBoot办公用品管理系统完整实现解决企业或机构对办公用品入库、领用、库存监控及报损等核心业务的数字化管理需求。资源包共508个文件13.15MB涵盖123个Java后端逻辑类、52个Vue前端组件、34个JS交互脚本、68个JPG界面截图与159个SVG图标资源辅以SQL建表语句、YML配置、BAT一键启停脚本及详细说明文档前后端分离结构清晰便于理解MVC分层与前后端联调流程。已有116人学习下载适合用于实战练手、毕设参考或二次开发。读者可直接导入IDEA或Eclipse运行配合Navicat导入MySQL 5.7/8数据库快速掌握SpringBootVueMySQL全栈开发典型范式并通过源码学习权限控制、库存事务处理、操作日志记录等关键业务实现细节。1. 项目背景与核心价值最近在整理硬盘翻出来一个几年前做的老项目——一个基于SpringBoot的办公用品管理系统。当时是为了解决公司行政部一个老大难问题办公用品的采购、领用、库存盘点全靠Excel表格和微信群吼月底对账时行政同事和财务同事经常因为数据对不上而“扯皮”。这个系统就是在那样的背景下花了大概一个半月时间从零到一搞出来的后来在公司内部稳定运行了两年多直到公司换了更大型的ERP系统。这个项目麻雀虽小五脏俱全。它采用了当时现在看也依然主流的SpringBoot Vue.js前后端分离架构后端用MySQL存数据。我把它重新整理了一下代码、数据库脚本、部署说明都打包好了。对于正在学习SpringBoot全栈开发的朋友来说这是一个非常不错的“练手级”实战项目。它不像电商、社交平台那么复杂但涵盖了后台管理系统最核心的CRUD增删改查、权限控制、数据统计等模块能让你清晰地理解一个业务系统从数据库设计到前端展示的完整链路。为什么说它有学习价值首先它的业务场景办公用品管理非常贴近实际需求明确你很容易就能理解“物品入库”、“员工领用”、“库存预警”这些功能是干嘛的。其次技术栈选型经典且实用SpringBoot让你快速搭建后端服务Vue.js让你构建现代化的管理界面MyBatis-Plus或JPA根据我当时的版本简化数据库操作这些都是企业里高频使用的技术。最后这是一个“完整”的项目你拿到手的不只是碎片化的代码而是一个可以跑起来、能看到效果、能顺着代码理清前后端交互逻辑的完整工程。这对于从理论过渡到实战理解“项目”而非“孤立的类或方法”至关重要。2. 系统核心功能模块拆解与业务逻辑这个办公用品管理系统核心目标是实现办公用品的数字化、流程化管理替代传统手工台账。它的功能模块是围绕“物品生命周期”和“管理流程”来设计的。我们可以把它拆解为几个核心部分每个部分都对应着实际业务中的一个环节。2.1 基础数据管理模块系统的基石任何管理系统首先要管理的就是“物”和“人”。在这个系统里“物”就是办公用品“人”就是公司的员工系统用户。物品信息管理是重中之重。每一样办公用品比如A4打印纸、黑色签字笔、USB扩展坞在系统里都是一个独立的记录。每条记录包含的字段远不止名称那么简单。除了物品名称、规格型号比如“70g/包”、“0.5mm”还必须包含分类文具、耗材、IT设备、单位包、支、个、当前库存数量、安全库存阈值以及存放位置如“三楼仓库A区3架”。这里有个关键的细节安全库存阈值。这个字段是实现自动预警的核心。比如我们设定黑色签字笔的安全库存是50支。当库存量低于50时系统应该在相关页面如库存列表高亮显示该物品或者向管理员发送提醒。这个逻辑是在后端服务层实现的通常会在每次库存变动入库、领用、报损后触发一次库存检查。员工用户信息管理则相对标准。除了工号、姓名、部门等基本信息更重要的是与权限系统的关联。一个普通员工可能只能查看和领用物品而部门经理可能有审批权限行政管理员则拥有所有物品和用户的管理权限。这部分数据是后续权限控制的基础。2.2 核心业务流程模块入库、领用与盘点这是系统最活跃的部分直接处理日常业务。采购入库流程模拟了实物采购到录入系统的过程。它通常始于一张“采购申请单”由需求部门提交经审批后生成“采购订单”。实物到货后行政人员需要创建“入库单”。入库单的核心是明细列表关联本次采购的订单然后逐条添加物品、数量、单价、供应商信息。点击“确认入库”后后端逻辑需要做两件事一是将入库明细持久化到数据库二是实时更新对应物品的库存数量。这里必须使用数据库事务确保明细记录和库存更新要么同时成功要么同时失败避免出现“记了账但库存没增加”的数据不一致问题。员工领用流程是最高频的操作。员工登录系统后可以浏览可领用的物品库存大于0选择物品并填写申领数量提交后生成“领用申请单”。这里我设计了一个简单的审批流领用申请默认提交给申请人的直属上级部门经理审批。经理在待办列表中可以看到申请选择通过或驳回。状态流转是这个流程的关键。申请单有“待审批”、“已通过”、“已驳回”、“已领取”等多个状态。只有状态为“已通过”的申请单员工才能在前台扫描二维码或由行政人员操作完成实物领取此时系统将申请单状态更新为“已领取”并扣减相应物品的库存。扣减库存时必须做并发控制比如使用数据库的乐观锁通过版本号或悲观锁防止超领。库存盘点流程是定期校准系统数据与实物数据的手段。管理员可以发起一次盘点选择要盘点的仓库或物品类别生成盘点任务。盘点人员根据任务清单清点实物数量并在系统中录入“实际盘点数量”。系统会自动计算“账面数量”与“实际数量”的差异盘盈或盘亏生成盘点差异报告。经相关负责人审核后可以选择将差异数量直接调整到库存中使系统数据与实物保持一致。这个流程体现了系统数据如何通过线下操作进行修正和同步。2.3 统计、预警与系统管理模块让数据产生价值基础业务跑通后系统需要提供管理视角的功能帮助决策。数据统计与报表模块将零散的业务数据聚合起来。常见的报表包括库存统计展示所有物品的当前库存、低于安全库存的物品列表。领用统计可按部门、时间范围本月、本季度统计领用总金额、Top N领用物品。这对于分析各部门办公成本非常有用。入库统计统计各供应商的采购频次和金额为采购决策提供依据。 这些报表的后端实现主要依赖于编写复杂的SQL查询语句或使用MyBatis-Plus的QueryWrapper进行多表关联与聚合计算然后将结果封装成前端图表如ECharts所需的数据格式。库存预警如前所述是一个被动触发的功能。除了在库存列表页面进行视觉提示如将库存量小于安全库存的物品行标红更实用的做法是结合定时任务。例如可以配置一个Spring的Scheduled任务每天上午10点运行查询所有库存低于安全阈值的物品将列表通过内部邮件或钉钉/企业微信机器人发送给行政管理员。这样就不用依赖管理员主动登录系统查看。系统管理是后台的标配包括菜单管理、角色管理、用户权限分配、操作日志查看等。这部分通常使用经典的RBAC基于角色的访问控制模型。一个用户可以拥有多个角色一个角色拥有多个菜单权限和操作权限如“新增”、“删除”。在SpringBoot后端这通常通过自定义注解如PreAuthorize(“hasRole(‘ADMIN’)”)和Spring Security或Shiro等安全框架来实现拦截校验。操作日志则通过AOP面向切面编程实现在关键业务方法上添加注解自动记录操作人、时间、IP、方法参数和结果。3. 技术架构详解与核心代码逻辑理解了业务我们再来看看这些功能是如何通过技术栈实现的。这个项目采用的是典型的前后端分离架构前端负责展示和交互后端提供API接口双方通过HTTP协议和JSON格式数据进行通信。3.1 后端SpringBoot工程结构解析打开后端项目你会看到一个标准的Maven多模块或单模块结构。以单模块为例核心的包package结构如下src/main/java/com/example/office/ ├── config/ // 配置类数据源、MyBatis-Plus、Swagger、拦截器等 ├── controller/ // 控制层接收HTTP请求调用Service返回JSON ├── entity/ // 实体层与数据库表一一对应的Java类 ├── mapper/ // 数据访问层MyBatis的Mapper接口或JPA的Repository ├── service/ // 业务逻辑层核心业务处理接口与实现分离 │ └── impl/ ├── dto/ // 数据传输对象用于前后端交互如请求参数、返回结果 ├── vo/ // 视图对象用于封装前端页面需要的复杂数据 ├── common/ // 通用工具类、常量、统一返回结果封装 └── OfficeApplication.java // SpringBoot主启动类核心依赖pom.xml除了SpringBoot的starter-web、starter-test等这个项目关键依赖包括mybatis-plus-boot-starter极大简化了单表CRUD操作内置分页插件。druid-spring-boot-starter阿里巴巴的数据库连接池提供强大的监控功能。spring-boot-starter-security或shiro-spring-boot-starter用于权限认证与授权。spring-boot-starter-aop用于实现操作日志切面。hutool-all一个国人开发的Java工具库提供了很多实用的方法能减少很多工具类的编写。swagger-spring-boot-starter自动生成API文档方便前后端联调。一个完整的业务逻辑链路示例员工领用Controller层 (RequisitionController):RestController RequestMapping(/requisition) public class RequisitionController { Autowired private RequisitionService requisitionService; PostMapping(/apply) PreAuthorize(hasAnyRole(USER, ADMIN)) // 权限注解 public Result apply(RequestBody RequisitionApplyDTO dto) { // 1. 参数基本校验可使用Validated配合注解 // 2. 调用Service层 return requisitionService.apply(dto); } }Controller只做三件事接收参数、调用Service、返回结果。它不应该包含任何业务逻辑。Service层 (RequisitionServiceImpl):Service Transactional(rollbackFor Exception.class) // 声明事务 public class RequisitionServiceImpl implements RequisitionService { Autowired private InventoryMapper inventoryMapper; Autowired private RequisitionMapper requisitionMapper; Override public Result apply(RequisitionApplyDTO dto) { // 1. 数据组装将DTO转换为Entity Requisition requisition new Requisition(); BeanUtil.copyProperties(dto, requisition); requisition.setStatus(RequisitionStatus.PENDING); // 初始状态待审批 requisition.setApplyTime(new Date()); // 2. 库存预检查防止超领 Inventory inventory inventoryMapper.selectById(dto.getItemId()); if (inventory.getStockQuantity() dto.getQuantity()) { throw new BusinessException(库存不足当前库存 inventory.getStockQuantity()); } // 3. 保存领用申请 requisitionMapper.insert(requisition); // 注意此时尚未扣减库存库存扣减发生在审批通过并实际领取后。 // 4. 可能触发消息通知如发送邮件/钉钉给审批人 // notificationService.notifyApprover(requisition.getApproverId(), requisition); return Result.success(领用申请提交成功等待审批); } }Service层是业务逻辑的核心。这里包含了校验、状态设置、数据持久化等操作。Transactional注解确保了方法内多个数据库操作的事务性。Mapper层与Entity:RequisitionMapper接口继承自MyBatis-Plus的BaseMapper立刻拥有了单表的基础CRUD方法。Requisition实体类通过TableName注解映射到数据库表office_requisition字段通过TableField注解映射。事务与并发控制在“确认领取”扣减库存时必须考虑并发。一种简单有效的做法是使用乐观锁。在inventory表中增加一个version字段版本号。// InventoryService中扣减库存的方法 public boolean reduceStock(Long itemId, Integer quantity) { Inventory inventory inventoryMapper.selectById(itemId); // 再次检查库存 if (inventory.getStockQuantity() quantity) { return false; } // 使用乐观锁更新 int updateCount inventoryMapper.updateStockWithVersion(itemId, quantity, inventory.getVersion()); // updateCount为0表示更新失败版本号不匹配数据已被其他线程修改 return updateCount 0; }对应的Mapper XML中的SQLupdate idupdateStockWithVersion UPDATE office_inventory SET stock_quantity stock_quantity - #{quantity}, version version 1 WHERE id #{id} AND version #{version} /update3.2 前端Vue.js工程与前后端交互前端项目通常使用Vue CLI创建结构清晰。src/views/目录下是按模块划分的页面组件如Inventory.vue、Requisition.vue。src/api/目录下是封装好的所有后端API调用接口使用axios库。前后端数据交互范式API统一封装在src/utils/request.js中会创建一个配置好的axios实例统一设置baseURL、请求超时时间并添加请求/响应拦截器。在拦截器中可以自动为每个请求携带Token从localStorage或Cookie读取也可以在收到响应时统一处理错误如Token过期跳转到登录页。// request.js 示例 import axios from axios; const service axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 15000 }); // 请求拦截器 service.interceptors.request.use( config { const token localStorage.getItem(token); if (token) { config.headers[Authorization] Bearer token; } return config; }, error { return Promise.reject(error); } ); // 响应拦截器 service.interceptors.response.use( response { const res response.data; if (res.code ! 200) { // 假设后端统一返回码200成功 // 处理业务错误如提示用户 return Promise.reject(new Error(res.message || Error)); } return res.data; // 直接返回后端封装的数据体 }, error { // 处理HTTP错误如401跳登录 return Promise.reject(error); } ); export default service;页面组件调用在具体的Vue组件中引入对应的API模块。!-- Inventory.vue 部分代码 -- template div el-table :datatableData !-- 表格列 -- /el-table el-pagination current-changehandlePageChange .../el-pagination /div /template script import { getInventoryList } from /api/inventory; // 引入API export default { data() { return { tableData: [], queryParams: { pageNum: 1, pageSize: 10, itemName: undefined } }; }, created() { this.getList(); }, methods: { async getList() { const loading this.$loading(); // 显示加载中 try { const res await getInventoryList(this.queryParams); this.tableData res.records; // 假设返回分页数据 this.total res.total; } catch (error) { this.$message.error(获取列表失败); } finally { loading.close(); } }, handlePageChange(val) { this.queryParams.pageNum val; this.getList(); } } }; /script这种模式清晰地将UI、数据和逻辑分离。API层负责与后端通信组件只关心如何调用API和处理返回的数据。权限控制在前端的体现除了后端接口的权限注解前端也需要根据用户角色动态渲染菜单和按钮。通常用户登录后后端会返回该用户拥有的权限列表菜单权限和操作权限。前端将其存储在Vuex或Pinia中。在渲染侧边栏菜单时会遍历所有路由元信息meta与用户权限进行比对过滤掉无权限的菜单。对于按钮可以使用自定义指令v-permission在指令的绑定值中判断用户是否拥有该操作权限没有则移除或禁用按钮。4. 数据库设计与关键表结构分析数据库设计是系统的骨架好的设计能保证业务清晰、查询高效、扩展方便。这个系统主要围绕“物品”、“流程单”、“用户”三个核心实体展开。核心表结构说明办公用品表 (office_item)存储物品的静态信息。字段名类型说明约束idbigint主键自增PKitem_codevarchar(50)物品编码唯一UK, NOT NULLitem_namevarchar(100)物品名称NOT NULLcategory_idbigint分类ID外键关联分类表FKspecificationvarchar(200)规格型号unitvarchar(20)单位个、支、包NOT NULLsafe_stockint安全库存阈值DEFAULT 0storage_locationvarchar(100)存放位置remarkvarchar(500)备注create_timedatetime创建时间update_timedatetime更新时间设计要点item_code物品编码通常有业务规则如“BGYP-WJ-001”办公用品-文具-001用于快速识别和盘点。category_id外键关联到一个独立的分类表(office_category)实现分类的灵活管理。库存表 (office_inventory)存储物品的动态库存信息。这里采用了物品与库存一对一的设计便于理解和操作。字段名类型说明约束idbigint主键PKitem_idbigint物品ID外键FK, UK, NOT NULLstock_quantityint当前库存数量DEFAULT 0, NOT NULLversionint版本号用于乐观锁DEFAULT 0update_timedatetime最后更新时间设计要点item_id设置唯一约束确保一种物品只有一条库存记录。version字段用于实现乐观锁并发控制如前文所述。为什么不把库存字段直接放在office_item表里从业务上区分“物品信息”是相对静态的属性而“库存”是高度动态的业务数据。分开设计更符合单一职责原则也便于未来扩展比如一个物品可能有多个仓库的库存。领用申请表 (office_requisition)核心流程表。字段名类型说明约束idbigint主键PKrequisition_novarchar(50)领用单号唯一UK, NOT NULLapplicant_idbigint申请人ID外键关联用户表FK, NOT NULLitem_idbigint物品IDFK, NOT NULLquantityint申请数量NOT NULLstatustinyint状态0待审批1已通过2已驳回3已领取NOT NULLapprover_idbigint审批人IDFKapprove_opinionvarchar(200)审批意见approve_timedatetime审批时间receiver_idbigint领取人ID通常是申请人自己FKreceive_timedatetime实际领取时间apply_timedatetime申请时间NOT NULLremarkvarchar(500)备注设计要点requisition_no单号生成有讲究通常使用“LQ年月日序列号”的规则如LQ20240520001在Service层用代码或数据库序列生成确保唯一和可读。status状态字段是驱动整个流程的核心。所有业务操作审批、领取本质上都是对这个状态的变更并在变更时触发其他操作如扣库存、发通知。关联字段通过applicant_id,approver_id,item_id等外键将流程与“人”、“物”关联起来便于后续关联查询和统计。入库表 (office_stock_in)结构与领用表类似但业务含义相反。主要字段包括入库单号、供应商ID、入库员ID、总金额、入库时间等。它通常还会有一张入库明细表 (office_stock_in_detail)用来记录单次入库中包含了哪些物品及其数量、单价。这是一对多的关系一个入库单对应多条明细。这种设计避免了在入库表中重复存储物品信息更加规范。索引策略为了提高查询效率必须在高频查询条件和关联字段上建立索引。office_item表在item_code(唯一索引)、item_name、category_id上建立索引。office_inventory表在item_id(唯一索引)上建立索引。office_requisition表在requisition_no(唯一索引)、applicant_id、status、apply_time上建立索引。例如查询“我的待审批申请”就是WHERE approver_id ? AND status 0在approver_id和status上建立复合索引效果更佳。所有外键字段都应建立普通索引以优化关联查询性能。5. 项目部署、配置与常见问题排查一个完整的项目除了代码还需要能运行起来。这个SpringBoot项目的部署非常灵活可以从IDE直接运行也可以打包成JAR/WAR部署到服务器。5.1 本地开发环境快速启动环境准备确保本地已安装JDK 8或11、Maven 3.6、Node.js 14用于运行前端、MySQL 5.7。导入数据库找到项目中的SQL脚本文件通常是doc/sql/office_db.sql在MySQL中创建一个新数据库如office_manager然后执行该SQL脚本创建所有表结构和初始数据如管理员账号。后端配置与启动用IDE如IntelliJ IDEA导入后端Maven项目。修改src/main/resources/application.yml或application.properties中的数据库连接配置包括URL、用户名、密码确保指向你刚创建的数据库。修改服务器端口如server.port: 8080。直接运行主启动类OfficeApplication的main方法。看到控制台输出SpringBoot的Banner和“Started ... in X seconds”即表示启动成功。前端配置与启动在终端进入前端项目根目录包含package.json的目录。运行npm install或yarn install安装所有依赖。修改前端请求的后端API地址。通常在src/utils/request.js或根目录下的.env.development文件中配置VUE_APP_BASE_API为http://localhost:8080与后端端口一致。运行npm run serve启动开发服务器。访问控制台提示的地址如http://localhost:8081即可打开管理界面。注意前后端分离项目在开发环境下前端请求后端接口会遇到跨域CORS问题。后端需要通过配置解决。在SpringBoot中可以添加一个全局CORS配置类Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) // 拦截所有请求 .allowedOriginPatterns(*) // 允许所有来源生产环境应指定具体域名 .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowCredentials(true) .maxAge(3600); } }5.2 生产环境部署以Linux服务器为例生产环境部署追求稳定和自动化。推荐将前后端分别打包使用Nginx作为反向代理服务器。后端打包与运行在后端项目根目录执行mvn clean package -DskipTests会在target目录生成一个可执行的JAR包如office-manager-0.0.1-SNAPSHOT.jar。将JAR包上传到服务器如/app/backend/目录。在服务器上运行nohup java -jar office-manager-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod app.log 21 。这里--spring.profiles.activeprod指定使用application-prod.yml配置文件该文件应配置生产环境的数据库、Redis等。使用ps -ef | grep java查看进程tail -f app.log查看日志确认启动成功。前端打包与Nginx配置在前端项目根目录执行npm run build会在dist目录生成静态资源文件。将dist目录下的所有文件上传到服务器的Web目录例如/usr/share/nginx/html/office/。配置Nginx将前端请求代理到后端API并处理静态文件。server { listen 80; server_name your-domain.com; # 你的域名或IP # 前端静态资源 location / { root /usr/share/nginx/html/office; index index.html; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } # 反向代理到后端API location /api/ { proxy_pass http://localhost:8080/; # 后端服务地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }重启Nginxsudo systemctl restart nginx。5.3 开发与部署中的常见“坑”与解决思路在实际开发和部署这个系统的过程中我踩过不少坑这里分享几个典型的1. 前端路由在刷新后404History模式现象在Vue Router使用history模式时直接访问http://your-domain.com/inventory这样的子路径或刷新页面Nginx会返回404。原因这个路径在前端是Vue Router管理的虚拟路径Nginx在/usr/share/nginx/html/office目录下找不到名为inventory的文件或目录。解决在Nginx配置中为前端静态资源服务的location /块内添加try_files $uri $uri/ /index.html;。这行配置会让Nginx在找不到对应文件时返回index.html由前端路由接管。2. 后端服务内存持续增长内存泄漏迹象现象服务运行一段时间后通过top或jstat命令查看Java进程占用内存RES不断上升甚至触发OOMOutOfMemoryError。排查思路检查日志首先查看应用日志和GC日志需在JVM启动参数中开启看是否有频繁Full GC的警告。使用工具分析在服务器上使用jmap -dump:live,formatb,fileheap.hprof pid导出堆内存快照。将heap.hprof文件下载到本地使用MATMemory Analyzer Tool或JVisualVM打开分析占用内存最大的对象是哪些以及是谁在引用它们GC Roots。常见嫌疑犯是未关闭的数据库连接、大集合对象如静态Map缓存未清理、线程池未正确关闭。本项目常见点检查是否在Controller或Service中定义了静态的HashMap用于缓存且只增不减。检查MyBatis的Mapper方法是否返回了大量数据如没有分页的全表查询。检查文件上传等操作流InputStream/OutputStream是否正确关闭。解决针对性地修复代码。对于缓存设置合理的过期策略或使用WeakReference。对于大数据查询强制分页。使用try-with-resources语句确保流关闭。3. 数据库连接池耗尽现象应用运行一段时间后前端请求大量超时后端日志出现Cannot get connection from datasource或Timeout waiting for connection from pool等错误。原因数据库连接是宝贵资源连接池如Druid有最大连接数限制。如果应用程序中获取连接后没有正确关闭归还到连接池就会导致连接泄漏最终耗尽。排查与解决开启Druid监控在application.yml中配置Druid的监控Servlet和Filter访问/druid路径可以查看活跃连接数、等待线程数等关键指标。如果“活跃连接数”持续接近“最大连接数”且不释放基本可以确定是连接泄漏。检查代码确保所有数据库操作都在try-catch-finally块或try-with-resources中并在finally块中关闭Connection、Statement、ResultSet。如果使用MyBatis确保SqlSession被正确关闭通常框架会自动管理但在手动编程式使用时需注意。配置合理的连接池参数根据应用并发量调整initialSize、minIdle、maxActive、maxWait等参数。生产环境maxActive不宜设置过大如50-100避免拖垮数据库。4. 跨域问题在部署后依然存在现象本地开发联调正常部署到服务器后前端调用后端API报跨域错误。原因本地开发时前端开发服务器如localhost:8081向后端localhost:8080发请求属于“协议、域名、端口”三者中端口不同是跨域。部署后前端通过Nginx访问http://your-domain.comNginx将/api/代理到后端http://localhost:8080。此时浏览器看到的是向your-domain.com发请求而实际处理请求的是localhost:8080。如果后端配置的CORS允许的来源allowedOrigins不包含your-domain.com或者Nginx没有正确转发相关头部就会出问题。解决后端配置将CORS配置中的allowedOrigins改为allowedOriginPatterns(*)生产环境建议设置为确切的前端域名如https://your-domain.com并确保允许携带凭证allowCredentials(true)。Nginx配置确保在代理配置中转发了必要的头部如上文示例中的proxy_set_header指令。特别是如果前端请求携带了Cookie等凭证信息必须设置proxy_set_header Host $host;和proxy_cookie_path / /;如果需要。这个项目虽然业务不复杂但把这些问题都经历一遍并解决掉你对一个完整Web应用从开发到上线的全链路理解会深刻很多。它就像一块很好的“磨刀石”能帮你把SpringBoot、Vue、MySQL这些技术栈真正地用起来串起来。代码和文档就在那里剩下的就是动手把它跑起来然后试着加个新功能比如“物品报损流程”或者“供应商评价模块”挑战一下自己。本文还有配套的精品资源点击获取