从需求文档到方案-无人售货机纯视觉与免密支付
02-从需求文档到方案-无人售货机纯视觉与免密支付作者黒漂技术佬系列URM Ultra 方案理念与架构篇上篇把 URM Ultra 的全景摊开了。这一篇咱们换个视角——从一份原始需求文档出发看一个卖货的柜子是怎么一步步变成软件方案的。很多新手写代码的通病是需求扔过来上手就建表、写接口结果写到一半发现支付怎么做识别结果怎么来全没想清楚。URM Ultra 的售货机部分恰恰是一个需求 → 方案 → Demo 简化的标准教科书案例。今天我就把它拆给你看。一、原始需求长什么样项目里的需求文档关于无人售货机这一段其实非常短我给你提炼成白话原始需求大白话纯视觉、商品识别用三方算法不装重力传感器、不贴 RFID靠摄像头看用户拿了啥设备端是安卓工控双门、2 路锁、4 摄、4G一台柜子俩门、两把电控锁、四个摄像头、走 4G 网支付打算用微信支付分免密用户先授权拿完货后台自动扣款不用现场扫码后台是 Spring Boot含商品/订单/设备商品等还要承接无人车、补货配送一个 Java 后台统管所有业务消费端是小程序用户用微信小程序下单本项目只做简单实现作为 Demo别堆生产级基建把闭环跑通就行你看需求里没有一句话提数据库表怎么设计、接口怎么命名。它描述的是业务事实和硬件事实。从事实到代码中间隔着一层翻译。二、翻译第一层纯视觉识别意味着什么纯视觉三个字对软件架构的影响极其深远。我们先对比一下三种识别方案方案原理软件侧成本缺点重力感应每层放称重托盘重量变化算拿了啥低读传感器即可只能感知重量变了同重商品区分不了RFID商品贴电子标签柜内读卡中要绑标签每个商品贴标签成本高、易损纯视觉摄像头拍照算法识别商品高依赖识别服务需要算法供应商、需要画面质量URM Ultra 选纯视觉意味着后台必须有一个识别服务的概念而且这个服务大概率是外部三方提供的需求明确写了三方识别。这直接催生了一个关键设计识别能力必须做成接口不能写死。项目源码里是这样落地的节选自vision包// 项目源码视觉识别抽象接口publicinterfaceVisionService{// deviceNo哪台柜子frameRef这一帧画面的引用如图片地址/帧IDListRecognitionItemrecognize(StringdeviceNo,StringframeRef);}RecognitionItem返回的字段就是视觉识别结果的标准结构// 项目源码识别结果项publicclassRecognitionItem{privateStringslotNo;// 货道号哪个格子privateLongproductId;// 商品IDprivateStringproductName;// 商品名privateStringbarcode;// 条码privatedoubleconfidence;// 置信度 0~1算法有多确定privateintquantity;// 拿了几个privateBigDecimalprice;// 货道售价}为什么要有confidence因为算法不是神仙它会不太确定。0.9~1.0 是高置信低于某个阈值可能要人工复核。Demo 里 Mock 实现固定返回 0.9~1.0真实三方算法接进来后这个值才是真家伙。划重点VisionService是接口MockVisionService是它的假实现。Demo 阶段 Mock 随机挑一个启用货道返回拿了 1 件目的只有一个——把识别→下单→扣款→扣库存这条链路先跑通。等真算法接进来只要新写一个实现类业务代码一行不动。这就是解耦的威力。三、翻译第二层安卓工控 双门两路锁四摄 4G需求里这句硬件描述新手最容易一笔带过。但它是设备建模的依据直接影响后台那张Device表长啥样。硬件事实软件里怎么体现安卓工控设备端跑安卓负责采摄像头、控锁、心跳双门doorCount 22 路锁lockCount 2每门一路电控锁4 摄cameraCount 4柜内 4 个摄像头4Gnetwork 4G网络类型字段这些字段不是我拍脑袋的它们直接来自需求里的硬件清单。后台把这些物理属性原样存进Device实体运营在后台就能看到这台柜子几扇门、几把锁、几个摄像头、走什么网。第 03 篇我会专讲这张表这里先记住硬件事实 → 软件字段是 URM Ultra 一以贯之的建模哲学。还有个隐藏点4G 网络意味着设备可能离线。所以Device必须有status在线/离线/故障和lastHeartbeat最后一次心跳时间——车、臂同理。这也是后面状态机的由来。四、翻译第三层微信支付分免密免密支付是这套方案体验的灵魂。传统柜子开门 → 拿货 → 关门 → 掏手机扫码付钱 → 走人。URM Ultra开门 → 拿货 → 关门 →走人后台已自动扣款。但这里有个合规前提不能真偷偷扣。它用的是微信支付分免密模式流程是1) 用户首次使用微信里授权支付分免密先签约 2) 用户拿货关门 3) 后台生成订单调用支付分先预授权冻结额度 4) 视觉识别出金额执行扣款payScoreOrderNo 落地 5) 出问题可退款refund源码里同样做成接口避免把微信写死// 项目源码微信支付分免密抽象publicinterfaceWechatPayScoreService{booleanpreAuthorize(StringopenId);// 预授权PayScoreResultpay(StringorderNo,StringopenId,BigDecimalamount,StringgoodsDesc);// 扣款PayScoreResultrefund(StringorderNo,BigDecimalamount,Stringreason);// 退款PayScoreResultquery(StringorderNo);// 查询}Mock 实现的假扣款很诚实——它不联网用内存 Map 记状态pay永远返回成功// 项目源码Mock 支付演示用非真实微信ServiceConditionalOnProperty(nameurm.wechat-pay.enabled,havingValuefalse,matchIfMissingtrue)publicclassMockWechatPayScoreServiceimplementsWechatPayScoreService{privatefinalConcurrentMapString,StringstatesnewConcurrentHashMap();publicPayScoreResultpay(StringorderNo,StringopenId,BigDecimalamount,StringgoodsDesc){states.put(orderNo,SUCCESS);// 假成功// 返回伪 payScoreOrderNo / transactionIdreturnPayScoreResult.success(...);}}注意ConditionalOnProperty这个注解——urm.wechat-pay.enabledfalse时加载 Mock设成true时加载真实微信实现。配置一改实现自动切换业务 Service 无感。这是 Spring Boot 条件化装配的标准玩法值得学。五、把三块拼成下单链路需求最终要落到一个消费者能用的动作在小程序点一下购买货道识别、扣款、扣库存一气呵成。后台OrderService.createAndPay就是这条链路的真实实现项目源码简化注释1) 校验设备是否存在deviceNo 查 Device 2) 视觉识别visionService.recognize(deviceNo) → 拿到商品列表 3) 生成订单 OrderstatusPENDING_PAYMENTpayTypeWECHAT_PAY_SCORE 4) 逐条组装 OrderItem单价×数量累加总金额 5) 免密扣款wechatPayScoreService.pay(...) 失败 → 订单 CANCELED抛支付失败 6) 扣库存deviceService.deductStock(deviceId, slotNo, qty) 7) 订单置 PAID写支付记录 PaymentRecord(SUCCESS)一张图看全貌小程序点购买 │ ▼ 后台 createAndPay ├─▶ 视觉识别VisionService ── 识别拿了啥 ├─▶ 生成订单Order ── 待支付 ├─▶ 免密扣款PayScore ── 自动扣钱 └─▶ 扣减库存deductStock ── 货道 -N │ ▼ 订单完成用户已走这条链路逻辑是 100% 真实的事务、扣库存、写支付记录都真刀真枪只有视觉识别和支付扣款这两步是 Mock。这正是 Demo 的精髓把不确定交给 Mock把确定性留给真实代码。六、Demo 做了哪些简化以及为什么可以简化需求说只做简单实现。我列一下简化点并说明为什么这些简化不影响你学架构简化项真实世界Demo 做法影响视觉识别真实摄像头 YOLO 类算法Mock 随机返回链路照跑接算法只换实现微信支付真实商户号 证书 回调Mock 内存成功扣款逻辑照跑接微信只换实现安卓工控真实安卓 App 采摄像头控锁设备端 heartbeat/recognize 接口模拟后台契约已定义App 照着调鉴权OAuth2 / 租户隔离不接纯演示生产必补设备事件持久化 驱动门锁/event仅回显received桩代码标注了真实要做啥看到没所有简化都集中在外部依赖和生产基建上而业务状态机、任务编排、库存扣减这些核心一个没省。你学这套代码学到的是真东西。七、给新手的两条心得需求里的每一个硬件参数都是一张表的一个字段。双门→doorCount4 摄→cameraCount别嫌烦照实记。凡是外部不确定的能力先抽象成接口 Mock。识别、支付、甚至未来的路径规划都该如此。这样你的主干代码永远可跑、可测、可读。下一篇我们钻进那张Device表看看双门两路锁四摄是怎么变成一行数据库记录的。

