全國(guó)咨詢(xún)/投訴熱線:400-618-4000

首頁(yè)技術(shù)文章正文

一文講透支付寶沙箱的基本應(yīng)用

更新時(shí)間:2022-11-10 來(lái)源:黑馬程序員 瀏覽量:

   在長(zhǎng)期的教學(xué)過(guò)程中,了解到很多同學(xué)在進(jìn)行畢業(yè)設(shè)計(jì)或課程設(shè)計(jì)時(shí)會(huì)開(kāi)發(fā)一些相應(yīng)的商城系統(tǒng),都有在線支付的相關(guān)需求,而做為個(gè)人,想在實(shí)現(xiàn)在線支付在很多平臺(tái)是不具備相關(guān)條件的,很多平臺(tái)要求具備獨(dú)立法人資格的企業(yè)或個(gè)人商業(yè)戶才可以申請(qǐng)?jiān)诰€支付,而支付寶提供的沙箱環(huán)境,對(duì)于個(gè)人實(shí)現(xiàn)在線支付測(cè)試環(huán)境來(lái)講,是一個(gè)不錯(cuò)的選擇,本文主要講解基于支付寶的沙箱環(huán)境來(lái)實(shí)現(xiàn)在線支付的功能。主要結(jié)合一個(gè)簡(jiǎn)易的商城系統(tǒng)來(lái)講解說(shuō)明在線支付的基本操作流程和相關(guān)API的應(yīng)用,從而實(shí)現(xiàn)基于支付寶沙箱在線支付的基本功能。

  一、案例說(shuō)明

   本案例基于一個(gè)簡(jiǎn)易的商城系統(tǒng),在這個(gè)系統(tǒng)基礎(chǔ)上實(shí)現(xiàn)在了在線沙箱支付的基本應(yīng)用。系統(tǒng)只保留了基本的商品展示和購(gòu)物基本功能,其它功能接口全部刪除。系統(tǒng)基于前后端分離的開(kāi)發(fā)方式,前端使用VUE開(kāi)發(fā)實(shí)現(xiàn),后端使用Springboot結(jié)合Mybatis開(kāi)發(fā)實(shí)現(xiàn)。

   首頁(yè)商品展示

1668063810582_1.jpg

  商品詳情

1668063824470_2.jpg

  點(diǎn)擊立即付款后進(jìn)入支付寶付款流程

 

1668063850100_3.jpg

  點(diǎn)擊下一步:

  

1668063879834_4.jpg

  確認(rèn)付款

  

1668063897638_5.jpg

  完成支付

  看完了案例的演示,是不是有一種想試一試的沖突,感覺(jué)好簡(jiǎn)單?OK,那么我們一起開(kāi)始學(xué)習(xí)支付寶沙箱支付的旅程!

  二,支付寶沙箱環(huán)境準(zhǔn)備

  2.1 支付寶沙箱介紹

   沙箱環(huán)境是支付寶開(kāi)放平臺(tái)為開(kāi)發(fā)者提供的與生產(chǎn)環(huán)境完全隔離的聯(lián)調(diào)測(cè)試環(huán)境,開(kāi)發(fā)者在沙箱環(huán)境中完成的接口調(diào)用不會(huì)對(duì)生產(chǎn)環(huán)境中的數(shù)據(jù)造成任何影響。

   沙箱為開(kāi)放的產(chǎn)品提供有限功能范圍的支持,可以覆蓋產(chǎn)品的絕大部分核心鏈路和對(duì)接邏輯,便于開(kāi)發(fā)者快速學(xué)習(xí)/嘗試/開(kāi)發(fā)/調(diào)試。

   沙箱環(huán)境會(huì)自動(dòng)完成或忽略一些場(chǎng)景的業(yè)務(wù)門(mén)檻,例如:開(kāi)發(fā)者無(wú)需等待產(chǎn)品開(kāi)通,即可直接在沙箱環(huán)境調(diào)用接口,使得開(kāi)發(fā)集成工作可以與業(yè)務(wù)流程并行,從而提高項(xiàng)目整體的交付效率。

  注意:

  - 由于沙箱環(huán)境并非 100% 與生產(chǎn)環(huán)境一致,接口的實(shí)際響應(yīng)邏輯請(qǐng)以生產(chǎn)環(huán)境為準(zhǔn),沙箱環(huán)境開(kāi)發(fā)調(diào)試完成后,仍然需要在生產(chǎn)環(huán)境進(jìn)行測(cè)試驗(yàn)收。

  - 沙箱環(huán)境擁有完全獨(dú)立的數(shù)據(jù)體系,沙箱環(huán)境下返回的數(shù)據(jù)(比如用戶 ID 等)在生產(chǎn)環(huán)境中都是不存在的,開(kāi)發(fā)者不可將沙箱環(huán)境返回的數(shù)據(jù)與生產(chǎn)環(huán)境中的數(shù)據(jù)混淆。

  2.2 支付寶沙箱注冊(cè)及配置

   打開(kāi)支付寶開(kāi)發(fā)者頁(yè)面進(jìn)行注冊(cè)登陸:https://opendocs.alipay.com/common/02kkv7

   登陸后進(jìn)入開(kāi)放平臺(tái)控制臺(tái):選擇左下解沙箱

1668063929950_6.jpg

  
       在沙箱應(yīng)用中可以查看沙箱的相關(guān)信息,其中APPID需要復(fù)制并記錄,我們?cè)谶M(jìn)行支付時(shí)要指定APPID。

  

