1. 程式人生 > >一步一步帶你完成支付寶支付功能的整合(超詳細)

一步一步帶你完成支付寶支付功能的整合(超詳細)

首先說說筆者的整合經歷,一開始整合時,像往常一樣百度了一下整合的方法,然後出來一大堆結果,以為應該會很簡單,然而事實卻並非如此。網上的整合方法很多都是舊版本的整合,現在支付寶已經對sdk以及demo進行了更新,雖說和舊版差別不是很大,不過對於不瞭解整個流程的開發人員來說,確實一個極大的痛苦;當然在整合過程中遇到各種各樣的問題,甚至對一些流程根本就不瞭解,當然這跟筆者的水平有一定關係。最後給大家的建議是,不要心急,一步一步跟著流程走,其實整合是很簡單的。本文介紹的是沙箱環境下的整合,到時候只需要在簽約後將程式碼中的各種ID改為簽約後的即可(整合app支付需要和支付寶進行簽約)。筆者將整個流程分為兩大部分,第一個是前期配置,第二個是開始整合。

前期配置

首先,進入開放平臺後,我們點選應用

這裡寫圖片描述


接著我們點選沙箱環境下的沙箱應用

這裡寫圖片描述

在這邊我們能看到支付寶給我們進行測試的應用ID和測試賬號等,我們點選設定RSA2金鑰(這邊我已經設定好了,RSA(SHA1)可以不用設定)這裡寫圖片描述


那麼如何設定金鑰呢->檢視金鑰生成方法 進入之後我們下載對應版本後,執行“RSA簽名驗籤工具.bat”(WINDOWS)或“RSA簽名驗籤工具.command”(MAC_OSX),然後如下圖勾選,點選生成金鑰(注意儲存)

這裡寫圖片描述


然後我們將這邊生成的應用公鑰複製並貼上到剛剛的需要設定應用公鑰的地方,設定完成後會生成一個對應的支付寶公鑰

這裡寫圖片描述


好了,這邊需要特別注意: ”應用公鑰、應用私鑰、支付寶公鑰”這三個不要混淆、不要混淆、不要混淆

。好了,第一部分的配置也差不多到這邊了。

開始整合

流程

我們先來看下整合的整個流程

這裡寫圖片描述

簡單介紹一下整個流程(圖中虛線標識商戶鏈路,實線標識支付寶鏈路。)

步驟1:使用者點選進行付款
步驟2:客戶端從商戶的服務端獲取簽名後的訂單訊息
步驟3:(商戶將訂單資訊加簽)返回簽名後的訂單資訊
步驟4、5、6、7、8:這幾個步驟是我們點選確認支付後自動執行的,不需要我們執行(其中第8步返回最終的支付結果(即同步通知))
步驟9、10:商戶客戶端將同步通知的支付結果傳送至支付寶服務端並返回最終結果(這兩個步驟可以不執行,因為我們後面還有步驟12的非同步通知)
步驟12、13:根據我們設定的非同步通知地址

(下面會介紹)獲取支付結果



好了,流程差不多就是這樣,接下來我們結合程式碼開始實戰。

編碼

我們下載支付寶提供的SDK和DEMO(更新時間:2017/05/11) 解壓匯入Android Studio後我們開啟PayDemoActivity

這裡寫圖片描述
如果我們只想進行支付功能的話,只要設定上圖的APPID和RSA2_PRIVATE即可。當然,這是沙箱環境,我們需要在onCreate下新增這一句:

EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);

位置如下:

這裡寫圖片描述

