APP接入支付寶支付完整流程及踩坑記錄(含服務(wù)端)

本篇主要講解APP接入支付寶支付完整流程,包含服務(wù)端,內(nèi)容稍長

要接入支付寶支付杯巨,需要將APP在支付寶平臺創(chuàng)建應(yīng)用,提交審核旦棉,并進(jìn)行商戶簽約以獲得支付能力

詳細(xì)參閱官方文檔https://docs.open.alipay.com/399/106917/


應(yīng)用創(chuàng)建及使用流程

下面主要從技術(shù)角度去講解下流程


開發(fā)設(shè)置

開發(fā)設(shè)置中一定要配置好APP相關(guān)信息齿风,支付寶網(wǎng)關(guān)地址是固定的,授權(quán)回調(diào)地址即是你成功支付后的回調(diào)地址绑洛,對于支付結(jié)果聂宾,請商戶依賴服務(wù)端的異步通知結(jié)果同步通知結(jié)果诊笤,僅作為支付結(jié)束的通知系谐,支付寶網(wǎng)關(guān)地址如果不配置,會造成即使你的授權(quán)回調(diào)地址正確讨跟,支付服務(wù)端也收不到任何的支付通知的信息(之前沒注意這個問題纪他,郁悶了倆小時)

支付寶平臺為開發(fā)者們提供個很好的沙箱測試工具,即使應(yīng)用沒有提交上線晾匠,也可以在沙箱環(huán)境中模擬一個APP去接入支付茶袒,并配置相關(guān)參數(shù),如密鑰凉馆,應(yīng)用網(wǎng)關(guān)薪寓,回調(diào)地址等等,這樣既能很好的測試程序是否能夠正常支付澜共,同時減少提交上線審核后出現(xiàn)的一些問題


沙箱應(yīng)用
沙箱賬號向叉,想充多少就充值多少,用來支付測試


沙箱工具嗦董,主要用來測試支付



程序流程

主要內(nèi)容:首先是客戶端SDK請求商戶服務(wù)端母谎,獲取簽名后的訂單信息,再去調(diào)用支付接口京革,發(fā)起支付請求(提示:如果是支付APP沙箱測試奇唤,需要在onCreate方法中加入EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX); )


加入此代碼表示APP處于沙箱環(huán)境

先上圖再上代碼




try {

String url = "http://xxx.com/AliPay?user_id=" + account + "&totalFee=" + total_fee;

byte[] buf = Util.httpGet(url);

if (buf != null && buf.length > 0) {

orderInfo = new String(buf);

} else {

Log.d("PAY_GET", "服務(wù)器請求錯誤");

Toast.makeText(MainActivity.this, "服務(wù)器請求錯誤", Toast.LENGTH_SHORT).show();

}

} catch (Exception e) {

Log.e("PAY_GET", "異常:" + e.getMessage());

}

Runnable payRunnable = new Runnable() {

@Override

public void run() {

PayTask alipay = new PayTask(MainActivity.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();

}

完成支付后返回通知支付結(jié)果


private Handler mHandler = new Handler() {

@Override

@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);

/**

* 對于支付結(jié)果,請商戶依賴服務(wù)端的異步通知結(jié)果匹摇。同步通知結(jié)果咬扇,僅作為支付結(jié)束的通知。

*/

String resultInfo = payResult.getResult();// 同步返回需要驗證的信息

String resultStatus = payResult.getResultStatus();

// 判斷resultStatus 為9000則代表支付成功

if (TextUtils.equals(resultStatus, "9000")) {

// 該筆訂單是否真實支付成功廊勃,需要依賴服務(wù)端的異步通知懈贺。

Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();

UnityPlayer.UnitySendMessage("PayMar", "IpayCallback",Integer.toString(MainActivity.number));

} else {

// 該筆訂單真實的支付結(jié)果,需要依賴服務(wù)端的異步通知供搀。

Toast.makeText(MainActivity.this, "支付失敗", Toast.LENGTH_SHORT).show();

}

break;

}

default:

break;

}

};

至此隅居,APP端的主要內(nèi)容完畢

下面介紹商戶服務(wù)端钠至,首先要配置相關(guān)參數(shù)葛虐,注意公鑰和RSA2或者RSA要一一對應(yīng)


配置相關(guān)參數(shù)

服務(wù)器端接口支付APP端發(fā)來的請求并返回訂單信息(先上圖,再上代碼)


處理客戶端發(fā)來的訂單請求并返回訂單信息


訂單號唯一


public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

? ? System.err.println(request.getParameter("totalFee"));

? ? String? totalFee = request.getParameter("totalFee");

// 實例化客戶端

AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID,

APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");

// 實例化具體API對應(yīng)的request類,類名稱和接口名稱對應(yīng),當(dāng)前調(diào)用接口名稱:alipay.trade.app.pay

AlipayTradeAppPayRequest alipayrequest = new AlipayTradeAppPayRequest();

// SDK已經(jīng)封裝掉了公共參數(shù)棉钧,這里只需要傳入業(yè)務(wù)參數(shù)屿脐。以下方法為sdk的model入?yún)⒎绞?model和biz_content同時存在的情況下取biz_content)。

AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

model.setBody("商品描述");//商品描述

model.setSubject("商品描述");//商品描述

model.setOutTradeNo(getOutTradeNo());//訂單號

model.setTimeoutExpress("30m");//超時時間

model.setTotalAmount(totalFee);//金額

model.setProductCode("QUICK_MSECURITY_PAY");

alipayrequest.setBizModel(model);

alipayrequest.setNotifyUrl("http://xxx.com/AliPayNotify"); //異步通知地址

try {

// 這里和普通的接口調(diào)用不同,使用的是sdkExecute

AlipayTradeAppPayResponse alipayresponse = alipayClient.sdkExecute(alipayrequest);

System.out.println(alipayresponse.getBody());// 就是orderString

// 可以直接給客戶端請求的诵,無需再做處理万栅。

response.getWriter().append(alipayresponse.getBody()).append(request.getContextPath());

} catch (AlipayApiException e) {

e.printStackTrace();

}

}


/**

* 要求外部訂單號必須唯一。

*

* @return

*/

private static String getOutTradeNo() {

SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());

Date date = new Date();

String key = format.format(date);

Random r = new Random();

key = key + r.nextInt();

key = key.substring(0, 15);

return key;

}

當(dāng)APP端支付成功后將會異步通知到服務(wù)端回調(diào)的接口



訂單信息驗簽西疤,確保支付完成烦粒,返回success

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 支付寶支付結(jié)束回調(diào)接口

String result = "failure";

// 獲取支付寶POST過來反饋信息

Map<String, String> params = new HashMap<String, String>();

Map requestParams = request.getParameterMap();

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] + ",";

}

// 亂碼解決,這段代碼在出現(xiàn)亂碼時使用代赁。

// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");

params.put(name, valueStr);

}

// 切記alipaypublickey是支付寶的公鑰扰她,請去open.alipay.com對應(yīng)應(yīng)用下查看。

try {

boolean flag = AlipaySignature.rsaCheckV1(params, alipaypublicKey, charset, "RSA2");

if (flag) {

// TODO 驗簽成功后

System.out.println("=============================驗簽成功==============================");

result = "success";

response.getOutputStream().write(result.getBytes("utf-8"));// 指定編碼為utf-8

} else {

System.out.println("=============================驗簽失敗==============================");

response.getOutputStream().write(result.getBytes("utf-8"));// 指定編碼為utf-8

}

} catch (AlipayApiException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

最后再次提醒各位開發(fā)者容易出錯的幾個點:

1.沙箱測試時通過芭碍,而在項目APP里卻不通過徒役,很有可能是APP沒有提交上線簽約的緣故,或者是密鑰和公鑰未更改(或RSA窖壕,RSA2加密與公鑰不對照的問題)忧勿,以及初始化時候沙箱環(huán)境未取消
2.服務(wù)器訂單驗簽時候服務(wù)端提示驗簽成功,但是官方提供的驗簽工具卻提示失敗瞻讽,這個我也不太清楚原因鸳吸,好多開發(fā)者朋友都反映過,建議大家以服務(wù)器端的驗簽結(jié)果為準(zhǔn)
3.APP設(shè)置詳情里支付寶的網(wǎng)關(guān)地址默認(rèn)是空白的速勇,這時候要改成https://openapi.alipay.com/gateway.do层释,否則會遇到即使客戶端支付成功了,服務(wù)端也收不到異步通知的情況

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末快集,一起剝皮案震驚了整個濱河市贡羔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌个初,老刑警劉巖乖寒,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異院溺,居然都是意外死亡楣嘁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門珍逸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逐虚,“玉大人,你說我怎么就攤上這事谆膳“劝” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵漱病,是天一觀的道長买雾。 經(jīng)常有香客問我把曼,道長,這世上最難降的妖魔是什么漓穿? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任嗤军,我火速辦了婚禮,結(jié)果婚禮上晃危,老公的妹妹穿的比我還像新娘叙赚。我一直安慰自己,他們只是感情好僚饭,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布纠俭。 她就那樣靜靜地躺著,像睡著了一般浪慌。 火紅的嫁衣襯著肌膚如雪冤荆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天权纤,我揣著相機(jī)與錄音钓简,去河邊找鬼。 笑死汹想,一個胖子當(dāng)著我的面吹牛外邓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播古掏,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼损话,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了槽唾?” 一聲冷哼從身側(cè)響起丧枪,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎庞萍,沒想到半個月后拧烦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钝计,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年恋博,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片私恬。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡债沮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出本鸣,到底是詐尸還是另有隱情疫衩,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布永高,位于F島的核電站隧土,受9級特大地震影響提针,放射性物質(zhì)發(fā)生泄漏命爬。R本人自食惡果不足惜曹傀,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望饲宛。 院中可真熱鬧皆愉,春花似錦、人聲如沸艇抠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至督怜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姨蟋,已是汗流浹背芬探。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人别智。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像丽啡,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坑雅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容