1668063957774_7.jpg

  其它的均保持默認(rèn)配置即可,接口的加簽方式選擇系統(tǒng)默認(rèn)密鑰即可,選用公鑰模式,點(diǎn)擊查看可以看到對(duì)應(yīng)的公鑰和私鑰:做支付時(shí)需要用到。

  

1668063973842_8.jpg

  支付寶網(wǎng)關(guān)地址:https://openapi.alipaydev.com/gateway.do

  支付寶沙箱網(wǎng)關(guān)地址,開(kāi)發(fā)者在沙箱環(huán)境調(diào)用 OpenAPI 發(fā)送 http(s) 請(qǐng)求的目標(biāo)地址,需配置在AlipayClient中。此地址為固定的,在程序中需要配置。

  選擇左邊沙賬戶:創(chuàng)建申請(qǐng)個(gè)人和商家對(duì)應(yīng)的虛擬賬戶,并可以在線模擬充值和取現(xiàn)。

  

1668063997381_9.jpg

  至此,我們需要準(zhǔn)備的沙箱環(huán)境和配置己準(zhǔn)備就緒。

  三,內(nèi)網(wǎng)穿透工具準(zhǔn)備

   支付寶沙箱支付成功后,要回調(diào)本地的服務(wù)地址進(jìn)行支付結(jié)果的通知,而我們的測(cè)試環(huán)境是運(yùn)行在內(nèi)網(wǎng)中,所以需要借助內(nèi)網(wǎng)穿透工具來(lái)實(shí)現(xiàn)外網(wǎng)調(diào)用內(nèi)網(wǎng)的服務(wù)接口。內(nèi)網(wǎng)穿透的工具網(wǎng)上有很多免費(fèi)的,我們今天使用的是NATAPP這款工具。

   1、打開(kāi)官網(wǎng)注冊(cè)并登陸:https://natapp.cn/login

   2、登陸后選擇購(gòu)買(mǎi)隧道:選擇免費(fèi)隧道(有效期一個(gè)月)

 

1668064026939_10.jpg

  3、指定名字,選擇Web協(xié)議,并指定本地的應(yīng)用通訊的端口

  

1668064042411_11.jpg

  4、購(gòu)買(mǎi)成功后會(huì)生成認(rèn)證令牌:復(fù)制并保存

  

1668064059288_12.jpg

  5、下載客戶端工具:根據(jù)你電腦情況選擇合適的版本下載,這里我選用Windows64位

  

1668064074871_13.jpg

  6、創(chuàng)建配置文件:config.ini 具體下載:https://natapp.cn/article/config_ini

   放在客戶端natapp.exe同級(jí)目錄下,并將其中的authtoken換成我們剛申請(qǐng)的免費(fèi)隧道的令牌

  

1668064089129_14.jpg

  7、啟動(dòng)客戶端:windows下,直接雙擊natapp.exe 即可。紅框內(nèi)就是我們的隧道通信地址。

  

1668064110100_15.jpg

   注意:每次啟動(dòng)客戶端都會(huì)分配一個(gè)新的隧道地址:要注意后期更換程序中配置 的地址。

  8、測(cè)試:此時(shí)t2vnvc.natappfree.cc臨時(shí)域名就是代表了本地應(yīng)用程序的訪問(wèn)地址http://localhost:80

   可以直接使用此域名來(lái)訪問(wèn)應(yīng)用程序下的任意一個(gè)接口,如能訪問(wèn),則環(huán)境OK。

   http://t2vnvc.natappfree.cc/order/findAll 查詢(xún)所有訂單:測(cè)試成功

1668064136310_16.jpg

  四,沙箱支付相關(guān)API說(shuō)明

  支付寶支付提供了很多種支付應(yīng)用場(chǎng)景以及對(duì)應(yīng)的API應(yīng)用,打開(kāi)網(wǎng)址:https://open.alipay.com/api

  

1668064164101_17.jpg

   可以看到有對(duì)應(yīng)的應(yīng)用類(lèi)型:選中其中某一個(gè)進(jìn)入,則有相關(guān)的文檔介紹和API應(yīng)用案例,所以學(xué)習(xí)和使用起來(lái)還是比較簡(jiǎn)單。

  4.1 當(dāng)面付

   如果我們想通過(guò)支付寶生成二維碼,讓客戶端掃描二維碼進(jìn)行支付,可以選擇當(dāng)面付:

   https://open.alipay.com/api/detail?code=I1080300001000041016#api-detail-content

1668064184376_18.jpg

  各個(gè)接口有在線文檔和在線調(diào)試的案例,可以自行查看。以其中的統(tǒng)一收單線下交易預(yù)創(chuàng)建為例說(shuō)明:

package com.java.sdk.demo;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;

public class AlipayTradePrecreate {

