Files
vipnub 45452c1799 1、合作商余额查询
2、分油账户司机可用额度
2026-10-08 23:12:33 +08:00

10 KiB
Raw Permalink Blame History

慧明宝供应链平台 · Java 对接示例

对接方(下单平台)调用慧明宝接口的完整示例,与平台 PHP 端口径一一对应。

配套文档:《慧明宝供应链平台接口文档 V1.0.17》。本示例等价于平台自带的联调脚本 qyt_test.php。


一、对接链路

flowchart LR
    subgraph A["你方(下单平台)"]
        A1["业务系统"]
    end
    subgraph B["慧明宝平台"]
        B1["开放接口<br/>partners.php"]
        B2["发放队列"]
        B3["回调队列"]
    end
    subgraph C["上游油品平台(企油通)"]
        C1["运单油费下发"]
        C2["司机加油"]
    end

    A1 -->|"① 分油 share<br/>RSA+AES 加密"| B1
    B1 -->|"② 同步返回 oilCardNo<br/>(仅代表受理)"| A1
    B1 --> B2
    B2 -->|"③ 下发油费"| C1
    C1 -->|"④ 查发放结果"| B2
    B2 -->|"⑤ 通知 share_oil"| A1
    C2 -->|"⑥ 加油消费推送"| B3
    B3 -->|"⑦ 通知 add_oil(每笔一次)"| A1
    A1 -->|"⑧ 退款 refund(可选)"| B1
    B1 -->|"⑨ 通知 refund"| A1

不看图的话,一句话版本:分油是异步的。同步返回只代表平台受理,真正到账要等 share_oil 通知,或自己查订单状态。

sequenceDiagram
    participant Y as 你方系统
    participant P as 慧明宝平台
    participant Q as 企油通

    Y->>P: share 分油(金额/司机/身份证/车牌)
    P-->>Y: code=00 + oilCardNo(受理)
    P->>Q: 运单油费下发
    Q-->>P: 受理
    P->>Q: 查发放结果(轮询)
    Q-->>P: 发放成功
    P-->>Y: 通知 optType=share_oil
    Note over Y,P: 此时 oil_status_zsy=2,油费才真正到账

    Q-->>P: 司机加油(一单可多次)
    P-->>Y: 通知 optType=add_oil(每笔推一次)

    opt 司机没加完,需要退款
        Y->>P: refund 退款
        P->>Q: 调低司机凭证额度
        P-->>Y: 通知 optType=refund
    end

二、快速开始

mvn -q compile exec:java -Dexec.mainClass=com.hmb.openapi.demo.ShareDemo

运行前改 ShareDemo.java 顶部 5 个配置(平台分配):

配置 说明
BASE_URL 接口域名,不含结尾斜杠
APP_KEY 平台分配的 appKey
ORG_NO 公司编号,作为业务参数 orgNo
PARTNER_PRIVATE_KEY 你方私钥,PKCS#8 一行 base64,用于加签
PLATFORM_PUBLIC_KEY 平台公钥,X.509 一行 base64,用于加密与验签回调

私钥若是 PKCS#1(-----BEGIN RSA PRIVATE KEY-----),Java 读不了,先转换:

openssl pkcs8 -topk8 -inform PEM -in old.pem -outform PEM -nocrypt -out pkcs8.pem

目录结构

src/main/java/com/hmb/openapi/
├── HmbConfig.java           配置与地址拼接
├── HmbCrypto.java           签名、加解密、PHP 兼容的 urlencode
├── JsonPhp.java             请求体序列化(必须与 PHP 口径一致)
├── HmbApiClient.java        五个业务接口
├── HmbResponse.java         响应封装
├── HmbNotifyVerifier.java   接收油卡变动通知(解密 + 验签)
└── demo/
    ├── ShareDemo.java            下单 → 查状态 → 取加油地址
    └── NotifyControllerDemo.java 接收通知的 Spring 示例

三、请求地址

域名 + /partners.php + 接口路径。平台没配 URL 重写,中间的入口文件不能省。

接口 method(请求头) 路径
用户分油 syb.oil.oilCard.share /oilCard/share
订单状态查询 syb.oil.oilCard.orderStatus /oilCard/orderStatus
订单退款 syb.oil.oilCard.refund /oilCard/refund
付款码申请 syb.pay.qrCode.request /oilCard/getPayQrCode
分油记录查询 syb.oil.oilCard.shareList /oilCard/shareList
合作商余额查询 syb.oil.account.balance /oilCard/balance
司机可用额度 syb.oil.driver.quota /oilCard/driverQuota

例:http://47.104.73.7/partners.php/oilCard/share


四、报文结构

请求

请求头(自定义 HTTP 头):

头 说明
version 固定 1.0.0
appKey 平台分配
method 接口标识,填错返回 0005
requestId 必须全局唯一,重复返回 0012
sign 见下方加签步骤

请求体(业务参数不出现在明文里):

{"key": "RSA加密后的AES密钥(base64)", "data": "AES加密后的业务报文(base64)"}

加签与加密(顺序不能变)

  1. 业务参数序列化成 bodyJson(PHP 口径,见「六、常见坑」第 2 条)
  2. 拼待签串:http_build_query([version, appKey, method, requestId, body])
  3. SHA256withRSA 用你方私钥签名,base64 → 放进请求头 sign
  4. 随机 32 字节 AES 密钥,AES-256-ECB/PKCS5Padding 加密 bodyJson,base64 → data
  5. 用平台公钥 RSA/ECB/PKCS1Padding 加密该 AES 密钥,base64 → key

