开发指导.md 9.5 KB

这是一份面向CTO、架构师及核心开发人员的《智能视觉售卖机系统技术开发指导文档》。

该文档不讲业务故事,只讲代码怎么写、库怎么建、第三方接口怎么接,以及核心技术难点的解决方案。


智能视觉售卖机系统 - 技术开发指导书 (Technical Guide)

项目属性 定义
后端技术栈 Java 21, Spring Boot 3.5.9, Maven, Lombok, MyBatis-Plus, Hutool
前端技术栈 Uni-app (Vue 3 + TypeScript + Vite + Pinia)
中间件 MySQL 8.0, Redis 7.0 (缓存/分布式锁/消息订阅)
第三方核心 哈哈零兽开放平台 API, 微信支付V3 (支付分)
开发模式 前后端分离,RESTful API

1. 核心架构与交互时序

1.1 系统逻辑拓扑

  • 网关层: Nginx/Spring Cloud Gateway (可选),负责SSL终结和路由。
  • 应用层: Spring Boot 单体/微服务。
    • Module-User: C端用户、鉴权、支付分。
    • Module-Device: 设备状态、指令下发、哈哈API代理。
    • Module-Order: 订单状态机、回调处理、算费逻辑。
    • Module-Admin: 商家管理、商品库同步。
  • 数据层:
    • MySQL: 核心业务数据。
    • Redis:
      • Key: device_status:{sn} -> 存储设备实时状态(在线/离线/购物中)。
      • Key: lock:door:{sn} -> 分布式锁,防止并发开门。
      • Key: order:temp:{sn} -> 临时存储回调数据。

1.2 关键交互流程 (购物全链路)

  1. 开门请求: 小程序 -> 后端 (校验余额/风控) -> Redis加锁 -> 调用哈哈API (apply_open_door) -> 设备开门。
  2. 购物中: 设备上传视频流至哈哈云端 (黑盒)。
  3. 结算回调:
    • 哈哈云端 -> 后端 Webhook (/api/callback/haha/notify).
    • 后端 -> 匹配本地 out_trade_no.
    • 后端 -> 算费 -> 微信支付分扣款.
    • 后端 -> WebSocket/Redis PubSub -> 前端提示“支付成功”。

2. 数据库详细设计 (Schema Design)

2.1 核心表结构 (MySQL 8.0)

A. 商品表 (t_product)

视觉柜的核心在于商品与AI模型的绑定

CREATE TABLE `t_product` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `barcode` varchar(32) NOT NULL COMMENT '69码,全局唯一,核心识别键',
  `name` varchar(128) NOT NULL,
  `price` decimal(10,2) NOT NULL COMMENT '零售价',
  `image_url` varchar(512) NOT NULL COMMENT '白底图URL,用于展示及AI同步',
  `haha_sync_status` tinyint DEFAULT 0 COMMENT '0-未同步 1-已同步 2-同步失败',
  `haha_model_id` varchar(64) DEFAULT NULL COMMENT '哈哈侧返回的商品ID',
  `is_deleted` tinyint DEFAULT 0,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_barcode` (`barcode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';

B. 设备表 (t_device)

CREATE TABLE `t_device` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `device_id` varchar(64) NOT NULL COMMENT '哈哈设备SN序列号',
  `shop_id` bigint NOT NULL COMMENT '归属点位ID',
  `name` varchar(64) DEFAULT NULL,
  `auth_token` varchar(128) DEFAULT NULL COMMENT '设备端通信Token(如需)',
  `status` tinyint DEFAULT 1 COMMENT '0-离线 1-在线 2-购物中 3-故障',
  `current_inventory_hash` varchar(64) DEFAULT NULL COMMENT '当前库存快照Hash,用于补货比对',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_sn` (`device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='设备表';

C. 订单表 (t_order)

