SpringBoot集成支付寶沙箱支付的實(shí)現(xiàn)示例
開(kāi)發(fā)前準(zhǔn)備
1、密鑰工具
在線工具地址:https://miniu.alipay.com/keytool/create
無(wú)需下載,直接在線生成你的應(yīng)用私鑰

點(diǎn)擊生成即可生成自己的公鑰和私鑰
這個(gè)公鑰后面會(huì)用到叫做alipayPublicKey
這個(gè)私鑰后面會(huì)用到叫做appPrivateKey
如果遇到生成失敗點(diǎn)擊鏈接選擇Web在線加密https://opendocs.alipay.com/open/291/introduce

再不行就自己下載客戶端工具
2、沙箱環(huán)境
注冊(cè)支付寶開(kāi)發(fā)者賬戶,進(jìn)入開(kāi)發(fā)者控制臺(tái)
https://auth.alipay.com/login/ant_sso_index.htm?goto=https%3A%2F%2Fopenhome.alipay.com%2Fplatform%2FdeveloperIndex.htm


這個(gè)appid后面配置springboot會(huì)用到

這里的公鑰就是上面生成的,不要填錯(cuò)了
3、內(nèi)網(wǎng)穿透工具
我用的是natapp,下載地址:https://natapp.cn/
啟動(dòng)命令:natapp.exe -authtoken=你的authtoken 這個(gè)authtoken是在natapp里面創(chuàng)建免費(fèi)隧道產(chǎn)生的。
注意隧道的端口要配置成你的后臺(tái)端口,例如9090


直接在上面的命令后面加上就可以啟動(dòng)你的 natapp,設(shè)置內(nèi)網(wǎng)穿透了。
內(nèi)網(wǎng)穿透就是把本機(jī)的 ip 和端口暴露到外網(wǎng),通過(guò)指定的 url 可以訪問(wèn)你本地的服務(wù),當(dāng)然 ,這存在一定的安全風(fēng)險(xiǎn),請(qǐng)謹(jǐn)慎使用!使用命令開(kāi)啟 natapp 后,會(huì)生成一個(gè)外網(wǎng)的地址指向你本地的服務(wù)地址,當(dāng)你訪問(wèn)http://tdqxnr.natappfree.cc,跟你訪問(wèn) 127.0.0.1:9090 效果是一樣的,只不過(guò)一個(gè)是對(duì)外的,一個(gè)是只能本地訪問(wèn)。

代碼集成
1、Java SDK
打開(kāi)支付寶官方文檔:https://opendocs.alipay.com/open/54/00y8k9
他提供了一個(gè)Easy版本的Java SDK集成方案,我們可以直接用這個(gè)。

maven依賴:
<dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-easysdk</artifactId> <version>2.2.0</version> </dependency>
2、支付寶配置
在 application.properties 文件里面加上這些配置,appId 就是上面看到的沙箱環(huán)境里面提
供的appId,appPrivateKey 和 alipayPublicKey也是上面已經(jīng)有了,直接復(fù)制過(guò)來(lái)即可。
notifyUrl是支付成功后的一個(gè)回調(diào)接口,用來(lái)修改訂單的狀態(tài),我們可以在
AliPayController 加上這個(gè)接口(后面有講到),注意,這個(gè)回調(diào)接口的地址必須是我們?cè)?br />
natapp 里面獲取到的公網(wǎng)地址,否則接口無(wú)法回調(diào)。

新建一個(gè)配置類(lèi)AliPayConfig
package com.example.demo.common.config;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String notifyUrl;
@PostConstruct
public void init() {
// 設(shè)置參數(shù)(全局只需設(shè)置一次)
Config options = getOptions();
options.appId = this.appId;
options.merchantPrivateKey = this.appPrivateKey;
options.alipayPublicKey = this.alipayPublicKey;
options.notifyUrl = this.notifyUrl;
Factory.setOptions(options);
System.out.println("=======支付寶SDK初始化成功=======");
}
private Config getOptions() {
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipaydev.com";
config.signType = "RSA2";
return config;
}
}
注意:在攔截器里面加上忽略alipay接口的配置!