待签串长这样(注意 body 整体被 urlencode 了):

version=1.0.0&appKey=abc&method=syb.oil.oilCard.share&requestId=abcXXXX&body=%7B%22orgNo%22%3A%22U230%22%2C%22name%22%3A%22%E5%BC%A0%E4%B8%89%22%7D

响应

平台响应是明文 JSON,不加密:

{"code":"00","message":"请求成功","errCode":null,"errMessage":null,"data":{"oilCardNo":"OIL1756...","amount":"100.00"}}

code=00 为成功,否则看 errCode / errMessage。


五、接口字段

5.1 用户分油 share

参数 必填 说明
orgNo 是 公司编号
amount 是 分油金额(元),最多两位小数且大于 0
mobile 是 司机手机号
name 是 司机姓名,用于上游实名二要素核验
idCard 是 司机身份证号,18 位
plateNo 是 车牌号,平台侧留存展示,不上送上游
saleOrderNo 是 你方内部销售单号,同一单号重复提交返回原订单(幂等)
oilCardType 是 固定 zsy_ticket

返回 data:oilCardNo(油卡编号,后续接口都用它)、amount。

5.2 订单状态查询 orderStatus

入参 orgNo + oilCardNo。关键返回字段:

字段 说明
oil_status_zsy 0 未提交 / 1 发放中 / 2 发放成功 / 3 发放失败。只有 2 才是真正到账
used_amount 已加油金额(一单可多次加油,累计值)
used_num 加油次数
remain_amount 剩余金额 = 分油金额 − 已加油 − 已退款,未退款时即可退金额
refund_status 0 未退款 / 1 退款中 / 2 已退款 / 3 退款失败 / 4 退款结果确认中
use_status 0 未加油 / 1 有加油记录(可能只加了一部分)

5.3 订单退款 refund

入参 orgNo + oilCardNo + reason(选填)。

  • 退款金额固定为剩余未加油金额,不能指定,已加油部分不退
  • 每单只能成功退一次
  • 返回 refundStatus=2 成功;=4 表示结果确认中,此时切勿重复发起,稍后查订单状态或等 refund 通知

六、常见坑

1. http_build_query 的编码规则和 Java URLEncoder 不一样

Java 的 URLEncoder 不编码 *,PHP 会编成 %2A;报文里只要出现一个这样的字符,验签就失败。本示例用 HmbCrypto.phpUrlEncode() 复刻了 PHP 规则:只有 A-Z a-z 0-9 - _ . 原样保留,空格编成 +,其余按 UTF-8 编成 %XX 大写十六进制。

2. 请求体 JSON 里的 / 必须转义成 \/

平台收到后会把 body 反序列化再重新序列化去验签,用的是 PHP json_encode($body, JSON_UNESCAPED_UNICODE),它默认转义斜杠,而 Java 的 JSON 库不会。备注里带个日期 2026/09/29 就会对不上。所以请求体请用本示例的 JsonPhp.encode(),不要换成 Jackson/Gson。中文要原样输出,不能转 \uXXXX。

3. requestId 必须全局唯一

平台按它拦重复请求,重复返回 0012。

4. 分油是异步的

同步返回只代表受理。真正到账看 oil_status_zsy=2,或等 share_oil 通知。

5. 一张订单可以分多次加油

每笔加油单独推一次 add_oil 通知,amount 是本次占用金额,orderAmount 才是订单总金额。请按 shareNo(企油通消费订单号,每笔不同)做幂等去重。

6. 验签回调时,body 用解密出来的明文原串

不要反序列化后再序列化 —— 不同语言的 JSON 输出不一定一致。本示例已这样处理。


七、接收油卡变动通知

把你的接收地址填到平台后台的合作商「回调地址」。报文与请求方向同构,解析步骤:

  1. 用你方私钥解出 AES 密钥 → 解出业务报文明文
  2. 用平台公钥验签,待签串是原样拼接(不 urlencode): version=..&appKey=..&method=..&requestId=..&body={解密出的明文}

业务字段:

字段 说明
oilCardNo 油卡编号,对应下单返回值
optType share_oil 分油 / add_oil 加油 / refund 退款
amount 分油=分油金额;加油=本次加油占用金额;退款=退款金额
orderAmount 订单实付金额(即分油金额),三种场景都推,便于与 amount 对照
shareNo 分油=分油记录编号;加油=企油通消费订单号(每笔不同,用于去重)
type add 增加 / sub 减少

处理成功必须返回 {"code":"00","message":"请求成功"},否则平台按 60 秒 / 5 分钟 / 30 分钟退避重试 3 次。


八、错误码

errCode 含义
0001 缺少必填请求参数(如未传 idCard / plateNo)
0005 请求头 method 不正确
0006 签名验证不通过
0012 请求流水号重复
0013 请求参数不正确(格式校验未过)
0014 orgNo 与 appKey 不匹配
2023 销售单号重复且原单发放失败,请换新单号
2028 账户余额不足
2032 该订单退款正在处理中
2036 未找到对应的分油记录
2048 退单状态异常(不满足退款前置条件,如已全部加油)
2049 调用上游退款失败(凭证余额不足或上游拒绝)

完整列表见接口文档附录 4.3。