相关新闻

选矿厂巡检怎么做?破碎、球磨与浮选三处

选矿厂巡检怎么做?破碎、球磨与浮选三处

选矿厂给人的印象是“噪音大、灰尘多”,但巡检真正要分清的,是三段工艺各自不同的风险类型:破碎看粉尘与机械,球磨看转动与衬板,浮选看药剂与腐蚀。混在一起看,等于什么都没看。 破碎与筛分段 破碎段是粉…

2026/10/3 7:10:51 阅读更多 →
百科词条和问答社区哪个更容易被AI引用?信任权重不同

百科词条和问答社区哪个更容易被AI引用?信任权重不同

百科词条和问答社区哪个更容易被AI引用?做过几十次内容审计后我的结论是:百科词条赢在结构和权威背书,问答社区赢在细节和时效,AI会按问题类型切换信任的天平,不存在一边倒的答案。这个判断对做内容运营的人尤其重要&a…

2026/10/3 7:10:51 阅读更多 →
能力强却省token:API工具提取GPT-6 Astra隐藏思维链

能力强却省token:API工具提取GPT-6 Astra隐藏思维链

Capable yet Parsimonious: Extracting and Characterizing Hidden Chain-of-Thought in Frontier Models 作者:Xiaoyu Luo, Tao Ren, Wenrui Yu, Xiao Li, Qiongxiu Li, Johannes Bjerva 核心发表机构:Aalborg University、Seafill 论文链接&#xff1a…