3、支付和回調(diào)接口
新建一個(gè) AliPayController,寫(xiě)一個(gè) Get 接口,這個(gè)是支付的接口,前端需要把 訂單的標(biāo)
題、訂單編號(hào)、訂單的總金額傳到后臺(tái)來(lái),后臺(tái)去調(diào)用支付寶的 APi 生成支付訂單,在網(wǎng)頁(yè)上
實(shí)現(xiàn)支付。
@GetMapping("/pay")
public String pay(AliPay aliPay) {
AlipayTradePagePayResponse response;
try {
// 發(fā)起API調(diào)用(以創(chuàng)建當(dāng)面付收款二維碼為例)
response = Factory.Payment.Page()
.pay(aliPay.getSubject(), aliPay.getTraceNo(), aliPay.getTotalAmount(), "");
} catch (Exception e) {
System.err.println("調(diào)用遭遇異常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
return response.getBody();
}
第二個(gè)接口是支付成功回調(diào)的接口,我們?cè)谶@個(gè)接口可以獲取到支付訂單的訂單編號(hào)和支付時(shí)
間,然后我們可以修改本地訂單的支付狀態(tài)。注意:這是一個(gè) POST 接口。
@PostMapping("/notify") // 注意這里必須是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("=========支付寶異步回調(diào)========");
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
// System.out.println(name + " = " + request.getParameter(name));
}
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
// 支付寶驗(yàn)簽
if (Factory.Payment.Common().verifyNotify(params)) {
// 驗(yàn)簽通過(guò)
System.out.println("交易名稱(chēng): " + params.get("subject"));
System.out.println("交易狀態(tài): " + params.get("trade_status"));
System.out.println("支付寶交易憑證號(hào): " + params.get("trade_no"));
System.out.println("商戶訂單號(hào): " + params.get("out_trade_no"));
System.out.println("交易金額: " + params.get("total_amount"));
System.out.println("買(mǎi)家在支付寶唯一id: " + params.get("buyer_id"));
System.out.println("買(mǎi)家付款時(shí)間: " + params.get("gmt_payment"));
System.out.println("買(mǎi)家付款金額: " + params.get("buyer_pay_amount"));
// 更新訂單未已支付
orderMapper.updateState(tradeNo, 1, gmtPayment);
}
}
return "success";
}
4、前端Vue調(diào)用
在書(shū)籍的表格里,我加了個(gè) 購(gòu)買(mǎi)的按鈕用來(lái)測(cè)試支付功能。

點(diǎn)擊購(gòu)買(mǎi)按鈕,會(huì)發(fā)生一次網(wǎng)絡(luò)請(qǐng)求。請(qǐng)求后臺(tái)的 OrderController 生成一個(gè)訂單,并返
回調(diào)用 AliPayController 的調(diào)用地址:

@GetMapping("/buy/{bookId}")
public Result<?> buy(@PathVariable Long bookId) {
Book book = bookMapper.selectById(bookId);
String orderNo = IdUtil.getSnowflake().nextIdStr();
String payUrl = "http://localhost:9090/alipay/pay?subject=" + book.getName() + "&traceNo=" + orderNo + "&totalAmount=" + book.getPrice();
User user = getUser();
Order order = new Order();
order.setOrderNo(orderNo);
order.setTotalPrice(book.getPrice());
order.setPayPrice(book.getPrice());
order.setTransportPrice(BigDecimal.ZERO);
order.setUserId(user.getId());
order.setUsername(user.getUsername());
order.setName(book.getName());
save(order);
// 新建訂單,扣減庫(kù)存
return Result.success(payUrl);
}
前端拿到這個(gè)地址,直接在新窗口打開(kāi)即可出現(xiàn)支付寶的沙箱支付頁(yè)面:

