JAVA實現的支付寶掃描二維碼支付

前期醞釀準備

最近項目中要上線支付功能、前段時間剛開發完微信的掃碼支付、不得不說微信開發團隊的文檔真是一個爛。但總算是對照着API把功能交付上線了。

前幾天公司申請下來了企業支付寶,得空所以也把支付寶的掃碼支付給集成進去。這裏又不得不說,是支付寶的文檔寫的不咋地還是自己沒有仔細閱讀,總之翻遍了API最終在沙箱裏面運行成功(切記、認真讀文檔,不然各種BUG等着你)

什麼是掃碼支付?

掃碼支付,指用戶打開支付寶錢包中的“掃一掃”功能,掃描商家展示在某收銀場景下的二維碼並進行支付的模式。該模式適用於線下實體店支付、面對面支付等場景。

業務流程:

使用步驟:

用戶登陸支付寶錢包,點擊首頁“付款-掃碼付”,進入掃一掃界面; 收銀員在商家收銀系統操作生成支付寶訂單,用戶確認支付金額,並生成二維碼; 用戶使用錢包的“掃碼付”,掃收銀員提供的二維碼,確認支付; 用戶付款後商家收銀系統會拿到支付成功或者失敗的結果。

具體產品介紹

如何快速接入?

前面的大家可以大體瞭解一下

開放平臺服務端SDK下載地址(這裏選擇JAVA版本)、點擊下載、裏面有詳細的API測試方法。

如何集成到項目中去?

下載DEMO解壓、仔細閱讀裏面的readme.txt文件、裏面有詳細的項目結構。

參數配置zfbinfo.properties(沙箱環境網關參數不同)

# 支付寶網關名、partnerId和appId
#open_api_domain = https://openapi.alipay.com/gateway.do
#支付寶沙箱環境
open_api_domain = https://openapi.alipaydev.com/gateway.do
mcloud_api_domain = http://mcloudmonitor.com/gateway.do
pid = 此處請填寫你的PID
appid = 此處請填寫你當面付的APPID

# RSA私鑰、公鑰和支付寶公鑰
private_key = 此處請填寫你的商戶私鑰且轉PKCS8格式
public_key = 此處請填寫你的商戶公鑰
alipay_public_key = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB

# 當面付最大查詢次數和查詢間隔(毫秒)
max_query_retry = 5
query_duration = 5000

# 當面付最大撤銷次數和撤銷間隔(毫秒)
max_cancel_retry = 3
cancel_duration = 2000

# 交易保障線程第一次調度延遲和調度間隔(秒)
heartbeat_delay = 5
heartbeat_duration = 900

RSA私鑰、公鑰和支付寶公鑰 獲取方法。 生成與配置密鑰

這裏我選擇的是方式一,使用支付寶提供的一鍵生成工具(內附使用說明)。

如果是JAVA程序public_key參數對應rsa_private_key_pkcs8.pem文件裏面的內容, public_key參數對用rsa_public_key.pem文件裏面的內容。然後把公鑰複製到沙箱中的RSA(SHA1)密鑰中生成支付寶公鑰、對應的是alipay_public_key參數。

如何生成二維碼訂單?

然後你就可以運行Main.java 中的額main方法進行測試了,運行結果如下:

