news 2026/10/28 22:20:12

基于微信小程序的行李寄存管理系统:Spring Boot+Redis实现全链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于微信小程序的行李寄存管理系统:Spring Boot+Redis实现全链路

简介:面向需要完成微信小程序相关毕业设计或课程项目的学生,一套完整的行李寄存管理系统设计与实现方案包含论文与可运行源码,可直接用于课题参考。系统围绕用户出行场景,设计了注册登录、行李寄存预约、支付、行李状态跟踪与用户反馈等模块,前端采用微信小程序与Vue,后端基于Java,并配有SQL数据库脚本,覆盖从原型到部署的完整开发链路。压缩包共413个文件,主要包括Java后端源码、Vue前端页面、小程序脚本、SQL数据文件、图标与图片素材以及论文docx文档,总容量44.14MB,目录按前后端和文档分类,便于检索与二次开发。资源附带的部署运行bat脚本和说明文档,可帮助读者快速搭建环境并启动项目。目前已有140人学习下载,适合正在准备同类课题答辩、需要完整源码与论文框架的学生。

1. 一刷二维码就能存行李:行李寄存管理系统的场景、交付物与适用人群

在高铁站、景区和展会现场,行李寄存大多还停留在填单子、手写凭条、取件时人工核对的阶段,高峰期排队,凭条易丢,格口是否空闲只能靠人工去看。基于微信小程序的行李寄存管理系统,就是把“寄存 → 支付 → 取件 → 超时计费”这条链整体搬到微信里:用户扫柜面二维码自助下单,得到取件码;管理员在后台实时看到格口占用和超时订单;微信支付自动结算。标题里的“论文+源码”是一份毕业设计交付物,论文负责把设计讲清楚,源码负责把业务跑通。它适合两类人:一是正在开题或准备答辩的计算机、软件工程学生,需要一套能演示、能讲清设计点的完整系统;二是景区、商场、展馆的运营方,想先做一版小体量的寄存数字化验证需求。

2. 先把系统拆开:业务边界、表结构与取件码方案

2.1 为什么选微信小程序而不选 App / H5:三个真实理由

行李寄存是典型的低频、强即时需求。用户拖着行李箱走到寄存点,只想扫码、付钱、拿码走人,不可能为存一次行李专门下载 App。H5 也能做到扫码即用,但有两个硬伤:一是没法调用微信支付 JSAPI 拿到原生支付体验,二是没有订阅消息通道,取件提醒发不出去。微信小程序在微信生态内天然解决这些问题:wx.login直接拿到身份,wx.requestPayment拉起微信支付,订阅消息能在超时前提醒用户回来。

成本也是一条很实在的理由。做个人主体的小程序不需要企业认证费用,大部分功能都能跑通;管理端用 Web 页面或小程序内嵌页,和后端共用一套接口,不必单独开发 App。如果你的寄存柜未来要接蓝牙开柜锁,小程序对蓝牙 BLE 的支持比 H5 稳定得多,这是物联网方案里调用门槛最低的一条路。综合下来,小程序是这个小体量业务场景里性价比最高的承载形态。

2.2 运营视角看边界:用户端、管理端、后端各管什么

动手写代码前,先分清三条业务线。用户端的小程序只做四件事:选格口、下单支付、查看取件码、超时后续费或补缴。管理端负责格口状态维护、订单查询、手动开柜和收入统计。后端是核心,它要管住身份、订单状态机和支付回调。

整张系统的核心是一张寄存单,它的生命周期是一个状态机:待支付 → 已寄存 → 已取件 → 已关闭。待支付说明用户还没付钱,格口不锁定,超时未支付自动关闭;已寄存是支付回调成功那一刻的状态,格口标记占用,取件码生效;已取件后订单关闭。我一般会把状态机放在后端枚举里,不允许小程序端直接改状态,前端只能通过下单、支付、取件三个接口推进订单。这样答辩时能讲清楚,出问题时也只需顺着状态查日志。

2.3 数据库三张核心表:用户表、寄存单表、柜子表的字段设计

