支付宝支付-当面付之扫码支付「扫码支付」
前言
支付寶支付—沙箱環(huán)境使用
支付寶支付-支付寶PC端掃碼支付
支付寶支付-手機瀏覽器H5支付
支付寶支付-當面付之掃碼支付「本文」
當面付包含兩種支付方式:商品條形碼支付 + 掃碼支付
經(jīng)過前面兩篇PC端掃碼支付、手機H5支付,我們可以看到一個共同的特點就是接口返回的都是一個Form表單,然后交給提交執(zhí)行,然后調(diào)起支付。其中PC端提交Form表單后跳轉(zhuǎn)至新的窗口進行支付,而手機端H5支付則是喚起支付寶APP支付。
但是現(xiàn)在有這么個場景,我不希望在PC端支付時跳轉(zhuǎn)支付寶網(wǎng)頁支付,而是直接將二維碼嵌入到系統(tǒng)當中,用戶直觀看到的就是一個彈窗二維碼,然后用戶拿支付寶掃碼支付…這就是本文的當面付之掃碼支付了。
廢話不多說,直接進入主題。
本文開發(fā)環(huán)境:IDEA + Tomcat8.5 + 支付寶沙箱環(huán)境 + SpringBoot
補充:調(diào)用沙箱環(huán)境接口,需要安裝沙箱環(huán)境下的支付寶APP,不了解的小伙伴可以參考上方 支付寶支付—沙箱環(huán)境使用。
一、pom引入依賴 + 參數(shù)準備
引入支付寶支付依賴文件,本文基于4.9.153.ALL版本,及供參考, 最新版本可去官方文檔查閱。
<!--alipay--><dependency>
????<groupId>com.alipay.sdk</groupId>
????<artifactId>alipay-sdk-java</artifactId>
????<version>4.9.153.ALL</version>
</dependency>
關于支付寶公鑰、私鑰、回調(diào)地址啥的就不再重復了,不清楚的去看支付寶支付—沙箱環(huán)境使用。
配置可以單獨創(chuàng)建一個類,靜態(tài)初始化參數(shù)::AlipayConfig.java
public?class?AlipayConfig?{????/**?商戶appid?**/
????public?static?String?APPID?=?"201610170070";
????/**?私鑰?pkcs8格式的?**/
????public?static?String?RSA_PRIVATE_KEY?=?"";
????/**?服務器異步通知頁面路徑?需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數(shù),必須外網(wǎng)可以正常訪問?**/
????public?static?String?notify_url?=?"http://ngrok.sscai.club/alipay_trade_wap_pay_java_utf_8_war_exploded/notify_url.jsp";
????/**?頁面跳轉(zhuǎn)同步通知頁面路徑?需http://或者https://格式的完整路徑,不能加?id=123這類自定義參數(shù),必須外網(wǎng)可以正常訪問?商戶可以自定義同步跳轉(zhuǎn)地址?**/
????public?static?String?return_url?=?"http://ngrok.sscai.club/alipay_trade_wap_pay_java_utf_8_war_exploded/return_url.jsp";
????/**?請求網(wǎng)關地址?**/
????public?static?String?URL?=?"https://openapi.alipaydev.com/gateway.do";
????/**?編碼?**/
????public?static?String?CHARSET?=?"UTF-8";
????/**?返回格式?**/
????public?static?String?FORMAT?=?"json";
????/**?支付寶公鑰?**/
????public?static?String?ALIPAY_PUBLIC_KEY?=?"";
????/**?日志記錄目錄?**/
????public?static?String?log_path?=?"/log";
????/**?RSA2?**/
????public?static?String?SIGNTYPE?=?"RSA2";
????/**?商戶門店編號「需要申請當面付」?**/
????public?static?String?STORE_ID?=?"122211242";
}
幾個主要的參數(shù):
這幾個參數(shù)不清楚的,可以看一下 沙箱環(huán)境使用,或者看一下官方文檔參數(shù)說明。
二、后端代碼
還是之前的代碼,一個controller接口方法,一個具體的實現(xiàn)方法「沒有使用開源SDK」:
Controller
(value?=?"獲取支付寶支付二維碼")public?Result<AlipayResponse>?getAliPayQrCode(?UserModel?user,??AlipayOrderRequest?alipayOrderRequest?)?{
????/**?返回給前端的二維碼內(nèi)容?**/
????String?sHtmlText?=?null;
????try?{
????????/**?判斷是否已經(jīng)存在訂單,根據(jù)自己業(yè)務的不同自行判斷**/
????????if(!StringUtils.isNotBlank(alipayOrderRequest.getWidOutTradeNo())){
????????????Orders?orders=ordersService.createOrder(user,alipayOrderRequest.getWidTotalFee(),alipayOrderRequest.getAppType());
????????????alipayOrderRequest.setWidOutTradeNo(orders.getOrderId());
????????}else{
????????????OrderResponse?orders=ordersService.searchOrderDetail(user,alipayOrderRequest.getWidOutTradeNo());
????????????alipayOrderRequest.setWidTotalFee(orders.getAmount().toString());
????????}
????????/**?這是主要的方法?**/
????????sHtmlText?=?alipayService.alipayOrder(alipayOrderRequest);
????}?catch?(AlipayApiException?e)?{
????????e.printStackTrace();
????}
????AlipayResponse?alipayResponse?=?new?AlipayResponse();
????alipayResponse.setSHtmlText(sHtmlText);
????alipayResponse.setOrderId(alipayOrderRequest.getWidOutTradeNo());
????return?ResultUtil.success(alipayResponse);
}
ServerImpl
@Transactionalpublic?String?alipayOrder(AlipayOrderRequest?alipayOrderRequest)?throws?AlipayApiException?{
????/**獲得初始化的AlipayClient**/
????AlipayClient?alipayClient?=?new?DefaultAlipayClient(AlipayConfig.gatewayUrl,
????????????AlipayConfig.app_id,
????????????AlipayConfig.merchant_private_key,
????????????"json",
????????????AlipayConfig.charset,
????????????AlipayConfig.alipay_public_key,
????????????AlipayConfig.sign_type);
????/**當面付之「掃碼支付」**/
????AlipayTradePrecreateRequest?alipayTradePrecreateRequest?=?new?AlipayTradePrecreateRequest();
????/**回調(diào)地址+異步通知**/
????alipayTradePrecreateRequest.setNotifyUrl(AlipayConfig.notify_url);
????alipayTradePrecreateRequest.setReturnUrl(AlipayConfig.return_url);
????/**商戶訂單號,商戶網(wǎng)站訂單系統(tǒng)中唯一訂單號,必填**/
????String?out_trade_no?=?alipayOrderRequest.getWidOutTradeNo();
????/**付款金額,必填**/
????String?total_amount?=?alipayOrderRequest.getWidTotalFee();
????/**訂單名稱,必填**/
????String?subject?=?alipayOrderRequest.getWidSubject();
????/**商戶門店編號,必填**/
????String?store_id?=?AlipayConfig.STORE_ID;
????/**交易超時時間,訂單允許的最晚付款時間,必填**/
????String?timeout_express?=?"120m";
????/**拼接參數(shù)**/
????alipayTradePrecreateRequest.setBizContent(
????????"{\"out_trade_no\":\""+?out_trade_no?+"\","
????????+?"\"total_amount\":\""+?total_amount?+"\","
????????+?"\"subject\":\""+?subject?+"\","
????????+?"\"store_id\":\""+?store_id?+"\","
????????+?"\"timeout_express\":\""+timeout_express+"\"}");
????return?alipayClient.execute(alipayTradePrecreateRequest).getBody();
}
三、返回結(jié)果+測試
如上代碼調(diào)用execute之后的返回結(jié)果:
{????"alipay_trade_precreate_response":{
????????"code":"10000",
????????"msg":"Success",
????????"out_trade_no":"20200508160037744742",
????????"qr_code":"https://qr.alipay.com/bax06173nktjyrrwupss00bf"
????},
????"sign":"sdk3Q6idlQC+SRuuxc6xXv3g4BAkxEgpA9WYJoiE8oYH5mA6K8+GMwAETNKOhOPh/SoYS4CECzswk/H7qw9A=="
}
我們可以看到qr_code參數(shù)了,剩下的就是交給前端生成二維碼了,然后用戶掃碼支付,在這我就不展示了,直接拿鏈接去草料二維碼直接生成個二維碼試試。
四、掃碼支付回調(diào)地址
支付成功后支付寶會回調(diào)前邊設置的回調(diào)地址,由后端的的 return_url 參數(shù)控制。
再看看支付成功后的回調(diào)接口,由后端的 notify_url 參數(shù)控制「沒有使用開源的SDK演示」:
public?String?alipaynotify(Model?model,?HttpServletRequest?request)?{????log.info("支付寶異步回調(diào)?------------beg-----------");
????String?result?=?"fail";
????/**獲取支付寶POST過來反饋信息**/
????/*?*
?????*?功能:支付寶服務器異步通知頁面
?????*?說明:
?????*?以下代碼只是為了方便商戶測試而提供的樣例代碼,商戶可以根據(jù)自己網(wǎng)站的需要,按照技術文檔編寫,并非一定要使用該代碼。
?????*?該代碼僅供學習和研究支付寶接口使用,只是提供一個參考。
?????*/
????Map<String,?String>?params=this.getAlipayRequest(request);
????if(params?==?null?||?params.size()==0){
????????BufferedReader?bufferReader?=?null;
????????StringBuilder?sb?=?new?StringBuilder();
????????try?{
????????????bufferReader?=?new?BufferedReader(request.getReader());
????????????String?line?=?null;
????????????while?((line?=?bufferReader.readLine())?!=?null)?{
????????????????sb.append(new?String(line.getBytes("ISO-8859-1"),?"utf-8"));
????????????}
????????}?catch?(IOException?e)?{
????????????e.printStackTrace();
????????}
????????String?body=?null;
????????try?{
????????????body?=?URLDecoder.decode(sb.toString(),"UTF-8");
????????}?catch?(UnsupportedEncodingException?e)?{
????????????e.printStackTrace();
????????}
????????params=UriComponentsBuilder.newInstance().query(body).build().getQueryParams().toSingleValueMap();
????}
????boolean?signVerified?=false;
????try?{
????????signVerified?=?AlipaySignature.rsaCheckV1(params,?AlipayConfig.alipay_public_key,?AlipayConfig.charset,?AlipayConfig.sign_type);
????}?catch?(AlipayApiException?e1)?{
????????log.error("由于"+e1.getErrMsg()+"返回給支付寶系統(tǒng)的結(jié)果result:fail");
????????model.addAttribute("result",?"fail");
????????return?result;
????}
????/**——請在這里編寫您的程序(以下代碼僅作參考)——**/
????/*?實際驗證過程建議商戶務必添加以下校驗:
????1、需要驗證該通知數(shù)據(jù)中的out_trade_no是否為商戶系統(tǒng)中創(chuàng)建的訂單號,
????2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單創(chuàng)建時的金額),
????3、校驗通知中的seller_id(或者seller_email)?是否為out_trade_no這筆單據(jù)的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)
????4、驗證app_id是否為該商戶本身。
????*/
????log.error("支付寶驗證簽名:---------------------------------"+signVerified);
????if(signVerified)?{/**驗證成功**/
????????/**商戶訂單號**/
????????/**交易狀態(tài)**/
????????log.info("支付寶異步回調(diào)驗簽成功!");
????????String?trade_status?=?params.get("trade_status");
????????if("TRADE_FINISHED".equals(trade_status)){
????????????/**判斷該筆訂單是否在商戶網(wǎng)站中已經(jīng)做過處理**/
????????????/**如果沒有做過處理,根據(jù)訂單號(out_trade_no)在商戶網(wǎng)站的訂單系統(tǒng)中查到該筆訂單的詳細,并執(zhí)行商戶的業(yè)務程序**/
????????????/**如果有做過處理,不執(zhí)行商戶的業(yè)務程序**/
????????????/**注意:**/
????????????/**退款日期超過可退款期限后(如三個月可退款),支付寶系統(tǒng)發(fā)送該交易狀態(tài)通知**/
????????????try?{
????????????????/**?在這里處理支付成功后的操作,比如修改訂單狀態(tài)等等**/
????????????????coding...
????????????????result?=?"success";
????????????}?catch?(Exception?e)?{
????????????????log.error(e.getMessage());
????????????????result?=?"fail";
????????????}
????????}else?if?("TRADE_SUCCESS".equals(trade_status)){
????????????/**判斷該筆訂單是否在商戶網(wǎng)站中已經(jīng)做過處理**/
????????????/**如果沒有做過處理,根據(jù)訂單號(out_trade_no)在商戶網(wǎng)站的訂單系統(tǒng)中查到該筆訂單的詳細,并執(zhí)行商戶的業(yè)務程序**/
????????????/**如果有做過處理,不執(zhí)行商戶的業(yè)務程序**/
????????????/**注意:**/
????????????/**付款完成后,支付寶系統(tǒng)發(fā)送該交易狀態(tài)通知**/
????????????try?{
????????????????/**?在這里處理支付成功后的操作,比如修改訂單狀態(tài)等等**/
????????????????coding...
????????????????result?=?"success";
????????????}?catch?(Exception?e)?{
????????????????log.error(e.getMessage());
????????????????result?=?"fail";
????????????}
????????}else{
????????????result?=?"fail";
????????}
????}else?{/**驗證失敗**/
????????result?=?"fail";
????????/**調(diào)試用,寫文本函數(shù)記錄程序運行情況是否正常**/
????????/**String?sWord?=?AlipaySignature.getSignCheckContentV1(params);**/
????????/**AlipayConfig.logResult(sWord);**/
????????log.debug("支付寶異步回調(diào)驗簽失敗");
????}
????log.debug("異步回調(diào)返回給支付寶系統(tǒng)的結(jié)果result:"+result);
????model.addAttribute("result",?result);
????log.info("支付寶異步回調(diào)??-------------end?------------");
????return?result;
}
該方法返回給支付寶的 result 就 success、fail 兩個結(jié)果。
從以上看來,其實不難發(fā)現(xiàn)支付寶支付是非常簡單的,盡管我上邊貼了大量的代碼,其實采用開源SDK的話可以更加縮減、美化一些。
ok,這篇文章就到這結(jié)束了,上邊并沒有詳細介紹接口調(diào)用、參數(shù)說明等,詳細介紹請查看官方文檔:
https://opendocs.alipay.com/open/194/106078/
https://opendocs.alipay.com/open/194/103296
文章最后
博客地址:https://www.cgblog.com/niceyoo
如果覺得這篇文章有丶東西,不妨關注一下我,關注是對我最大的鼓勵~
總結(jié)
以上是生活随笔為你收集整理的支付宝支付-当面付之扫码支付「扫码支付」的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos7安装SVN+HTTP
- 下一篇: 全球气象数据的网站集合数据包含(大气数据