ARTICLE DETAIL

资讯详情

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

Java+Springboot+Vue WMS仓库管理系统与微信小程序实战

Java+Springboot+Vue WMS仓库管理系统与微信小程序实战 简介这是一套面向计算机、通信、自动化等相关专业学生与开发者的WMS仓库管理系统完整项目源码采用JavaSpringBoot后端与Vue前端架构并配套微信小程序端可作为毕业设计、课程大作业或进阶练手项目。压缩包共1923个文件约14.51MB涵盖302个Java源文件、222个Vue组件、406个JavaScript脚本、95个XML配置、37个WXML与37个WXSS小程序页面文件以及数据库脚本、说明文档、PDF资料与构建脚本等前后端与小程序三端结构完整。项目经调试测试可正常运行答辩评审分达98分已有1163人学习下载。读者可从中获取完整的三端源码、数据库设计与文档说明理解仓库入库、出库、库存管理等模块的实现思路并在此基础上修改调整实现个性化功能适合小白学习与进阶参考。1. 从一张入库单说起JavaSpringbootVue 的 WMS 到底在管什么很多做企业信息化的朋友第一次接触 WMS 仓库管理系统都是从一张入库单开始的。货到了仓库收货员扫码、填数量、选库位系统自动生成库存流水同时把这条记录同步到微信小程序端让采购和销售在手机上就能看到实时库存。这套动作背后就是 Java 做后端服务、Springboot 做快速集成、Vue 做管理后台、微信小程序做移动作业的典型组合。它解决的核心问题只有一个让仓库里的每一次货物移动都有据可查、有账可对而不是靠 Excel 和微信群吼来吼去。这套技术栈适合谁一是中小型仓储团队预算有限但需要一套能自己维护的系统二是接私活或做毕设的开发者需要一套结构完整、能跑通、能讲清楚的项目三是想从 CRUD 进阶到业务系统设计的 Java 开发者WMS 的库存扣减、批次管理、库位分配是很好的练手场景。下面我会按「先跑起来、再拆模块、最后避坑」的顺序把 JavaSpringbootVue 的 WMS 加微信小程序这条链路讲透包括数据库怎么设计、接口怎么联调、小程序怎么接以及我踩过的那些血泪坑。2. 环境搭建与项目骨架把 Springboot 后端和 Vue 前端先跑通2.1 后端骨架Springboot 项目初始化与数据库连接拿到一套 WMS 源码第一步不是急着看业务代码而是先把后端跑起来。我一般会先确认 JDK 版本和 Maven 依赖是否完整。常见做法是 JDK 1.8 或 11Springboot 2.7.x 居多因为很多 WMS 源码用的 MyBatis-Plus 和 Druid 在这个版本下最稳。数据库一般是 MySQL 5.7 或 8.0建库语句通常在sql目录下。# 1. 创建数据库并导入初始化脚本 mysql -u root -p -e CREATE DATABASE wms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -u root -p wms sql/wms_init.sql # 2. 修改 application.yml 中的数据库连接 # spring.datasource.url: jdbc:mysql://localhost:3306/wms?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai # spring.datasource.username: root # spring.datasource.password: 你的密码 # 3. 编译并启动 mvn clean package -DskipTests java -jar target/wms-backend-1.0.0.jar上面三步里建库和导脚本是最容易翻车的地方。很多源码的 SQL 文件里用了utf8mb4但 MySQL 配置文件没开innodb_large_prefix导入时会报「Specified key was too long」。解决办法是在 my.cnf 里加上innodb_large_prefixON和innodb_file_formatBarracuda或者直接把索引长度改小。启动成功后访问http://localhost:8080/doc.html看 Swagger 接口文档是否正常这是判断后端是否跑通的最快方式。参数方面server.port默认 8080如果被占用就改成 8081spring.datasource.druid.initial-size设 5 就够WMS 并发不会太高mybatis-plus.mapper-locations要指向classpath*:mapper/**/*.xml否则 XML 里的 SQL 加载不到。这些配置在application.yml里都有注释照着改就行。2.2 前端骨架Vue 项目安装依赖与代理配置Vue 前端一般是 Vue2 Element UI 或 Vue3 Element Plus。拿到源码后先看package.json里的依赖版本然后执行安装。这里有个高频坑node-sass和sass-loader版本不匹配会导致npm install直接失败。我一般会先删掉node_modules和package-lock.json再用npm install --legacy-peer-deps绕过 peer 依赖检查。# 进入前端目录 cd wms-web # 清理旧依赖 rm -rf node_modules package-lock.json # 安装依赖指定国内镜像加速 npm install --registryhttps://registry.npmmirror.com --legacy-peer-deps # 启动开发服务器 npm run serve启动后默认访问http://localhost:8081。前端要能调通后端关键在vue.config.js里的代理配置。很多源码写的是target: http://localhost:8080但后端如果改了端口这里必须同步改。代理路径一般是/api所以后端接口也要统一加/api前缀否则会出现 404 但浏览器控制台看不到跨域报错因为请求根本没发出去。// vue.config.js 关键配置 module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, // 后端地址 changeOrigin: true, pathRewrite: { ^/api: } // 如果后端没有 /api 前缀这里要去掉 } } } }changeOrigin: true是为了让后端看到的请求来源是它自己避免跨域拦截。pathRewrite要看后端 Controller 的RequestMapping有没有/api有就去掉这行没有就保留。这两个参数搞反了前端就会一直报 404但后端日志里连请求记录都没有。2.3 微信小程序端项目导入与接口域名配置微信小程序端一般是原生开发或 uni-app。原生小程序用微信开发者工具导入wms-miniprogram目录即可。导入后第一件事是改app.js里的globalData.baseUrl指向你的后端地址。开发阶段可以在开发者工具里勾选「不校验合法域名」这样http://localhost:8080也能请求。// app.js App({ globalData: { baseUrl: http://localhost:8080/api, // 后端接口地址 userInfo: null }, onLaunch() { // 检查登录态 const token wx.getStorageSync(token); if (!token) { wx.redirectTo({ url: /pages/login/login }); } } });小程序请求封装一般放在utils/request.js里统一加 token 和错误处理。这里要注意微信小程序的wx.request默认超时是 60 秒但 WMS 的库存查询接口如果 SQL 没优化可能超过 3 秒用户就会觉得卡。我一般会把常用查询加 Redis 缓存或者在小程序端做分页加载每页 20 条避免一次性拉全量库存。3. 核心模块拆解库存、库位、批次与小程序联调3.1 库存扣减乐观锁与悲观锁怎么选WMS 最核心的逻辑就是库存扣减。出库时系统要保证不会超卖。常见做法有两种悲观锁和乐观锁。悲观锁是SELECT ... FOR UPDATE在事务里锁住库存行扣完再提交。优点是简单缺点是并发高时锁等待严重。乐观锁是加version字段更新时检查版本号失败就重试。-- 悲观锁写法 START TRANSACTION; SELECT quantity FROM wms_stock WHERE sku_id 1001 AND location_id 5 FOR UPDATE; -- 业务判断库存是否充足 UPDATE wms_stock SET quantity quantity - 10 WHERE sku_id 1001 AND location_id 5; INSERT INTO wms_stock_log (sku_id, location_id, change_qty, type) VALUES (1001, 5, -10, OUT); COMMIT;// 乐观锁写法MyBatis-Plus Version private Integer version; // 更新时自动带 version 条件 UpdateWrapperStock wrapper new UpdateWrapper(); wrapper.eq(sku_id, skuId).eq(location_id, locationId).ge(quantity, qty); Stock stock new Stock(); stock.setQuantity(stock.getQuantity() - qty); int rows stockMapper.update(stock, wrapper); if (rows 0) { throw new BusinessException(库存不足或并发冲突请重试); }我一般会选乐观锁因为 WMS 的并发不会像秒杀那么高乐观锁重试成本低而且不会长时间占着数据库连接。但要注意乐观锁的重试次数要限制比如 3 次超过就返回「系统繁忙」避免无限重试拖垮服务。另外库存扣减和流水记录必须在同一个事务里否则会出现库存扣了但流水没记对账时就是一笔糊涂账。3.2 库位分配上架策略与小程序扫码联动库位分配是 WMS 区别于普通进销存的关键。货到了仓库不能随便放要按策略推荐库位。常见策略有就近上架、按品类分区、按周转率分区。实现上一般是在wms_location表里加zone、row、col、max_capacity字段然后写一个推荐算法。// 库位推荐优先找同品类且容量足够的库位 public Location recommendLocation(String skuId, int qty) { // 1. 查该 SKU 的品类 String category skuMapper.selectById(skuId).getCategory(); // 2. 找同品类库位按剩余容量降序 ListLocation locations locationMapper.selectList( new QueryWrapperLocation() .eq(category, category) .apply(max_capacity - used_capacity {0}, qty) .orderByDesc(max_capacity - used_capacity) ); if (locations.isEmpty()) { // 3. 没有同品类库位找任意有空位的库位 locations locationMapper.selectList( new QueryWrapperLocation() .apply(max_capacity - used_capacity {0}, qty) .orderByAsc(used_capacity) ); } return locations.isEmpty() ? null : locations.get(0); }小程序端扫码上架时调用这个接口拿到推荐库位然后让操作员确认。这里有个细节小程序扫码用的是wx.scanCode返回的条码可能是 SKU 编码也可能是库位编码。我一般会在条码前加前缀区分比如SKU-1001和LOC-A01-01解析时按前缀路由到不同逻辑。如果不加前缀扫到库位码当成 SKU 查就会报「商品不存在」操作员会一脸懵。3.3 批次与效期管理先进先出怎么落地食品、医药类 WMS 必须管批次和效期。出库时要按先进先出FIFO或先过期先出FEFO扣减。实现上wms_stock表要加batch_no和expire_date字段出库时按expire_date升序查库存逐批扣减。-- 按效期升序查可用库存 SELECT * FROM wms_stock WHERE sku_id 1001 AND quantity 0 ORDER BY expire_date ASC; -- 逐批扣减伪代码 for (Stock stock : stockList) { if (qty 0) break; int deduct Math.min(stock.getQuantity(), qty); stock.setQuantity(stock.getQuantity() - deduct); stockMapper.updateById(stock); qty - deduct; // 记录流水关联批次 stockLogService.record(stock.getBatchNo(), -deduct); }这里最容易翻车的是批次库存和总库存不一致。比如总库存显示 100但按批次查只有 80剩下 20 是历史脏数据。我一般会在系统里加一个「库存对账」定时任务每天凌晨跑一次把总库存和批次库存汇总比对不一致就告警。另外小程序端查库存时默认只展示总库存点进去才看批次明细避免操作员被一堆批次号搞晕。4. 避坑与排查WMS 联调中最容易翻车的 5 个地方4.1 跨域问题前端 404 但后端没日志现象Vue 前端调接口报 404但后端控制台没有任何请求记录。原因vue.config.js的pathRewrite配置和后端RequestMapping不匹配请求被代理转发到了错误路径。解决先确认后端接口完整路径比如http://localhost:8080/stock/list如果前端代理配了pathRewrite: { ^/api: }那前端请求/api/stock/list会被转发到/stock/list这是对的。如果后端本身就有/api前缀就要去掉pathRewrite。4.2 小程序登录态失效token 过期没刷新现象小程序用着用着突然所有接口返回 401但重新进入小程序又好了。原因token 存在wx.setStorageSync里过期后没有自动刷新机制用户只能杀掉小程序重进。解决在request.js里拦截 401调用刷新 token 接口拿到新 token 后重试原请求。如果刷新也失败再跳登录页。注意刷新接口本身不能走拦截器否则会死循环。4.3 库存扣减为负数并发下乐观锁重试没生效现象压测时库存扣成了负数。原因乐观锁的version字段在更新时没有正确带上或者重试逻辑写在了事务外面导致重试时读到的还是旧数据。解决确保Version注解生效MyBatis-Plus 的乐观锁插件要注册重试逻辑要包在事务里或者用Retryable注解但要注意事务传播行为。4.4 数据库时区问题入库时间差 8 小时现象小程序端显示的入库时间比实际时间少 8 小时。原因MySQL 的serverTimezone配成了 UTC而业务用的是东八区。解决JDBC URL 里加serverTimezoneAsia/Shanghai同时 MySQL 全局时区也设成08:00。如果已经存了脏数据要写脚本批量修正。4.5 微信小程序扫码无响应相机权限没配现象点击扫码按钮没反应也不报错。原因app.json里没有声明scope.camera权限或者用户之前拒绝过。解决在app.json的permission字段里加scope.camera: { desc: 用于扫码出入库 }然后在扫码前用wx.authorize检查权限被拒后引导用户去设置页开启。5. 进阶技巧用 Redis 缓存库存与小程序端性能优化5.1 Redis 缓存库存把查询 QPS 从 200 提到 2000WMS 的库存查询是高频操作每次查 MySQL 都要走索引QPS 上不去。我一般会把库存数据缓存到 Redis用Hash结构存sku_id location_id对应的数量查询时先走 Redis扣减时先更新 Redis 再异步落库。这样查询 QPS 能从 200 提到 2000 以上。// Redis 缓存库存查询 public Integer getStockFromCache(Long skuId, Long locationId) { String key stock: skuId : locationId; Object val redisTemplate.opsForHash().get(key, quantity); if (val ! null) { return Integer.parseInt(val.toString()); } // 缓存未命中查数据库并回写 Integer qty stockMapper.selectQuantity(skuId, locationId); redisTemplate.opsForHash().put(key, quantity, qty.toString()); redisTemplate.expire(key, 30, TimeUnit.MINUTES); return qty; }注意缓存和数据库的一致性要靠「先更新数据库再删除缓存」来保证不要用「先删缓存再更新数据库」那样并发下容易读到旧数据。另外缓存过期时间设 30 分钟就够WMS 的库存变化不会特别频繁太短了缓存没意义太长了脏数据风险高。5.2 小程序端性能分页加载与图片懒加载小程序端最怕一次拉太多数据。库存列表我一般做分页每页 20 条上拉加载更多。商品图片用lazy-load属性避免一次性加载几十张图卡死。另外小程序的setData是性能瓶颈不要频繁调用能合并就合并。// 分页加载库存列表 Page({ data: { list: [], page: 1, hasMore: true }, onReachBottom() { if (!this.data.hasMore) return; this.setData({ page: this.data.page 1 }); this.loadList(); }, loadList() { wx.request({ url: ${app.globalData.baseUrl}/stock/page, data: { page: this.data.page, size: 20 }, success: (res) { this.setData({ list: this.data.list.concat(res.data.records), hasMore: res.data.records.length 20 }); } }); } });最后说一个我自己的习惯每次改完库存逻辑我一定会用 JMeter 跑一轮 100 并发的出库测试看库存会不会扣成负数、流水有没有漏记。这个习惯帮我省了至少三次线上事故。WMS 这种系统功能跑通只是及格并发和数据一致性才是真正的门槛。希望帮到你。本文还有配套的精品资源点击获取
返回列表