之前做开发过程中,没有接触过支付相关的功能,最近做了一个支付相关功能的开发,包括支付宝和微信支付,为了避免以后忘记相关的流程,记录一下这次的开发经验,这里先介绍一下支付宝相关的开发。
? ? ? ? 首先在进行java开发功能之前,先要在支付宝开放平台创建应用或者绑定应用,然后配置密钥,开放签约功能,具体流程,参考支付宝文档中心,附上链接
开放能力 | API支付宝文档中心https://opendocs.alipay.com/apis/01da3s
网页&移动应用学习路径 - 支付宝文档中心 (alipay.com)https://opendocs.alipay.com/apis/01ddgu应用创建完成,相关配置生成并且签约功能审核通过之后,?才可以发起支付,这里不再多说,先看一下支付宝支付的整体流程图:
支付宝整体的流程为,?商户客户端向商户服务端发起请求,获取签名后的订单信息,获取到信息之后调用支付宝支付接口完成支付请求,支付完成后商户客户端会收到支付结果,同时也会给商户服务端配置的异步通知地址发送一份支付结果,获取到异步结果之后,需要给支付宝接受响应的回应,将服务端异步获取的信息记录到数据库中,并提供给客户端,具体以哪个结果为准,可以根据各自的需要,一般来说,可以将服务端异步获取到的信息,作为支付是否成功的标准。
首先需要客户端发起支付请求,获取到相关的支付配置,比如支付金额,是否是签约订单,支付文案等相关信息,然后将这些信息传给服务端,服务端获取到这些信息,创建订单,需要的参数如下
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回调地址,数据验签校验之后,获取相应的数据,更新订单信息即可。
|