Java开发支付宝支付功能

489 阅读3分钟

支付宝支付流程.jpg

  • 支付宝整体的流程为, 商户客户端向商户服务端发起请求,获取签名后的订单信息,获取到信息之后调用支付宝支付接口完成支付请求,支付完成后商户客户端会收到支付结果,同时也会给商户服务端配置的异步通知地址发送一份支付结果,获取到异步结果之后,需要给支付宝接受响应的回应,将服务端异步获取的信息记录到数据库中,并提供给客户端,具体以哪个结果为准,可以根据各自的需要,一般来说,可以将服务端异步获取到的信息,作为支付是否成功的标准。

  • 首先需要客户端发起支付请求,获取到相关的支付配置,比如支付金额,是否是签约订单,支付文案等相关信息,然后将这些信息传给服务端,服务端获取到这些信息,创建订单,需要的参数如下

  • app支付接口2.0 - 支付宝文档中心 (alipay.com) https://opendocs.alipay.com/apis/02e7gq?scene=20

//客戶端唤起APP 公参
Map<String, String> publicParameter = new HashMap<>();
//支付宝分配给开发者的应用ID
publicParameter.put("app_id", "XXXXXXXXX");
publicParameter.put("charset", "UTF-8");
//商户生成签名字符串所使用的签名算法类型
publicParameter.put("sign_type", "RSA");// 签名方式RSA/RSA2
//接口名称
publicParameter.put("method", "alipay.trade.app.pay");//支付宝交易接口
//发送请求的时间
publicParameter.put("timestamp",DateUtil.getDateByDatePattern(DateUtil.LONG_DATE_FORMAT));
publicParameter.put("version", "1.0");
publicParameter.put("format", "JSON");
publicParameter.put("notify_url", callbackUrl);// 回调地址
Map<String, String> privateParameter = new HashMap<>();
//订单号
privateParameter.put("out_trade_no", tradeNo);//外部交易订单号
privateParameter.put("product_code", "QUICK_MSECURITY_PAY");//销售产品码,可根据实际修改
//支付价格
privateParameter.put("total_amount", amount + "");
//绝对超时时间
privateParameter.put("time_expire", DateUtil.addMinute("", 10, "yyyy-MM-dd HH:mm"));
//商品描述
privateParameter.put("body", body);
//合作商ID
privateParameter.put("seller_id", "XXXXXXXX");
//附属字段
publicParameter.put("biz_content", JsonUtil.obj2Json(privateParameter));
//参数字符串化
String linkString = FreePayUtils.buildOrderParam(publicParameter);
//签名
String signstr = FreePayUtils.getSign(publicParameter, "XXXXXXX"(阿里私钥),false);

Map<String, String> callAliPay = new HashMap<>();
callAliPay.put("callAliPayUrl", linkString + "&" + signstr);
  • 下面是参数字符串化的代码:
public static String buildOrderParam(Map<String, String> map) {
    List<String> keys = new ArrayList<String>(map.keySet());

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < keys.size() - 1; i++) {
        String key = keys.get(i);
        String value = map.get(key);
        sb.append(buildKeyValue(key, value, true));
        sb.append("&");
    }

    String tailKey = keys.get(keys.size() - 1);
    String tailValue = map.get(tailKey);
    sb.append(buildKeyValue(tailKey, tailValue, true));

    return sb.toString();
}
private static String buildKeyValue(String key, String value, boolean isEncode) {
    StringBuilder sb = new StringBuilder();
    sb.append(key);
    sb.append("=");
    if (isEncode) {
        try {
            sb.append(URLEncoder.encode(value, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            sb.append(value);
        }
    } else {
        sb.append(value);
    }
    return sb.toString();
}
  •  签名有公钥与公钥证书两种签名方法,下面是我们签名的代码:
public static String getSign(Map<String, String> map, String rsaKey, boolean rsa2) {
    List<String> keys = new ArrayList<String>(map.keySet());
    // key排序
    Collections.sort(keys);

    StringBuilder authInfo = new StringBuilder();
    for (int i = 0; i < keys.size() - 1; i++) {
        String key = keys.get(i);
        String value = map.get(key);
        authInfo.append(buildKeyValue(key, value, false));
        authInfo.append("&");
    }

    String tailKey = keys.get(keys.size() - 1);
    String tailValue = map.get(tailKey);
    authInfo.append(buildKeyValue(tailKey, tailValue, false));

    String oriSign = sign(authInfo.toString(), rsaKey, rsa2);
    String encodedSign = "";

    try {
        encodedSign = URLEncoder.encode(oriSign, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return "sign=" + encodedSign;
}
public static String sign(String content, String privateKey, boolean rsa2) {
    try {
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
                FreePayBase64.decode(privateKey));
        KeyFactory keyf = KeyFactory.getInstance(ALGORITHM);
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);

        java.security.Signature signature = java.security.Signature
                .getInstance(getAlgorithms(rsa2));

        signature.initSign(priKey);
        signature.update(content.getBytes('UTF-8'));

        byte[] signed = signature.sign();

        return FreePayBase64.encode(signed);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}
  • FreePayBase64.encode方面是我们做的base64的编码,这里就不再展示了,具体也可以参考支付宝的签名文档:数据签名 - 支付宝文档中心 (alipay.com) https://opendocs.alipay.com/common/02kf5q

  • 签名信息生成之后,将这些信息返回给客户端,callAliPay.put("callAliPayUrl", linkString + "&" + signstr);客户端拿到这些信息后,调用支付宝的SDK请求支付,支付成功后,支付宝会将支付结果同步发送给客户端,同时将信息发送到callbackUrl回调地址,数据验签校验之后,获取相应的数据,更新订单信息即可。