恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

高校危化品仓储系统实战:SpringBoot+Vue前后端分离开发详解

  • 首页
  • 资讯中心
  • /
  • 高校危化品仓储系统实战:SpringBoot+Vue前后端分离开发详解

相关资讯

微信API对接必备:Jackson对象映射与性能优化实战 2026/10/11 9:52:34
Cursor SSH 远程连接卡死 Waiting for server log?TaoToken 场景下的故障排查全流程 2026/10/11 9:52:34
RAG 项目实战:MCP 协议 + GraphRAG + Cross-Encoder 精排从零搭建(附完整代码)|TaoToken 统一 Key 接入 2026/10/11 9:52:34

最新资讯

从GitHub热门榜单到技术风向标:拆解一周开源项目规律
ACM 51个经典算法大全:126页Word实战源码与避坑指南
WebBrowser控件在Windows桌面应用中的工程化实践
科技前沿的EMBA:如何判断是否适配你的职业阶段
Windows Server下UHD630驱动装不上?绕过限制手工安装与QSV硬解指南
SecureCRT 9.5 安装与中文显示配置:从编码到避坑的完整指南

今日推荐

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

高校危化品仓储系统实战:SpringBoot+Vue前后端分离开发详解

发布时间:2026/10/11 9:52:34
高校危化品仓储系统实战:SpringBoot+Vue前后端分离开发详解 高校实验室的危化品管理说大不大说小不小但每一瓶试剂背后都牵着一份安全责任。早些年实验室管理员最怕两件事一是月底盘点时台账数量跟实物对不上二是学生领用三乙基铝这类试剂时说不清上次那瓶用在哪里、还剩多少。我做的这个前后端分离的高校危化试剂仓储系统就是为了把这些线下流程彻底搬上线——从试剂采购入库、领用申请、教师审批、库存扣减到归还登记、报废记录全程电子化留痕。整套系统基于SpringBootVueMyBatisMySQL开发适合课程设计、毕业设计参考也适合刚接触前后端分离项目想找一个完整案例练手的开发者。下面我把这套系统的需求拆解、技术选型、数据库设计、核心业务实现和部署过程完整写出来包括我实际开发中踩过的坑和优化过的细节。1. 高校危化品管理场景剖析这个系统到底在解决什么问题1.1 传统手工台账的三个致命痛点高校实验室的属性比较特殊它不像企业仓库那样有专职库管和物流系统支撑多数实验室的试剂管理由实验员或研究生兼职负责。这就带来第一个痛点台账记录完全依赖人工试剂名称写错一个字或者CAS号漏填月底盘点时就是一笔糊涂账。第二个痛点是流程不规范。按照规定剧毒、易制爆类危险化学品必须双人双锁、双人领用领用时要有审批记录、用途说明。但在实际操作中很多实验室就是一本登记本谁领了什么试剂签个字就走事后追溯难度极大。真出了问题谁拿着这本登记本都说不清楚。第三个痛点是库存状态不透明。某个课题组要用三氯甲烷仓库里到底还有多少什么时候采购的是否过期这些问题不是跑一趟仓库翻台账就能立刻答出来的于是经常出现重复采购积压资金或者临到实验时发现试剂已经用完的尴尬局面。1.2 系统的核心业务边界什么该做什么不该做在做这个项目之前我先给自己划了一条业务边界免得需求无限扩张导致项目烂尾。必须做好的核心闭环是建档-入库-领用审批-出库-归还-报废。具体来说危化品基础档案由管理员统一维护包括名称、CAS号、危险类别、规格、存放位置、库存上下限采购到货后做入库登记生成入库流水学生或实验人员提交领用申请填写用途、用量、预计归还日期指导教师在线审批超量或高风险领用由管理员二次审核审批通过后库房出库系统扣减库存并生成出库记录归还时做数量核验损耗部分单独登记过期或变质试剂走报废流程生成处置记录。不该做的部分我也明确划掉了不做硬件物联网设备直连温湿度传感器、门禁联动因为要对接的硬件型号五花八门工作量不可控不做复杂的财务报表只保留简单的出入库台账导出。明确边界之后前后端开发就有了清晰的验收标准整体项目大概花了两周半的业余时间做完。2. 技术栈选型为什么是SpringBootVueMyBatisMySQL这一套2.1 前后端分离的价值不只是看起来高级很多人一听到前后端分离就觉得是为了赶时髦其实放在这个场景里分离架构有实实在在的好处。危化品仓储系统涉及的角色天然分散——教师要在手机上审批领用申请实验员在实验室电脑上做入库登记管理员在办公室查看库存台账。前后端分离之后前端只是一个静态资源包部署在Nginx或者任意Web服务器上后端是一套无状态API服务天然适合这种多终端访问的形态。另外前后端分离还能把接口文档作为团队协作的契约。我在开发时先用在线文档把接口定义清楚前端mock数据开始写页面后端专心实现业务逻辑。两边并行推进不互相等待这也是单人开发时保持效率的手段。2.2 后端SpringBootMyBatis的组合逻辑SpringBoot选得很果断理由也没什么争议。它内置了Tomcat一个java -jar命令就能把服务跑起来省掉以前配置Web.xml、Spring容器那一大堆麻烦。对于这种中小型管理系统SpringBoot的自动配置已经把90%的样板代码消化掉了开发者只需要关注业务逻辑。持久层我没有选JPA或MyBatis-Plus而是用了原生MyBatis。原因很简单这类仓储系统的核心是出入库流水和各种统计报表SQL往往带多表关联、分组聚合、条件拼接MyBatis把SQL掌握在开发者自己手里写起来透明可控。例如统计某个危险等级化学品的月度领用量一条group by语句就能完成用JPA反而要折腾Criteria API。MyBatis-Plus固然方便但自带的那套CRUD抽象在这个场景里有点偏重而且一旦涉及复杂查询还是要手写XML和注解SQL不如直接上手原生MyBatis干净。2.3 前端Vue生态的成熟与务实前端选择了Vue 2.6加Element UI。我知道有些朋友会用Vue 3 Element Plus但考虑到课程设计和毕业设计场景下的资料丰富程度以及学校机房Node环境的兼容性Vue 2 Element UI依然是稳妥且多数教程覆盖的路线。Vue的双向绑定和组件化机制让入库登记、领用申请这类表单密集型页面写起来非常顺手Element UI自带表格、弹窗、分页、日期选择器省去造轮子的时间。期间我也对比过若依这样的脚手架框架确实开箱即用但前提是你能接受它的代码风格和项目约束。自己做这个项目就是希望把每一步的来龙去脉讲清楚所以我选择从零搭建而非直接套用脚手架。3. 数据库设计用一张流水表贯穿所有库存业务3.1 整体表结构规划数据库设计是这类系统的地基我前前后后修改了三版最终定下来六张核心表sys_user用户表保存账号密码和角色信息chemical_info化学品档案表维护试剂基本信息stock_record出入库流水表每一笔入库、出库、归还、报废都记录在这里apply_record领用申请表保存审批流的状态流转approval_record审批记录表完整记录每一步审批人、审批意见和时间sys_config系统配置表存放默认审批阈值等参数。这里最核心的设计决策是不要把库存数量作为单独字段一直翻来覆去地改而是把库存计算建立在流水表之上。也就是说chemical_info表里有一个current_stock字段作为缓存但它不是每次操作直接改数字而是通过插入一条stock_record流水再根据流水动态计算并更新缓存库存。这样任何一笔数量变动都能在流水表中找到依据回溯问题时有据可查。3.2 核心表设计细节用户表字段不复杂但要特别注意密码存储方式我用了bcrypt加密而非MD5。有些项目为了演示方便用MD5但放在涉及安全管理的系统里实在不应该。化学品档案表是重中之重字段包含cas_no、chemical_name、danger_class危险等级、specification、unit单位、location存放位置、min_stock、max_stock、lifecycle_status。其中cas_no是化学品的唯一身份标识我加了唯一索引。danger_class我用枚举存储比如剧毒品、易制爆品、易燃液体、腐蚀品等后端的枚举类负责做转换。这个字段在MySQL里存的是varchar配合MyBatis的TypeHandler可以在Java代码里直接把它当成枚举对象使用具体映射逻辑写一个DangerClassTypeHandler即可。出入库流水表的字段设计决定了系统能回答什么问题CREATE TABLE stock_record ( id BIGINT PRIMARY KEY AUTO_INCREMENT, chemical_id BIGINT NOT NULL, record_type VARCHAR(20) NOT NULL, -- IN/OUT/RETURN/SCRAP quantity DECIMAL(10,3) NOT NULL, before_stock DECIMAL(10,3), after_stock DECIMAL(10,3), operator_id BIGINT NOT NULL, apply_id BIGINT DEFAULT NULL, remark VARCHAR(255), create_time DATETIME NOT NULL );before_stock和after_stock这两个字段很多仓管系统会省略我却建议保留。它们的价值在于任何一笔流水你都能立刻看出操作前后的库存变化连计算都不用做。配合record_type可以很容易实现双向追溯——从库存台账点进某瓶试剂能看到它完整的一生什么时候进来的、被谁领走过、归还过多少、最终怎么处理的。3.3 设计时容易忽略的细节数据库方面有几个细节我是在开发中才补齐的。第一个细节是DECIMAL而不是FLOAT。危化品用量经常是0.25L、500mL这种带小数的量FLOAT存在二进制浮点误差累计库存时间长了会出现0.0001的偏差。用DECIMAL(10,3)虽然牺牲了一点灵活性但精确性有保障。第二个细节是时间字段的类型统一。我全部使用DATETIME后端实体用LocalDateTime接收避免java.util.Date的时区序列化问题。MySQL 8的驱动默认时区是UTC如果连接串里不指定serverTimezoneAsia/Shanghai所有时间都会差8小时。这个坑我后面部署的时候还会再提。第三个细节是物理外键不要加。我所有的表关联都只是逻辑上的外键比如stock_record.chemical_id指向chemical_info.id但数据库层面没有创建FOREIGN KEY约束。原因很简单一旦加了物理外键测试数据清理时要先删子表再删主表顺序颠倒就报错。逻辑外键配合业务层的事务控制对这类系统来说已经足够。4. 后端核心业务登录鉴权、库存流水与审批状态机4.1 登录鉴权与角色权限设计后端模块划分我按照业务边界分了四个包sys用户与权限、chemical化学品档案、stock出入库流水、apply领用审批。登录这一块用的是经典JWT方案。流程是这样的用户提交账号密码服务端校验通过后签发一个JWT令牌返回给前端前端把令牌存进localStorage每次请求在Authorization头带上后端拦截器统一解析令牌把当前用户信息放进ThreadLocal供业务层使用。JWT的好处是无状态不需要在服务端保存会话前后端分离部署之后接口层可以水平扩展不用考虑Session共享的问题。角色模型我设计了三种ADMIN管理员、TEACHER指导教师、USER普通实验人员。权限控制没有引入Spring Security的复杂规则而是用拦截器加自定义注解解决。比如出库接口要求ADMIN角色就写一个RequireRole(ADMIN)注解挂在Controller方法上拦截器里用反射读取注解判断。这样做代码量少逻辑直白也方便二次开发时按需调整。4.2 出入库的并发控制出入库操作有一个典型的并发安全场景两个实验员同时领用某一种试剂都在事务里先查库存、判断够不够、再扣减。如果都用最朴素的先查后扣极端情况下两个人读到的都是还有3L各自扣完2L实际库存变成负1L。这个隐患在单机开发环境几乎不会暴露并发一上来就现出原形。处理方案有两种。一种是用SQL里的UPDATE ... WHERE quantity #{need}做原子条件更新影响行数为0说明库存不足直接抛出业务异常回滚事务。另一种是给化学档案表加一个乐观锁版本号字段每次更新前比较版本号。我在这个项目里选了前者因为出入库操作本身就是单行更新一条原子更新语句比版本号方案更省事。Transactional public void stockOut(Long chemicalId, BigDecimal quantity, Long operatorId) { int updated stockMapper.reduceStock(chemicalId, quantity); if (updated 0) { throw new BusinessException(库存不足操作已取消); } // 插入流水记录 StockRecord record StockRecord.of(chemicalId, quantity, RecordType.OUT); stockMapper.insertRecord(record); }核心就是reduceStock那一条更新语句UPDATE chemical_info SET current_stock current_stock - #{quantity} WHERE id #{chemicalId} AND current_stock #{quantity}这里再强调一个容易被忽略的点库存扣除和流水插入必须在同一个事务里否则会出现库存扣了但流水没记或反之的不一致状态。4.3 审批流程的状态机设计领用审批是这个系统和普通库存系统拉开差距的地方因为危化品领用不能像普通文具一样直接扣库存必须走一条完整的审批链路。我在apply_record表里用status字段管理状态流转取值定义如下PENDING_TEACHER等待指导教师审批PENDING_ADMIN教师已同意等待管理员复核APPROVED审批通过等待出库REJECTED审批驳回FINISHED已完成出库流程终结。状态机的转移规则就两条普通化学品领用教师同意后直接PENDING_ADMIN管理员复核即可以出库涉及剧毒品或超过设定阈值比如单次领用超过500mL教师同意后必须进入PENDING_ADMIN管理员还要额外填写复核意见才能通过。这个阈值的数值我放在了sys_config表里而不是写死在代码里方便实验室根据上级检查要求灵活调整。审批记录表approval_record的作用是审计留痕。每个状态节点的操作人都必须落一条记录记录谁在什么时间做了什么决定、批语是什么。这项功能平时看起来冗余但一旦上级安全检查调阅使用记录这些完整数据就是实验室管理响应的底气。4.4 库存预警怎么实现最省力库存预警的常规方案是用定时任务每天扫一遍所有化学档案把低于下限或者接近上限的试剂找出来生成一条预警消息。我第一期也是这么做的后来发现一个问题预警消息的实时性不够管理员早上看到的统计数字到了下午就可能过时。这里我换了个思路预警不在定时任务里做而是在两个时机触发其一每次出库扣减库存成功后立刻检查当前库存是否低于下限低于则向管理员发送站内提醒其二每次入库之后检查是否高于上限提示库存过多请评估是否调整采购计划。这样预警就变成了业务链路中的自然环节不用单独跑定时任务实时性也更好。当然如果系统目前还没有接入消息推送渠道那就在登录后的主界面加载一个库存预警列表的接口把低于下限的试剂全部列出来效果一样。5. Vue前端页面组织、路由守卫与核心交互5.1 前端项目的模块划分前端部分我用的标准Vue CLI创建的项目目录结构划分如下src/api/按后端模块拆分的接口请求封装src/router/路由配置与导航守卫src/store/Vuex保存用户登录态和全局信息src/views/页面组件按业务模块建子目录src/components/通用组件比如档案选择器、库存警示标签src/utils/request.js封装axios实例统一处理token和错误提示。我对axios做了一层薄封装请求拦截器里从localStorage取token塞进请求头响应拦截器里统一处理HTTP 401跳转到登录页、HTTP 500弹出错误提示。这一步很重要否则每个页面都要自己写一堆重复的异常处理代码。5.2 路由守卫控制页面访问权限前端路由不是简单的登录后都能看需要按角色控制。我的做法是路由配置里给每个meta加roles字段然后在全局导航守卫里做判断router.beforeEach((to, from, next) { const token localStorage.getItem(token); if (!token to.path ! /login) { next(/login); return; } const userRole store.state.user.role; if (to.meta.roles !to.meta.roles.includes(userRole)) { next(/403); return; } next(); });这种方式相较于动态路由简单很多适合这种菜单数量可控的管理系统。如果以后要做一个大型的微前端或者多租户平台再考虑从后端拉取路由表动态生成也不迟。5.3 领用申请页面的交互细节领用申请是使用频率最高的页面交互上我特别注意了两点。第一点是化学品选择器必须支持按名称和CAS号模糊搜索因为用户不一定记得全名更多时候只记得那个银白色的瓶装试剂。第二点是填用量时要联动显示该试剂当前的库存如果申请量超过当前库存前端直接给出红色预警不再允许提交。这些看起来不起眼的小交互恰恰是系统好不好用的关键。入库登记页面则采用了类似购物车的设计管理员可以一次性添加多行试剂最后一并提交。每一行需要填名称、CAS号、规格、危险等级、数量、存放位置。表单提交前统一做一次非空校验校验逻辑我放在前端而不是后端重复写后端只做最终的数据合法性快照。数据看板页面是盘点统计的入口用了几张卡片展示今日出入库笔数、低库存试剂数量、待审批申请数下面配了几个Element UI的表格展示最近出入库流水。我一开始想做ECharts图表后来觉得在系统V1.0里表格反而信息更准确图表留到二期再做。6. 部署配置与上线Nginx托管前端SpringBoot作为后端服务6.1 本地运行环境的准备这套系统要用到的本地环境JDK 1.8以上我用的是8、Maven 3.6、Node.js建议14以上、MySQL 8.0。前端依赖安装用npm install如果网络不好或版本冲突频繁可以考虑换淘宝镜像源。后端依赖统一在pom.xml里管理核心依赖是spring-boot-starter-web、mybatis-spring-boot-starter、mysql-connector-java、jjwt。数据库连接配置里面最容易出错的就是MySQL 8的驱动类名和时区参数。驱动类名是com.mysql.cj.jdbc.Driver而且连接串中一定要带上serverTimezoneAsia/Shanghai。我见过很多新手在这一步报SSL连接错误或Public Key Retrieval is not allowed都是因为连接串少了useSSLfalseallowPublicKeyRetrievaltrue这两个参数。完整配置如下spring: datasource: url: jdbc:mysql://localhost:3306/chemical_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver项目里附带一个init.sql脚本按顺序建库、建表、插入管理员初始账号和演示数据。执行的时候注意先切到目标库再执行建表语句避免建到默认库里。6.2 构建与服务器部署前端构建npm run build构建产物在dist目录下这就是一个纯静态文件集合。后端的构建更简单mvn clean package -DskipTests生成的可执行jar包名形如chemical-warehouse-1.0.0.jar。有两种部署姿态可以选择一是直接用内置Tomcat运行jar包这是SpringBoot推荐方式二是打war包丢到独立Tomcat的webapps目录下。我更推荐第一种既省资源又少一层配置。Nginx配置要点是用location /api/把接口请求反向代理到后端jar服务上同时把前端dist目录作为根路径。这是前后端分离部署最关键的一步server { listen 80; server_name your.domain.com; root /usr/share/nginx/chemical-front; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1: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; } }上面location /里的try_files规则解决了Vue Router的history模式刷新404问题。如果不想配这个也可以改用hash模式URL会多个#号但没有服务端配置负担。有洁癖的朋友建议直接上history模式加上面的配置。后端jar包的启动命令我是这么跑的nohup java -jar chemical-warehouse-1.0.0.jar --spring.profiles.activeprod app.log 21 配置上注意生产环境的数据源账号密码不要跟开发环境共用可以单独建一个application-prod.yml用启动参数激活对应profile。6.3 系统初始化与验收清单部署完成后不要急着演示先按验收清单走一遍管理员能否登录新增化学品档案后能否入库库存低于下限时是否出现预警提交领用申请后教师端能否看到待办教师同意后能否出库扣库存归还登记后库存是否恢复导出台账Excel是否正常。我在实际部署时就遇到过一次奇怪的现象前端页面能打开但登录接口一直报404。排查了一会儿才发现是Nginx的/api/代理路径没有生效原因是build的时候前端请求底路径带了/context-path而后端没有配置对应的server.servlet.context-path两边路径对不上。这类前后端分离联调的问题排查思路永远是先看浏览器Network面板里的实际URL再顺着请求链路一层层找不要瞎猜。7. 开发过程踩过的坑和优化建议7.1 MyBatis的一级缓存与列表查询的血泪教训MyBatis默认开启一级缓存同一个SqlSession内相同查询参数会命中缓存。听起来是好事但我在做库存台账列表分页时发现一个问题如果在一个事务里先查询了某个化学品的档案信息随后另一条业务代码插入了出入库流水再执行同一条查询返回的竟然还是旧数据。原因就是一级缓存没有自动失效。解决方式有两个要么把后续插入操作和查询操作放到不同事务要么在关键查询的select标签上添加flushCachetrue。同时我也关闭了二级缓存因为这类仓储系统的数据实时性要求高多一级缓存意味着多一处遗漏失效的可能。7.2 前端Element UI的表格渲染性能危化品台账最多的时候有一万多条记录。Element UI的el-table直接渲染一万行会明显卡顿尤其是带自定义列和行内按钮的表格。解决办法有两个方向数据量可控的情况下后端分页默认每页20条数据量不可控且确实需要滚动加载一万行时改用el-table的虚拟滚动方案。对高校实验室的体量后端分页已经足够我最终选择了分页加简单搜索的方案实测翻页稳定在300ms以内。7.3 关于源码学习的建议拿到完整源码之后建议先不要急着启动项目。我个人的学习路径是先打开init.sql把表结构和初始数据看一遍理清业务关系再跟着数据库表看后端controller-service-mapper三层的路径划分最后才启动前端页面把界面操作和后端日志对照起来看。这样跳过了很多代码能跑但不知道在跑什么的低效阶段。另外不建议去网上找工具做jar包反编译来看内部逻辑效果差且浪费精力。项目本身附带全部源码遇到不明白的地方直接用IDE跳转到定义比任何反编译工具都清晰。7.4 可扩展的方向这套系统目前还没有接消息推送如果实验室要求审批消息实时通知到教师手机可以对接企业微信或者钉钉的机器人Webhook在审批状态变更的地方调用一个消息推送服务即可。文档存证方面化学品的安全技术说明书MSDS和采购单据目前只是简单的文件路径存字段如果要完善可以引入MinIO做对象存储chemical_info表加一个附件URL字段前端上传组件做个文件名回显这个扩展大概一天能完成。我自己在实际使用中的体会是做一个管理系统最难的不是某个技术点而是把所有业务节点串联起来形成闭环。危化品仓储系统这个项目恰恰能让你把SpringBoot事务、MyBatis复杂查询、JWT鉴权、前端路由守卫、Nginx部署这些知识点全部串起来练一遍这也是我推荐拿它做学习项目的原因。如果你正在找前后端分离的实战案例直接拿这套东西跑一遍比看十篇零散的框架教程都管用。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号