# 哈哈零售 SDK 使用示例 本文档提供完整的SDK使用示例,涵盖从初始化到实际业务场景的各种用法。 ## 目录 1. [基础示例](#基础示例) 2. [设备管理场景](#设备管理场景) 3. [商品管理场景](#商品管理场景) 4. [订单处理场景](#订单处理场景) 5. [完整业务流程](#完整业务流程) --- ## 基础示例 ### 1. SDK初始化 ```java import com.haha.sdk.HahaClient; import com.haha.sdk.config.HahaConfig; import com.haha.sdk.exception.HahaException; public class HahaSDKExample { public static void main(String[] args) { // 创建配置 HahaConfig config = HahaConfig.builder() .apiBaseUrl("http://api.hahabianli.com") .appId("your_app_id") .appSecret("your_app_secret") .connectTimeout(10) .readTimeout(30) .build(); // 验证配置 config.validate(); // 创建客户端 HahaClient client = new HahaClient(config); try { // 测试获取access_token String token = client.getAccessToken(); System.out.println("获取Token成功: " + token); } catch (HahaException e) { System.err.println("初始化失败: " + e.getMessage()); } finally { // 关闭客户端(可选) client.shutdown(); } } } ``` ### 2. Spring Boot集成 ```java import com.haha.sdk.HahaClient; import com.haha.sdk.config.HahaConfig; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class HahaSDKConfig { @Value("${haha.api.baseUrl}") private String apiBaseUrl; @Value("${haha.api.appId}") private String appId; @Value("${haha.api.appSecret}") private String appSecret; @Bean public HahaClient hahaClient() { HahaConfig config = HahaConfig.builder() .apiBaseUrl(apiBaseUrl) .appId(appId) .appSecret(appSecret) .build(); return new HahaClient(config); } } ``` **application.yml配置:** ```yaml haha: api: baseUrl: http://api.hahabianli.com appId: your_app_id appSecret: your_app_secret ``` --- ## 设备管理场景 ### 场景1:查询并展示所有设备 ```java import com.haha.sdk.model.DeviceInfo; import java.util.List; public class DeviceListExample { public void listAllDevices(HahaClient client) { try { // 获取第一页 List devices = client.getDeviceApi().getDeviceList(1, 20); System.out.println("=== 设备列表 ==="); for (DeviceInfo device : devices) { System.out.println("--------------------"); System.out.println("设备ID: " + device.getId()); System.out.println("设备名称: " + device.getName()); System.out.println("设备地址: " + device.getAddress()); System.out.println("设备状态: " + getStatusText(device.getStatus())); } } catch (HahaException e) { System.err.println("获取设备列表失败: " + e.getMessage()); } } private String getStatusText(String status) { return "1".equals(status) ? "正常" : "冻结"; } } ``` ### 场景2:设备开门完整流程 ```java import com.haha.sdk.model.OpenDoorResult; import com.haha.sdk.model.DeviceOnlineStatus; public class OpenDoorExample { public void openDoorWithCheck(HahaClient client, String deviceId) { try { // 1. 检查设备在线状态 DeviceOnlineStatus status = client.getDeviceApi().getOnlineStatus(deviceId); if (status.getOnlineStatus() != 1) { System.out.println("设备离线,无法开门"); System.out.println("最后在线时间: " + status.getLastOnlineTime()); return; } // 2. 检查是否多门单开 Integer multiDoorType = client.getDeviceApi().isMultiDoorUnique(deviceId); Integer doorIndex = null; if (multiDoorType == 2) { // 双门柜,需要指定开哪个门 doorIndex = 0; // 0-A门, 1-B门 System.out.println("这是双门柜,将打开A门"); } // 3. 生成商户订单号 String outTradeNo = "ORDER_" + System.currentTimeMillis(); // 4. 开门 OpenDoorResult result = client.getDeviceApi() .openDoor(deviceId, outTradeNo, doorIndex); System.out.println("开门成功!"); System.out.println("商户订单号: " + outTradeNo); System.out.println("哈哈订单号: " + result.getOrderNo()); // 5. 保存订单号,用于后续查询识别结果 saveOrderInfo(outTradeNo, result.getOrderNo()); } catch (HahaException e) { System.err.println("开门失败: " + e.getMessage()); } } private void saveOrderInfo(String outTradeNo, String orderNo) { // 保存到数据库 System.out.println("订单信息已保存"); } } ``` ### 场景3:设备状态监控 ```java import java.util.Map; public class DeviceMonitorExample { public void monitorDevice(HahaClient client, String deviceId) { try { // 获取设备详细状态 Map status = client.getDeviceApi().getDeviceStatus(deviceId); int deviceStatus = (int) status.get("device_status"); int doorStatus = (int) status.get("door_status"); int lockStatus = (int) status.get("lock_status"); int cameraStatus = (int) status.get("camera_status"); int networkStatus = (int) status.get("network_status"); System.out.println("=== 设备状态报告 ==="); System.out.println("设备ID: " + deviceId); System.out.println("设备状态: " + getDeviceStatusText(deviceStatus)); System.out.println("门状态: " + (doorStatus == 1 ? "打开" : "关闭")); System.out.println("锁状态: " + (lockStatus == 1 ? "已锁" : "未锁")); System.out.println("摄像头: " + (cameraStatus == 1 ? "正常" : "异常")); System.out.println("网络: " + (networkStatus == 1 ? "连接" : "断开")); // 异常告警 if (deviceStatus == 2) { System.err.println("⚠️ 警告:设备故障,需要维护!"); } if (cameraStatus == 0) { System.err.println("⚠️ 警告:摄像头异常,可能影响识别!"); } } catch (HahaException e) { System.err.println("获取设备状态失败: " + e.getMessage()); } } private String getDeviceStatusText(int status) { switch (status) { case 0: return "离线"; case 1: return "在线"; case 2: return "故障"; default: return "未知"; } } } ``` --- ## 商品管理场景 ### 场景4:商品库管理 ```java import java.util.List; import java.util.Map; public class GoodsManagementExample { // 从总库添加商品到商家库 public void addGoodsToMerchant(HahaClient client) { try { // 1. 搜索商品总库 Map result = client.getGoodsApi() .getTotalList(1, 20, "可乐"); List> list = (List) result.get("list"); if (list.isEmpty()) { System.out.println("未找到商品"); return; } // 2. 选择第一个商品 Map goods = list.get(0); String goodsId = (String) goods.get("goods_id"); String goodsName = (String) goods.get("goods_name"); System.out.println("找到商品: " + goodsName); // 3. 添加到商家库,设置价格 String price = "3.50"; boolean success = client.getGoodsApi().addToMerchant(goodsId, price); if (success) { System.out.println("商品已添加到商家库,售价: " + price); } } catch (HahaException e) { System.err.println("操作失败: " + e.getMessage()); } } // 设备商品上架 public void setupDeviceGoods(HahaClient client, String deviceId) { try { // 1. 获取商家商品库 Map result = client.getGoodsApi().getMerchantList(1, 100); List> goodsList = (List) result.get("list"); System.out.println("商家商品库共有 " + goodsList.size() + " 个商品"); // 2. 将商品上架到指定设备 for (Map goods : goodsList) { String goodsId = (String) goods.get("goods_id"); String goodsName = (String) goods.get("goods_name"); // 上架 boolean success = client.getGoodsApi().setStatus(deviceId, goodsId, 1); if (success) { System.out.println("✓ " + goodsName + " 已上架"); } } } catch (HahaException e) { System.err.println("上架失败: " + e.getMessage()); } } } ``` ### 场景5:新品申请流程 ```java public class NewGoodsExample { public void applyNewGoods(HahaClient client, String barcode, String name, String imageUrl) { try { // 1. 先查询商品是否已存在 Map existingGoods = searchGoodsByBarcode(client, barcode); if (existingGoods != null) { System.out.println("商品已存在: " + existingGoods.get("goods_name")); return; } // 2. 提交新品申请 String description = "这是一款新商品"; boolean success = client.getGoodsApi() .applyNew(name, barcode, imageUrl, description); if (success) { System.out.println("新品申请已提交,等待审核"); System.out.println("商品名称: " + name); System.out.println("商品条码: " + barcode); } } catch (HahaException e) { System.err.println("申请失败: " + e.getMessage()); } } private Map searchGoodsByBarcode(HahaClient client, String barcode) { try { Map result = client.getGoodsApi() .getTotalList(1, 10, barcode); List> list = (List) result.get("list"); return list.isEmpty() ? null : list.get(0); } catch (HahaException e) { return null; } } } ``` --- ## 订单处理场景 ### 场景6:处理识别结果通知 ```java import java.math.BigDecimal; import java.util.List; import java.util.Map; public class OrderRecognizeExample { // 模拟接收哈哈平台的识别结果通知 public void handleRecognizeCallback(HahaClient client, String orderNo) { try { // 1. 查询识别结果 Map result = client.getOrderApi() .getRecognizeResult(orderNo, null); // 2. 解析识别结果 List> goodsList = (List) result.get("goods_list"); Double totalAmount = (Double) result.get("total_amount"); Double confidence = (Double) result.get("confidence"); String videoUrl = (String) result.get("video_url"); System.out.println("=== 识别结果 ==="); System.out.println("订单号: " + orderNo); System.out.println("总金额: " + totalAmount); System.out.println("置信度: " + confidence); // 3. 显示商品明细 System.out.println("\n商品明细:"); for (Map goods : goodsList) { String goodsName = (String) goods.get("goods_name"); int quantity = (int) goods.get("quantity"); double price = (double) goods.get("price"); double amount = (double) goods.get("amount"); System.out.println(" " + goodsName + " x" + quantity + " = ¥" + amount); } // 4. 判断是否需要人工审核 if (confidence < 0.8) { System.out.println("\n⚠️ 置信度较低,建议人工审核"); System.out.println("视频地址: " + videoUrl); // 可以通过getOrderMedia获取更多图片 Map media = client.getOrderApi().getOrderMedia(orderNo); System.out.println("开门前图片: " + media.get("before_image")); System.out.println("关门后图片: " + media.get("after_image")); return; } // 5. 置信度高,直接扣款 boolean paySuccess = processPayment(orderNo, new BigDecimal(totalAmount)); // 6. 通知哈哈平台支付结果 int payStatus = paySuccess ? 1 : 2; String payTime = getCurrentTime(); String transactionId = "PAY_" + System.currentTimeMillis(); client.getOrderApi().setPayStatus(orderNo, payStatus, payTime, transactionId); if (paySuccess) { System.out.println("\n✓ 支付成功"); } else { System.out.println("\n✗ 支付失败"); } } catch (HahaException e) { System.err.println("处理识别结果失败: " + e.getMessage()); } } private boolean processPayment(String orderNo, BigDecimal amount) { // 调用第三方支付接口扣款 System.out.println("正在扣款 ¥" + amount + "..."); return true; // 模拟支付成功 } private String getCurrentTime() { return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new java.util.Date()); } } ``` ### 场景7:订单查询和对账 ```java public class OrderQueryExample { public void queryAndVerifyOrder(HahaClient client, String orderNo) { try { // 1. 查询订单详情 Map order = client.getOrderApi().queryOrder(orderNo, null); String outTradeNo = (String) order.get("out_trade_no"); String deviceId = (String) order.get("device_id"); String orderStatus = (String) order.get("order_status"); Double totalAmount = (Double) order.get("total_amount"); String createTime = (String) order.get("create_time"); String payTime = (String) order.get("pay_time"); System.out.println("=== 订单详情 ==="); System.out.println("哈哈订单号: " + orderNo); System.out.println("商户订单号: " + outTradeNo); System.out.println("设备ID: " + deviceId); System.out.println("订单状态: " + getOrderStatusText(orderStatus)); System.out.println("订单金额: ¥" + totalAmount); System.out.println("创建时间: " + createTime); System.out.println("支付时间: " + payTime); // 2. 查询回调状态 Map callbackStatus = client.getOrderApi() .getCallbackStatus(orderNo); int status = (int) callbackStatus.get("callback_status"); int retryCount = (int) callbackStatus.get("retry_count"); System.out.println("\n=== 回调状态 ==="); System.out.println("推送状态: " + getCallbackStatusText(status)); System.out.println("重试次数: " + retryCount); } catch (HahaException e) { System.err.println("查询失败: " + e.getMessage()); } } private String getOrderStatusText(String status) { switch (status) { case "paying": return "支付中"; case "paid": return "已支付"; case "refund": return "已退款"; case "closed": return "已关闭"; default: return status; } } private String getCallbackStatusText(int status) { switch (status) { case 0: return "未推送"; case 1: return "推送成功"; case 2: return "推送失败"; default: return "未知"; } } } ``` --- ## 完整业务流程 ### 场景8:完整购物流程 ```java import com.haha.sdk.HahaClient; import com.haha.sdk.config.HahaConfig; import com.haha.sdk.model.OpenDoorResult; import com.haha.sdk.exception.HahaException; import java.util.Map; public class CompleteShoppingExample { private HahaClient client; public CompleteShoppingExample() { // 初始化SDK HahaConfig config = HahaConfig.builder() .apiBaseUrl("http://api.hahabianli.com") .appId("your_app_id") .appSecret("your_app_secret") .build(); this.client = new HahaClient(config); } /** * 完整购物流程 */ public void completeShopping(String deviceId, String userId) { String orderNo = null; String outTradeNo = null; try { // ========== 步骤1: 开门前检查 ========== System.out.println("=== 步骤1: 开门前检查 ==="); if (!checkDeviceStatus(deviceId)) { System.out.println("设备检查未通过,无法开门"); return; } // ========== 步骤2: 用户验证 ========== System.out.println("\n=== 步骤2: 用户验证 ==="); if (!verifyUser(userId)) { System.out.println("用户验证未通过"); return; } // ========== 步骤3: 开门 ========== System.out.println("\n=== 步骤3: 开门 ==="); outTradeNo = "ORDER_" + System.currentTimeMillis(); OpenDoorResult result = client.getDeviceApi() .openDoor(deviceId, outTradeNo, null); orderNo = result.getOrderNo(); System.out.println("开门成功!"); System.out.println("商户订单号: " + outTradeNo); System.out.println("哈哈订单号: " + orderNo); // 保存订单 saveOrder(userId, deviceId, outTradeNo, orderNo); // ========== 步骤4: 等待关门和识别 ========== System.out.println("\n=== 步骤4: 等待用户购物 ==="); System.out.println("请用户取货并关门..."); System.out.println("(实际业务中,识别结果会通过回调通知)"); // 模拟等待 Thread.sleep(5000); // ========== 步骤5: 处理识别结果 ========== System.out.println("\n=== 步骤5: 处理识别结果 ==="); processRecognizeResult(orderNo); System.out.println("\n✓ 购物流程完成"); } catch (HahaException e) { System.err.println("业务异常: " + e.getMessage()); // 异常处理:如果已经开门,记录异常订单 if (orderNo != null) { handleException(orderNo, e); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { // 清理资源 cleanup(); } } /** * 检查设备状态 */ private boolean checkDeviceStatus(String deviceId) throws HahaException { // 检查在线状态 var status = client.getDeviceApi().getOnlineStatus(deviceId); if (status.getOnlineStatus() != 1) { System.out.println("✗ 设备离线"); return false; } // 检查详细状态 Map detailStatus = client.getDeviceApi().getDeviceStatus(deviceId); int deviceStatus = (int) detailStatus.get("device_status"); int doorStatus = (int) detailStatus.get("door_status"); if (deviceStatus != 1) { System.out.println("✗ 设备故障"); return false; } if (doorStatus == 1) { System.out.println("✗ 设备使用中"); return false; } System.out.println("✓ 设备状态正常"); return true; } /** * 用户验证(示例) */ private boolean verifyUser(String userId) { // 实际业务中需要验证: // 1. 用户是否签约免密支付 // 2. 用户余额是否充足 // 3. 用户是否被锁定 System.out.println("✓ 用户验证通过"); return true; } /** * 保存订单到本地数据库 */ private void saveOrder(String userId, String deviceId, String outTradeNo, String orderNo) { System.out.println("✓ 订单已保存到数据库"); } /** * 处理识别结果 */ private void processRecognizeResult(String orderNo) throws HahaException { // 查询识别结果 Map result = client.getOrderApi() .getRecognizeResult(orderNo, null); Double totalAmount = (Double) result.get("total_amount"); Double confidence = (Double) result.get("confidence"); System.out.println("识别完成"); System.out.println("总金额: ¥" + totalAmount); System.out.println("置信度: " + confidence); // 判断是否需要人工审核 if (confidence < 0.8) { System.out.println("⚠️ 置信度较低,转人工审核"); return; } // 扣款 System.out.println("正在扣款..."); boolean paySuccess = true; // 调用支付接口 // 通知哈哈平台 int payStatus = paySuccess ? 1 : 2; client.getOrderApi().setPayStatus( orderNo, payStatus, getCurrentTime(), "PAY_" + System.currentTimeMillis() ); System.out.println(paySuccess ? "✓ 支付成功" : "✗ 支付失败"); } /** * 异常处理 */ private void handleException(String orderNo, Exception e) { System.err.println("记录异常订单: " + orderNo); // 保存到异常订单表,人工处理 } /** * 清理资源 */ private void cleanup() { // 必要时清理资源 } private String getCurrentTime() { return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new java.util.Date()); } /** * 主函数示例 */ public static void main(String[] args) { CompleteShoppingExample example = new CompleteShoppingExample(); // 模拟用户购物 String deviceId = "device001"; String userId = "user123"; example.completeShopping(deviceId, userId); } } ``` --- ## 异常处理最佳实践 ```java import com.haha.sdk.exception.HahaException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ExceptionHandlingExample { private static final Logger log = LoggerFactory.getLogger(ExceptionHandlingExample.class); public void handleWithRetry(HahaClient client, String deviceId) { int maxRetry = 3; int retryCount = 0; while (retryCount < maxRetry) { try { // 尝试开门 OpenDoorResult result = client.getDeviceApi() .openDoor(deviceId, "ORDER_" + System.currentTimeMillis(), null); log.info("开门成功: {}", result.getOrderNo()); break; } catch (HahaException e) { retryCount++; // 根据错误码判断是否需要重试 Integer errorCode = e.getCode(); if (errorCode != null) { switch (errorCode) { case -3: case -4: // token问题,SDK会自动刷新,可以重试 log.warn("Token问题,重试第{}次", retryCount); break; case -101: // 设备离线,不需要重试 log.error("设备离线,停止重试"); return; case -103: // 设备使用中,可以等待后重试 log.warn("设备使用中,等待5秒后重试"); try { Thread.sleep(5000); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } break; default: log.error("开门失败: {}", e.getMessage()); return; } } else { log.error("未知错误: {}", e.getMessage(), e); return; } if (retryCount >= maxRetry) { log.error("重试{}次后仍然失败", maxRetry); } } } } } ``` --- ## 总结 本文档提供了哈哈零售SDK的完整使用示例,涵盖: 1. ✅ SDK初始化和Spring Boot集成 2. ✅ 设备管理(列表、开门、状态监控) 3. ✅ 商品管理(添加、上架、新品申请) 4. ✅ 订单处理(识别结果、支付状态) 5. ✅ 完整购物流程 6. ✅ 异常处理和重试机制 更多信息请参考 [README.md](README.md) 和 [API文档](https://showdoc.hahabianli.com/web/#/685869388/275897889)。