SpringBoot集成支付寶沙箱支付的實(shí)現(xiàn)示例
開發(fā)前準(zhǔn)備
1、密鑰工具
在線工具地址:https://miniu.alipay.com/keytool/create
無需下載,直接在線生成你的應(yīng)用私鑰
點(diǎn)擊生成即可生成自己的公鑰和私鑰
這個(gè)公鑰后面會用到叫做alipayPublicKey
這個(gè)私鑰后面會用到叫做appPrivateKey
如果遇到生成失敗點(diǎn)擊鏈接選擇Web在線加密https://opendocs.alipay.com/open/291/introduce
再不行就自己下載客戶端工具
2、沙箱環(huán)境
注冊支付寶開發(fā)者賬戶,進(jìn)入開發(fā)者控制臺
https://auth.alipay.com/login/ant_sso_index.htm?goto=https%3A%2F%2Fopenhome.alipay.com%2Fplatform%2FdeveloperIndex.htm
這個(gè)appid后面配置springboot會用到
這里的公鑰就是上面生成的,不要填錯(cuò)了
3、內(nèi)網(wǎng)穿透工具
我用的是natapp,下載地址:https://natapp.cn/
啟動命令:natapp.exe -authtoken=你的authtoken 這個(gè)authtoken是在natapp里面創(chuàng)建免費(fèi)隧道產(chǎn)生的。
注意隧道的端口要配置成你的后臺端口,例如9090
直接在上面的命令后面加上就可以啟動你的 natapp,設(shè)置內(nèi)網(wǎng)穿透了。
內(nèi)網(wǎng)穿透就是把本機(jī)的 ip 和端口暴露到外網(wǎng),通過指定的 url 可以訪問你本地的服務(wù),當(dāng)然 ,這存在一定的安全風(fēng)險(xiǎn),請謹(jǐn)慎使用!使用命令開啟 natapp 后,會生成一個(gè)外網(wǎng)的地址指向你本地的服務(wù)地址,當(dāng)你訪問http://tdqxnr.natappfree.cc,跟你訪問 127.0.0.1:9090 效果是一樣的,只不過一個(gè)是對外的,一個(gè)是只能本地訪問。
代碼集成
1、Java SDK
打開支付寶官方文檔: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ù)制過來即可。
notifyUrl是支付成功后的一個(gè)回調(diào)接口,用來修改訂單的狀態(tài),我們可以在
AliPayController 加上這個(gè)接口(后面有講到),注意,這個(gè)回調(diào)接口的地址必須是我們在
natapp 里面獲取到的公網(wǎng)地址,否則接口無法回調(diào)。
新建一個(gè)配置類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,寫一個(gè) Get 接口,這個(gè)是支付的接口,前端需要把 訂單的標(biāo)
題、訂單編號、訂單的總金額傳到后臺來,后臺去調(diào)用支付寶的 APi 生成支付訂單,在網(wǎng)頁上
實(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)的接口,我們在這個(gè)接口可以獲取到支付訂單的訂單編號和支付時(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)簽通過 System.out.println("交易名稱: " + params.get("subject")); System.out.println("交易狀態(tài): " + params.get("trade_status")); System.out.println("支付寶交易憑證號: " + params.get("trade_no")); System.out.println("商戶訂單號: " + params.get("out_trade_no")); System.out.println("交易金額: " + params.get("total_amount")); System.out.println("買家在支付寶唯一id: " + params.get("buyer_id")); System.out.println("買家付款時(shí)間: " + params.get("gmt_payment")); System.out.println("買家付款金額: " + params.get("buyer_pay_amount")); // 更新訂單未已支付 orderMapper.updateState(tradeNo, 1, gmtPayment); } } return "success"; }
4、前端Vue調(diào)用
在書籍的表格里,我加了個(gè) 購買的按鈕用來測試支付功能。
點(diǎn)擊購買按鈕,會發(fā)生一次網(wǎng)絡(luò)請求。請求后臺的 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); // 新建訂單,扣減庫存 return Result.success(payUrl); }
前端拿到這個(gè)地址,直接在新窗口打開即可出現(xiàn)支付寶的沙箱支付頁面:
buy(bookId) { request.get("/order/buy/" + bookId).then(res => { // 請求成功跳轉(zhuǎn)沙箱支付的頁面 window.open(res.data) }) },
支付寶沙箱頁面是這樣的:
這里的賬戶和密碼都是模擬的,可以在自己的沙箱賬戶里找到,地址:
https://openhome.alipay.com/platform/appDaily.htm?tab=account
賬戶是虛擬的,可以隨意充值。
如果一不小心出現(xiàn)了下面的這個(gè)頁面
別慌!你有 2 個(gè)選擇:
打開一個(gè)新的瀏覽器,進(jìn)入系統(tǒng)再次購買即可!關(guān)閉所有網(wǎng)頁,清除緩存,重新進(jìn)入購買頁面,點(diǎn)擊購買。
然后你輸入上面看到的賬戶密碼繼續(xù)就行了:
支付密碼也是 111111 ,點(diǎn)擊確認(rèn)付款
跳轉(zhuǎn)到這個(gè)頁面,表示支付成功
一定要注意:每次重啟 natapp 都會重新生成新的外網(wǎng)地址,你需要在你的配置文件里面及
時(shí)更換,否則,無法回調(diào)!
到此這篇關(guān)于SpringBoot集成支付寶沙箱支付的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot 支付寶沙箱支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot對接支付寶支付接口(詳細(xì)開發(fā)步驟總結(jié))
- springboot+vue+對接支付寶接口+二維碼掃描支付功能(沙箱環(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)查分頁的實(shí)現(xiàn)代碼
本篇文章主要介紹了Mybatis-Plus 多表聯(lián)查分頁的實(shí)現(xiàn)代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06IDEA連接postgressql數(shù)據(jù)庫操作
這篇文章主要介紹了IDEA連接postgressql數(shù)據(jù)庫操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Java報(bào)NoClassDefFoundError異常的原因及解決
在 Java 開發(fā)過程中, java.lang.NoClassDefFoundError 是一個(gè)令人頭疼的運(yùn)行時(shí)錯(cuò)誤,本文將深入探討這一問題的原因和常見場景,并提供實(shí)用的解決方法,希望對大家有所幫助2025-03-03Java8 使用工廠方法supplyAsync創(chuàng)建CompletableFuture實(shí)例
這篇文章主要介紹了Java8 使用工廠方法supplyAsync創(chuàng)建CompletableFuture實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11一文講透為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)
這篇文章主要為大家介紹了為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)的透徹詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04詳解SpringBoot程序啟動時(shí)執(zhí)行初始化代碼
這篇文章主要介紹了詳解SpringBoot程序啟動時(shí)執(zhí)行初始化代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09SpringCloud Webflux過濾器增加header傳遞方式
這篇文章主要介紹了SpringCloud Webflux過濾器增加header傳遞方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02