buy(bookId) {
request.get("/order/buy/" + bookId).then(res => {
// 請(qǐng)求成功跳轉(zhuǎn)沙箱支付的頁(yè)面
window.open(res.data)
})
},
支付寶沙箱頁(yè)面是這樣的:

這里的賬戶和密碼都是模擬的,可以在自己的沙箱賬戶里找到,地址:
https://openhome.alipay.com/platform/appDaily.htm?tab=account

賬戶是虛擬的,可以隨意充值。
如果一不小心出現(xiàn)了下面的這個(gè)頁(yè)面

別慌!你有 2 個(gè)選擇:
打開(kāi)一個(gè)新的瀏覽器,進(jìn)入系統(tǒng)再次購(gòu)買(mǎi)即可!關(guān)閉所有網(wǎng)頁(yè),清除緩存,重新進(jìn)入購(gòu)買(mǎi)頁(yè)面,點(diǎn)擊購(gòu)買(mǎi)。

然后你輸入上面看到的賬戶密碼繼續(xù)就行了:

支付密碼也是 111111 ,點(diǎn)擊確認(rèn)付款

跳轉(zhuǎn)到這個(gè)頁(yè)面,表示支付成功

一定要注意:每次重啟 natapp 都會(huì)重新生成新的外網(wǎng)地址,你需要在你的配置文件里面及
時(shí)更換,否則,無(wú)法回調(diào)!
到此這篇關(guān)于SpringBoot集成支付寶沙箱支付的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot 支付寶沙箱支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot對(duì)接支付寶支付接口(詳細(xì)開(kāi)發(fā)步驟總結(jié))
- springboot+vue+對(duì)接支付寶接口+二維碼掃描支付功能(沙箱環(huán)境)
- SpringBoot集成支付寶沙箱支付(支付、退款)
- springboot調(diào)用支付寶第三方接口(沙箱環(huán)境)
- SpringBoot接入支付寶支付的方法步驟
- SpringBoot實(shí)現(xiàn)支付寶沙箱支付的完整步驟
- SpringBoot集成支付寶支付的實(shí)現(xiàn)示例
- SpringBoot下如何實(shí)現(xiàn)支付寶接口的使用
- SpringBoot+MyBatis集成支付寶支付流程
相關(guān)文章
Mybatis-Plus 多表聯(lián)查分頁(yè)的實(shí)現(xiàn)代碼
本篇文章主要介紹了Mybatis-Plus 多表聯(lián)查分頁(yè)的實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
IDEA連接postgressql數(shù)據(jù)庫(kù)操作
這篇文章主要介紹了IDEA連接postgressql數(shù)據(jù)庫(kù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
Java報(bào)NoClassDefFoundError異常的原因及解決
在 Java 開(kāi)發(fā)過(guò)程中, java.lang.NoClassDefFoundError 是一個(gè)令人頭疼的運(yùn)行時(shí)錯(cuò)誤,本文將深入探討這一問(wèn)題的原因和常見(jiàn)場(chǎng)景,并提供實(shí)用的解決方法,希望對(duì)大家有所幫助2025-03-03
Java8 使用工廠方法supplyAsync創(chuàng)建CompletableFuture實(shí)例
這篇文章主要介紹了Java8 使用工廠方法supplyAsync創(chuàng)建CompletableFuture實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
一文講透為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)
這篇文章主要為大家介紹了為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)的透徹詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
詳解SpringBoot程序啟動(dòng)時(shí)執(zhí)行初始化代碼
這篇文章主要介紹了詳解SpringBoot程序啟動(dòng)時(shí)執(zhí)行初始化代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
SpringCloud Webflux過(guò)濾器增加header傳遞方式
這篇文章主要介紹了SpringCloud Webflux過(guò)濾器增加header傳遞方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02