    public static void main(String[] args) throws AlipayApiException {
        String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCs5FX6NlZEq8t43tnAT91hcGhTPL6Iieq/e1foh3N0ME601PwtfXzFPac0Qp5qygLtyZkYFY8UiYqdXPQpvO4T4ah5Rus8IiCwGDBpyg3ha6xSWnD7QCvc/YgOJ+ei1XD6F5Y+t2X3gbTCsy1H9wTe9XLh78tcpuhib/4OEwxJfHxEi5fBzQQJBE6vo8pX7mTeeP7f1RBxAgRsswMvCQs1SX362XdD3IRWErf8dUOqV0tT5ahjhXdbFv6fUQmnt+1i00CIAlOPm7vLWslw1qJT4ubZuL0HPQLWEoD3ab0OdgaJvPdoWvnUVzBQqwZgnXHFN5nV1QQbVTe3Q3XWIWTNAgMBAAECggEBAI2JI8WBRCBVj2306cgg2XfSQOWbfdNjLHTzMaUfdemxPk2VapiG+WSzMzV6MBv2Im2tsxHfXFGQw5RNq2ibzT8jZftajmqc+auPMdr42WIn9ls4xPM6tm3kc8Q68MsB9soWEx5mnyf+3A7kBfa7BxbLUvAZkZ7Y2Lb1PcMh3tYso7FYERStxpdtUgPSkqXgZERrzrtHpFDe05CI/xjZUfmvXsTrKiIXxqvil9hYGISkMyVJjaJUXvZwmgzLtHd7I8z7sNXOw26Ie1DihCy3VzPh5pwZPQId2v2LBABdUogTwVfb7GAV6swP+OMxoffYPdW7AV+82zOYybm3GjKCTiECgYEA57ukyNybLE7h7yeDSFKdkoBnY7RmIW4NRwQNFopb5LlNt9vTm5easuEdDhPlGoNpJ5Ul/ms9pDVDnH2ZkU7IaiMPd/MxQpQ5dos5tRsjb02YwligiD3ZxDBRCNSjcqiR7+5jYb68H2c8bXLtOtZ/dsYyqZmEhH0OsV/2WKMr9bUCgYEAvv9EO9J2UEVBPkEKvhLfH7X8GZK6CROEehNG8qbDqxJ5AbFmo8lzNvbcHjJoiwEMzYU1q5VMhMVMepk1Lk5Q4VRouAMTUY3o8byQMeX7BYHlmmLaXuw8NAFFE43Mr14UGkrWesZR9u1LSw0QPNag3cyL2XxmgpWCmPAwLzQ+obkCgYEAnFukKFOR8CeZkwCaOGZmI7+4AzJp5wyWsOAu5JKexomxwuj0svtsSl5SeHk8ENOyVB7y7+P0R6QY5rJot/7sg5D8kvbouf/Bdhci7OxO0H8PH7MlPkhdc18WjlrLnkXXkojLTdygmp/RyhfNsfGhN8crz/vhynOHQm95jP0sYDECgYBGJ2zgrEVY5pc4TpurhTL/atDWc9ZxTwHx9PKyXh6wz3Ay9v5EWtI+9h2T2eAcbp5NPwifpY8dlXqp7WxjPdDncyGjtT17Tyyo3iH4sgip1TSIqJadFxhl4bGFpSfxohSwM5zkK8QfdrmZL4svTYZ48ZDMqazdeh0mH9MTA5WdwQKBgFO79TUR5fq+u0sBjYW7VLiQ5J6Tq7U0phFjFFjR/eYqkKUtE5K/BdOsSQjwY21TOkoTazyDJiVLEx5pWQueIa0ez1WPNswz7VN2su9N/jwP+G5ILrz1I+nj2PiWXVbfWZ2qd2h0qB27CF7gZ9lQgjg5dQMt4Fmd7f8uzBzrwLQW";
        String alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydfxVYSMISxqvitww5063ZQFVRzrcRW9a+xQ0Pozz7ve9IeK1h9p7xFwSUtTNi/ki9ZcnZ7wP0xunKrYPVXyUvRz/vSVnovkzvmcSTdqlgtzTAQTJFYL0nmzhnv4RWbcDnVbo+IIlu8g0p6wQv7V8P5EGpbh63+d3q/DYhsbxVVZN1fKjnw/y38/GuqGoiaxkcrf6h65rGO/aRGbX6gbGnRxUgBOEiFGFdkuCx9ACg4cskSme69lDbIBDpsmSbQpUKhTEA4Wv36mqrbee+hGf5sTaqDUHl0/SPgP45ab15J3BeWHB/yXbdK4Z/gPfMFMweOupg54Sm+kJOGmq73cMwIDAQAB";
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl("https://openapi.alipaydev.com/gateway.do");
        alipayConfig.setAppId("2021000121607425");
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF8");
        alipayConfig.setSignType("RSA2");
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo("20150320010101001");
        model.setTotalAmount("88.88");
        model.setSubject("Iphone6 16G");
        request.setBizModel(model);
        AlipayTradePrecreateResponse response = alipayClient.execute(request);
        //可以將此字符串返回到客戶端,使用二維碼生成工具來(lái)生成二維碼圖片即可
        System.out.println("支付地址:"+response.getQrCode());
       
        if (response.isSuccess()) {
            System.out.println("調(diào)用成功");
        } else {
            System.out.println("調(diào)用失敗");
        }
    }
}

  4.2 手機(jī)網(wǎng)站支付API

   如果我們基于手機(jī)網(wǎng)站來(lái)實(shí)現(xiàn)在線支付,比如HTML5網(wǎng)站或小程序等,可以通過(guò)手機(jī)網(wǎng)站支付API進(jìn)行實(shí)現(xiàn):

  https://open.alipay.com/api/detail?code=I1080300001000041949

1668064560177_19.jpg

  各個(gè)接口有在線文檔和在線調(diào)試的案例,可以自行查看。以其中的手機(jī)網(wǎng)站支付接口2.0為例說(shuō)明:

package com.java.sdk.demo;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.AlipayConfig;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;

public class AlipayTradeWapPay {

    public static void main(String[] args) throws AlipayApiException {
        String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCs5FX6NlZEq8t43tnAT91hcGhTPL6Iieq/e1foh3N0ME601PwtfXzFPac0Qp5qygLtyZkYFY8UiYqdXPQpvO4T4ah5Rus8IiCwGDBpyg3ha6xSWnD7QCvc/YgOJ+ei1XD6F5Y+t2X3gbTCsy1H9wTe9XLh78tcpuhib/4OEwxJfHxEi5fBzQQJBE6vo8pX7mTeeP7f1RBxAgRsswMvCQs1SX362XdD3IRWErf8dUOqV0tT5ahjhXdbFv6fUQmnt+1i00CIAlOPm7vLWslw1qJT4ubZuL0HPQLWEoD3ab0OdgaJvPdoWvnUVzBQqwZgnXHFN5nV1QQbVTe3Q3XWIWTNAgMBAAECggEBAI2JI8WBRCBVj2306cgg2XfSQOWbfdNjLHTzMaUfdemxPk2VapiG+WSzMzV6MBv2Im2tsxHfXFGQw5RNq2ibzT8jZftajmqc+auPMdr42WIn9ls4xPM6tm3kc8Q68MsB9soWEx5mnyf+3A7kBfa7BxbLUvAZkZ7Y2Lb1PcMh3tYso7FYERStxpdtUgPSkqXgZERrzrtHpFDe05CI/xjZUfmvXsTrKiIXxqvil9hYGISkMyVJjaJUXvZwmgzLtHd7I8z7sNXOw26Ie1DihCy3VzPh5pwZPQId2v2LBABdUogTwVfb7GAV6swP+OMxoffYPdW7AV+82zOYybm3GjKCTiECgYEA57ukyNybLE7h7yeDSFKdkoBnY7RmIW4NRwQNFopb5LlNt9vTm5easuEdDhPlGoNpJ5Ul/ms9pDVDnH2ZkU7IaiMPd/MxQpQ5dos5tRsjb02YwligiD3ZxDBRCNSjcqiR7+5jYb68H2c8bXLtOtZ/dsYyqZmEhH0OsV/2WKMr9bUCgYEAvv9EO9J2UEVBPkEKvhLfH7X8GZK6CROEehNG8qbDqxJ5AbFmo8lzNvbcHjJoiwEMzYU1q5VMhMVMepk1Lk5Q4VRouAMTUY3o8byQMeX7BYHlmmLaXuw8NAFFE43Mr14UGkrWesZR9u1LSw0QPNag3cyL2XxmgpWCmPAwLzQ+obkCgYEAnFukKFOR8CeZkwCaOGZmI7+4AzJp5wyWsOAu5JKexomxwuj0svtsSl5SeHk8ENOyVB7y7+P0R6QY5rJot/7sg5D8kvbouf/Bdhci7OxO0H8PH7MlPkhdc18WjlrLnkXXkojLTdygmp/RyhfNsfGhN8crz/vhynOHQm95jP0sYDECgYBGJ2zgrEVY5pc4TpurhTL/atDWc9ZxTwHx9PKyXh6wz3Ay9v5EWtI+9h2T2eAcbp5NPwifpY8dlXqp7WxjPdDncyGjtT17Tyyo3iH4sgip1TSIqJadFxhl4bGFpSfxohSwM5zkK8QfdrmZL4svTYZ48ZDMqazdeh0mH9MTA5WdwQKBgFO79TUR5fq+u0sBjYW7VLiQ5J6Tq7U0phFjFFjR/eYqkKUtE5K/BdOsSQjwY21TOkoTazyDJiVLEx5pWQueIa0ez1WPNswz7VN2su9N/jwP+G5ILrz1I+nj2PiWXVbfWZ2qd2h0qB27CF7gZ9lQgjg5dQMt4Fmd7f8uzBzrwLQW";
        String alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydfxVYSMISxqvitww5063ZQFVRzrcRW9a+xQ0Pozz7ve9IeK1h9p7xFwSUtTNi/ki9ZcnZ7wP0xunKrYPVXyUvRz/vSVnovkzvmcSTdqlgtzTAQTJFYL0nmzhnv4RWbcDnVbo+IIlu8g0p6wQv7V8P5EGpbh63+d3q/DYhsbxVVZN1fKjnw/y38/GuqGoiaxkcrf6h65rGO/aRGbX6gbGnRxUgBOEiFGFdkuCx9ACg4cskSme69lDbIBDpsmSbQpUKhTEA4Wv36mqrbee+hGf5sTaqDUHl0/SPgP45ab15J3BeWHB/yXbdK4Z/gPfMFMweOupg54Sm+kJOGmq73cMwIDAQAB";
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl("https://openapi.alipaydev.com/gateway.do");
        alipayConfig.setAppId("2021000121607425");
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF8");
        alipayConfig.setSignType("RSA2");
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo("70501111111S001111119");
        model.setTotalAmount("9.00");
        model.setSubject("大樂(lè)透");
        //手機(jī)網(wǎng)站支付指定productCode為固定值:QUICK_WAP_WAY
        model.setProductCode("QUICK_WAP_WAY");
        model.setSellerId("2088102147948060");
        request.setBizModel(model);
        AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
        //getBody()返回的就是提交支付的嵌套頁(yè)面,返回前端后自動(dòng)跳轉(zhuǎn)到支付寶支付操作界面
        System.out.println(response.getBody());
        if (response.isSuccess()) {
            System.out.println("調(diào)用成功");
        } else {
            System.out.println("調(diào)用失敗");
        }
    }
}

  4.3 電腦網(wǎng)站支付API

  如果我們基于PC電腦網(wǎng)站來(lái)實(shí)現(xiàn)在線支付,比如相關(guān)電商平臺(tái)等,可以通過(guò)電腦網(wǎng)站支付API進(jìn)行實(shí)現(xiàn):

  https://open.alipay.com/api/detail?code=I1080300001000041203#api-detail-content

 

1668064247157_20.jpg

  各個(gè)接口有在線文檔和在線調(diào)試的案例,可以自行查看。以其中的統(tǒng)一收單下單并支付頁(yè)面接口為例說(shuō)明:

package com.java.sdk.demo;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;

public class AlipayTradePagePay {

    public static void main(String[] args) throws AlipayApiException {
        String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCs5FX6NlZEq8t43tnAT91hcGhTPL6Iieq/e1foh3N0ME601PwtfXzFPac0Qp5qygLtyZkYFY8UiYqdXPQpvO4T4ah5Rus8IiCwGDBpyg3ha6xSWnD7QCvc/YgOJ+ei1XD6F5Y+t2X3gbTCsy1H9wTe9XLh78tcpuhib/4OEwxJfHxEi5fBzQQJBE6vo8pX7mTeeP7f1RBxAgRsswMvCQs1SX362XdD3IRWErf8dUOqV0tT5ahjhXdbFv6fUQmnt+1i00CIAlOPm7vLWslw1qJT4ubZuL0HPQLWEoD3ab0OdgaJvPdoWvnUVzBQqwZgnXHFN5nV1QQbVTe3Q3XWIWTNAgMBAAECggEBAI2JI8WBRCBVj2306cgg2XfSQOWbfdNjLHTzMaUfdemxPk2VapiG+WSzMzV6MBv2Im2tsxHfXFGQw5RNq2ibzT8jZftajmqc+auPMdr42WIn9ls4xPM6tm3kc8Q68MsB9soWEx5mnyf+3A7kBfa7BxbLUvAZkZ7Y2Lb1PcMh3tYso7FYERStxpdtUgPSkqXgZERrzrtHpFDe05CI/xjZUfmvXsTrKiIXxqvil9hYGISkMyVJjaJUXvZwmgzLtHd7I8z7sNXOw26Ie1DihCy3VzPh5pwZPQId2v2LBABdUogTwVfb7GAV6swP+OMxoffYPdW7AV+82zOYybm3GjKCTiECgYEA57ukyNybLE7h7yeDSFKdkoBnY7RmIW4NRwQNFopb5LlNt9vTm5easuEdDhPlGoNpJ5Ul/ms9pDVDnH2ZkU7IaiMPd/MxQpQ5dos5tRsjb02YwligiD3ZxDBRCNSjcqiR7+5jYb68H2c8bXLtOtZ/dsYyqZmEhH0OsV/2WKMr9bUCgYEAvv9EO9J2UEVBPkEKvhLfH7X8GZK6CROEehNG8qbDqxJ5AbFmo8lzNvbcHjJoiwEMzYU1q5VMhMVMepk1Lk5Q4VRouAMTUY3o8byQMeX7BYHlmmLaXuw8NAFFE43Mr14UGkrWesZR9u1LSw0QPNag3cyL2XxmgpWCmPAwLzQ+obkCgYEAnFukKFOR8CeZkwCaOGZmI7+4AzJp5wyWsOAu5JKexomxwuj0svtsSl5SeHk8ENOyVB7y7+P0R6QY5rJot/7sg5D8kvbouf/Bdhci7OxO0H8PH7MlPkhdc18WjlrLnkXXkojLTdygmp/RyhfNsfGhN8crz/vhynOHQm95jP0sYDECgYBGJ2zgrEVY5pc4TpurhTL/atDWc9ZxTwHx9PKyXh6wz3Ay9v5EWtI+9h2T2eAcbp5NPwifpY8dlXqp7WxjPdDncyGjtT17Tyyo3iH4sgip1TSIqJadFxhl4bGFpSfxohSwM5zkK8QfdrmZL4svTYZ48ZDMqazdeh0mH9MTA5WdwQKBgFO79TUR5fq+u0sBjYW7VLiQ5J6Tq7U0phFjFFjR/eYqkKUtE5K/BdOsSQjwY21TOkoTazyDJiVLEx5pWQueIa0ez1WPNswz7VN2su9N/jwP+G5ILrz1I+nj2PiWXVbfWZ2qd2h0qB27CF7gZ9lQgjg5dQMt4Fmd7f8uzBzrwLQW";
        String alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydfxVYSMISxqvitww5063ZQFVRzrcRW9a+xQ0Pozz7ve9IeK1h9p7xFwSUtTNi/ki9ZcnZ7wP0xunKrYPVXyUvRz/vSVnovkzvmcSTdqlgtzTAQTJFYL0nmzhnv4RWbcDnVbo+IIlu8g0p6wQv7V8P5EGpbh63+d3q/DYhsbxVVZN1fKjnw/y38/GuqGoiaxkcrf6h65rGO/aRGbX6gbGnRxUgBOEiFGFdkuCx9ACg4cskSme69lDbIBDpsmSbQpUKhTEA4Wv36mqrbee+hGf5sTaqDUHl0/SPgP45ab15J3BeWHB/yXbdK4Z/gPfMFMweOupg54Sm+kJOGmq73cMwIDAQAB";
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setServerUrl("https://openapi.alipaydev.com/gateway.do");
        alipayConfig.setAppId("2021000121607425");
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF8");
        alipayConfig.setSignType("RSA2");
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo("20150320010101001");
        model.setTotalAmount("88.88");
        model.setSubject("Iphone6 16G");
        //電腦網(wǎng)站支付指定productCode為固定值:FAST_INSTANT_TRADE_PAY
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        request.setBizModel(model);
        AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
        //getBody()返回的就是提交支付的嵌套頁(yè)面,返回前端后自動(dòng)跳轉(zhuǎn)到支付寶支付操作界面
        System.out.println(response.getBody());
        if (response.isSuccess()) {
            System.out.println("調(diào)用成功");
        } else {
            System.out.println("調(diào)用失敗");
        }
    }
}

  五,沙箱支付功能實(shí)現(xiàn)

  我們今天就以電腦網(wǎng)站支付為例進(jìn)行講解實(shí)現(xiàn)。

  后臺(tái)開(kāi)發(fā)實(shí)現(xiàn)步驟:

  5.1:支付功能的實(shí)現(xiàn)

   1、創(chuàng)建配置類(lèi):配置沙箱相關(guān)環(huán)境信息 把配置類(lèi)中相關(guān)的信息改為自己的即可。

package com.qiu.config;

import com.qiu.util.general.PropertiesUtil;
import lombok.Data;
import org.springframework.stereotype.Component;

/**
 * @author ZNZ
 */
@Data
@Component
public class AlipayConfig {
    /**
     * 沙箱appId
     */
    public static final String APPID = "2021000121607425";
    /**
     * 請(qǐng)求網(wǎng)關(guān)  固定
     */
    public static final String URL = "https://openapi.alipaydev.com/gateway.do";

    /**
     * 設(shè)置內(nèi)網(wǎng)穿透回調(diào)地址
     */
    public static final String CALLBACK = "fcswjw.natappfree.cc";
    /**
     * 編碼
     */
    public static final String CHARSET = "UTF-8";

    /**
     * 返回格式
     */
    public static final String FORMAT = "json";

    /**
     * RSA2
     */
    public static final String SIGNTYPE = "RSA2";

    /**
     * 異步通知地址
     */
     public static final String NOTIFY_URL = "http://"+CALLBACK+"/alipay/notify";
    /**
     * 同步地址
     */
     //使用內(nèi)網(wǎng)穿透進(jìn)行回調(diào)
    public static final String RETURN_URL = "http://"+CALLBACK+"/alipay/success";

    /**
     * 應(yīng)用私鑰 pkcs8格式
     */
    public static final String RSA_PRIVATE_KEY =
            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCs5FX6NlZEq8t43tnAT91hcGhTPL6Iieq/e1foh3N0ME601PwtfXzFPac0Qp5qygLtyZkYFY8UiYqdXPQpvO4T4ah5Rus8IiCwGDBpyg3ha6xSWnD7QCvc/YgOJ+ei1XD6F5Y+t2X3gbTCsy1H9wTe9XLh78tcpuhib/4OEwxJfHxEi5fBzQQJBE6vo8pX7mTeeP7f1RBxAgRsswMvCQs1SX362XdD3IRWErf8dUOqV0tT5ahjhXdbFv6fUQmnt+1i00CIAlOPm7vLWslw1qJT4ubZuL0HPQLWEoD3ab0OdgaJvPdoWvnUVzBQqwZgnXHFN5nV1QQbVTe3Q3XWIWTNAgMBAAECggEBAI2JI8WBRCBVj2306cgg2XfSQOWbfdNjLHTzMaUfdemxPk2VapiG+WSzMzV6MBv2Im2tsxHfXFGQw5RNq2ibzT8jZftajmqc+auPMdr42WIn9ls4xPM6tm3kc8Q68MsB9soWEx5mnyf+3A7kBfa7BxbLUvAZkZ7Y2Lb1PcMh3tYso7FYERStxpdtUgPSkqXgZERrzrtHpFDe05CI/xjZUfmvXsTrKiIXxqvil9hYGISkMyVJjaJUXvZwmgzLtHd7I8z7sNXOw26Ie1DihCy3VzPh5pwZPQId2v2LBABdUogTwVfb7GAV6swP+OMxoffYPdW7AV+82zOYybm3GjKCTiECgYEA57ukyNybLE7h7yeDSFKdkoBnY7RmIW4NRwQNFopb5LlNt9vTm5easuEdDhPlGoNpJ5Ul/ms9pDVDnH2ZkU7IaiMPd/MxQpQ5dos5tRsjb02YwligiD3ZxDBRCNSjcqiR7+5jYb68H2c8bXLtOtZ/dsYyqZmEhH0OsV/2WKMr9bUCgYEAvv9EO9J2UEVBPkEKvhLfH7X8GZK6CROEehNG8qbDqxJ5AbFmo8lzNvbcHjJoiwEMzYU1q5VMhMVMepk1Lk5Q4VRouAMTUY3o8byQMeX7BYHlmmLaXuw8NAFFE43Mr14UGkrWesZR9u1LSw0QPNag3cyL2XxmgpWCmPAwLzQ+obkCgYEAnFukKFOR8CeZkwCaOGZmI7+4AzJp5wyWsOAu5JKexomxwuj0svtsSl5SeHk8ENOyVB7y7+P0R6QY5rJot/7sg5D8kvbouf/Bdhci7OxO0H8PH7MlPkhdc18WjlrLnkXXkojLTdygmp/RyhfNsfGhN8crz/vhynOHQm95jP0sYDECgYBGJ2zgrEVY5pc4TpurhTL/atDWc9ZxTwHx9PKyXh6wz3Ay9v5EWtI+9h2T2eAcbp5NPwifpY8dlXqp7WxjPdDncyGjtT17Tyyo3iH4sgip1TSIqJadFxhl4bGFpSfxohSwM5zkK8QfdrmZL4svTYZ48ZDMqazdeh0mH9MTA5WdwQKBgFO79TUR5fq+u0sBjYW7VLiQ5J6Tq7U0phFjFFjR/eYqkKUtE5K/BdOsSQjwY21TOkoTazyDJiVLEx5pWQueIa0ez1WPNswz7VN2su9N/jwP+G5ILrz1I+nj2PiWXVbfWZ2qd2h0qB27CF7gZ9lQgjg5dQMt4Fmd7f8uzBzrwLQW";

