# 企得宝ERP Java SDK [![Java](https://img.shields.io/badge/Java-21%2B-orange)](https://www.oracle.com/java/technologies/downloads/) [![Maven](https://img.shields.io/badge/Maven-3.6%2B-red)](https://maven.apache.org/) **qdb-sdk** 是企得宝ERP开放平台的 Java SDK,提供对 73 个开放API接口的完整封装。支持签名生成、请求发送、响应解析等全链路功能。 --- ## 📦 技术栈 | 技术 | 版本 | 用途 | |------|------|------| | Java | 21 | 开发语言 | | Maven | 3.6+ | 项目构建 | | OkHttp | 4.12.0 | HTTP 客户端 | | FastJson2 | 2.0.53 | JSON 序列化/反序列化 | | Lombok | 1.18.36 | 代码简化 | | SLF4J | 2.0.13 | 日志门面 | > **注意**:本 SDK 为独立 Maven 项目,不依赖 haha 零售系统任何内部模块,可独立使用或引入到任意 Java 项目。 --- ## 🚀 快速开始 ### 1. 引入依赖 将 `qdb-sdk` 安装到本地 Maven 仓库后,在项目中添加依赖: ```xml com.qdb qdb-sdk 1.0.0 ``` 或直接引入源码作为模块: ```xml com.qdb qdb-sdk 1.0.0 system ${project.basedir}/lib/qdb-sdk-1.0.0.jar ``` ### 2. 初始化 SDK ```java import com.qdb.sdk.QdbClient; import com.qdb.sdk.QdbConfig; // 创建配置(必填:clientId 和 clientSecret) QdbConfig config = QdbConfig.builder() .clientId("your_client_id") // 开放平台分配的 clientId .clientSecret("your_client_secret") // 开放平台分配的 clientSecret .build(); // 校验配置 config.validate(); // 创建客户端(单例使用,线程安全) QdbClient client = new QdbClient(config); ``` ### 3. 选择环境 SDK 默认接入正式环境,切换测试环境只需修改 `apiUrl`: ```java QdbConfig config = QdbConfig.builder() .clientId("your_client_id") .clientSecret("your_client_secret") .apiUrl("https://apitest.7debao.com/router/api") // 测试环境 .build(); ``` | 环境 | 默认值 | |------|--------| | **正式环境** | `https://api.7debao.com/router/api` | | **测试环境** | `https://apitest.7debao.com/router/api` | --- ## 🏗️ 架构说明 ### 请求流程 ``` ┌─────────────────────────────────────────────────────┐ │ 调用方代码 │ │ QdbClient.getXxxApi().method(request) │ └─────────────────┬───────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ BaseQdbApi │ │ ① 序列化请求参数为 JSON │ │ ② 调用 HttpUtil.post() │ │ ③ 解析响应 QdbResponse │ │ ④ 检查 success 标识,失败则抛出 QdbException │ └─────────────────┬───────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ HttpUtil │ │ ① 构建公共参数 Map(TreeMap 自动排序) │ │ ② 调用 SignUtil 计算 MD5 签名 │ │ ③ 拼接完整 URL:baseUrl?公共参数+sign │ │ ④ POST 请求,Body 为业务参数 JSON │ │ ⑤ 返回原始响应 JSON 字符串 │ └─────────────────┬───────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ 企得宝ERP 开放平台 │ │ https://api.7debao.com/router/api │ └─────────────────────────────────────────────────────┘ ``` ### 签名算法 签名规则(与企得宝开放平台文档一致): 1. 将所有**公共参数**按照参数名的首字母先后顺序排列(字典序) 2. 把排序后的结果按照**参数名+参数值**的方式拼接 3. 拼装好的字符串**首尾拼接** `client_secret` 进行 MD5(小写32位) ```java // 示例:SDK 内部自动完成签名 // 公共参数排序拼接后:client_idxxxformatjsonmethodxxxpartner_idxxx... // 加签:secret + 拼接字符串 + secret → MD5 ``` ### 统一响应格式 所有 API 返回统一结构: ```json { "errorCode": null, "msg": "操作成功", "data": { ... }, "date": null, "version": null, "success": true } ``` | 字段 | 类型 | 说明 | |------|------|------| | errorCode | String | 错误编码,成功时为 null | | msg | String | 提示信息 | | data | Object | 成功时返回数据,失败为 null | | date | Date | 响应时间 | | version | Integer | 版本信息 | | success | Boolean | 成功为 true,失败为 false | --- ## 💻 使用示例 ### 订单上传 ```java import com.qdb.sdk.QdbClient; import com.qdb.sdk.QdbConfig; import com.qdb.sdk.QdbException; import com.qdb.sdk.model.request.*; import com.qdb.sdk.model.response.QdbResponse; import java.math.BigDecimal; import java.util.List; public class OrderExample { public static void main(String[] args) { // 1. 初始化客户端 QdbConfig config = QdbConfig.builder() .clientId("your_client_id") .clientSecret("your_client_secret") .build(); QdbClient client = new QdbClient(config); try { // 2. 构建订单商品 OrderGoods goods = OrderGoods.builder() .platformGoodsCode("SKU001") // 平台商品编码 .platformGoodsName("测试商品") // 平台商品标题 .quantity(new BigDecimal("2")) // 数量 .price(new BigDecimal("49.90")) // 单价 .realPrice(new BigDecimal("45.00")) // 实际售价 .build(); // 3. 构建支付信息(可选) OrderPay pay = OrderPay.builder() .payTypeCode("2") // 微信支付 .payTime("2024-01-24 15:30:00") .payNo("WX202401241530001") .build(); // 4. 构建订单上传请求 OrderSaveRequest request = OrderSaveRequest.builder() .shopId(9900100000000136L) // 店铺ID .tradeNo("T202401240001") // 平台交易单号 .platformTradeStatus("02") // 待发货 .platformRefundStatus("0") // 未退款 .orderTypeCode("2") // 在线交易 .postAmount(new BigDecimal("10.00")) // 运费 .payAmount(new BigDecimal("100.00")) // 付款金额 .receiverName("张三") .receiverMobile("13800138000") .receiverProvince("广东省") .receiverCity("深圳市") .receiverDistrict("南山区") .receiverAddress("科技园南区A栋1001") .ordersGoods(List.of(goods)) // 商品列表 .ordersPay(List.of(pay)) // 支付信息(可选) .buyerMessage("请尽快发货") .build(); // 5. 调用订单上传接口 QdbResponse response = client.getOrderApi().saveOrder(request); if (response.isSuccess()) { System.out.println("✅ 订单上传成功"); } } catch (QdbException e) { System.err.println("❌ 订单上传失败: [" + e.getErrorCode() + "] " + e.getMessage()); } finally { // 6. 关闭客户端 client.shutdown(); } } } ``` ### Spring Boot 集成 ```java import com.qdb.sdk.QdbClient; import com.qdb.sdk.QdbConfig; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class QdbSdkConfig { @Value("${qdb.client-id}") private String clientId; @Value("${qdb.client-secret}") private String clientSecret; @Value("${qdb.api-url:https://api.7debao.com/router/api}") private String apiUrl; @Bean public QdbClient qdbClient() { QdbConfig config = QdbConfig.builder() .clientId(clientId) .clientSecret(clientSecret) .apiUrl(apiUrl) .build(); return new QdbClient(config); } } ``` **application.yml 配置:** ```yaml qdb: client-id: your_client_id client-secret: your_client_secret api-url: https://api.7debao.com/router/api ``` --- ## 📋 API 模块列表 SDK 目前已实现以下 API 模块(共 **73** 个接口),完整接口明细请参考对应文档: ### 已实现 | 模块 | API 类 | 已实现方法 | 对应文档 | |------|--------|-----------|----------| | 订单管理 | `OrderApi` | `saveOrder()` 订单上传 | [04-订单管理.md](./04-订单管理.md) | ### 待扩展(基础框架已就绪,按需添加) | 模块 | 接口数 | 对应文档 | |------|--------|----------| | 基础资料 | 9 | [01-基础资料.md](./01-基础资料.md) | | 商品管理 | 6 | [02-商品管理.md](./02-商品管理.md) | | 平台商品管理(个性) | 19 | [03-平台商品管理(个性).md](./03-平台商品管理(个性).md) | | 订单管理(其余) | 15 | [04-订单管理.md](./04-订单管理.md) | | 采购管理 | 5 | [05-采购管理.md](./05-采购管理.md) | | 调拨管理 | 2 | [06-调拨管理.md](./06-调拨管理.md) | | 其他出入库管理 | 3 | [07-其他出入库管理.md](./07-其他出入库管理.md) | | 盘点管理 | 2 | [08-盘点管理.md](./08-盘点管理.md) | | 库存管理 | 2 | [09-库存管理.md](./09-库存管理.md) | | 消息推送(回调接收) | 8 | [10-消息推送.md](./10-消息推送.md) | | 路由管理 | 1 | [11-路由管理.md](./11-路由管理.md) | --- ## ⚠️ 异常处理 SDK 统一使用 `QdbException` 异常类: ```java import com.qdb.sdk.QdbException; try { QdbResponse response = client.getOrderApi().saveOrder(request); } catch (QdbException e) { // 错误编码(对应企得宝API返回的 errorCode) String errorCode = e.getErrorCode(); // 错误信息 String errorMsg = e.getMessage(); // 原始异常(如有) Throwable cause = e.getCause(); System.err.println("错误码: " + errorCode + ", 信息: " + errorMsg); } ``` ### 常见异常场景 | 异常场景 | 说明 | |----------|------| | `clientId`/`clientSecret` 为空 | 抛出 `IllegalArgumentException`,配置时需调用 `config.validate()` | | 网络异常 | `QdbException` 包装 `IOException`,检查网络连通性 | | HTTP 状态码非 200 | `QdbException("HTTP 请求失败,状态码: xxx")` | | API 业务错误 | `QdbException` 包含 `errorCode` 和 `msg`(从企得宝返回) | | 响应解析失败 | `QdbException("API 响应解析失败")` | --- ## 🔧 开发指南 ### 项目结构 ``` qdb-sdk/ ├── pom.xml # Maven 构建文件(Java 21) ├── src/main/java/com/qdb/sdk/ │ ├── QdbClient.java # 主客户端入口 │ ├── QdbConfig.java # SDK 配置类 │ ├── QdbException.java # 自定义异常 │ ├── api/ │ │ ├── BaseQdbApi.java # API 基类(通用调用逻辑) │ │ └── OrderApi.java # 订单管理 API │ ├── model/ │ │ ├── request/ # 请求参数模型 │ │ │ ├── OrderSaveRequest.java # 订单上传请求 │ │ │ ├── OrderGoods.java # 订单商品 │ │ │ ├── OrderInvoice.java # 订单发票 │ │ │ └── OrderPay.java # 订单支付 │ │ └── response/ │ │ └── QdbResponse.java # 统一响应对象 │ └── util/ │ ├── SignUtil.java # MD5 签名工具 │ ├── HttpUtil.java # HTTP 客户端(OkHttp) │ └── JsonUtil.java # JSON 工具(FastJson2) ├── 00-概述与接入指南.md # 企得宝 API 文档 ├── 01-基础资料.md ├── ... # 其他 API 文档 ``` ### 扩展新模块 新增一个业务 API 模块只需 3 步: **1. 创建请求模型**(`model/request/` 目录下): ```java @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ShopQueryRequest { private Long shopId; private String shopName; // ... 其他请求参数 } ``` **2. 创建 API 类**(`api/` 目录下): ```java public class ShopApi extends BaseQdbApi { private static final String METHOD_SHOP_LIST = "foonsu.erp.shop.shopInfo"; public ShopApi(QdbClient client) { super(client); } public QdbResponse> queryShops(ShopQueryRequest request) throws QdbException { return execute(METHOD_SHOP_LIST, request); } } ``` **3. 注册到 QdbClient**: ```java // 在 QdbClient.java 中添加 private final ShopApi shopApi; // 在构造方法中初始化 this.shopApi = new ShopApi(this); // 添加 Getter public ShopApi getShopApi() { return shopApi; } ``` ### 构建与测试 ```bash # 编译 mvn clean compile # 打包 mvn clean package # 安装到本地仓库 mvn clean install # 跳过测试打包 mvn clean package -DskipTests ``` --- ## ❓ 常见问题 ### Q1: SDK 是否线程安全? **是的**。`QdbClient` 可在多线程环境中安全使用,建议作为单例管理(如在 Spring 中声明为 `@Bean`)。 ### Q2: 签名计算失败怎么办? 检查 `clientId` 和 `clientSecret` 是否正确。SDK 内部已实现完整的签名逻辑,包括字典序排列、key+value 拼接、首尾加 secret、MD5 加密。 ### Q3: 如何切换正式/测试环境? 修改 `QdbConfig.apiUrl`: - 正式:`https://api.7debao.com/router/api`(默认) - 测试:`https://apitest.7debao.com/router/api` ### Q4: 如何获取 clientId 和 clientSecret? 登录企得宝ERP开放平台后台,在应用管理中创建应用获取。 ### Q5: 响应中 success=false 但 data 不为 null? 以 `success` 字段为准。SDK 内部通过 `isSuccess()` 判断,该方法只检查 `success` 是否为 `true`。 --- ## 📄 参考文档 - [企得宝ERP 开放平台](https://open.7debao.com) - [00-概述与接入指南](./00-概述与接入指南.md) - API 总览与接入规范 - [01-基础资料.md](./01-基础资料.md) - 店铺、仓库、物流公司等 - [02-商品管理.md](./02-商品管理.md) - 商品信息管理 - [03-平台商品管理(个性).md](./03-平台商品管理(个性).md) - 平台商品独立管理 - [04-订单管理.md](./04-订单管理.md) - 订单上传、查询、发货、售后 - [05-采购管理.md](./05-采购管理.md) - 供应商、采购订单、入库 - [06-调拨管理.md](./06-调拨管理.md) - 调拨单管理 - [07-其他出入库管理.md](./07-其他出入库管理.md) - 其他出入库单 - [08-盘点管理.md](./08-盘点管理.md) - 盘点单管理 - [09-库存管理.md](./09-库存管理.md) - 库存查询 - [10-消息推送.md](./10-消息推送.md) - 推送通知接收 - [11-路由管理.md](./11-路由管理.md) - 物流路由查询 --- **版本**: 1.0.0 **Java**: 21+ **更新日期**: 2026-04-30