数据模型是这套系统最容易被低估的部分。很多毕设为了赶进度,把柜号直接塞进订单表一个字符串字段,看起来省事,但一旦要做空柜查询、费用统计,就会卡在数据结构上。下面的建表 SQL 是按常见做法写的最小集合,拿到交付源码后可以对照调整:

-- 用户表:只存小程序端识别所需的最小字段 CREATE TABLE `user` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `openid` VARCHAR(64) NOT NULL UNIQUE COMMENT '微信openid,每个用户在小程序下唯一', `nickname` VARCHAR(64) DEFAULT '' COMMENT '昵称,可空,避免过度收集', `phone` VARCHAR(20) DEFAULT '' COMMENT '手机号,用户主动填写再存', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, KEY `idx_openid` (`openid`) ) COMMENT '用户表'; -- 寄存单表:一次寄存的唯一记录 CREATE TABLE `storage_order` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `order_no` VARCHAR(32) NOT NULL UNIQUE COMMENT '业务单号,格式如 yyyyMMdd+随机数', `user_id` BIGINT NOT NULL, `locker_id` BIGINT NOT NULL COMMENT '关联柜子表,锁定具体格口', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0待支付 1已寄存 2已取件 3已关闭', `start_time` DATETIME DEFAULT NULL COMMENT '实际寄存开始时间,支付成功时落', `end_time` DATETIME DEFAULT NULL COMMENT '实际取件时间', `fee_total` DECIMAL(10,2) DEFAULT 0 COMMENT '合计费用,单位元', `pickup_code` VARCHAR(6) NOT NULL COMMENT '取件码,仅存哈希,不存明文', `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, KEY `idx_user_status` (`user_id`, `status`), KEY `idx_locker_status` (`locker_id`, `status`) ) COMMENT '寄存单表'; -- 柜子表:物理或虚拟格口 CREATE TABLE `locker` ( `id` BIGINT AUTO_INCREMENT PRIMARY KEY, `location` VARCHAR(128) NOT NULL COMMENT '位置描述,例如 3号柜 12格', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0空闲 1占用 2禁用', `size_type` TINYINT DEFAULT 0 COMMENT '0小 1中 2大,影响计费单价', `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT '柜子表';

这段 SQL 里有三个细节值得专门说。第一,order_no用业务单号而不是数据库自增 id 暴露给前端,防止用户通过遍历订单号窥探别人的订单,这是安全上最容易翻车的地方。第二,pickup_code只存哈希,因为取件码是 6 位数字,明文存放一旦脱库,攻击者可以直接拿去开柜。第三,storage_order通过locker_id关联柜子表,而不是冗余一个柜号字符串,这样查“哪些柜子空闲”就是一条status=0的查询,后续做格口统计也不用手撕字符串。

2.4 取件码方案:6 位随机数 + Redis 原子校验

取件码用 6 位纯数字,生成时要避开 0、1、O、I 这些易混淆字符,同时排除连续同号和单调升序、降序,否则用户手输时特别容易错。我一般用ThreadLocalRandom生成,配合 Redis 的SET key value EX设置半小时有效,取件时用GETDEL取一次并立刻删除,天然防止重复取件:

// 生成6位取件码并写入Redis,过期时间1800秒 String code = String.format("%06d", ThreadLocalRandom.current().nextInt(100000, 1000000)); // 取件时,GETDEL 取出的同时删除,第二个用户再来就取不到 String stored = redisTemplate.opsForValue().getAndDelete("pickup:" + code); if (stored == null || !stored.equals(orderNo)) { throw new BizException("取件码无效或已过期"); }

参数说明:过期时间按寄存时长来定,普通寄存建议 30 分钟;过短会把用户卡在码过期上,过长则格口空置期间取件码仍有价值。实际项目里我会让过期时间与订单超时时间一致,并在小程序端提供“刷新取件码”按钮,刷新时旧码立即失效,避免码被截图冒用。GETDEL是 Redis 6.2 之后的原子命令,如果你用的老版本 Redis,要用 Lua 脚本包一层 get 加 del,保证两步原子性,否则两个请求同时取件码会有一方读到空。

3. 后端实现:Spring Boot 代码里,订单创建到取件码校验的完整链路

3.1 技术栈与三个易错的配置项

毕业设计里最常见的后端组合是 Spring Boot + MyBatis Plus + MySQL + Redis。选 Spring Boot 不是因为它新,而是因为微信支付 SDK、小程序登录校验这些官方资源都以 Java 生态为第一优先,文档齐全,答辩时也容易讲清楚。MyBatis Plus 省掉大部分单表 CRUD 的样板代码,让代码量控制在论文能写清楚的范围内。

pom.xml 依赖里除了spring-boot-starter-web、mybatis-plus-boot-starter之外,有三个容易被忽略的点:一是 Redis starter,用来存取件码和会话;二是微信支付官方 SDK,签名验签不用自己写;三是 Lombok,少写 getter/setter。版本号以你拉到的交付源码为准,建议留在 Spring Boot 2.7 或 3.x 的兼容区间,不要盲目升到最新大版本——微信支付 SDK 对旧版兼容性更成熟。

配置文件里有三个关键项:appid、mchid、apiV3Key。appid是小程序后台的 AppID,mchid是微信支付商户号,apiV3Key是商户平台设置的 32 位 APIv3 密钥。这三个值任何一个出错,支付回调验签就失败,现象表现为“用户支付成功但订单状态不更新”,这是后文避坑章会重点讲的地方。

3.2 创建订单接口:先锁柜子,再写订单,再调微信预支付

创建订单的完整链路是:小程序端传柜子 id 和预计寄存时长 → 后端锁柜子 → 生成订单(状态为待支付)→ 调微信支付统一下单接口拿prepay_id→ 返回给小程序端拉起支付。下面是核心 Service 代码:

@Transactional public CreateOrderResp createOrder(CreateOrderReq req, Long userId) { // 1. 用悲观锁锁住柜子行,防止两个用户同时抢同一个格口 Locker locker = lockerMapper.selectByIdForUpdate(req.getLockerId()); if (locker == null || locker.getStatus() != LockerStatus.FREE) { throw new BizException("该格口不可用"); } // 2. 生成业务单号并落库 StorageOrder order = new StorageOrder(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setLockerId(locker.getId()); order.setStatus(OrderStatus.WAITING_PAY); storageOrderMapper.insert(order); // 3. 计算费用:基础价 + 超时价 BigDecimal amount = calcFee(locker.getSizeType(), req.getExpectHours()); // 4. 调微信支付预下单 String prepayId = wechatPayService.createJsapiOrder( order.getOrderNo(), "行李寄存", amount, req.getOpenid() ); return new CreateOrderResp(prepayId, order.getOrderNo(), amount); }

逻辑说明:第一步用selectByIdForUpdate给柜子行加行级锁,这一步非常关键——不加锁的话,两个用户同时点同一个格口,会插入两条都认为自己占用成功的订单,出现“柜子被两个人同时占用”的脏数据。第三步费用计算建议放到独立方法里,把基础价和超时单价做成配置项,因为寄存计费规则在不同场景差异很大:景区按小时,高铁站按天,展会按天但超时半小时内免费。

参数说明:expectHours是小程序端传的整数,后端不能直接信这个值。常见做法是根据柜子位置和服务配置,把预计时长限定在 1~48 小时,超出范围直接拒绝。这个约束在答辩时可以主动讲,属于“业务规则由服务端兜底”的设计点。

3.3 支付回调:验签、幂等与掉单补偿

支付回调是整个系统里最容易翻车的环节。微信不会因为你的接口报错就无限重试,它只会在短时间内重试几次然后放弃,所以回调接口必须保证两件事:先验签、再处理,处理逻辑要幂等。下面这段是回调的骨架:

@PostMapping("/api/pay/callback") public String payCallback(@RequestBody String body, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Serial") String serial) { // 1. 用微信支付平台证书验证签名 if (!wechatPayValidator.verify(serial, body, signature, nonce, timestamp)) { return "FAIL"; } // 2. 解析回调体,拿到订单号 PayCallbackData data = JSON.parseObject(body); String orderNo = data.getOutTradeNo(); // 3. 幂等处理:订单已经是已支付状态就直接返回成功 StorageOrder order = storageOrderMapper.selectByOrderNo(orderNo); if (order == null || order.getStatus() != OrderStatus.WAITING_PAY) { return "SUCCESS"; } // 4. 更新订单为已寄存,写支付流水,占用柜子 order.setStatus(OrderStatus.STORED); order.setStartTime(LocalDateTime.now()); storageOrderMapper.updateById(order); lockerMapper.updateStatus(order.getLockerId(), LockerStatus.OCCUPIED); return "SUCCESS"; }

逻辑说明:第 3 步的幂等检查能防住两类问题:一是微信回调因网络超时重发同一条通知,二是测试时重复推送同一笔支付。验签失败直接返回FAIL,让微信按它的重试策略再推一次,不要自己手动补偿。第 4 步里的更新动作要放在同一个事务里,避免“订单状态已改但柜子没占用”的中间态。

参数说明:验签所需的平台证书序列号Wechatpay-Serial由微信在每次回调请求头携带,后端拿到后用它去微信支付平台下载对应证书公钥。本地开发时如果日志反复打印“验签失败”,先检查 APIv3 密钥配置里是否混入了空格或换行符,这是最常见也最隐蔽的低级错误。

3.4 掉单补偿:定时任务兜底

支付回调不是 100% 可靠的。用户付完钱小程序闪退、回调接口刚好在发布、网络分区,都会导致“微信扣了款,订单还是待支付”。常见做法是加一个定时任务,定期调微信查单接口把本地状态对齐:

// 每天凌晨跑一次,把微信侧已支付但本地待支付的订单补上 for (StorageOrder order : storageOrderMapper.selectStuckOrders()) { WechatPayOrder queryResp = wechatPayService.queryOrder(order.getOrderNo()); if (queryResp.isPaid()) { markOrderPaid(order); // 复用支付回调里的幂等处理逻辑 } }

这个定时任务在答辩时几乎是必问题:“你们怎么处理支付掉单?”讲清楚回调是实时通道、定时任务是最终一致性兜底,两者必须同时存在。只靠回调,掉单永远存在;只靠定时任务,用户支付后拿不到即时反馈。两者的关系比代码本身更重要。

4. 小程序端:登录、下单、倒计时与订阅消息的实现

4.1 登录链路:wx.login 换 openid,用服务端 token 管会话

小程序端用微信原生开发(WXML + JS)就够,不必为了“前后端一体”硬上 uniapp;如果交付源码本身是 uniapp,也可以直接接着写,但要注意 4.4 节的打包体积问题。登录态是小程序端第一个难点,微信提供的 openid 不能当作业务身份直接暴露给前端,后端应该把它换成自己签发的 token:

// 小程序端登录 login() { wx.login({ success: async res => { const loginResp = await request('/api/login', { method: 'POST', data: { code: res.code } // code 是临时凭证,后端拿它换 openid }); wx.setStorageSync('token', loginResp.token); } }); } // 封装请求:自动附带 token,响应里发现 401 就重新登录 function request(path, options) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + path, method: options.method || 'GET', data: options.data || {}, header: { Authorization: 'Bearer ' + (wx.getStorageSync('token') || '') }, success: res => { if (res.statusCode === 401) { doReLogin(); reject(res); } else resolve(res.data); }, fail: reject }); }); }

逻辑说明:登录链路是wx.login拿到一次性 code,后端用这个小程序的appid和secret去微信接口换回 openid,再用 openid 查用户表、签发自己的 token。这样设计的好处是后端不依赖微信的session_key,完全掌控会话有效期。你在调试时如果发现“第一次登录成功,第二次点登录却报错”,先检查是不是把 code 缓存后重复使用了——code 有效期只有 5 分钟且只能用一次。

参数说明:wx.login返回的 code 是一次性的,不要落盘。另外,涉及自定导航栏时,不要用写死的顶部高度适配所有机型,用wx.getMenuButtonBoundingClientRect()拿胶囊按钮位置再算导航栏高度,否则刘海屏和普通屏的登录页布局会错位。这个看起来小的问题,在答辩现场换一台手机演示时很容易露馅。

4.2 下单页:格口选择、计费规则与 requestPayment 的坑

下单页是小程序端的核心转化页面。它要做的是让用户在 30 秒内完成三件事:选格口、选寄存时长、发起支付。格口列表由后端接口拉取,前端展示size_type和价格,但空闲状态最终以下单接口的锁行校验为准:

async selectLocker(locker) { if (locker.status !== 0) return; // 非空闲格口直接置灰 this.setData({ selectedLocker: locker }); const price = await request('/api/price?sizeType=' + locker.size_type + '&hours=3'); this.setData({ fee: price.fee }); } submitOrder() { const l = this.data.selectedLocker; if (!l) { wx.showToast({ title: '请先选择格口', icon: 'none' }); return; } request('/api/order', { method: 'POST', data: { lockerId: l.id, expectHours: this.data.hours } }).then(resp => { // 拿到 prepay_id 后调起微信支付 wx.requestPayment({ timeStamp: resp.timeStamp, nonceStr: resp.nonceStr, package: resp.package, // 这是预支付单的标识,不是npm包 signType: 'RSA', paySign: resp.paySign, success: () => { wx.redirectTo({ url: '/pages/order/detail?id=' + resp.orderNo }); } }); }); }

这里最容易踩的坑是wx.requestPayment的package参数,它的值是后端预下单接口直接带回的prepay_id=xxx字符串,很多新手把订单号填进去,结果支付调起直接失败。signType也要和后端协商一致,微信支付 V3 下用RSA,沿用旧的MD5会报签名错误。

计费规则建议做成阶梯价格而不是线性计费。行李寄存的典型时长分布是 1~3 小时和过夜两个高峰,线性计费会让过夜单价格高到不现实,用户看一眼价格就放弃了。

4.3 订单详情页:取件码展示、倒计时与 onHide 清理

用户存好行李后最关心两件事:取件码是什么、还剩多长时间。取件码在详情页大号展示,同时提供“刷新取件码”按钮,刷新的本质是调后端接口生成新码、旧码立即失效。倒计时建议用setInterval实现,但页面隐藏时必须清理,否则小程序切到后台再回来,定时器还在跑,界面时间和真实时间产生漂移:

onShow() { this.loadOrder(); this.timer = setInterval(() => this.tick(), 1000); } onHide() { if (this.timer) { clearInterval(this.timer); this.timer = null; } } tick() { const remain = this.computeRemainSeconds(); // 从订单数据算剩余时间 if (remain <= 0) { clearInterval(this.timer); wx.showModal({ title: '已超时', content: '请尽快回柜取件,将产生超时费' }); } else { this.setData({ remainText: format(remain) }); } }

逻辑说明:onHide是微信小程序的生命周期方法,用户切到微信聊天窗口或按 Home 键回桌面时都会触发,它是“监听用户离开小程序”的标准入口。凡是页面里有倒计时,必须在onHide和onUnload里清理对应定时器,否则回来时看到的是一段早已过期的虚假倒计时。我从实际经验讲,这个问题不到真机用户报“时间不准”几乎测不出来,属于必改项。

参数说明:computeRemainSeconds应该从订单的end_time计算,而不是从前端本地时间加减,因为后端会在支付回调时更新确切时间,前端本地时钟可能不准。展示层再优雅,数据源不对就是错的。

4.4 uniapp 打包体积超 2MB:把页面拆成分包

如果你的交付源码是用 uniapp 写的,大概率会踩到“source size 2612kb exceed max limit 2mb”这个编译错误。uniapp 会把 Vue 工程编译成微信小程序原生代码,再把所有页面塞进主包,图片多、UI 库大就会超限。常见对策有三个:主包只放 tabBar 页和登录页,把下单页、订单详情、管理端页面全部放进分包;图片不要直接放工程目录,用懒加载或云存储 URL 替代;UI 组件库按需引入,不要全局注册。

我把这条放在小程序实现里提醒,是因为很多同学最后发现功能全写好了,但代码传不上微信开发者工具,卡在编译阶段。先规划分包结构再写页面,比写完后拆分包省事得多。

5. 踩坑排查:跑不起来多半是这五个问题

5.1 支付回调不通:订单卡在“待支付”

现象:用户在小程序里付了钱,微信扣款成功,但订单状态一直是“待支付”,柜子没有被占用。

原因:微信支付回调没到后端。最常见的两个原因是 APIv3 密钥配置里混入了空格或换行符,导致验签失败;或者回调地址是http://localhost,微信服务器根本访问不到。

解决:先看后端日志里有没有“验签失败”或“签名错误”的异常,再确认回调地址是公网可达的 HTTPS 地址。本地开发时用内网穿透工具把 8080 映射到公网,把回调地址临时配成外网域名,调试通过后再换成正式地址。微信不会往 HTTP 地址推回调,这一点经常被忽略。

5.2 并发抢格口:两个用户同时下单同一个柜子

现象:两个用户同时点了同一个空闲格口,都提示下单成功,但格口只有一个。

原因:下单接口没有锁柜子行。本地用单账号手动测试时,请求是串行的,永远测不出这个问题;一旦答辩现场有人多台手机同时操作,就会暴露。

解决:在下单 Service 里先用selectByIdForUpdate锁住柜子行,锁定后再次校验状态,再插入订单。锁行必须和插入订单在同一个事务里,否则锁在事务提交前就释放了,等于没锁。如果长期做这个系统,还可以给locker表加version字段做乐观锁,但毕设阶段悲观锁足够讲清楚。

5.3 提审被拒:类目与实际功能不符

现象:小程序提交微信审核,反馈“类目与实际功能不符”,常见于页面里有支付和下单,但服务类目填的是“工具”。

原因:行李寄存涉及线下储物服务,属于经营性服务类目,不是纯工具。微信审核看的是你页面里实际提供的能力,而不是你嘴上说的定位。

解决:在微信公众平台把服务类目调整为“生活服务 > 其他生活服务”,提审附言说明是配合线下门店使用的寄存服务。同时一定要配置隐私协议,明确说明收集用户位置信息(用于定位寄存点)和手机号(用于取件通知)的用途,否则审核大概率过不了。

5.4 订阅消息“只发一条”:一次性模板的授权限制

现象:用户下单时点了“接收取件提醒”,但等到超时前需要发第二条时,消息发不出去。

原因:微信一次性订阅消息的机制是“用户同意一次,只能发一条”。下单时订阅的那一次授权,在第一条消息发出后就消耗掉了,后面再调订阅消息接口会被拦截。

解决:把提醒做成“用户主动订阅 + 服务端选择最关键的时机发送”。例如只在超时前 10 分钟发一条,而不是先发“已寄存”再发“超时提醒”。需要多次通知的场景,要在页面上引导用户每次手动点击“接收提醒”,而不是下单时一次性订阅到底。行李寄存这个业务里,最值得通知的时机就是“快超时了”,把这一条发对,比发很多条更有效。

5.5 真机白屏:合法域名没配置

现象:微信开发者工具里一切正常,一用真机扫预览码,页面白屏,请求全部失败。控制台常见报错是“url not in domain list”或网络错误 10002。

原因:开发者工具默认勾选了“不校验合法域名”,真机没有这个豁免。小程序真机环境的wx.request只允许请求后台配置过的域名,直接填 IP 或没备案的域名都会被拦。

解决:在小程序后台的“开发管理 > 开发设置 > 服务器域名”里配好 request 合法域名,域名必须备案且是 HTTPS,路径指向后端网关。这个坑在换真机联调第一天必现,提前在提审前配好能少折腾两天。

6. 上线前的验证清单:把演示系统变成能生产的小方案

把“能跑”变成“能用”,靠的是完整链路验证。我给自己定过一条规矩:不上真机不算测完。开发工具里的模拟器和真机存在很多差异,至少准备两台手机,一台用户端、一台管理端,把“选格口 → 下单 → 支付 → 查看取件码 → 超时 → 补缴 → 取件 → 柜子复位”这条链路完整走一遍。走链路时开一个流量抓包工具(Charles 或 Reqable 都可以)看小程序发出的请求,重点确认两件事:登录 token 是否每次都带上了,请求域名是否是 HTTPS。很多“时好时坏”的玄学问题,最后都落在请求头缺字段或证书链不完整上。

如果要做成可交付的产品,下一步是接蓝牙格口锁。取件码校验成功后,后端向柜体控制器下发开锁指令,这一步的协议设计以“校验通过才发开锁”为红线,所有校验逻辑放后端,不在锁端放任何业务判断。这个扩展不会改变现有订单结构,只需要在取件接口返回值里增加开锁命令字段,是成本最低的硬件化路径。

最后说一个我自己的血泪经验:第一版实现为了图省事,把取件码明文存进数据库,管理后台能看到所有订单的取件码,后来迁移数据时才发现这个隐患。改成了只存哈希,取件时用 RedisGETDEL做原子校验,明文只在生成瞬间出现在接口响应里,落库一律不存明文。行李寄存涉及用户财产,安全设计不是论文里的一句话,而是真实要承担的责任。这个系统做完,你收获的不仅是一份毕设,更是一整套“小程序 + 后端 + 支付 + 状态机”的设计方法。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 22:19:49

MemTether:让多个AI客户端共享记忆的开源记忆层方案

我这半年被多个 AI 客户端反复折磨到没脾气&#xff0c;每天要在 ChatGPT、Claude、Kimi 和手机上的各类 App 之间来回切换&#xff0c;同一句话至少重复讲四遍。后来实在忍不了&#xff0c;才动手做了 MemTether——一个让多个 AI 客户端共享同一份记忆的开源工具。它的思路很…

作者头像 李华
网站建设 2026/10/28 22:19:47

AI编码助手突破盲区:chrome-devtools-mcp让浏览器对AI打开真实实时状态

1. 为什么说 AI 编码助手过去是"盲人摸象"1.1 传统 AI 编码助手的运行闭环里缺了什么我一直觉得&#xff0c;AI 编码助手写前端代码时最尴尬的一点是——它根本不看浏览器。你让它在某个页面上调样式、查报错、修交互&#xff0c;它能做的只有读代码、猜问题、给出修…

作者头像 李华
网站建设 2026/10/28 22:18:20

OpenWorkBuddy:本地优先AI办公Agent,直接交付Word/Excel真文件

1. 为什么“交付真文件”是 AI 办公 Agent 的分水岭1.1 从聊天记录到可交付成果的认知转变过去两年&#xff0c;我陆陆续续试过不下二十款号称能“帮你办公”的 AI 工具。绝大多数产品的交互模式高度雷同&#xff1a;一个对话框&#xff0c;你输入需求&#xff0c;它吐出一段文…

作者头像 李华
网站建设 2026/10/28 22:18:02

ROS2工业级配置与具身智能落地实战指南

1. 这不是“机器人课”&#xff0c;而是一场具身智能的产业级认知重构“咕泡科技 J4&#xff1a;具身智能机器人从入门到产业应用”——这个标题里藏着三个被严重低估的信号。第一&#xff0c;“J4”不是课程编号&#xff0c;而是指代Joint-4层级的具身智能系统架构&#xff0c…

作者头像 李华
网站建设 2026/10/28 22:16:11

AI生命叙事理解:KnowMe-Bench框架解析与应用

1. 项目概述&#xff1a;当AI开始理解你的生命叙事KnowMe-Bench的出现标志着AI认知能力的重要突破——从简单的对话交互升级到对个体生命历程的深度理解。这个开源框架通过构建"认知流"分析模型和"证据链"验证系统&#xff0c;使AI能够像人类朋友一样解读用…

作者头像 李华
网站建设 2026/10/28 22:15:13

供应链安全事件分析:LiteLLM与Apifox投毒案例

1. 供应链安全事件深度解析&#xff1a;LiteLLM与Apifox投毒案例上周连续曝出的LiteLLM和Apifox供应链投毒事件&#xff0c;给整个技术圈敲响了警钟。作为经历过多次供应链攻击的安全工程师&#xff0c;我完整复盘了这两起事件的攻击路径和影响范围。攻击者通过污染官方更新渠道…

作者头像 李华