    /**
     * 沙箱支付寶公鑰
     */
    public static final String ALIPAY_PUBLIC_KEY =
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydfxVYSMISxqvitww5063ZQFVRzrcRW9a+xQ0Pozz7ve9IeK1h9p7xFwSUtTNi/ki9ZcnZ7wP0xunKrYPVXyUvRz/vSVnovkzvmcSTdqlgtzTAQTJFYL0nmzhnv4RWbcDnVbo+IIlu8g0p6wQv7V8P5EGpbh63+d3q/DYhsbxVVZN1fKjnw/y38/GuqGoiaxkcrf6h65rGO/aRGbX6gbGnRxUgBOEiFGFdkuCx9ACg4cskSme69lDbIBDpsmSbQpUKhTEA4Wv36mqrbee+hGf5sTaqDUHl0/SPgP45ab15J3BeWHB/yXbdK4Z/gPfMFMweOupg54Sm+kJOGmq73cMwIDAQAB";

    private AlipayConfig() {
    }
}

  2、定義支付接口地址:用戶點(diǎn)擊立即購(gòu)買(mǎi)后提交請(qǐng)求至下單接口,添加訂單成功后,發(fā)送請(qǐng)求到支付接口,向支付寶發(fā)送支付請(qǐng)求。

  前端頁(yè)面代碼:在前端工程src/comments/mall/MallPurchase.vue中

createOrder(formName){
        this.$refs[formName].validate((valid) => {
            if (valid) {
              if(this.isVip){
                this.order.payPrice = this.order.discountPrice;
              }
              let loading = this.$loading({lock: true, text: "訂單提交中",background:"rgba(255,255,255,0.1)"});
              this.$http.post('/order/add',this.$qs.stringify(this.order,{skipNulls: true})).then((rep)=>{
                loading.close();
                if(rep.data.code===200){
                  let orderNo = this.order.orderNo;
                  let orderName = '新新商城-'+this.productInfo.productType+'-'+this.productInfo.productName+'支付訂單';
                  let payPrice = this.order.payPrice;
                  let loading = this.$loading({lock: true, text: "正在跳轉(zhuǎn)支付頁(yè)面",background:"rgba(255,255,255,0.1)"});
                  this.$http.post('/alipay/create?orderNo='+orderNo+'&orderName='+orderName+'&payPrice='+payPrice).then((response)=>{
                    loading.close();
                    const div = document.createElement('div');
                    div.innerHTML = response.data;
                    document.body.appendChild(div);
                    document.forms[document.forms.length-1].submit();
                  }).catch((err)=>{loading.close();this.$msg.error(err)})
                }
              }).catch((err)=>{loading.close();this.$msg.error(err);})
              this.orderFormVisible=false;
            }else{
              return false;
            }
        });
      }

  后端對(duì)應(yīng)的支付接口實(shí)現(xiàn):AlipayController

/**
     * 創(chuàng)建支付
     * @param orderNo
     * @param orderName
     * @param payPrice
     * @return
     */
    @ResponseBody
    @PostMapping(value = "/create", produces = "text/html;charset=utf-8")
    public String create(@RequestParam("orderNo") String orderNo,
                         @RequestParam("orderName") String orderName,
                         @RequestParam("payPrice") String payPrice) {
        return alipayService.create(orderNo, orderName, payPrice);
    }

  業(yè)務(wù)方法實(shí)現(xiàn):

/**
     * 創(chuàng)建支付訂單
     *
     * @param orderId   訂單編號(hào)
     * @param orderName 訂單名稱(chēng)
     * @param payPrice  支付金額
     * @return 支付表單
     */
    @Override
    public String create(String orderId, String orderName, String payPrice) {
        //創(chuàng)建支付寶支付連接客戶端
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,
                AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT,
                AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,
                AlipayConfig.SIGNTYPE);
        AlipayTradeWapPayRequest payRequest = new AlipayTradeWapPayRequest();
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(orderId);
        model.setSubject(orderName);
        model.setTotalAmount(payPrice);
        model.setProductCode(PRODUCTCODE);
        payRequest.setBizModel(model);
        payRequest.setReturnUrl(AlipayConfig.RETURN_URL);
        payRequest.setNotifyUrl(AlipayConfig.NOTIFY_URL);
        try {
            return client.pageExecute(payRequest).getBody();
        } catch (AlipayApiException e) {
            log.error("[支付寶] 支付失敗", e);
        }
        return null;
    }

  此接口返回的字符串其實(shí)是一個(gè)FORM表單,并執(zhí)行自動(dòng)提交:所以接口執(zhí)行完后自動(dòng)跳轉(zhuǎn)到支付寶支付平臺(tái)頁(yè)面。