當然整個支付的精華莫過於此處(程式碼已給出註釋)

  boolean rsa2 = (RSA2_PRIVATE.length() > 0);
        Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, rsa2,"英語課程(20次)",20);//設定訂單詳情和價格
        String orderParam = OrderInfoUtil2_0.buildOrderParam(params);

        String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;
        String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);//本地加簽
        final String orderInfo = orderParam + "&" + sign;//加簽後的訂單資訊

        Runnable payRunnable = new Runnable() {

            @Override
            public void run() {
                PayTask alipay = new PayTask(PayDemoActivity.this);//呼叫支付介面
                Map<String, String> result = alipay.payV2(orderInfo, true);//支付結果
                Log.i("msp", result.toString());

                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };

        Thread payThread = new Thread(payRunnable);
        payThread.start();



好了,完成如上操作即可通過客戶端發起支付了。是不是發現這跟筆者剛剛介紹的服務端沒有半點關係?其實,我們只是將加簽驗籤放在客戶端進行,這是非常不安全的。所以,下面開始介紹服務端的任務。


現在客戶端中大部分程式碼都可以去掉,因為將這些過程都被放在了放在了服務端,比如下面的這些引數

這裡寫圖片描述

我們所需要的程式碼,只剩下一下兩部分,即呼叫支付介面的程式碼和Handle部分(case INFO為新增的程式碼,下面會用到)

    Runnable payRunnable = new Runnable() {

            @Override
            public void run() {
                PayTask alipay = new PayTask(PayDetailActivity.this);
                Map<String, String> result = alipay.payV2(orderInfo, true);
                Log.i("msp", result.toString());

                Message msg = new Message();
                msg.what = SDK_PAY_FLAG;
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };
@SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @SuppressWarnings("unused")
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SDK_PAY_FLAG: {
                    @SuppressWarnings("unchecked")
                    PayResult payResult = new PayResult((Map<String, String>) msg.obj);
                    /**
                     對於支付結果,請商戶依賴服務端的非同步通知結果。同步通知結果,僅作為支付結束的通知。
                     */
                    String resultInfo = payResult.getResult();// 同步返回需要驗證的資訊
                    String resultStatus = payResult.getResultStatus();
                    // 判斷resultStatus 為9000則代表支付成功
                    if (TextUtils.equals(resultStatus, "9000")) {
                        // 該筆訂單是否真實支付成功,需要依賴服務端的非同步通知。
                        Toast.makeText(PayDetailActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
                        flag=true;
                        btn_pay.setVisibility(View.GONE);
                        detail_state.setText("已支付");
                    } else {
                        // 該筆訂單真實的支付結果,需要依賴服務端的非同步通知。
                        Toast.makeText(PayDetailActivity.this, "支付失敗", Toast.LENGTH_SHORT).show();
                    }
                    break;
                }
                case INFO: {
                    orderInfo = (String) msg.obj;
                    EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
                    PayThread p = new PayThread();
                    p.start();

                    break;
                }
                default:
                    break;
            }
        };
    };


將Runnable修改如下:

    class PayThread extends Thread{

        public void run(){
            //EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
            PayTask alipay = new PayTask(PayDetailActivity.this);
            Map<String, String> result = alipay.payV2(orderInfo, true);
            Log.i("msp", result.toString());

            Message msg = new Message();
            msg.what = SDK_PAY_FLAG;
            msg.obj = result;
            mHandler.sendMessage(msg);

        }
    }



然後在客戶端新建一個執行緒(用於從伺服器獲取加簽的訂單詳情)

class  accessThread2 extends Thread{

        @Override
        public void run() {
            Message msg1=mHandler.obtainMessage();
            msg1.what=INFO;
            msg1.obj= GetPostUtil.sendPost("http://10.143.224.18:8080/HttpServer/Myserver","name=qwe123");
            mHandler.sendMessage(msg1);
           // super.run();
        }

    }

總結一下客戶端的工作,先啟動執行緒從伺服器獲取到加簽後的訂單詳情,賦給msg1.obj;然後在Handle執行case INFO 部分的程式碼,接著呼叫PayTask 介面,並將支付結果賦給msg.obj,最後執行case SDK_PAY_FLAG這部分的程式碼。好了,客戶端相比之前就整潔清爽多了。

接下來是服務端,我們在工程中匯入服務端的SDK然後新建一個類用於獲取加簽後的訂單詳情(程式碼已給出註釋):

public class GetSign {
    /** 支付寶支付業務:入參app_id */
    public static final String APPID = ""

    /** 支付寶閘道器*/
    public static final String GATE = "https://openapi.alipay.com/gateway.do";

    /** 支付寶私鑰*/
    public static final String APP_PRIVATE_KEY = "";

    /** 支付寶公鑰 */
    public static final String ALIPAY_PUBLIC_KEY = "";

    /** 編碼方式 */
    public static final String CHARSET = "utf-8";

    public static AlipayTradeAppPayResponse response;