2026/10/3 7:10:51 阅读更多 →

最新新闻

如何在5分钟内搭建Cloudflare OS工作空间?新手必备的完整指南

如何在5分钟内搭建Cloudflare OS工作空间?新手必备的完整指南

如何在5分钟内搭建Cloudflare OS工作空间?新手必备的完整指南 【免费下载链接】cloudflare-os Agent workspace built on Cloudflare Workers for creating documents, building apps, and running agents with your company’s context and systems. 项目地址: h…

2026/10/4 9:53:40 阅读更多 →
插件系统原理与加载失败排查:从IAR、MusicFree到web boot

插件系统原理与加载失败排查:从IAR、MusicFree到web boot

干嵌入式开发的调 IAR,偶尔会看到插件相关的提示;用 MusicFree 听歌的,装个音源插件失败也会一头雾水;做前端或者维护插件化平台的,可能天天跟harness failed to load plugins web boot: 2 entries did not activate l…

2026/10/4 9:53:40 阅读更多 →
插件加载失败排查指南:从did not activate到根治

插件加载失败排查指南:从did not activate到根治

先说实话:过去一周我至少收到了三条跟plugins相关的求助消息,报错长得几乎一模一样——Failed to load plugins web boot: 2 entries did not activate,后面还跟着一串奇怪的包名,比如linxin666/dsh-p、huayu-yuan。问的人多了&am…

2026/10/4 9:53:40 阅读更多 →
QwenPaw安装与使用手册:从API Key配置到终端高效调用通义千问

QwenPaw安装与使用手册:从API Key配置到终端高效调用通义千问

今天这篇内容就是一份完整的 QwenPaw 安装与使用手册,我会从零开始讲清楚环境准备、安装步骤、API Key 的获取与查看、日常使用技巧,以及我踩过的几个坑。适合刚接触 API 调用的新手,也适合想把本地工作流搬到终端的老手。QwenPaw 说白了就是…

2026/10/4 9:53:40 阅读更多 →
Apache Fesod(Incubating)Committer 成长指南:从持续贡献到获得提交权限的完整路径

Apache Fesod(Incubating)Committer 成长指南:从持续贡献到获得提交权限的完整路径

后端 【免费下载链接】fesod Fast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM. 项目地址: https://gitcode.com/gh_mirrors/fast/fesod 点击查看 免费下载 Apache Fesod(Incubating)是一个正处在…

2026/10/4 9:53:40 阅读更多 →
把经典蒸馏成可执行技能:知识蒸馏的实践方法论

把经典蒸馏成可执行技能:知识蒸馏的实践方法论

1. 项目概述:当“知识蒸馏”从AI实验室走进书房书桌最近在几个读书社群里,反复看到有人问:“读完《道德经》八遍,还是说不出它到底教人怎么做事”;也常有产品经理、独立开发者、内容创作者私下聊:“道理都懂…

2026/10/4 9:52:40 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →