說下業務場景, 公司之前的支付寶業務是PHP對接的現在改成 Java ,在接入出現不同的問題。之前PHP用的是老的移動支付, 現在Java的新接口 , 需要簽約。 跟運維溝通好幾次, 說簽約不了, 只能用老的移動支付方式;
1.1 移動支付文檔
https://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103563&docType=1
1.2 基本配置
按照支付寶的流程 。 生成 用戶的私鑰和公鑰對 。 把 開發者的公約上傳 到支付寶, 支付寶會生成一對, 支付寶私鑰公鑰對。 意思就是 兩套私鑰公鑰 ; 怎么使用呢?
用戶加簽 的時候是用用戶的私鑰, 解密的時候是用 支付寶的 公鑰 。
支付寶解密的時候用 用戶的 公約, 加密的時候用支付寶 的私鑰, 雙向的; 這個邏輯必須要明白。
說下我這里的難題:因為以前的開發者公鑰和私鑰都是 PHP的, Java接入需要 使用 pks 8格式, 這里怎么解決了? 只用一步 , 把 PHP開發者的私鑰 ---》轉換成 Java的 的pks 8 私鑰、 其他都不用管了。(因為涉及到了兩種 語言的兼顧)。
1.3 Java 服務端需要考慮哪寫?
第一個: 預購單簽名 。 用戶下單的時候 , 對 參數校驗, 用開發者私鑰, 生成簽名字符串 給 APP。 APP 去完成支付、
第二個: 支付回調、 支付完成了, 支付寶會異步通知商戶系統,我們要定義一個接口去處理參數。
第三個:可能加個查詢接口 ,查詢訂單等。
第四個:支付寶退款。
第五個:支付寶退款回調。
=============================================
1.4 例子:
1. 下預購單:
public String getPayInfo(PayRequest request) { // 簽約合作者身份ID String orderInfo = "partner=" + "\"" + AliPayConstants.PARTER_ID + "\""; // 簽約賣家支付寶賬號 orderInfo += "&seller_id=" + "\"" + AliPayConstants.APP_ACCOUNT + "\""; // 商戶網站唯一訂單號 orderInfo += "&out_trade_no=" + "\"" + request.getOutTradeNo() + "\""; // 商品名稱 orderInfo += "&subject=" + "\"" + request.getSubject() + "\""; // 商品詳情 orderInfo += "&body=" + "\"" + request.getBody() + "\""; // 商品金額 orderInfo += "&total_fee=" + "\"" + new BigDecimal(request.getTotalFee()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP) + "\""; // 服務器異步通知頁面路徑 orderInfo += "¬ify_url=" + "\"" + "" + "\""; // 服務接口名稱, 固定值 orderInfo += "&service=\"mobile.securitypay.pay\""; // 支付類型, 固定值 orderInfo += "&payment_type=\"1\""; // 參數編碼, 固定值 orderInfo += "&_input_charset=\"utf-8\""; // 設置未付款交易的超時時間 // 默認30分鍾,一旦超時,該筆交易就會自動被關閉。 // 取值范圍:1m~15d。 // m-分鍾,h-小時,d-天,1c-當天(無論交易何時創建,都在0點關閉)。 // 該參數數值不接受小數點,如1.5h,可轉換為90m。 orderInfo += "&it_b_pay=\"30m\""; // extern_token為經過快登授權獲取到的alipay_open_id,帶上此參數用戶將使用授權的賬戶進行支付 // orderInfo += "&extern_token=" + "\"" + extern_token + "\""; // 支付寶處理完請求后,當前頁面跳轉到商戶指定頁面的路徑,可空 orderInfo += "&return_url=\"m.alipay.com\""; // 調用銀行卡支付,需配置此參數,參與簽名, 固定值 (需要簽約《無線銀行卡快捷支付》才能使用) // orderInfo += "&paymethod=\"expressGateway\""; /** * 特別注意,這里的簽名邏輯需要放在服務端,切勿將私鑰泄露在代碼中! */ // sign = AlipaySignature.rsaSign(result, // Constants.Ali_QM.ALI_APP_PRIVATE_KEY, Constants.Ali_QM.ALI_UNICODE); String sign = SignUtils.sign(orderInfo, AliPayConstants.PRIVATE_KEY); try { sign = URLEncoder.encode(sign, "UTF-8"); } catch (UnsupportedEncodingException e) { LOGGER.error(e.getMessage()); } final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + "sign_type=\"RSA\""; LOGGER.info("返回信息:" + payInfo); return payInfo; }
2. 支付寶支付完成回調: 傳過來一個 request, 獲取里面的參數, 如果校驗正確, 返回 個給 支付寶 一個字符串 success。 告訴 支付寶 我們已經成功接收到回調了
public String aliCallback(HttpServletRequest request) { LOGGER.info("正在回調"); PaymentDetail detail = new PaymentDetail(); detail.setorderOutId(request.getParameter("out_trade_no")); detail.setTradeNo(request.getParameter("trade_no")); detail.setUserId(request.getParameter("buyer_logon_id")); // 設置為已回調 detail.setCallbackStatus(CallbackType.callable.getStatusValue()); boolean isPaySuccess = false; if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) { Enumeration<?> pNames = request.getParameterNames(); Map<String, String> param = new HashMap<String, String>(); try { while (pNames.hasMoreElements()) { String pName = (String) pNames.nextElement(); param.put(pName, request.getParameter(pName)); } boolean signVerified = AlipaySignature.rsaCheckV1(param, AliPayConstants.PUBLIC_KEY, AliPayConstants.CHARSET); // 校驗簽名是否正確 if (signVerified) { // 按照支付結果異步通知中的描述,對支付結果中的業務內容進行1\2\3\4二次校驗,校驗成功后在response中返回success,校驗失敗返回failure LOGGER.info("訂單支付成功:" + JSON.toJSONString(param)); // 設置訂單狀態為支付成功 detail.setStatus(PayStatus.paySuccess.getStatusValue()); isPaySuccess = true; } } catch (Exception e) { LOGGER.error("回調異常"); throw new TradeException(MessageCode.PayBackError); } } Integer callBackStatus = isPaySuccess ? PaymentConstant.PayCallBackStatus.SUCCESS : PaymentConstant.PayCallBackStatus.FAILURE; tradeService.dealWithPayCallBack(request.getParameter("out_trade_no"), request.getParameter("trade_no"), callBackStatus, PaymentConstant.TradeAction.ALI_ACCOUNT); paymentDetailsMapper.updatePayment(detail); return "success";