    public static String getsign(){
        AlipayClient alipayClient = new DefaultAlipayClient(GATE, 
                APPID, 
                APP_PRIVATE_KEY, 
                "json", 
                CHARSET, 
                ALIPAY_PUBLIC_KEY, 
                "RSA2");

        //例項化具體API對應的request類,類名稱和介面名稱對應,當前呼叫介面名稱:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已經封裝掉了公共引數,這裡只需要傳入業務引數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

        model.setBody("我是測試資料");
        model.setSubject("App支付測試Java");
        model.setOutTradeNo("100342312764512");
        model.setTimeoutExpress("30m");
        model.setTotalAmount("0.01");
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl("商戶外網可以訪問的非同步地址");
        try {
                //這裡和普通的介面呼叫不同,使用的是sdkExecute
                response = alipayClient.sdkExecute(request);
                System.out.println(response.getBody());//就是orderString 可以直接給客戶端請求,無需再做處理。
            } catch (AlipayApiException e) {
                e.printStackTrace();
        }
        return response.getBody();
    }

以上程式碼就是加簽的過程。其中response.getBody()即為加簽過的訂單詳情。這邊需要注意的是,訂單資料格式不能隨意亂寫,比如OutTradeNo只能為數字、英文或下劃線;此外,OutTradeNo不可以重複,若重複則會出現系統繁忙等錯誤。程式碼中各請求引數說明點這

再接下來,就是我們的非同步通知了。在上一步的請求引數中,request.setNotifyUrl就是支付寶通知我們的地址。什麼時候會觸發呢?交易成功、交易建立、交易關閉、支付成功。由支付寶主動發起。來看一下回調部分的程式碼:

public String aliPay_notify(Map requestParams){
        System.out.println("支付寶支付結果通知"+requestParams.toString());
        //獲取支付寶POST過來反饋資訊
        Map<String,String> params = new HashMap<String,String>();

        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
          }
          //亂碼解決,這段程式碼在出現亂碼時使用。
          //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
          params.put(name, valueStr);
         }
        //切記alipaypublickey是支付寶的公鑰,請去open.alipay.com對應應用下檢視。
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        try {
            boolean flag = AlipaySignature.rsaCheckV1(params, alipay_public_key, charset, "RSA2");
            if(flag){
                if("TRADE_SUCCESS".equals(params.get("trade_status"))){
                    //付款金額
                    String amount = params.get("buyer_pay_amount");
                    //商戶訂單號
                    String out_trade_no = params.get("out_trade_no");
                    //支付寶交易號
                    String trade_no = params.get("trade_no");
                    //附加資料
                    String passback_params = URLDecoder.decode(params.get("passback_params"));

                }
            }
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    return "success";
    }

在if(flag)中,我們需要做如下判斷:
**1、商戶需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單號
2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單建立時的金額)
3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)
4、驗證app_id是否為該商戶本身。**
在上述驗證通過後商戶必須根據支付寶不同型別的業務通知,正確的進行不同的業務處理,並且過濾重複的通知結果資料。在支付寶的業務通知中,只有交易通知狀態為TRADE_SUCCESS或TRADE_FINISHED時,支付寶才會認定為買家付款成功。

好了,整個開發流程大概就這樣。如果要換為正式環境下的話只需要將引數修改為簽約後支付寶提供的引數,切記去掉onCreate下的這句程式碼:

EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);

相關推薦

完成支付支付功能整合詳細

首先說說筆者的整合經歷,一開始整合時,像往常一樣百度了一下整合的方法,然後出來一大堆結果,以為應該會很簡單,然而事實卻並非如此。網上的整合方法很多都是舊版本的整合,現在支付寶已經對sdk以及demo進行了更新,雖說和舊版差別不是很大,不過對於不瞭解整個流程的開發

實現自定義圓形進度條詳解

        每次看到別人做出炫酷的都會想,這個應該很難吧?這是心理上先入為主的就這麼認為了,其實實現很簡單,下面一步一步的詳細剖析自定義圓形進度條的步驟。 首先看效果圖: 篇幅有點長,耐心看完肯定get新技能。 看每一個檢視都包含了些什麼。 最

瞭解微服務架構和設計多圖

![南嶽衡陽(封面)](https://pcloud-1258173945.cos.ap-guangzhou.myqcloud.com/uPic/b670310e76c4381777a7eb437048e9d8的副本.jpg) 最近幾年微服務很火,大家都在建設微服務,如果不懂點微服務相關的技術,都不好意

okhttp原始碼分析——基本流程詳細

1.okhttp原始碼分析(一)——基本流程(超詳細) 2.okhttp原始碼分析(二)——RetryAndFollowUpInterceptor過濾器 3.okhttp原始碼分析(三)——CacheInterceptor過濾器 4.okhttp原始碼分析(四)——Conn

手把手打造一個 Android 熱修復框架上篇

本文來自網易雲社群作者:王晨彥前言熱修復和外掛化是目前 Android 領域很火熱的兩門技術,也是 Android 開發工程師必備的技能。目前比較流行的熱修復方案有微信的 Tinker,手淘的 Sophix,美團的 Robust,以及 QQ 空間熱修復方案。QQ 空間熱修復方

《設計模式》之一文理解策略模式、原型模式深淺拷貝、觀察者模式、裝飾模式

原型模式 什麼是原型模式 原型模式是一個建立型的模式。原型二字表明瞭該模式應該有一個樣板例項,使用者從這個樣板物件中複製一個內部屬性一致的物件,這個過程也就是我們稱的“克隆”。被複制的例項就是我們所稱的“原型”,這個原型是可定製的。原型模式多用於建立複雜

沒有基礎小編,用python畫機器貓有程式碼

小編帶你玩python 沒有基礎小編帶你,用python畫機器貓。只需要python3和小編的程式碼即可。python3小編送,程式碼文章有,現在就差個你了。 執行不了的找小編,小編包教會你。 重要的事情說三遍: python3小編送,程式碼文章有。 python3小編送,程式碼文章有。 python

學習筆記-5安裝 Github中文漢化外掛詳細

今天看視訊的時候聽老師說以後面試面試官會問你你在github有上傳開源專案嗎,訪問量是多少。然後我看完視訊後馬上去弄一個github帳號,然後發現github基本是英文。。。。。在百度上查了一下後發現有一個好用基於chrome的外掛,然後安裝,途中碰到了一些問題,於是寫下這篇

手把手教使用markdown編輯器詳細

如何使用markdown編輯器來寫部落格 之前使用markdown格式編寫文件,但是都是一些零零散散的格式,今天有點空閒時間來總結一下markdown的格式,便於自己以後書寫marikdown文件。 目錄 用[TOC]來生成目錄: code如下:

支付第三方介面對接JAVA語言

alipay 的幾個核心功能檔案: ====================================================================================================== AlipayFunctio

仿支付賬單的效果listview分組

最近公司要 新增類似支付寶賬單 的listview分組頂部懸浮 的效果,其實總的實現思想很簡單。由於 後臺給的資料 的不同 ,可能處理的方式也不一樣。 接下來咱們就一起來探討研究一下。 首先  ,自定義ListView ,建立 UpLoadPinnedHeaderListV

絕密資料洩露!支付系統架構參考架構圖

來源:Talkwithtrend ID:Talkwithtrend 在此收集的支付寶的系統架構圖包含:清算、客服、處理、資金、財務等等,由於資料年限限制,僅供參考,但基本架構相信還是變化不大的。作為支付行業的龍頭,架構系統值得學習!

在瀑布下用火焰烤餅:三步法助快速定位網站效能問題詳細

> DevUI是一支兼具設計視角和工程視角的團隊,服務於華為雲[DevCloud](https://www.huaweicloud.com/devcloud/)平臺和華為內部數箇中後臺系統,服務於設計師和前端工程師。 > 官方網站:[devui.design](https://devui.desi

瞭解微信/支付支付的相關概念

今天寫了一篇非技術文,需求來源於老大的老大,老老大。 這偏文章用以說明微信/支付寶相關引數之間錯綜複雜的關係,所有資料來自微信/支付寶官網,以及相關銀聯給的微信/支付寶對接文件。 嘿嘿,如果同行的小夥伴,也有這個疑惑,希望本篇文章幫你解惑。 ## 微信 名詞解釋: - **appid**:公眾號、小

註冊會計師用Python進行探索性風險分析

專 欄 ❈Rho,Python中文社群專欄作者,現居深圳。知乎專欄地址:https://zhuanlan.zhihu.com/BecomingaDataScientist❈ 專案介紹 所謂探索性資料分析(Exploratory Data Analysis,以下簡稱EDA),是指對已有的資料(特別是調查

盤沙拉”入門Dagger2引數怎麼辦

系列文章 如果被依賴類的建構函式帶有引數,要把這個引數的型別也管理起來 現在要在Salad裡新加入一個水果Orange,但是Orange的建構函式裡需要傳入一個Knife來

盤沙拉”入門Dagger2之@Qualifier

系列文章 當一個類有兩個建構函式時,使用Dagger2時,如何獲取指定建構函式new出來的物件 或者說雖然這有一個建構函式,但是這個建構函式new出了兩個具有不同屬性的

篇部落格輕鬆應對java面試中的多執行緒與高併發

1. Java執行緒的建立方式 (1)繼承thread類 thread類本質是實現了runnable介面的一個例項,代表執行緒的一個例項。啟動執行緒的方式start方法。start是一個本地方法,執行後,執行run方法的程式碼。       (2)實現runnable

接入支付支付接口():發起支付請求

支付寶一、前言在接入支付寶接口之前,需要在支付寶官網進行應用註冊和實名認證,地址不再貼出。在此,貼出支付寶開放平臺文檔地址:https://docs.open.alipay.com/58/103585/在這個地址中,詳細介紹了如何接入支付寶接口二、發起請求支付寶的簽名方式等不做詳細介紹,在開發文檔中有詳細說明

步步教創建自己的數字貨幣代幣進行ICO

允許 總量 ted exe init allow transfer ner 定義 本文從技術角度詳細介紹如何基於以太坊ERC20創建代幣的流程. 寫在前面 本文所講的代幣是使用以太坊智能合約創建,閱讀本文前,你應該對以太坊、智能合約有所了解,如果你還不了解,建議你先看以太坊