签名算法

1. 将发送或接收到的所有参数按照参数名按照ASCII码从小到大排序(a-z) sign    sign_type     空值   不参与签名.

2. 将排序后的参数拼接成URL键值对的格式; 如: k1=v1&k2=v2&k3=v3..... 得到待签名字符串 strA.

3. 将签名字符串 strA 后面拼接 商户密钥 得到待签名字符串 strB.

4. 将待签名字符串 strB 进行 MD5 就得到签名值 sign.

5. 参数值不要进行url编码。

例如: sign = md5(key1=value1&key2=value2...商户密钥)

submit.php
接口说明

此接口可用于用户前台直接发起支付,使用form表单跳转或拼接成url跳转。

URL地址:/submit.php

字段名 变量名 必填 类型 示例值 描述
商户ID pid String 1001
支付方式 type String alipay 找客服获取
商户订单号 out_trade_no String 20160806151343349
异步通知地址 notify_url String http://www.pay.com/notify_url.php 服务器异步通知地址
跳转通知地址 return_url String http://www.pay.com/return_url.php 页面跳转通知地址
商品名称 name String VIP会员 如超过127个字节会自动截取
商品金额 money String 1.00 单位:元,最大2位小数
业务扩展参数 param String 没有请留空 支付后原样返回
签名字符串 sign String 202cb962ac59075b964b07152d234b70 签名算法 sign = md5 (a=b&c=d&e=f+商户密钥 )
签名类型 sign_type String MD5 默认为MD5
mapi.php
接口说明

此接口可用于服务器后端发起支付请求,会返回支付链接。

URL地址:/mapi.php

字段名 变量名 必填 类型 示例值 描述
商户ID pid Int 1001
支付方式 type String alipay 找客服获取
商户订单号 out_trade_no String 20160806151343349
异步通知地址 notify_url String http://www.pay.com/notify_url.php 服务器异步通知地址
跳转通知地址 return_url String http://www.pay.com/return_url.php 页面跳转通知地址
商品名称 name String VIP会员 如超过127个字节会自动截取
商品金额 money String 1.00 单位:元,最大2位小数
用户IP地址 clientip String 192.168.1.100 用户发起支付的IP地址
设备类型 device String pc 根据当前用户浏览器的UA判断,
传入用户所使用的浏览器
或设备类型,默认为pc
业务扩展参数 param String 没有请留空 支付后原样返回
签名字符串 sign String 202cb962ac59075b964b07152d234b70 签名算法 sign = md5 (a=b&c=d&e=f+商户密钥 )
签名类型 sign_type String MD5 默认为MD5

返回结果(json)

字段名 变量名 类型 示例值 描述
返回状态码 code Int 1 1为成功,其它值为失败
返回信息 msg String 失败时返回原因
订单号 trade_no String 20160806151343349 支付订单号
支付跳转url payurl String https://www.pay.com/pay/wxpay/202010903/ 如果返回该字段,则直接跳转到该url支付
二维码链接 qrcode String weixin://wxpay/bizpayurl?pr=04IPMKM 如果返回该字段,则根据该url生成二维码
小程序跳转url urlscheme String weixin://dl/business/?ticket=xxx 如果返回该字段,则使用js跳转该url,可发起微信小程序支付
api.php
接口说明

查询单个订单。

URL地址:/api.php

字段名 变量名 必填 类型 示例值 描述
操作类型 act String act 此API固定值
商户ID pid String 1001 系统分配的唯一商户ID
商户密钥 key String 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i 系统分配的唯一签名密钥
系统订单号 trade_no String P1988492264548581376 系统唯一订单号
商户订单号 out_trade_no String 20160806151343349 合作商系统中唯一订单号

提示:系统订单号 和 商户订单号 二选一传入即可,如果都传入以系统订单号为准!

返回结果(json)

