前段时间对接了全民付的支付宝小程序和微信小程序支付,
支付宝是可以直接唤起全民付主体的小程序,
微信则必须申请自己主体的小程序,
进而两者流程上有一定的不同,

项目整体框架包括:原生壳子,页面为jsp(SpringMVC框架)。

支付宝小程序支付对接流程:
1.支付确认页js请求自己的支付接口
2.自己的支付接口内拼装好参数调用全民付支付接口
3.全民付支付接口将支付结果返回(appPayRequest:APP支付用的请求报文,带有签名信息)给自己的支付接口
4.自己的支付接口将支付结果的APP支付用的请求报文(appPayRequest)返回给js
5.js拿到将APP支付用的请求报文(appPayRequest)作为参数,调用原生方法
6.原生加载APP支付用的请求报文(appPayRequest),唤起全民付支付宝小程序,
7.用户通过唤起的支付宝小程序进行支付操作,支付结果通过回调url(支付请求参数中传入)返回给系统。
8.支付确认页通过调用接口一直监听支付结果,拿到结果后跳转到支付结果页

微信小程序支付对接流程:
1.支付确认页js将支付请求参数拼接好作为参数调用原生方法
2.原生唤起自己主体的微信小程序,将支付请求参数传给小程序
3.自己主体的小程序携带支付请求参数调用自己的支付接口
4.自己的支付接口内拼装好参数调用全民付支付接口
5.全民付支付接口将支付结果返回(miniPayRequest:小程序支付用的请求报文,带有签名信息)给自己的支付接口
6.自己的支付接口将支付结果的小程序支付用的请求报文(miniPayRequest)返回给自己主体的微信小程序
7.微信小程序拿到支付用的请求报文(miniPayRequest)作为参数调用小程序方法wx.requestPayment,唤起支付页面
8.用户通过唤起的微信小程序支付页面进行支付操作,支付结果通过回调url(支付请求参数中传入)返回给系统
9.支付确认页通过调用接口一直监听支付结果,拿到结果后跳转到支付结果页

支付宝小程序js主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
function toQmfZfbPay(order_code,poundage,orderIds){
var cookiePlatform=getCookie("platform");
if (cookiePlatform != 'android'&& cookiePlatform != 'ios') {
$("#payTimeAlert").children("p").text("请在XXXXAPP内打开").end().show(1).delay(2000).hide(1);
return;
}

$(".l_tcSquare").show();
payDomain =$("#payDomain").val();

$.ajax({
type:'post',
url:payDomain+'/IHDouApiPay/api/pay/qmfZfbPay/request',
data:JSON.stringify({orderCode:order_code,payFee:poundage}),
dataType:'json',
contentType:'application/json',
success:function(json){
$(".l_tcSquare").hide();
if(json.retCode=='0000'){
var platform = getCookie("platform");
// $("#wsh_dialog_none").removeClass("l_none");
// $("#wshDialog").removeClass("l_none");
var redata = json.retData;
var flag = redata[0].flag;
if(flag=="success"){
var appPayRequest = redata[0].appPayRequest;
if(platform == 'android'){
// 跳转支付宝小程序
window.pos.goQmfZfbXcXPay(appPayRequest);
// 跳转支付宝
// window.pos.goQmfZfbPay(appPayRequest);
}else if(platform == 'ios'){
// 跳转支付宝小程序
// goQmfZfbXcXPay(appPayRequest);
window.webkit.messageHandlers.goQmfZfbXcXPay.postMessage({"zfbPayXbStr":appPayRequest});
// 跳转支付宝
// goQmfZfbPay(appPayRequest);
}
}else{
$("#payTimeAlert").children("p").text("支付请求异常,请稍后重试").end().show(1).delay(2000).hide(1);
}
}else{
$("#payTimeAlert").children("p").text(json.retMsg).end().show(1).delay(2000).hide(1);
}
},
error:function(data){
$(".l_tcSquare").hide();
$("#payTimeAlert").children("p").text("网络错误").end().show(1).delay(2000).hide(1);
}
});
setTimeout(function () { goToPaySuccess(orderIds) },3000);
}

微信小程序js主要代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
function toQmfWxPay(order_code,poundage,orderIds){
payDomain =$("#payDomain").val();
var totalAmount = $("#actualPayAmount").val();
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
//修改日期格式
if (day >= 0 && day <= 9) {
day = "0" + day;
}
//修改小时格式
if (hours >= 0 && hours <= 9) {
hours = "0" + hours;
}
//修改分钟格式
if (minutes >= 0 && minutes <= 9) {
minutes = "0" + minutes;
}
//修改秒格式
if (seconds >= 0 && seconds <= 9) {
seconds = "0" + seconds;
}
var currentFormatDate = year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
var pathStr = 'orderCode='+order_code+'&totalAmount='+totalAmount+'&requestTimestamp='+currentFormatDate+'&payFee='+poundage+'&payType=36&domain='+payDomain;

var cookiePlatform=getCookie("platform");
if(cookiePlatform == 'android'){
window.pos.OrderPayProgramPage(pathStr);
}else if(cookiePlatform == 'ios'){
// OrderPayProgramPage(pathStr);
window.webkit.messageHandlers.OrderPayProgramPage.postMessage({"pathStr":pathStr});
}else{
$("#payTimeAlert").children("p").text("请在XXXXAPP内打开").end().show(1).delay(2000).hide(1);
return;
}
setTimeout(function () { goToPaySuccess(orderIds) },3000);
}

支付请求相关代码(java):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        JSONObject json = new JSONObject();
json.put("requestTimestamp", DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
json.put("merOrderId", payCode);
json.put("notifyUrl", QmfpayUtil.notifyUrl_ZFB);
json.put("mid", QmfpayUtil.MID_ZFB);
json.put("tid", QmfpayUtil.TID_ZFB);
// 微信子商户appId,必传
// json.put("subAppId", "**************");
// 业务类型
json.put("instMid", "APPDEFAULT");
// TODO 支付总金额
json.put("totalAmount", total_amount);
// 测试先用1分
// json.put("totalAmount", "1");
// 交易类型,微信必传
json.put("tradeType", "APP");
String placeOrderUrl = QmfpayUtil.request_url_ZFB;

log.info("QmfZfbPayServiceImpl payRequestHandler json:[{}]", json);
String response = QmfpayUtil.placeOrder(placeOrderUrl,json.toString(),QmfpayUtil.appid_ZFB,QmfpayUtil.appkey_ZFB);
log.info("QmfZfbPayServiceImpl payRequestHandler response:"+response);
JSONObject result = JSONObject.fromObject(response);
String errCode = result.getString("errCode");
if ("SUCCESS".equals(errCode)) {
List<Map<String,String>> ls = new ArrayList<Map<String,String>>();
Map<String,String> map = new HashMap<>();
JSONObject appPayRequest = result.getJSONObject("appPayRequest");
if (appPayRequest != null) {
// String qrCode = appPayRequest.getString("qrCode");
map.put("appPayRequest", appPayRequest.toString());
}
map.put("flag","success");
map.put("payCode",payCode);
ls.add(map);
return BaseResultResponse.success(ls);
}

QmfpayUtil相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public static String placeOrder(String url, String entity,String appId,String appKey) throws Exception {
/* post参数,格式:JSON */

String send = send(url, entity,appId,appKey);
return send;
}

public static String send(String url, String entity,String appId,String appKey) throws Exception{
authorization = getOpenBodySig(appId, appKey, entity);
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Authorization", authorization);
StringEntity se = new StringEntity(entity,"UTF-8");
se.setContentType("application/json");
httpPost.setEntity(se);
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity1 = response.getEntity();
String resStr = null;
if(entity1 != null){
resStr = EntityUtils.toString(entity1, "UTF-8");
}
httpClient.close();
response.close();
return resStr;
}
public static String getOpenBodySig(String appId, String appKey, String body) throws Exception{
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String nonce = UUID.randomUUID().toString().replace("-", "");
byte[] data = body.getBytes("UTF-8");
System.out.println("data:\n" + body);
InputStream is = new ByteArrayInputStream(data);
String bodyDigest = testSHA256(is);
String str1_C = appId+timestamp+nonce+bodyDigest;

byte[] localSignature = hmacSHA256(str1_C.getBytes(), appKey.getBytes());

String localSignatureStr = Base64.encodeBase64String(localSignature);
System.out.println("Authorization:\n" + "OPEN-BODY-SIG AppId="+"\""+appId+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"");
return ("OPEN-BODY-SIG AppId="+"\""+appId+"\""+", Timestamp="+"\""+timestamp+"\""+", Nonce="+"\""+nonce+"\""+", Signature="+"\""+localSignatureStr+"\"");
}