支付系统实战 | 支付宝支付
文章目錄
- 1.支付
- 2.支付寶支付
- 支付分類
- 快捷支付
- 手機支付
- 二維碼支付
- 聲波支付
- NFC支付
- iptv支付
- 指紋支付
- 刷臉支付
- 3.沙箱(沙盒)
- 4.支付流程
- 5.支付寶支付準備工作
- 6.代碼開發
- 7.手機網站支付沙箱接入注意點
1.支付
現代生活,什么付款方式最常見?不是現金,也不是銀行卡,而是手機支付。支付寶和微信支付是當今社會必備的付款方式,所以在中國,出門帶手機,就什么都可以做到,而這個生活上的變化離不開互聯網的發展以及辛勤的開發人員的努力。而對于眾多的app或web網站,一個二維碼掃碼支付功能是必備的,那么如何實現支付功能呢?讓我們一起來探索一下吧~
2.支付寶支付
支付寶官方網站:https://www.alipay.com/。
支付寶(中國)網絡技術有限公司是國內的第三方支付平臺,致力于提供“簡單、安全、快速”的支付解決方案 。支付寶公司從2004年建立開始,始終以“信任”作為產品和服務的核心。旗下有“支付寶”與“支付寶錢包”兩個獨立品牌。自2014年第二季度開始成為當前全球最大的移動支付廠商。
支付分類
快捷支付
快捷支付是指支付機構與銀行合作直連,形成一個高效、安全、專用(消費)的支付方式
手機支付
2008年開始支付寶開始介入手機支付業務,2009年推出首個獨立移動支付客戶端,2013年初更名為“支付寶錢包”,并于2013年10月成為與“支付寶”并行的獨立品牌;
二維碼支付
2010年10月,支付寶推出國內首個二維碼支付技術,幫助電商從線上向線下延伸發展空間。
使用方式:用戶在“支付寶錢包”內,點擊“掃一掃”,對準二維碼按照提示就能完成。
聲波支付
2013年4月12日,支付寶與合作方青島易觸聯合推出全球首個聲波售貨機。市面尚無同類支付技術商用。
使用方式:用戶在支持聲波支付的售貨機等場景下,選擇商品,然后在“支付寶錢包”內點擊“當面付”。按照提示完成支付。
NFC支付
2012年7月31日,支付寶推出利用NFC、LBS等技術的新客戶端。隨后這一技術方案得到進一步改進。
2014年4月28日,支付寶錢包8.1版支持NFC功能,用戶可以用于向北京公交一卡通進行充值。
使用方式:將公交卡等放置在具有NFC的安卓手機后,即可查詢公交卡余額以及充值。
值得注意的是,支付寶移動支付均為遠程在線支付方案,NFC在當中的作用為“近場握手、遠程支付”。與統稱的NFC略有差異。
iptv支付
2012年3月29日,華數傳媒與支付寶推出互聯網電視支付,實現3秒支付。
使用方式:注冊為華數會員,并關注服務窗號。使用“支付寶錢包”掃描電視上的二維碼,完成支付。
指紋支付
2014年7月16日,移動支付平臺支付寶錢包宣布試水指紋支付服務。
刷臉支付
2018年12月13日,支付寶宣布推出一款全新的刷臉支付產品—— “蜻蜓”,直接將刷臉支付的接入成本降低80%。
3.沙箱(沙盒)
? Sandboxie(又叫沙箱、沙盤)即是一個虛擬系統程序,允許你在沙盤環境中運行瀏覽器或其他程序,因此運行所產生的變化可以隨后刪除。它創造了一個類似沙盒的獨立作業環境,在其內部運行的程序并不能對硬盤產生永久性的影響。 在網絡安全中,沙箱指在隔離環境中,用以測試不受信任的文件或應用程序等行為的工具。
? 沙箱是一種按照安全策略限制程序行為的執行環境。早期主要用于測試可疑軟件等,比如黑客們為了試用某種病毒或者不安全產品,往往可以將它們在沙箱環境中運行。
經典的沙箱系統的實現途徑一般是通過攔截系統調用,監視程序行為,然后依據用戶定義的策略來控制和限制程序對計算機資源的使用,比如改寫注冊表,讀寫磁盤等。
4.支付流程
為了保證交易雙方(商戶和支付寶)的身份和數據安全,開發者在調用接口前,需要配置雙方密鑰,對交易數據進行雙方校驗。密鑰包含應用私鑰(APP_PRIVATE_KEY)和應用公鑰(APP_PUBLIC_KEY)。生成密鑰后,開發者需要在開放平臺開發者中心進行密鑰配置,配置完成后可以獲取支付寶公鑰(ALIPAY_PUBLIC_KEY)。密鑰的配置旨在對交易數據進行雙方校驗。具體流程如下圖所示:
說明:
支付寶開放平臺 SDK 封裝了簽名和驗簽過程,只需配置賬號及密鑰參數。
- 應用公鑰(商戶自身的 RSA/RSA2 公鑰): 支付寶使用該公鑰驗證該交易是商戶發起。
- 支付寶公鑰(支付寶的 RSA/RSA2 公鑰):商戶使用該公鑰驗證該結果是支付寶返回的。
注意:
- 由于同步返回的不可靠性,支付結果必須以異步通知或查詢接口返回為準,不能依賴同步跳轉。
- 商戶系統接收到異步通知以后,必須通過驗簽(驗證通知中的 sign 參數)來確保支付通知是由支付寶發送的。
- 接收到異步通知并驗簽通過后,一定要檢查通知內容,包括通知中的 app_id、out_trade_no、total_amount 是否與請求中的一致,并根據 trade_status 進行后續業務處理。
- 在支付寶端,partnerId 與 out_trade_no 唯一對應一筆單據,商戶端保證不同次支付 out_trade_no 不可重復;若重復,支付寶會關聯到原單據,基本信息一致的情況下會以原單據為準進行支付。
補充:SDK和API的區別
? SDK全稱software development kit,軟件開發工具包。
? API就是可以輕松實現和其他軟件的交互。
? API是數據接口,SDK相當于開發集成工具環境。要在SDK的環境下調用API.
? API是接口對接接口的過程,SDK不僅提供開發環境,還提供很多的API
掃碼支付接入流程
? https://opendocs.alipay.com/open/194/106078
5.支付寶支付準備工作
正式的支付功能上線,需要使用企業的信息,所以我們這里使用支付寶提供的沙箱功能實現測試,如何訪問沙箱呢?下面看一下實現步驟:
訪問支付寶首頁,選擇角色:“我是開發者”
使用手機上的支付寶,掃碼登錄到系統。登錄后選擇左上角“控制臺”,然后在頁面下方有“開發服務”
沙箱的使用步驟:
步驟1:查看信息
步驟2:設置秘鑰
大家第一次使用時,文本框內是空的,點擊“支付寶密鑰生成器”,下載exe文件,并安裝。
運行程序,生成密鑰:
把這里的“應用公鑰”復制到“加簽管理”中的公鑰位置。設置完畢后,密鑰位置會變成“設置/查看”
步驟3:下載沙箱錢包進行測試,注意這里必須使用沙箱版錢包進行測試,賬戶信息已給定。此軟件只支持安卓系統
步驟4:測試賬戶的信息
6.代碼開發
6.1 支付工具類:AlipayConfig.java
public class AlipayConfig {//↓↓↓↓↓↓↓↓↓↓請在這里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓// 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號public static String app_id = "";// 商戶私鑰,您的PKCS8格式RSA2私鑰public static String merchant_private_key = "";// 支付寶公鑰public static String alipay_public_key = "";// 服務器異步通知頁面路徑 //需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問public static String notify_url = "";// 頁面跳轉同步通知頁面路徑 //需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問public static String return_url = "";// 簽名方式public static String sign_type = "RSA2";// 字符編碼格式public static String charset = "utf-8";// 支付寶網關,注意這些使用的是沙箱的支付寶網關,與正常網關的區別是多了devpublic static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";// 支付寶網關public static String log_path = "C:\\";//↑↑↑↑↑↑↑↑↑↑請在這里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑/** * 寫日志,方便測試(看網站需求,也可以改成把記錄存入數據庫)* @param sWord 要寫入日志里的文本內容*/public static void logResult(String sWord) {FileWriter writer = null;try {writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");writer.write(sWord);} catch (Exception e) {e.printStackTrace();} finally {if (writer != null) {try {writer.close();} catch (IOException e) {e.printStackTrace();}}}} }6.2.添加maven依賴
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies><!--springBoot依賴包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 支付功能SDK --><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.10.124.ALL</version></dependency><!--springBoot支持jsp--><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency></dependencies>6.3 修改application.properties屬性文件
#頁面默認前綴目錄 spring.mvc.view.prefix=/ #響應頁面默認后綴 spring.mvc.view.suffix=.jsp #修改訪問的端口號 server.port=8081 #設置訪問的項目路徑 server.servlet.context-path=/6.4 創建頁面
<%@ page language="java" contentType="text/html; charset=utf-8"pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>支付寶網站支付</title> <style> * {margin: 0;padding: 0; }ul, ol {list-style: none; }body {font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande",sans-serif; }.tab-head {margin-left: 120px;margin-bottom: 10px; }.tab-content {clear: left;display: none; }h2 {border-bottom: solid #02aaf1 2px;width: 200px;height: 25px;margin: 0;float: left;text-align: center;font-size: 16px; }.selected {color: #FFFFFF;background-color: #02aaf1; }.show {clear: left;display: block; }.hidden {display: none; }.new-btn-login-sp {padding: 1px;display: inline-block;width: 75%; }.new-btn-login {background-color: #02aaf1;color: #FFFFFF;font-weight: bold;border: none;width: 100%;height: 30px;border-radius: 5px;font-size: 16px; }#main {width: 100%;margin: 0 auto;font-size: 14px; }.red-star {color: #f00;width: 10px;display: inline-block; }.null-star {color: #fff; }.content {margin-top: 5px; }.content dt {width: 100px;display: inline-block;float: left;margin-left: 20px;color: #666;font-size: 13px;margin-top: 8px; }.content dd {margin-left: 120px;margin-bottom: 5px; }.content dd input {width: 85%;height: 28px;border: 0;-webkit-border-radius: 0;-webkit-appearance: none; }#foot {margin-top: 10px;position: absolute;bottom: 15px;width: 100%; }.foot-ul {width: 100%; }.foot-ul li {width: 100%;text-align: center;color: #666; }.note-help {color: #999999;font-size: 12px;line-height: 130%;margin-top: 5px;width: 100%;display: block; }#btn-dd {margin: 20px;text-align: center; }.foot-ul {width: 100%; }.one_line {display: block;height: 1px;border: 0;border-top: 1px solid #eeeeee;width: 100%;margin-left: 20px; }.am-header {display: -webkit-box;display: -ms-flexbox;display: box;width: 100%;position: relative;padding: 7px 0;-webkit-box-sizing: border-box;-ms-box-sizing: border-box;box-sizing: border-box;background: #1D222D;height: 50px;text-align: center;-webkit-box-pack: center;-ms-flex-pack: center;box-pack: center;-webkit-box-align: center;-ms-flex-align: center;box-align: center; }.am-header h1 {-webkit-box-flex: 1;-ms-flex: 1;box-flex: 1;line-height: 18px;text-align: center;font-size: 18px;font-weight: 300;color: #fff; } </style> </head> <body text=#000000 bgColor="#ffffff" leftMargin=0 topMargin=4><header class="am-header"><h1>支付寶體驗入口頁</h1></header><div id="main"><div id="tabhead" class="tab-head"><h2 id="tab1" class="selected" name="tab">付 款</h2></div><form name=alipayment action=pay method=posttarget="_blank"><div id="body1" class="show" name="divcontent"><dl class="content"><dt>商戶訂單號 :</dt><dd><input id="WIDout_trade_no" name="WIDout_trade_no" /></dd><hr class="one_line"><dt>訂單名稱 :</dt><dd><input id="WIDsubject" name="WIDsubject" /></dd><hr class="one_line"><dt>付款金額 :</dt><dd><input id="WIDtotal_amount" name="WIDtotal_amount" /></dd><hr class="one_line"><dt>商品描述:</dt><dd><input id="WIDbody" name="WIDbody" /></dd><hr class="one_line"><dt></dt><dd id="btn-dd"><span class="new-btn-login-sp"><button class="new-btn-login" type="submit"style="text-align: center;">付 款</button></span> <span class="note-help">如果您點擊“付款”按鈕,即表示您同意該次的執行操作。</span></dd></dl></div></form><div id="foot"><ul class="foot-ul"><li>版權所有 2015-2018</li></ul></div></div> </body> <script language="javascript">function GetDateNow() {var vNow = new Date();var sNow = "";sNow += String(vNow.getFullYear());sNow += String(vNow.getMonth() + 1);sNow += String(vNow.getDate());sNow += String(vNow.getHours());sNow += String(vNow.getMinutes());sNow += String(vNow.getSeconds());sNow += String(vNow.getMilliseconds());document.getElementById("WIDout_trade_no").value = sNow;document.getElementById("WIDsubject").value = "測試";document.getElementById("WIDtotal_amount").value = "0.01";}GetDateNow(); </script> </html>6.5 在springBoot環境下創建支付對象
| URL | 支付寶網關(固定),注意沙箱時的地址不同 | https://openapi.alipay.com/gateway.do |
| APP_ID | APPID 即創建應用后生成 | 詳情見 創建應用并獲取 APPID |
| APP_PRIVATE_KEY | 開發者應用私鑰,由開發者自己生成 | 詳見 配置密鑰 |
| FORMAT | 參數返回格式,只支持 json 格式 | json(固定) |
| CHARSET | 請求和簽名使用的字符編碼格式,支持 GBK和 UTF-8 | 開發者根據實際工程編碼配置 |
| ALIPAY_PUBLIC_KEY | 支付寶公鑰,由支付寶生成 | 詳見 配置密鑰 |
| SIGN_TYPE | 商戶生成簽名字符串所使用的簽名算法類型,目前支持 RSA2 和 RSA,推薦商家使用 RSA2。 | RSA2 |
6.7 配置異步通知的處理類
@Controller public class NotifyUrlController {@RequestMapping("/notifyUrl")public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception{//獲取支付寶POST過來反饋信息Map<String,String> params = new HashMap<String,String>();Map<String,String[]> requestParams = request.getParameterMap();Iterator<String> iter = requestParams.keySet().iterator();while(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);}boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //調用SDK驗證簽名//——請在這里編寫您的程序(以下代碼僅作參考)——/* 實際驗證過程建議商戶務必添加以下校驗:1、需要驗證該通知數據中的out_trade_no是否為商戶系統中創建的訂單號,2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單創建時的金額),3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)4、驗證app_id是否為該商戶本身。*/response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();if(signVerified) {//驗證成功//商戶訂單號String out_trade_no =request.getParameter("out_trade_no");//支付寶交易號String trade_no = request.getParameter("trade_no");//交易狀態String trade_status = request.getParameter("trade_status");if(trade_status.equals("TRADE_FINISHED")){//判斷該筆訂單是否在商戶網站中已經做過處理//如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,并執行商戶的業務程序//如果有做過處理,不執行商戶的業務程序//注意://退款日期超過可退款期限后(如三個月可退款),支付寶系統發送該交易狀態通知}else if (trade_status.equals("TRADE_SUCCESS")){//判斷該筆訂單是否在商戶網站中已經做過處理//如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,并執行商戶的業務程序//如果有做過處理,不執行商戶的業務程序//注意://付款完成后,支付寶系統發送該交易狀態通知}out.println("success");}else {//驗證失敗out.println("fail");//調試用,寫文本函數記錄程序運行情況是否正常//String sWord = AlipaySignature.getSignCheckContentV1(params);//AlipayConfig.logResult(sWord);}} }異步通知: 其實是雙保險機制, 如果同步通知后沒有跳轉到你的網址, 可能用戶關了, 可能網速慢, 即無法觸發你更新訂單狀態為已支付的controller, 這時候異步通知就有作用了, 不過你要判斷一下, 如果訂單已經變為已支付, 則不必再更新一次了, 只返回給支付寶success即可, 否則他會一直異步通知你
異步通知參數說明文檔:https://opendocs.alipay.com/open/203/105286
6.8 添加同步通知處理類
@Controller //回調請求 public class ReturnUrl {@RequestMapping("/returnUrl")public void returnUrl(HttpServletRequest request, HttpServletResponse response) throws Exception{//獲取支付寶GET過來反饋信息Map<String,String> params = new HashMap<String,String>();Map<String,String[]> requestParams = request.getParameterMap();Iterator<String> iter = requestParams.keySet().iterator();while(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);}//RSA2驗證boolean signVerified = AlipaySignature.rsaCheckV2(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //調用SDK驗證簽名response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//——請在這里編寫您的程序(以下代碼僅作參考)——if(signVerified) {//商戶訂單號String out_trade_no = request.getParameter("out_trade_no");//支付寶交易號String trade_no = request.getParameter("trade_no");//付款金額String total_amount = request.getParameter("total_amount");out.println("trade_no:"+trade_no+"<br/>out_trade_no:"+out_trade_no+"<br/>total_amount:"+total_amount);}else {out.println("驗簽失敗");}} }同步通知: 用于用戶在支付寶頁面付款完畢后自動跳轉回你自己的網址, 你根據他的參數告訴用戶已經支付成功, 然后你再更新你自己訂單表的狀態為已支付.
區別:1.同步通知是給用戶看的 2.異步通知是給服務器看的
6.9 測試
訪問地址:http://localhost:8081/
跳轉到支付頁面:
掃碼支付,支付成功后,返回訂單相關信息:
7.手機網站支付沙箱接入注意點
1、手機網站支付支持沙箱接入;在沙箱調通接口后,必須在線上進行測試與驗收,所有返回碼及業務邏輯以線上為準;
2、手機網站支付只支持余額支付,不支持銀行卡、余額寶等其他支付方式;
3、支付時,請使用沙箱買家賬號支付,在登錄支付寶,輸入手機號的頁面,點擊右下角支付寶賬戶登錄
總結
以上是生活随笔為你收集整理的支付系统实战 | 支付宝支付的全部內容,希望文章能夠幫你解決所遇到的問題。