字段名 变量名 类型 示例值 描述
返回状态码 code Int 1 1为成功,其它值为失败
返回信息 msg String 失败时返回原因
订单号 trade_no String P1988492264548581376 系统订单号
商户订单号 out_trade_no String 20160806151343349 商户系统内部的订单号
支付方式 type String alipay 支付方式
商户ID pid String 1001 发起支付的商户ID
创建订单时间 addtime String 2016-08-06 22:55:52 订单下单时间
完成交易时间 endtime String 2016-08-06 22:55:52 未支付的订单此值是空
商品名称 name String VIP会员 下单传入的值
商品金额 money String 商品金额 商品下单金额
支付状态 status Int 0 1为支付成功,0为未支付
业务扩展参数 param String 下单传递有值时此项才有值, 否则是空
支付者账号 buyer String 默认留空
支付回调
字段名 变量名 必填 类型 示例值 描述
商户ID pid String 1001 系统分配的唯一商户ID
系统订单号 trade_no String 89unJUB8HZ54Hj7x4nUj56HN4nUzUJ8i 系统订单号
商户订单号 out_trade_no String P1988492264548581376 商户下单传递的订单号
支付类型 type String alipay
商品名称 name String VIP
支付金额 money String 10.00
扩展参数 param String 商户下单传递的扩展参数
支付状态 trade_status String TRADE_SUCCESS TRADE_SUCCESS=支付成功;TRADE_REFUND=支付退款
签名 sign String 平台回调签名值
签名类型 sign_type String MD5 固定值(不参与签名)

提示:商户收到回调后需要校验签名以及订单是否处理过,以免重复上分,收到回调后请返回success

POST JSON
						
private static void postJson() {
    String url = "http://127.0.0.1/mapi.php";
    String appid = "17732920843";
    String token = "45be38411d8747a874aebe0d667";

    Map<String, String> data = new HashMap<>();
    data.put("pid", appid);
    data.put("type", "alipay");
    data.put("out_trade_no", Long.toString(System.currentTimeMillis()));
    data.put("notify_url", "http://127.0.0.1/api/notify/tm");
    data.put("name", "VIP充值");
    data.put("money", "10");
    data.put("clientip", IpUtils.getImitationIP());

    String sign = SignUtils.signStr(data);
    data.put("sign", PwdUtils.getMd5Spring(sign + token));
    data.put("sign_type", "MD5");

    String result = HttpRequest.post(url).body(JSON.toJSONString(data)).execute().body();
    System.out.println("================ POST JSON ===================");
    System.out.println("请求地址:" + url);
    System.out.println("请求参数:" + JSON.toJSONString(data));
    System.out.println("请求返回:" + result);
}
						
					
POST FORM
						
private static void postForm() {
    String url = "http://127.0.0.1/mapi.php";
    String appid = "17732920843";
    String token = "45be38411d8747a874aebe0d667";

    Map<String, String> data = new HashMap<>();
    data.put("pid", appid);
    data.put("type", "alipay");
    data.put("out_trade_no", Long.toString(System.currentTimeMillis()));
    data.put("notify_url", "http://127.0.0.1/api/notify/tm");
    data.put("name", "VIP充值");
    data.put("money", "10");
    data.put("clientip", IpUtils.getImitationIP());

    String sign = SignUtils.signStr(data);
    data.put("sign", PwdUtils.getMd5Spring(sign + token));
    data.put("sign_type", "MD5");

    String result = HttpRequest.post(url).formStr(data).execute().body();
    System.out.println("================ POST FORM ===================");
    System.out.println("请求地址:" + url);
    System.out.println("请求参数:" + JSON.toJSONString(data));
    System.out.println("请求返回:" + result);
}
						
					
GET FORM
						
private static void getForm() {
    String url = "http://127.0.0.1/mapi.php";
    String appid = "17732920843";
    String token = "45be38411d8747a874aebe0d667";

    Map<String, String> data = new HashMap<>();
    data.put("pid", appid);
    data.put("type", "alipay");
    data.put("out_trade_no", Long.toString(System.currentTimeMillis()));
    data.put("notify_url", "http://127.0.0.1/api/notify/tm");
    data.put("name", "VIP充值");
    data.put("money", "10");
    data.put("clientip", IpUtils.getImitationIP());

    String sign = SignUtils.signStr(data);
    data.put("sign", PwdUtils.getMd5Spring(sign + token));
    data.put("sign_type", "MD5");

    String result = HttpRequest.get(url).formStr(data).execute().body();
    System.out.println("================ GET FORM ===================");
    System.out.println("请求地址:" + url);
    System.out.println("请求参数:" + JSON.toJSONString(data));
    System.out.println("请求返回:" + result);
}
						
					
ASCII 排序
						
/**
 * 严格区分大小的 ascii 排序 ---> 自行移除不需要拼接的字符串
 * 
 * @param params
 * @return
 */
public static String signStr(Map<String, String> params) {
    if (params == null || params.isEmpty()) {
        return "";
    }

    return params.entrySet().stream().filter(entry -> entry.getKey() != null && !ObjectUtils.isEmpty(entry.getValue())).sorted(Map.Entry.comparingByKey())
            .map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.joining("&"));
}