2019-04-13

阅读对象

本文阅读对象:商户系统集成品信支付涉及的技术架构师,研发工程师,测试工程师,系统运维工程师。

协议规则

提交方式:Get / Post

字符编码:UTF-8

签名算法:MD5

金额:分

签名算法

签名生成的通用步骤如下:

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:

  1. ◆ 参数名ASCII码从小到大排序(字典序);
  2. ◆ 如果参数的值为空不参与签名;
  3. ◆ 参数名区分大小写;
  4. ◆ sign参数不参与签名,将生成的签名与该sign值作校验。

第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

◆ key设置路径:亿付商户平台-->密钥管理-->商户密钥

举例(假设传送参数如下):

mch_id : 1002

mch_order_id : 20181130A001

money : 100

notify_url : http://www.example.com/notify

第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:

stringA="mch_id=117&mch_order_id=l20191212161294208320481100&money=10000¬ify_url=http://baidu.com&pay_type=alipay&trade_type=native_wap&user_tag=test_";

第二步:拼接API密钥:

//key为商户平台设置的密钥key
stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d"

//MD5签名方式
sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"

签名算法java代码示例:

    /**
     * 实体类转map 
     *
     * @param object 参数封装类
     * @return       待签名数据
     */
    public static Map objectToMap(Object object) {
        Map map = new LinkedHashMap<>();
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field entityField : fields) {
            Field field = null;
            try {
                field = object.getClass().getDeclaredField(entityField.getName());
                map.put(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, field.getName()), field.get(object) == null ? "" : field.get(object).toString());
            } catch (NoSuchFieldException exception) {
                exception.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

   /**
     * 签名处理
     *
     * @param data 待签名数据
     * @param key  私钥
     * @return 签名
     */
    public static String generateSignature(final Map data, String key) throws Exception {
        Set keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals("sign")) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        //System.out.println(MD5(sb.toString()).toUpperCase());
        return MD5(sb.toString()).toUpperCase();
    }

   /**
     * 生成 MD5
     *
     * @param data 待处理数据
     * @return MD5结果
     */
    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

   /**
     * 判断签名是否正确
     *
     * @param data   待签名数据
     * @param key    私钥
     * @return 签名是否正确
     * @throws Exception
     */
    public static boolean isSignatureValid(
        Map data, String key) throws Exception {
        if (!data.containsKey("sign")) {
            return false;
        }
        String sign = data.get("sign");
        return generateSignature(data, key).equals(sign);
    }

统一下单

应用场景:商户系统调用统一下单接口发起支付渠道支付订单

接口地址:http://121.37.16.158:8080/pay/order

提交方式:post提交

注意:

  • 金额 money 存在限制,不同通道情况不同(通常 100-9999元)
  • 默认支付宝, 对应参数 pay_type = alipay
  • 快捷支付(quick-pay) card_no 必传

请求参数

参数 类型 是否必填 描述 示例值
mch_id long 商户id 1002
mch_order_id string(32) 商户订单id 20181202A001
money int 订单金额/分 1000
user_tag string(32) 用户唯一标示 用户id,用户电话,用户IP。。。
pay_type string(32) 支付类型:附录 alipay
trade_type string(32) 支付方式(重要):附录 native_wap
notify_url string(128) 商户系统接受异步通知地址,
不可携带参数,请求方式为Post
http://www.example.com/notify
redirect_url string(128) 用于商户系统在支付完毕后跳转至自己业务系统
sign string(64) 签名:参见签名算法 F545F8C26B3811126417E
card_no string(32) only快捷支付(pay_type = quick-pay)必传,其他支付类型忽略此字段。 6217920274920374
参数示例:

  "mch_id" : "1002",
    "money" : 100,
    "mch_order_id" : "20181129A001",
    "notify_url" : "http://www.example.com/pay/notify",
    "redirect_url" : "",
    "sign" : "F545F8C26B3811126417E3F26F34258E",
    "pay_type" : "alipay"

返回结果

参数 类型 描述
code string 网关返回码:参加附录
message string 网关返回码描述:参加附录
type string 返回类型:form 与 url
data object 额外信息,部分请求失败会原样返回商户系统请求参数,请求成功data见示例
sign string 签名,当网关返回码为成功时,会额外返回签名值

type 为data 数据的返回结果类型,设为 form 与 url。
商户系统需注意,返回结果:code,message,type,data均参与签名

对于返回form,部分通道会返回form。商户需要根据返回形式 type || form 进行相应处理,

系统默认返回url . (特殊通道不能处理除外)

type = url 请求成功示例
{
    "code": "A000",
    "message": "成功",
    "sign": "C67DA60C3775867093B92F9438E39A43",
    "type": "url",
 "sys_order_id": "20181202035005B000100200000007",
    "data": "http://gateway.iexindex.com/ydpay/PayH5New.aspx?price=500&istype=1&return_url=http://gateway.iexindex.com:80/return/AliPay/AlipayThree_return.aspx&payurl=https%3a%2f%2fnwww.kexpay.com%2falipay%3fM2481wNJDW1oehjLTO-2088432126584038-500.00&id=19010612302481020760"
}



