支付流程

陳世流年發表於2017-01-04

【連結】支付寶整合過程詳解——執行DEMO-Daniel_s-開源
https://my.oschina.net/daniels/blog/597356

支付寶整合過程詳解——執行DEMO

前言,夢想是需要堅持的,在路上,一路前行。加油。

 

這兩天軟體需要整合支付寶了,第一次整合,過程還是挺簡單的,不過由於支付寶官方文件寫的不夠清晰,也是走了一些彎路,下面把過程寫出來分享給大家

 

一、申請移動支付許可權

首先登入【支付寶開放平臺】http://open.alipay.com/platform/home.htm,新增應用,申請移動支付許可權。申請開通支付,是需要公司檔案的,個人是不允許開始支付的。
具體細節就不再詳聊了,下面就講講如何將阿里給出的demo執行起來。

二、阿里支付DEMO

1、概述

(1)支付呼叫頁面及測試

支付寶在呼叫時,會首先看本地是不是存在支付寶客戶端,如果有的話,就直接呼叫客戶端進行支付,如果沒有,則呼叫jar包中的H5頁面支付。
所以在測試時,需要有測試兩種情境:有支付寶客戶端和沒有支付寶客戶端的情況。

(2)、客戶端與伺服器

在demo中大家可以看到,有客戶端的demo也有服務端的demo,大家可能覺得需要服務端寫好之後,客戶端才能整合,其實並不是。整個流程是這樣的:
1,APP客戶端通過SDK傳送支付請求 (客戶端處理)
2,SDK支付成功並同步返回支付結果(客戶端處理)
3,支付寶伺服器向我們的伺服器傳送支付結果字串(服務端處理)
客戶端:從上面的流程可以看出,服務端只是用來接出非同步返回的支付結果的。而支付與同步結果返回都是在客戶端可以直接看得到的。所以在整合支付寶支付介面時,主要功能是在客戶端,即便服務端沒有做整合,也是可能付款成功的。
服務端:服務端只需要新增一個功能:介面支付結果返回

下面幾張圖顯示了整個demo的執行過程,由於沒辦法在真機上錄製gif,所以只能用圖片來代替了。
初始化介面:

點選支付後,跳出確認付款介面:

點選確認付款後,跳出輸入密碼介面:

最後是支付成功介面:

在看DEMO的程式碼之前,我們需要先配置幾個變數:

2、配置幾個變數

這部分會對程式碼中用到的幾個變數的找到方法或生成方法進行講述,部分資料引自支付寶開放平臺。

(1)PID

合作者身份ID(PID)是商戶與支付寶簽約後,商戶獲得的支付寶商戶唯一識別碼。當商戶把支付寶功能接入商戶網站時會用到PID,以便讓支付寶認證商戶。
檢視PID步驟如下:
1、登入支付寶官方網站b.alipay.com
2、點選導航欄中“商家服務”

3、點選“查詢PID、Key”

(2)、APPID、APP SECRET和支付寶公鑰

在https://openhome.alipay.com/platform/createApp.htm頁面,建立一個應用

完成之後:在我的應用中是可以看得到的:

然後轉到帳戶基本資訊頁面:https://openhome.alipay.com/platform/keyManage.htm

在開放平臺金鑰欄,可以找到APPID,APP SECRET,和支付寶金鑰
這三個資料,都是在應用建立後,支付寶為我們生成好的,無法更改!

(3)、生成商戶私鑰【windows生成方法】

(有關mac的生成方法,下面會再補充)
1、下載DEMO及SDK
到文件中心,檢視移動支付對應的文件,文件地址:http://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103563&docType=1
然後,點選(SDK&DEMO下載)下載程式碼

2、得到原始私鑰
在程式碼中的DEMO/openssl/bin目錄下,有openssl.exe檔案

開啟openssl.exe
輸入

genrsa -out rsa_private_key.pem 1024

得到生成成功的結果,如下圖:

此時,我們可以在bin資料夾中看到一個檔名為rsa_private_key.pem的檔案

用記事本方式開啟它,可以看到-----BEGIN RSA PRIVATE KEY-----開頭,-----END RSA PRIVATE KEY-----結尾的沒有換行的字串,這個就是原始的私鑰。

但這段原始私鑰程式碼中是用不到的,我們需要將它轉化為PKCS8格式
3、轉換為PKCS8格式
在openssl.exe中輸入:並回車

pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

得到生成功的結果,這個結果就是PKCS8格式的私鑰,如下圖:

注意,私鑰是紅框包括的那部分,是不包含BEGIN PRIVATE KEY和END PRIVATE KEY這兩行的。

