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

一文講透支付寶沙箱的基本應用

更新時間:2022-11-10 來源:黑馬程序員 瀏覽量:

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

  一、案例說明

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

   首頁商品展示

1668063810582_1.jpg

  商品詳情

1668063824470_2.jpg

  點擊立即付款后進入支付寶付款流程

 

1668063850100_3.jpg

  點擊下一步:

  

1668063879834_4.jpg

  確認付款

  

1668063897638_5.jpg

  完成支付

  看完了案例的演示,是不是有一種想試一試的沖突,感覺好簡單?OK,那么我們一起開始學習支付寶沙箱支付的旅程!

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

  2.1 支付寶沙箱介紹

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

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

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

  注意:

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

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

  2.2 支付寶沙箱注冊及配置

   打開支付寶開發(fā)者頁面進行注冊登陸:https://opendocs.alipay.com/common/02kkv7

   登陸后進入開放平臺控制臺:選擇左下解沙箱

1668063929950_6.jpg

  
       在沙箱應用中可以查看沙箱的相關(guān)信息,其中APPID需要復制并記錄,我們在進行支付時要指定APPID。

  

1668063957774_7.jpg

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

  

1668063973842_8.jpg

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

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

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

  

1668063997381_9.jpg

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

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

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

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

   2、登陸后選擇購買隧道:選擇免費隧道(有效期一個月)

 

1668064026939_10.jpg

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

  

1668064042411_11.jpg

  4、購買成功后會生成認證令牌:復制并保存

  

1668064059288_12.jpg

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

  

1668064074871_13.jpg

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

   放在客戶端natapp.exe同級目錄下,并將其中的authtoken換成我們剛申請的免費隧道的令牌

  

1668064089129_14.jpg

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

  

1668064110100_15.jpg

   注意:每次啟動客戶端都會分配一個新的隧道地址:要注意后期更換程序中配置 的地址。

  8、測試:此時t2vnvc.natappfree.cc臨時域名就是代表了本地應用程序的訪問地址http://localhost:80

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

   http://t2vnvc.natappfree.cc/order/findAll 查詢所有訂單:測試成功

1668064136310_16.jpg

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

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

  

1668064164101_17.jpg

   可以看到有對應的應用類型:選中其中某一個進入,則有相關(guān)的文檔介紹和API應用案例,所以學習和使用起來還是比較簡單。

  4.1 當面付

   如果我們想通過支付寶生成二維碼,讓客戶端掃描二維碼進行支付,可以選擇當面付:

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

1668064184376_18.jpg

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

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);
        //可以將此字符串返回到客戶端,使用二維碼生成工具來生成二維碼圖片即可
        System.out.println("支付地址:"+response.getQrCode());
       
        if (response.isSuccess()) {
            System.out.println("調(diào)用成功");
        } else {
            System.out.println("調(diào)用失敗");
        }
    }
}

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

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

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

1668064560177_19.jpg

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

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("大樂透");
        //手機網(wǎng)站支付指定productCode為固定值:QUICK_WAP_WAY
        model.setProductCode("QUICK_WAP_WAY");
        model.setSellerId("2088102147948060");
        request.setBizModel(model);
        AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
        //getBody()返回的就是提交支付的嵌套頁面,返回前端后自動跳轉(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)站來實現(xiàn)在線支付,比如相關(guān)電商平臺等,可以通過電腦網(wǎng)站支付API進行實現(xiàn):

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

 

1668064247157_20.jpg

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

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()返回的就是提交支付的嵌套頁面,返回前端后自動跳轉(zhuǎn)到支付寶支付操作界面
        System.out.println(response.getBody());
        if (response.isSuccess()) {
            System.out.println("調(diào)用成功");
        } else {
            System.out.println("調(diào)用失敗");
        }
    }
}

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

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

  后臺開發(fā)實現(xiàn)步驟:

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

   1、創(chuàng)建配置類:配置沙箱相關(guān)環(huán)境信息 把配置類中相關(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";
    /**
     * 請求網(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)穿透進行回調(diào)
    public static final String RETURN_URL = "http://"+CALLBACK+"/alipay/success";

    /**
     * 應用私鑰 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、定義支付接口地址:用戶點擊立即購買后提交請求至下單接口,添加訂單成功后,發(fā)送請求到支付接口,向支付寶發(fā)送支付請求。

  前端頁面代碼:在前端工程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)支付頁面",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;
            }
        });
      }

  后端對應的支付接口實現(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ù)方法實現(xiàn):

/**
     * 創(chuàng)建支付訂單
     *
     * @param orderId   訂單編號
     * @param orderName 訂單名稱
     * @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;
    }

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

<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)洗烘一體機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>

  然后就進入到了我們文章開頭展示的支付流程頁面:

  

1668064325002_21.jpg

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

  

1668064345525_22.jpg

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

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

   我們在AlipayConfig中已經(jīng)定義了回調(diào)的接口地址:

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

     那么這個接口主要實現(xiàn)的功能就是根據(jù)支付的結(jié)果來實現(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("[支付成功] {交易時間:{},訂單號:{},訂單名稱:{},交易金額:{}}", 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響應
     * @param tradeNo  訂單編號
     * @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)到我的訂單頁面
         response.sendRedirect("http://localhost:8080/#/myOrder");
    }

  六.總結(jié)

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

分享到:
在線咨詢 我要報名
和我們在線交談!