[acts_pay]|2016-11-04 15:23:35:530|Configs{支付寶openapi網關: https://openapi.alipaydev.com/gateway.do
, 支付寶mcloudapi網關域名: http://mcloudmonitor.com/gateway.do
, pid: 2088102169116018
, appid: 2016073000123724
, 商戶RSA私鑰: MIICdw******rLZis=
, 商戶RSA公鑰: MIGfMA******IDAQAB
, 支付寶RSA公鑰: MIGfMA******IDAQAB
, 查詢重試次數: 5
, 查詢間隔(毫秒): 5000
, 撤銷嘗試次數: 3
, 撤銷重試間隔(毫秒): 2000
, 交易保障調度延遲(秒): 5
, 交易保障調度間隔(秒): 900
}
[acts_pay]|2016-11-04 15:23:35:719|trade.precreate bizContent:{"out_trade_no":"tradeprecreate14782442155652020005","seller_id":"","total_amount":"0.01","undiscountable_amount":"0","subject":"xxx品牌xxx門店當面付掃碼消費","body":"購買商品3件共20.00元","goods_detail":[{"goods_id":"goods_id001","goods_name":"xxx小麪包","quantity":1,"price":"10"},{"goods_id":"goods_id002","goods_name":"xxx牙刷","quantity":2,"price":"5"}],"operator_id":"test_operator_id","store_id":"test_store_id","extend_params":{"sys_service_provider_id":"2088100200300400500"}}
[acts_pay]|2016-11-04 15:23:37:875|{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"tradeprecreate14782442155652020005","qr_code":"https:\/\/qr.alipay.com\/bax03938xgzra2b5pijd00d2"},"sign":"LA2d5txq43c3t12sCsNEEGvu3plXUrqrd/uyzOy4HIMM5eRkWXaFkL+wqVNcYX/Jfn6no72yqiAUvYAivaWZkXZA3UxTRYlW+0EwZ96HrpnjFCK+QGOSDZuoiA2AyQlFgM/cQwdgTFGI+R2X9QZWxft1z3zYVG1uRGEZXed5RPQ="}
[acts_pay]|2016-11-04 15:23:37:878|支付寶預下單成功: )
[acts_pay]|2016-11-04 15:23:37:878|code:10000, msg:Success
[acts_pay]|2016-11-04 15:23:37:878|body:{"alipay_trade_precreate_response":{"code":"10000","msg":"Success","out_trade_no":"tradeprecreate14782442155652020005","qr_code":"https:\/\/qr.alipay.com\/bax03938xgzra2b5pijd00d2"},"sign":"LA2d5txq43c3t12sCsNEEGvu3plXUrqrd/uyzOy4HIMM5eRkWXaFkL+wqVNcYX/Jfn6no72yqiAUvYAivaWZkXZA3UxTRYlW+0EwZ96HrpnjFCK+QGOSDZuoiA2AyQlFgM/cQwdgTFGI+R2X9QZWxft1z3zYVG1uRGEZXed5RPQ="}
[acts_pay]|2016-11-04 15:23:37:878|filePath:D:\qr.png

最後下載沙箱錢包就可以完成手機支付了。

下載地址

如何實現異步通知?

相關參數說明

用戶會用手機掃碼給支付寶付款,然後支付寶收到之後會發送一條支付成功的消息給我們設置的notify_url

import java.io.BufferedOutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.acts.web.acc.service.IWeixinPayService;
import com.acts.web.common.utils.LogUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.demo.trade.config.Configs;
@Controller@RequestMapping(value = "alipay")
public class AliPayController {
     //初始化參數 不然signVerified會驗證失敗
     static {
            Configs.init("zfbinfo.properties");
     }
   /**
     * 支付寶支付回調
     * @param request
     * @param response
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value = "pay",method = RequestMethod.POST)
    public void alipay_notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        LogUtil.info("支付寶付款異步通知!");
        String  message = "success";
        Map<String, String> params = new HashMap<String, String>();
         // 取出所有參數是爲了驗證簽名
        Enumeration<String> parameterNames = request.getParameterNames();

                while (parameterNames.hasMoreElements()) {
            String parameterName = parameterNames.nextElement();
            params.put(parameterName, request.getParameter(parameterName));
        }        //驗證簽名
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(params, Configs.getAlipayPublicKey(), "UTF-8");
        } catch (AlipayApiException e) {
            e.printStackTrace();
            message =  "failed";
        }        if (signVerified) {
            LogUtil.info("驗證簽名成功!");
            // 若參數中的appid和填入的appid不相同,則爲異常通知
            if (!Configs.getAppid().equals(params.get("app_id"))) {
                LogUtil.info("與付款時的appid不同,此爲異常通知,應忽略!");
                message =  "failed";
            }else{
                String outtradeno = params.get("out_trade_no");
                LogUtil.info(outtradeno + "號訂單回調通知。");                
                //在數據庫中查找訂單號對應的訂單,並將其金額與數據庫中的金額對比,若對不上,也爲異常通知
                
                String status = params.get("trade_status");
                if (status.equals("WAIT_BUYER_PAY")) {
                 // 如果狀態是正在等待用戶付款
                    
                } else if (status.equals("TRADE_CLOSED")) {
                 // 如果狀態是未付款交易超時關閉,或支付完成後全額退款
                    
                } else if (status.equals("TRADE_SUCCESS") || status.equals("TRADE_FINISHED")) {
                 // 如果狀態是已經支付成功
                    //成功 更新狀態
                } else {
                    weixinpayBack.updateAccOrder(outtradeno);
                }
                LogUtil.info(outtradeno + "訂單的狀態已經修改爲" + status);
            }
        } else { // 如果驗證簽名沒有通過
            message =  "failed";
            LogUtil.info("驗證簽名失敗!");
        }
        BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
        out.write(message.getBytes());
        out.flush();
        out.close();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章