支付寶沙箱環境的坑


首先這是一個好東西,不需要商家認證那些,開發者可以直接整代碼並且效果和實際上線效果是一樣的。是一些技術研究者的福音。

好了如題,直接上步驟,百度也是遇到了不少坑。

1、首先登陸支付寶https://open.alipay.com

使用掃一掃登陸,然后選擇沙箱環境

 

2、填寫一些相關的信息就會進入沙箱應用里面,先別急找參數,先生成公匙和私匙。點擊里面的生成方法,會下載一個文件。里面有使用說明。

  用里面的方法生成公匙后點擊查看應用公匙(RSA2)把生成的公匙填進去。支付寶應用公匙就會自動生成。官方是推薦使用2048位的。

  生成的私匙也要保存,但是不用填寫在該頁面。下面的密匙應用不用管它。

3、提取相關應用參數:注意這個支付寶公匙不是你剛才填寫的那個,是旁邊系統自動生成的那一個。

 

 

 

4、根據這些參數提取到java應用程序中。我上面的圖片是另一個項目的參考,所以回調地址與下面的參數不一致。實際應用中回調地址是要一致的。

在此改正:這是官方文檔說明。也就是應用網關 和回調地址 沙箱測試不用設置。避免誤導大家,本地部署項目並測試沙箱支付的就不用設置這兩個值了,因為這兩個值必須保證外網能訪問。