<form name="punchout_form" method="post" action="https://openapi.alipaydev.com/gateway.do?charset=UTF-8&method=alipay.trade.wap.pay&sign=bdVLwcblQMIpdDuHtLtrT6J9KK4IH0Y0FgfS4TVO61VBrG8xfKHitFafkoNAKL6CvPjEoxAhr2cSjluRirt6FpLAffrTd0iVHctBD6JBoK3oUy1j472c8onqZ9x5y896bi3zRObobc7ygJEvvR04RdwIAQPPHObkKjvNEta5qqHOW9S%2FApZSBoPqBZozkijWXhsQDlCmIpvd%2FH4LlHAcpQe67owOAujsJezrGA2cg7Exm50rUGyiAVhA3ICsqi9PVFWU4FbD3jdELHTD3%2BgP2l7%2FLzWMeEIUj9Y0vw6wU9xI%2FhPl1emZGt9iUHLce3NetowYh96kdR6vnfYSYBZhJw%3D%3D&return_url=http%3A%2F%2Ft2vnvc.natappfree.cc%2Falipay%2Fsuccess&notify_url=http%3A%2F%2Ft2vnvc.natappfree.cc%2Falipay%2Fnotify&version=1.0&app_id=2021000121607425&sign_type=RSA2&timestamp=2022-07-17+16%3A09%3A55&alipay_sdk=alipay-sdk-java-4.10.192.ALL&format=json">
<input type="hidden" name="biz_content" value="{&quot;out_trade_no&quot;:&quot;2271716507374&quot;,&quot;product_code&quot;:&quot;QUICK_WAP_WAY&quot;,&quot;subject&quot;:&quot;新新商城-生活家電-米家互聯(lián)網(wǎng)洗烘一體機(jī)Pro 20kg支付訂單&quot;,&quot;total_amount&quot;:&quot;3299.00&quot;}">
<input type="submit" value="立即支付" style="display:none" >
</form>
<script>document.forms[0].submit();</script>

  然后就進(jìn)入到了我們文章開(kāi)頭展示的支付流程頁(yè)面:

  

1668064325002_21.jpg

  可以對(duì)照著沙箱的商家賬戶和買(mǎi)家賬戶的錢(qián)數(shù)來(lái)看看是否實(shí)現(xiàn)了買(mǎi)家賬戶扣款和商家賬戶收款的功能。

  

1668064345525_22.jpg

  5.2.回調(diào)本地接口更改支付狀態(tài)

   在線支付成功了,買(mǎi)家支付寶的賬戶的錢(qián)也已經(jīng)轉(zhuǎn)移到了商家的賬戶,可是本地應(yīng)用怎么知道支付是否成功呢?我們?cè)诒镜氐膽?yīng)用中也需要根據(jù)支付成功與否來(lái)更改訂單的支付狀態(tài),這就需要我們定義回調(diào)通知接口來(lái)實(shí)現(xiàn)。

   我們?cè)贏lipayConfig中已經(jīng)定義了回調(diào)的接口地址:

/**
     * 異步通知地址
     */
     public static final String NOTIFY_URL = "http://"+CALLBACK+"/alipay/notify";
```

     那么這個(gè)接口主要實(shí)現(xiàn)的功能就是根據(jù)支付的結(jié)果來(lái)實(shí)現(xiàn)訂單狀態(tài)的更新:

     在AlipayController中定義alipay/notify接口:
/**
    * @param map
    */
    @ResponseBody
    @PostMapping(value = "/notify")
    public String payNotify(@RequestParam Map<String, String> map) {
        if (TRADE_SUCCESS.equals(map.get(TRADE_STATUS))) {
            String payTime = map.get(TRADE_TIME);
            String tradeNo = map.get(OUT_TRADE_NO);
            String tradeName = map.get(TRADE_NAME);
            String payAmount = map.get(TRADE_AMOUNT);
            log.info("[支付成功] {交易時(shí)間:{},訂單號(hào):{},訂單名稱(chēng):{},交易金額:{}}", payTime, tradeNo, tradeName, payAmount);
        }
        return "success";
    }
/**
     * 支付回調(diào)成功
     * @param map
     * @param response
     */
    @GetMapping(value = "/success")
    public void success(@RequestParam Map<String, String> map, HttpServletResponse response) {
        try {
            String tradeNo = map.get(OUT_TRADE_NO);
            if (tradeNo.contains(VIP)) {
                openMember(response, tradeNo);
            } else {
                updateProductStatus(response, tradeNo);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 /**
     * 支付成功,更新商品狀態(tài)為待發(fā)貨
     *
     * @param response HTTP響應(yīng)
     * @param tradeNo  訂單編號(hào)
     * @throws IOException IO異常信息
     */
    private void updateProductStatus(HttpServletResponse response, String tradeNo) throws IOException {
         Integer orderId = orderService.selectIdByKey(orderNo);
         Order order = new Order();
         order.setOrderId(orderId);
         order.setOrderState("待發(fā)貨");
         orderService.updateById(order);
        //跳轉(zhuǎn)到我的訂單頁(yè)面
         response.sendRedirect("http://localhost:8080/#/myOrder");
    }

  六.總結(jié)

   支付寶沙箱支付給了我們一個(gè)模擬支付寶在線支付的環(huán)境來(lái)進(jìn)行測(cè)試,在本地通過(guò)沙箱支付測(cè)試成功后,可以在實(shí)際應(yīng)用中,將對(duì)應(yīng)的賬戶修改為自己企業(yè)賬號(hào)申請(qǐng)的對(duì)公支付的賬戶信息即可,支付寶對(duì)整個(gè)開(kāi)發(fā)提供的文檔和案例也是比較豐富的,對(duì)于我們?nèi)粘W(xué)習(xí)或做一些學(xué)校要求的簡(jiǎn)單課設(shè)來(lái)講,這篇文章所講解的基本支付功能應(yīng)該能幫到大家的。如果還需要實(shí)現(xiàn)其它的像退款等相關(guān)功能,查看文中給的API接口地址,根據(jù)官方案例進(jìn)行修改即可。

分享到:
在線咨詢(xún) 我要報(bào)名
和我們?cè)诰€交談!