右鍵點選openssl視窗上邊邊緣,選擇編輯→標記,選中要複製的文字(如上圖),
此時繼續右鍵點選openssl視窗上邊邊緣,選擇編輯→複製,
把複製的內容粘土進一個新的記事本中,可隨便命名,只要知道這個是PKCS8格式的私鑰即可。

(4)、生成商戶私鑰【MAC生成方法】

這裡來講一下mac端如何生成使用者私鑰的,由於mac系統是自帶openssl的,所以只需要開啟終端,利用cd 命令切到任意一個想存放生成Key的資料夾下:
比如,切到下載目錄下

然後執行下面的命令來生成私鑰原始金鑰

openssl genrsa -out rsa_private_key.pem 1024

然後執行下面的命令來生成轉換的PCKS8格式的命令。

openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt

然後將生成的私鑰複製儲存起來。
從上面的命令可以看出,與windows相比,mac上需要在前面新增openssl指定執行的是openssl命令。其它命令是完全一致的。

(5)、生成使用者公鑰及網頁填充

1、生成公鑰
同樣對於windows使用者而言,直接在openssl.exe中輸入下面的命令:

rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

同樣,如果是Mac的同學,輸入的命令應該是如下:

openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

得到生成成功的結果,如下圖:

此時,我們可以在bin資料夾中看到一個檔名為rsa_public_key.pem的檔案,用記事本方式開啟它,可以看到-----BEGIN PUBLIC KEY-----開頭,
-----END PUBLIC KEY-----結尾的沒有換行的字串,這個就是公鑰。

在生成網頁以後,複製----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----之間的部分,即那段純程式碼,不要把----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----給複製進去了。中間的這部分就是公鑰。
2、網頁填充
然後到https://openhome.alipay.com/platform/keyManage.htm?keyType=partner(需要登入)中,左側找到合作伙伴金鑰欄,再到右側的RSA加密中,將公鑰貼上進去。由於,我們已經貼上進去了,所以這裡顯示檢視開發者公鑰,在沒填之前寫的是“新增開發者公鑰”

到這裡,所有的準備工作都已經結束了。下面就是配置DEMO的過程了

3、配置DEMO

在剛才下載的sdk&demo的原始碼中,開啟DEMO/客戶端demo/支付寶Android 15.0.1/alipay_demo工程
路徑如下:

在PayDemoActivity中配置幾個變數:

//PID
public static final String PARTNER = "";

在這裡填上我們上面找到的PID;

// 商戶收款賬號
public static final String SELLER = "76949XXXX@qq.com";

然後在SELLER上寫上我們支付寶的登入帳戶,即那個你申請移動支付的支付寶賬號

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

然後在RSA_PUBLIC這裡填上支付寶公鑰

// 商戶私鑰,pkcs8格式
public static final String RSA_PRIVATE = "";

最後是填上RSA_PRIVATE對應的商戶私鑰,注意是PKCS8格式的。
私鑰這部分,注意是----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----之間的部分,即那段純程式碼,不要把----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----給複製進去了。中間的這部分就是公鑰。

現在執行demo就直接可以支付了。

本文中對應的DEMO在文章底部給出。

4、程式碼講解

通過上面的配置,demo應該就直接可以執行了,但這裡所涉及的程式碼,我們再仔細看看
主要的支付與結果返回就是pay()這個函式,這裡完成了支付所需要的所有功能。程式碼如下:

public void pay(View v) {
	…………
	// 訂單資訊
	String orderInfo = getOrderInfo("測試的商品""該測試商品的詳細描述""0.01");

	// 對訂單做RSA 簽名
	String sign = sign(orderInfo);
	try {
		// 僅需對sign 做URL編碼
		sign = URLEncoder.encode(sign, "UTF-8");
	} catch (UnsupportedEncodingException e) {
		e.printStackTrace();
	}

	// 完整的符合支付寶引數規範的訂單資訊
	final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"
			+ getSignType();

	Runnable payRunnable = new Runnable() {

		@Override
		public void run() {
			// 構造PayTask 物件
			PayTask alipay = new PayTask(PayDemoActivity.this);
			// 呼叫支付介面,獲取支付結果
			String result = alipay.pay(payInfo);

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

	// 必須非同步呼叫
	Thread payThread = new Thread(payRunnable);
	payThread.start();
}


這裡總是分了四步來完成支付與結果接收。

第一步:構造定單資訊:

String orderInfo = getOrderInfo("測試的商品""該測試商品的詳細描述""0.01");

主要是這句,即在getOrderInfo()函式中完成定單資訊的構造:(這裡對getOrderInfo函式做的精減,更多欄位及意義參考原始碼)

有關paymethod的方法使用,參考:https://cshall.alipay.com/support/help_detail.htm?help_id=476935
各個欄位的意義及取值參考:http://doc.open.alipay.com/doc2/detail?treeId=59&articleId=103663&docType=1

public String getOrderInfo(String subject, String body, String price) {

	// 簽約合作者身份ID
	String orderInfo = "partner=" + "\"" + PARTNER + "\"";

	// 簽約賣家支付寶賬號
	orderInfo += "&seller_id=" + "\"" + SELLER + "\"";

	// 商戶網站唯一訂單號
	orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";

	// 商品名稱
	orderInfo += "&subject=" + "\"" + subject + "\"";

	// 商品詳情
	orderInfo += "&body=" + "\"" + body + "\"";

	// 商品金額
	orderInfo += "&total_fee=" + "\"" + price + "\"";

	// 伺服器非同步通知頁面路徑
	orderInfo += "&notify_url=" + "\"" + "http://notify.msp.hk/notify.htm""\"";

    …………
	return orderInfo;
}

這裡就是通過我們的提供的商家ID,產品資訊,價格等資訊來構造定單及回撥頁面,這裡需要非常注意的一個地方:

// 伺服器非同步通知頁面路徑
orderInfo += "&noify_url=" + "\"" + "http://notify.msp.hk/notify.htm""\"";

伺服器非同步通知頁面路徑,首先我們用支付寶支付之後,支付寶會返回給我們兩個通知,一個是同步的,就是我們點選支付後支付寶直接反饋給我們客戶端的資訊,我們可以直接拿到,根據反饋的結果可以初步判定該次交易是否成功,第二個就是伺服器非同步的通知,這個非同步的通知是支付寶的伺服器端發給我們伺服器端的資訊,我們在客戶端是直接獲取不了的,那支付寶的伺服器怎麼知道我們伺服器的路徑呢,那就是這引數的作用了,我們給支付寶伺服器一個路徑,它就會在訂單狀態改變的時候給我們伺服器端一個反饋,告訴伺服器這次交易的狀態,如果伺服器結果判定該次交易成功了,就必須返給支付寶伺服器一個success,要不伺服器會一直給我們非同步通知,因為它不知道該次交易是否完成了(一般情況下25小時內8次通知,頻率一般是2m 10m 10m 1h 2h 6h 15h),我們一般會在收到非同步通知時,對訂單的狀態進行更新。
其它的就不講了,通過看原始碼都能看得懂,比如構造訂單號啥的。

第二步:對訂單字串做RSA簽名

為什麼要簽名呢?當然是防止傳輸出錯了,這可是跟錢相關的,如果orderInfo傳輸過程中出錯了,那怎麼樣來校驗它是不是出錯了呢,只有通過簽名演算法來了。所以這裡就需要對訂單字串做簽名。
具體簽名演算法就不講了,直接應用到專案中就行,不需要理解,如果想看看怎麼實現的,裡面有對應的原始碼,可以去研究一下。

// 對訂單做RSA 簽名
String sign = sign(orderInfo);
try {
	// 僅需對sign 做URL編碼
	sign = URLEncoder.encode(sign, "UTF-8");
} catch (UnsupportedEncodingException e) {
	e.printStackTrace();
}

第三步:構造完成的請求字串

在訂單字串和簽名做完以後,就可以用他們來構造完整的請求字串了:

// 完整的符合支付寶引數規範的訂單資訊
final String payInfo = orderInfo + "&sign=\"" + sign + "\"&"
		+ getSignType();

第四步:請求與結果返回

最後是傳送請求,程式碼如下:

Runnable payRunnable = new Runnable() {

	@Override
	public void run() {
		// 構造PayTask 物件
		PayTask alipay = new PayTask(PayDemoActivity.this);
		// 呼叫支付介面,獲取支付結果
		String result = alipay.pay(payInfo);

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

// 必須非同步呼叫
Thread payThread = new Thread(payRunnable);
payThread.start();

最關鍵的部分在這裡:

PayTask alipay = new PayTask(PayDemoActivity.this);
// 呼叫支付介面,獲取支付結果
String result = alipay.pay(payInfo);

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

在String result = alipay.pay(payInfo);中,就直接獲得了支付結果;
然後通過handler將結果傳送出去。
這就是同步的方式獲取支付結果的方式。
好了,有關支付寶對接的方法全部都在這了。至於getOrderInfo函式裡,使用的呼叫銀行卡支付,我覺得也沒啥用,在我們程式裡也沒接上。

 

本文所使用的DEMO原始碼下載地址:http://download.csdn.net/detail/harvic880925/9261363

 

如果本文有幫到你,記得加關注哦。

請大家尊重原創者版權,轉載請標明出處:http://blog.csdn.net/harvic880925/article/details/49779061  謝謝。

 

相關文章