请求失败示例:data可能不回返回
{
    "code": "A001",
    "message": "签名校验失败",
    "data": {
        "mch_id": 1002,
        "money": 100,
        "mch_order_id": "20181129A001",
        "notify_url": "http://127.0.0.1:8080/pay/notify",
        "redirect_url": "",
        "sign": "0CA41B17DC8840D56D5B09076D5FC583",
        "pay_type": "alipay"
    }
}

查询订单

应用场景:商户系统可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。

接口地址:http://121.37.16.158:8080/pay/order/query

请求参数

参数 类型 是否必填 描述 示例值
mch_id long 商户id 1002
mch_order_id string(32) 商户订单id 20181202A001
sign string(64) 签名:参见签名算法 F545F8C26B381112641
参数示例:

    "mch_id" : "1002",
    "mch_order_id" : "20181129A001",
    "sign" : "F545F8C26B3811126417E3F26F34258E"


返回结果

参数 类型 描述
code string 网关返回码:参加附录
message string 网关返回码描述:参加附录

以下字段在 code 为 A000 (成功) 的时候有返回

参数 类型 是否必填 描述 示例值
sys_order_id string(32) 系统订单id 20181202035005B000100200000007
mch_order_id string(32) 商户订单id 20181202A001
money int 订单金额/分 1000
status string 状态:S - 成功
F - 失败
I - 进行中
S 商户系统以此状态为订单判断标准
trade_time string 交易时间:yyyy-MM-dd HH:mm:ss 2018-11-28 00:00:00
sign string(64) 签名:参见签名算法 F545F8C26B3811126417E
请求成功示例:
{
    "code": "A000",
    "message": "成功",
    "sign": "8789F10F8C45E217E432995438D497C2",
    "sys_order_id": "20181202035005B000100200000007",
    "mch_order_id": "20181129A001",
    "money": 100,
    "status": "I"
}

请求失败示例:
{
    "code": "A006",
    "message": "订单不存在"
}

异步通知notify

应用场景:对应下单接口中的notify_url地址,请求方式POST,支付完成后,系统会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答;商户系统应答非成功时,系统会通过一定策略定期重发通知,时间依此增长 ;

注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

商户系统在成功接收请求后,需返回字符串 success 则表示成功。

返回参数

参数 类型 是否必填 描述 示例值
sys_order_id string(32) 系统订单id 20181202035005B000100200000007
mch_order_id string(32) 商户订单id 20181202A001
money int 订单金额/分 1000
status string 状态:S - 成功
F - 失败
I - 进行中
S 商户系统以此状态为订单判断标准
trade_time string 交易时间:yyyy-MM-dd HH:mm:ss 2018-11-28 00:00:00
sign string(64) 签名:参见签名算法 F545F8C26B3811126417E
//通知结果示例:

    "mch_order_id":"1011Alian41255360",
    "sys_order_id":"2018121402472700000009",
    "money":"11100",
    "trade_time":"2018-12-1402:48:21",
    "sign":"94064B807C5985CBBF612C62798DF3C1",
    "status":"S"

商户系统接受异步请求示例代码java:

public void paynotify(HttpServletRequest request, HttpServletResponse response) {
        InputStream inputStream;
        OutputStream outputStream = null;
        try {
            //读取参数
            StringBuffer sb = new StringBuffer();
            inputStream = request.getInputStream();
            String s;
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = in.readLine()) != null) {
                sb.append(s);
            }
            in.close();
            inputStream.close();
            outputStream = response.getOutputStream();

            //System.out.println(sb.toString());
            if (sb.length() == 0) {  
                outputStream.write("empty".getBytes("UTF-8"));
                return;
            }
            //verify sign
            //boolean flag = signVerify(sb.toString(), key);
            
            if (flag) {
                //业务处理
               
                outputStream.write("success".getBytes("UTF-8"));
            } else {
                outputStream.write("sign error".getBytes("UTF-8"));
            }
        } catch (Exception ex) {
            LOGGER.error(ex.getMessage());
        } finally {
            try {
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

单笔代发

应用场景:商户系统按照本接口数据规范将订单信息发往alianpay平台,完成单笔提现功能。

接口地址:http://121.37.16.158:8080/pay/bankPay/order

注意:

  • 金额 money 存在限制, 1 - 49999 元 注意金额单位为分
  • notify_url 商户传入回调地址。系统将采用post方式给商户发回调,30分钟内通知6次。url不可携带参数。若不传值,请商户调取查询接口获取订单终态,一般系统处理时间 3分钟。

请求参数

参数 类型 是否必填 描述 示例值
mch_id long 商户id 1002
mch_order_id string(32) 商户订单id 20181202A001
money long 订单金额/分 1000
acc_no string(64) 收款卡号 621792027492xxxx
acc_name string(64) 姓名 李玉龙
bank_address string 银行支行 龙华支行
mobile string(32) 手机 1575537XXXX
notify_url string(128) 系统采用post方式 http://www.example.com/notify 处理完返回 ”succes“字符串 就可以了
sign string(64) 签名:参见签名算法 F545F8C26B3811126417E
参数示例:

    "mch_id" : "1002",
    "money" : 100,
    "mch_order_id" : "20181129A001",
    "notify_url" : "http://www.example.com/bankpay/notify",
    "acc_no" : "62179202749203XX",
    "acc_name" : "李煜",
    "pay_type" : 1,
    "acc_type" : 1,
    "sign" : "F545F8C26B3811126417E3F26F34258E",


返回结果

参数 类型 描述
code string 网关返回码:参加附录
message string 网关返回码描述:参加附录
data object 额外信息,失败会原样返回商户系统请求参数,请求成功data见示例

data数据结构

参数 类型 描述
status string S - 成功
F - 失败
I - 进行中 商户系统以此来标识订单状态

{
    "code": "A000",
    "message": "success",
    "sign": "729C1273CCC9B5F062CB973CE64E73A9",
    "sys_order_id": "2190426131128e563b25067421579",
    "mch_order_id": "b20190427170483558406199",
    "money": 10,
    "status": "S"
}



请求失败示例:
{
    "code": "A001",
    "message": "签名校验失败"
}

异步通知示例代码

form 方式通知 普通post通知
通知参数

{
    "code": "A000",
    "message": "成功",
    "sign": "8789F10F8C45E217E432995438D497C2",
    "sys_order_id": "20181202035005B000100200000007",
    "mch_order_id": "20181129A001",
    "money": 100,
    "status": "I"
}
public void paynotify(HttpServletRequest request, HttpServletResponse response) {
        InputStream inputStream;
        OutputStream outputStream = null;
        try {
            //读取参数
            StringBuffer sb = new StringBuffer();
            inputStream = request.getInputStream();
            String s;
            BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            while ((s = in.readLine()) != null) {
                sb.append(s);
            }
            in.close();
            inputStream.close();
            outputStream = response.getOutputStream();
​
            //System.out.println(sb.toString());
            if (sb.length() == 0) {  
                outputStream.write("empty".getBytes("UTF-8"));
                return;
            }
            //verify sign
            //boolean flag = signVerify(sb.toString(), key);
            
            if (flag) {
                //业务处理
               
                outputStream.write("success".getBytes("UTF-8"));
            } else {
                outputStream.write("sign error".getBytes("UTF-8"));
            }
        } catch (Exception ex) {
            LOGGER.error(ex.getMessage());
        } finally {
            try {
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

查询订单

应用场景:商户系统可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。

接口地址:http://121.37.16.158:8080/pay/bankPay/order/query

请求参数

参数 类型 是否必填 描述 示例值
mch_id long 商户id 1002
mch_order_id string(32) 商户订单id 20181202A001
sign string(64) 签名:参见签名算法 F545F8C26B381112641
参数示例:

    "mch_id" : "1002",
    "mch_order_id" : "20181129A001",
    "sign" : "F545F8C26B3811126417E3F26F34258E"


返回结果

参数 类型 描述
code string 网关返回码:参加附录
message string 网关返回码描述:参加附录

以下字段在 code 为 A000 (成功) 的时候有返回

参数 类型 是否必填 描述 示例值
sys_order_id string(32) 系统订单id 20181202035005B000100200000007
mch_order_id string(32) 商户订单id 20181202A001
money int 订单金额/分 1000
status string 状态:S - 成功
F - 失败
I - 进行中
S 商户系统以此状态为订单判断标准
trade_time string 交易时间:yyyy-MM-dd HH:mm:ss 2018-11-28 00:00:00
sign string(64) 签名:参见签名算法 F545F8C26B3811126417E
请求成功示例:
{
    "code": "A000",
    "message": "成功",
    "sign": "8789F10F8C45E217E432995438D497C2",
    "sys_order_id": "20181202035005B000100200000007",
    "mch_order_id": "20181129A001",
    "money": 100,
    "status": "I"
}

请求失败示例:
{
    "code": "A006",
    "message": "订单不存在"
}

附录:

网关返回码

code message
A000 成功
A001 签名校验失败
A002 请先上传商户私钥
A003 非法的请求参数:%s
A004 订单号重复
A005 金额限制:%s
A006 订单不存在
A099 下单失败:%s
A100 商户被冻结,请联系管理员
A999 系统维护

支付类型

支付类型 参数值
支付宝 alipay
支付宝H5 aliwap
微信 wx
云闪付 union
综合支付 coin
拼多多微信 pdd
拼多多支付宝 pdd_zfb

支付方式

支付类型 参数值
没有自己系统的方式 native
自定义扫码界面 native_api
显示我们web页面 native_wap

你可能感兴趣的:(2019-04-13)