個人開發(fā)者如何使用支付寶沙箱開發(fā)支付功能?今天源碼碼網(wǎng)小編整理了一些資料,僅供大家學(xué)習(xí)參考:
登錄支付寶的開發(fā)者中心控制臺,如圖:
設(shè)置密鑰:
生成密鑰的工具,如圖:
下面還有安卓版的支付寶(沙箱版),配合使用。
接下來我們就可以著手進(jìn)行開發(fā)。文檔很豐富,大家可以根據(jù)自己的情況選用,我這里就是用Spring Boot,采用老版的支付寶服務(wù)端SDK,簡單地實現(xiàn)一下當(dāng)面付、PC網(wǎng)頁掃碼付、支付寶回調(diào)通知接口(無外網(wǎng)環(huán)境下如何測試)、基于AOP的驗簽、基于hibernate-validator的參數(shù)校驗以及全局異常捕獲。因為只是學(xué)習(xí)功能,所以代碼寫的不是那么規(guī)整,而且不涉及數(shù)據(jù)庫。
之前在工作中,支付作為一個基礎(chǔ)服務(wù),是用Dubbo服務(wù)提供對外接口的,隨著后續(xù)的發(fā)展,出現(xiàn)了一系列的問題:
一開始是沒有消息驗簽的。
回調(diào)業(yè)務(wù)系統(tǒng)的接口是HTTP,因為支付服務(wù)不可能也用Dubbo Service的方式調(diào)業(yè)務(wù)系統(tǒng)的接口,這得引入多少業(yè)務(wù)系統(tǒng)的jar啊。這樣一來,就很別扭了,你調(diào)我接口Dubbo Service,我調(diào)你接口HTTP請求。
業(yè)務(wù)系統(tǒng)都要引入支付服務(wù)的jar包。
所以后來改成HTTP服務(wù)了。
先看一下結(jié)構(gòu)圖:
pom.xml引入jar包:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>29.0-jre</version> </dependency> <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.10.145.ALL</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
在實際工作中,微服務(wù)的背景下,要分配給每個業(yè)務(wù)系統(tǒng)一個clientId、一個驗證消息簽名用的密鑰,還有支付渠道ID——支付寶當(dāng)面付、掃碼支付、APP支付,微信小程序支付等等,不同的channelId對應(yīng)不同的處理策略。
我們在工作中支付流程是:
1、用戶發(fā)起支付,業(yè)務(wù)系統(tǒng)搜集訂單信息,通過HTTP請求至支付服務(wù)(這里可以是異步也可以是同步)。
2、支付服務(wù)對消息進(jìn)行驗簽,校驗參數(shù)合法性,入庫,轉(zhuǎn)發(fā)請求至支付寶或微信(這里可以是異步也可以是同步)。
3、如果是同步,則直接將返回的信息回傳給業(yè)務(wù)系統(tǒng),例如PC網(wǎng)頁掃碼支付,支付寶就返回了<form>標(biāo)簽的HTML代碼,業(yè)務(wù)系統(tǒng)的前端頁面要嵌進(jìn)去。如果是當(dāng)面付這種,其實是可以走異步的,按需處理吧。
4、用戶完成支付后,支付寶會有兩個回調(diào)return_url、notify_url告知支付狀態(tài),支付服務(wù)接到結(jié)果后再回調(diào)業(yè)務(wù)系統(tǒng)的接口,回寫支付狀態(tài)。
驗簽的AOP代碼:
我在這里使用了AOP而非Filter,僅僅是因為我不喜歡Filter獲取消息體時,inputStream無法傳入Controller,還要額外處理一下。公司里面倒是用Filter的多,不知道大家在實際工作中是如何處理的。
消息加密方法:
消息加密的方法有很多種,而且每個客戶分配的密鑰也必須不同,我這里只是為了展示一下功能,采用了Guava的Hashing.sha256方法,實際工作中要按照要求進(jìn)行修改。
HTTP請求除了放在body的json消息體外,還要在header上放入固定的sign,postman請求如圖:
下面是PayController:
alipayNotify這個方法我們后面再說。支付渠道應(yīng)該有個枚舉類,這里省略了。
Controller里的pay方法有點像策略模式,根據(jù)不同的支付渠道ID,使用對應(yīng)的處理Service。只是我們這里省下了Context類。
對參數(shù)的校驗,這里放在Controller了,大家可以按照公司的開發(fā)規(guī)范,放在Service也可以。處理類代碼如下:
IPayService這個沒什么好說的,就是通用的方法,本例就寫了一個支付接口。
下面是當(dāng)面付的Service,因為是學(xué)習(xí)測試用,所以省略了訂單入庫的代碼:
其中AlipayConfig里面就是之前我們在支付寶上配置的公鑰、私鑰、網(wǎng)關(guān)地址、APPID、還有我們的回調(diào)接口,這些信息應(yīng)該從配置文件或者DB里面獲取。
支付寶接收的金額是元,小數(shù)點后兩位,也就是只到分了。而我們在工作中,實際上金額存的都是long型,沒有小數(shù)點,直接到分,這里要寫一個專門的工具類處理一下,本例省略了。
付款碼就是沙箱支付寶APP中,“付款”-“查看數(shù)字”。測試的時候要快,因為這段數(shù)字會變。
下面是PC網(wǎng)頁掃碼付的Service:
這里返回的是一段HTML代碼(微信支付返回的是一個二維碼),我們拿到之后,可以新建一個HTML文件放進(jìn)去,直接掃碼支付。
掃碼支付后,支付寶會回調(diào)我們提供的return_url和notify_url接口,告知結(jié)果,但是作為個人開發(fā),如果沒有外網(wǎng)IP,該如何驗證一下呢?
先說一下return_url和notify_url的區(qū)別。
掃碼支付完成后,支付網(wǎng)頁會同步跳轉(zhuǎn)到return_url,展示一些信息,這是個get請求,僅發(fā)一次。
而notify_url是由支付寶后端發(fā)起的post請求,如果我們不返回success消息,支付寶會進(jìn)行重發(fā)。
所以從工作中來說,我們一般是把return_url做一個臨時展示,而在notify_url中進(jìn)行一些邏輯處理,例如回寫訂單狀態(tài)等操作。
在測試開發(fā)中,因為我們沒有外網(wǎng)IP,網(wǎng)頁會彈出一個信息框,告知地址無法訪問,這時候我們就可以把整個url復(fù)制下來,自己在瀏覽器上訪問一下,從而可以驗證我們的回調(diào)接口是否正常。