CREATE TABLE `t_order` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `order_no` varchar(32) NOT NULL COMMENT '系统内部订单号',
  `out_trade_no` varchar(64) NOT NULL COMMENT '请求哈哈开门时的流水号',
  `haha_order_no` varchar(64) DEFAULT NULL COMMENT '哈哈侧订单号',
  `user_id` bigint NOT NULL,
  `device_id` varchar(64) NOT NULL,
  `total_amount` decimal(10,2) DEFAULT NULL,
  `pay_status` varchar(20) DEFAULT 'PENDING' COMMENT 'PENDING-识别中, WAIT_PAY-待支付, PAID-已支付, FAIL-失败, REVIEW-待人工',
  `video_url` varchar(512) DEFAULT NULL COMMENT '购物视频证据',
  `confidence` decimal(5,4) DEFAULT NULL COMMENT 'AI识别置信度(0.00-1.00)',
  `items_json` text COMMENT '识别到的原始商品JSON快照',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `pay_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_out_trade` (`out_trade_no`),
  INDEX `idx_user` (`user_id`),
  INDEX `idx_status` (`pay_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单主表';

3. 哈哈零兽 API 对接指南 (核心难点)

3.1 鉴权工具类封装

所有请求 Header 必须包含签名。

  • AppId: 平台申请。
  • Sign算法: MD5(app_id + app_secret + timestamp + body_json).
  • 建议封装 HahaApiClient 类,统一处理签名和 HTTP POST。

3.2 关键接口映射

业务动作 接口名 (参考) 请求参数重点 回调处理
同步商品 goods/add barcode, name, image(Url或Base64)
申请开门 device/applyOpen device_id, out_order_no (关键关联键) 仅返回开门指令发送结果,非订单结果
订单结果 (Webhook) - 接收 out_order_no, goods_list, video_url
设备状态 (Webhook) - 接收 device_id, status (update Redis)

3.3 回调处理策略 (Spring Event 模式)

为了解耦 HTTP 回调和业务逻辑:

  1. Controller 接收哈哈 Webhook JSON。
  2. 校验 Sign 确保安全。
  3. 发布 Spring Event (如 HahaOrderEvent)。
  4. @EventListener 异步处理:
    • 查询 t_order (通过 out_trade_no)。
    • 若订单存在且状态为 PENDING -> 计算金额 -> 扣款。
    • 幂等性保护:如果 Redis 中已有该订单处理记录,直接返回 success。

4. Phase 1: 用户端小程序开发要点

4.1 支付分/信用分对接流程

这是“先享后付”的基础。

  1. 查询授权: GET /api/user/credit_score_status.
    • 后端调用微信支付 v3/payscore/permissions 查询。
  2. 申请授权: 若未授权,前端拉起小程序插件 plugin-private-wxpay.
  3. 创单开门:
    • 后端先调用微信支付分“创建订单”接口 (Status: DOING)。
    • 锁定成功后,再调用哈哈 API 开门。
    • 原因:防止用户开门后无法扣款。

4.2 轮询与状态反馈

用户关门后,订单生成有 5-15秒 延迟。

  • 方案 A (推荐): 简单轮询。
    • 前端每 2秒 调用 GET /api/order/latest_status?device_id=xxx.
    • 后端查询 Redis 或 DB 中的最新订单状态。
  • 方案 B (进阶): WebSocket。
    • 后端处理完回调后,通过 SimpMessagingTemplate 推送 /topic/user/{userId}

5. Phase 2: PC 运营端开发要点

5.1 商品同步队列

商品图片上传和同步可能耗时。

  • 实现: 使用 Spring ApplicationEventPublisher 或 RabbitMQ。
  • 流程: 管理员保存商品 -> DB 状态设为 SYNCING -> 异步线程上传图片给哈哈 -> 获取哈哈 model_id -> 更新 DB 为 SYNCED

5.2 挂起订单处理 (人工审核)

针对置信度低的订单:

  • 后端逻辑: 接收回调 -> 判断 confidence < 0.85 -> 状态设为 REVIEW (不扣款)。
  • PC前端: 展示 video_url (引用哈哈CDN) -> 管理员勾选 t_product 中的商品 -> 提交 /api/admin/order/audit_confirm
  • 后续: 接口触发算费 -> 调用微信支付分“完结订单”接口扣款。

6. Phase 3: 商家端小程序开发要点

6.1 补货逻辑 (基于快照差异)

切记:视觉柜不手动输入数量。

  1. 开门: 调用 /api/device/maintain_open (类型: 补货)。
  2. 回调处理:
    • 哈哈返回 replenish_callback,包含 current_stock_list (当前柜子里的所有东西)。
    • 后端逻辑:
      • Last_Stock = 查询 DB 中该设备的上次库存。
      • Current_Stock = 回调数据。
      • Diff = Current - Last (计算出的补货量/取货量)。
      • 更新 DB t_device_stock 表为 Current_Stock
      • 记录 t_replenish_log (补货日志)。

7. 安全与风控实现

7.1 防逃单

  • 问题: 用户拿货,但微信余额不足,扣款失败。
  • 处理:
    1. 微信返回 PAY_FAIL
    2. 后端将 t_order 状态更为 DEBT (欠款)。
    3. 后端将 t_user 标记为 LOCKED
    4. Redis 锁: lock:user:forbidden:{userId}
    5. 下次开门前,Filter 拦截器检测到锁,直接拒绝,并返回 {code: 403, msg: "请先结清欠款"}

7.2 接口安全

  • 小程序与后端通信:使用 JWT (JSON Web Token),Token 中包含 userIdrole
  • 后端与哈哈通信:严格校验 Sign

8. 部署建议

  • JDK: Dragonwell 21.
  • Docker:
    • 应用容器: -m 512M (JVM优化).
    • Redis: 需开启 AOF 持久化,防止宕机丢失设备状态。
  • 域名: 必须配置 HTTPS (微信小程序强制要求)。
  • 内网穿透 (开发期): 使用 Ngrok 或 Cpolar 将本地 7070 端口暴露为公网域名,填入哈哈后台作为 Notify Url

这份指导文档作为开发实施的基准,请开发团队在编码前详细阅读,特别是 3. 哈哈零兽 API 对接6.1 补货逻辑 部分,这是最容易出错的环节。