因此本地項目測試支付能成功 但是回調不能成功也就沒什么好糾結的了。然而我支付寶沙箱頁面沒設置,只是項目中設置了上面的同步和異步地址還是回調成功了!

  • 應用網關:該地址用於接收開放平台的異步通知。目前沙箱環境不需要配置此參數;
  • 授權回調地址;第三方應用授權或獲取用戶信息中用於接收授權回調信息的地址。使用相關產品時再進行配置;

         1. 第三方應用授權:

             授權url中的redirect_uri必須與此值相同。

         2. 獲取用戶信息:

             授權url中的redirect_uri的域名必須與此值相同。(例如:授權回調地址配置:https://auth.example.com/authCallBack 高亮部分需和授權url相同)

  • RSA(SHA1)密鑰:目前推薦使用RSA2(SHA256)密鑰,請參考第1步進行配置;
  • AES密鑰:目前不再使用;

 

5、繼續下一步,下載沙箱錢包。不過有點坑,我用手機掃一掃沒能下載,是在電腦端下載了再安裝到手機上的。

6、下載安裝了沙箱錢包。還要解決登錄賬號的問題,這點支付寶都沒有直接說明有點奇葩。

https://openhome.alipay.com/platform/appDaily.htm?tab=account

進這個地址,支付寶掃一掃就有了,使用下面的賬號登錄測試支付就好了

7、測試成功

 

支付寶沙箱環境還有一個很大的功能,那就是余額,你的沙箱支付寶余額幾百萬。

你把這余額給老丈人、小妹妹一看,瞬間被你征服啊。真是程序員泡妞把妹的神器啊,哈哈哈!

 

下面把支付寶支付的代碼貼一下,萌新可以看看,也就是兩個類。有時候失敗可能是沙箱設置的參數和項目不一致,公私匙。因為實際線上環境就有重新生成公私匙解決了問題的例子。

配置文件類AlipayConfig,這個自己換成沙箱支付的請求網關:https://openapi.alipaydev.com/gateway.do

package com.sanyi.qibaobusiness.framework.payment.ali.config;

public class AlipayConfig {
    //發起請求的應用ID。沙箱與線上不同,請更換代碼中配置;
    public static String app_id ="";
    //支付寶私匙
    public static String merchant_private_key = "";
    //支付寶公匙
    public static String alipay_public_key = "";
    //服務器異步通知路徑
    public static String notify_url = "http://127.0.01/alipay/alipayNotifyNotice.action";
    //服務器同步通知路徑
    public static String return_url = "http://127.0.0.1/alipay/alipayReturnNotice.action";
    //公匙類型/簽名類型
    public static String sign_type = "RSA2";
    //編碼格式
    public static String charset = "utf-8";
    //向支付寶發起請求的網關。沙箱與線上不同,請更換代碼中配置;沙箱:https://openapi.alipaydev.com/gateway.do上線https://openapi.alipay.com/gateway.do
    public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";
}
View Code
AlipayController發起支付請求的類
package com.sanyi.qibaobusiness.framework.payment.ali.controller;


import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 阿里支付
 */
@Controller
@RequestMapping("/alipay")
public class AlipayController {

    final static Logger log = LoggerFactory.getLogger(AlipayController.class);

    @Resource
    private RentingtoolsBiz rentingtoolsBiz; //暫時只有出租工具的訂單在這里支付
    @Resource
    private CustomerOrderBiz customerOrderBiz;
    @Resource
    private BrowseRecordsCommonUtil browseRecordsCommonUtil;

    /**
     * 前往支付寶第三方網關進行支付
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/goAlipay", produces = "text/html; charset=UTF-8")
    @ResponseBody
    public String goAlipay( HttpServletRequest request, HttpServletRequest response) throws Exception {
        BrowseRecordsUtil browseRecordsUtil= browseRecordsCommonUtil.getBrowseRecords(request);
        Order order=browseRecordsUtil.getPayOrder();
        //獲得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

        //設置請求參數
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);

        String out_trade_no =null;
        //付款金額,必填
        String total_amount = null;
        //訂單名稱,必填
        String subject = null;
        //商品描述,可空
        String body = null;
        // 該筆訂單允許的最晚付款時間,逾期將關閉交易。取值范圍:1m~15d。m-分鍾,h-小時,d-天,1c-當天(1c-當天的情況下,無論交易何時創建,都在0點關閉)。 該參數數值不接受小數點, 如 1.5h,可轉換為 90m。
        String timeout_express = "1c";
        if(null!=total_amount){ //支付金額不等於空
            alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                    + "\"total_amount\":\""+ total_amount +"\","
                    + "\"subject\":\""+ subject +"\","
                    + "\"body\":\""+ body +"\","
                    + "\"timeout_express\":\""+ timeout_express +"\","
                    + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

            //請求
            String result = alipayClient.pageExecute(alipayRequest).getBody();
            return result;
        }
        return "訂單信息錯誤!";
    }

    /**
     * 支付寶同步通知頁面,成功返回首頁
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/alipayReturnNotice")
    public String alipayReturnNotice(Model model,HttpServletRequest request, HttpServletRequest response) throws Exception {

        log.info("支付成功, 進入同步通知接口...");

        //獲取支付寶GET過來反饋信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //亂碼解決,這段代碼在出現亂碼時使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //調用SDK驗證簽名
        //——請在這里編寫您的程序(以下代碼僅作參考)——
        if(signVerified) {
            //商戶訂單號
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付寶交易號
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //付款金額,這里獲取到三個參數就可以了,后面邏輯代碼自己創作
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");

            int result=0;
            //這里根據自身的業務寫代碼,我這里刪掉了
            
            if(result==0){
                model.addAttribute("resultinfo","更新訂單失敗!請業務員聯系后台管理員!");
            }else {
                model.addAttribute("resultinfo","出租工具成功!");
            }
            log.info("********************** 支付成功(支付寶同步通知) **********************");
            log.info("* 訂單號: {}", out_trade_no);
            log.info("* 支付寶交易號: {}", trade_no);
            log.info("* 實付金額: {}", total_amount);
            log.info("***************************************************************");
        }else {
            log.info("支付, 驗簽失敗...");
        }
        return "/business/index";//成功返回首頁
    }

    /**
     * 支付寶異步 通知頁面
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/alipayNotifyNotice")
    @ResponseBody
    public String alipayNotifyNotice(HttpServletRequest request, HttpServletRequest response) throws Exception {

        log.info("支付成功, 進入異步通知接口...");

        //獲取支付寶POST過來反饋信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //亂碼解決,這段代碼在出現亂碼時使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //調用SDK驗證簽名
        //——請在這里編寫您的程序(以下代碼僅作參考)——
        /* 實際驗證過程建議商戶務必添加以下校驗:
        1、需要驗證該通知數據中的out_trade_no是否為商戶系統中創建的訂單號,
        2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單創建時的金額),
        3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)
        4、驗證app_id是否為該商戶本身。
        */
        if(signVerified) {//驗證成功
            //商戶訂單號
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付寶交易號
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //交易狀態
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

            //付款金額 到這里獲取到這些信息就可以了,下面的不用看
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");

            if(trade_status.equals("TRADE_FINISHED")){
                //判斷該筆訂單是否在商戶網站中已經做過處理
                //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
                //如果有做過處理,不執行商戶的業務程序

                //注意: 尚自習的訂單沒有退款功能, 這個條件判斷是進不來的, 所以此處不必寫代碼
                //退款日期超過可退款期限后(如三個月可退款),支付寶系統發送該交易狀態通知
            }else if (trade_status.equals("TRADE_SUCCESS")){
                //判斷該筆訂單是否在商戶網站中已經做過處理
                //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
                //如果有做過處理,不執行商戶的業務程序

                //注意:
                //付款完成后,支付寶系統發送該交易狀態通知

                int result=0;
                //這里根據自身的業務寫代碼,我這里刪掉了
                
                if(result==0){
                    log.info("resultinfo","更新訂單失敗!請業務員聯系后台管理員!");
                }else {
                    log.info("resultinfo","出租工具成功!");
                }

                log.info("********************** 支付成功(支付寶同步通知) **********************");
                log.info("* 訂單號: {}", out_trade_no);
                log.info("* 支付寶交易號: {}", trade_no);
                log.info("* 實付金額: {}", total_amount);
                log.info("***************************************************************");
            }
            log.info("支付成功...");
        }else {//驗證失敗
            log.info("支付, 驗簽失敗...");
        }
        return "success";
    }

}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM