支付寶支付接口的調用(轉)


支付寶支付接口的調用

 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/zoroduyu/article/details/79825880

應公司業務要求,需要調用支付寶的支付接口進行支付的操作,於是將整個調用過程用博客形式記錄下來,以供以后使用。

本次調用支付寶采用的是電腦支付,官方文檔頁面如下:

這里寫圖片描述

電腦端調用支付寶,流程很簡單,在頁面有一個立即支付的按鈕,點擊進入商戶的后台,商戶的后台將支付所需的參數傳給支付寶,支付寶返回給商戶一個字符串形式的form表單,商戶將這個form表單傳給前台,前台對表單進行提交即可跳轉到支付包頁面,用戶在支付寶頁面支付完成后,支付寶會先調取我們的通知接口進行支付結果通知。然后跳轉到我們傳給支付包的回調頁面。這就是電腦端調用支付寶的整個流程。

要調用支付寶的接口,首先需要下載支付寶的sdk。這里給出官方的下載地址: 
支付寶sdk下載地址。下載下來的是一個zip包,里面文件如下:

這里寫圖片描述

這四個jar包文件如下: 
alipay-sdk-java-3.0.0.jar┈┈┈┈┈┈┈支付寶SDK編譯文件jar 
alipay-sdk-java-3.0.0-source.jar┈┈┈ 支付寶SDK源碼文件jar 
commons-logging-1.1.1.jar┈┈┈┈┈┈SDK依賴的日志jar 
commons-logging-1.1.1-sources.jar┈┈SDK依賴的日志源碼jar 
項目中需要引入的是alipay-sdk-java-3.0.0.jar和commons-logging-1.1.1.jar。對於commons-logging-1.1.1.jar,可以直接在pom文件中添加依賴:

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> 

 

對於alipay-sdk-java-3.0.0.jar,目前maven倉庫沒有該依賴,只能手動添加。首先將alipay-sdk-java-3.0.0.jar放入D盤的根目錄下,然后運行mvn命令:

 mvn install:install-file -DgroupId=com.alipay -DartifactId=sdk-java -Dversion=3.0.0 -Dpackaging=jar -Dfile=alipay-sdk-java-3.0.0.jar
  • 1

此命令會把支付寶的jar包打包到maven本地倉庫下,然后在pom文件中引用:

<dependency> <groupId>com.alipay</groupId> <artifactId>sdk-java</artifactId> <version>3.0.0</version> </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

即可完成支付寶jar包的導入。

前面准備工作已經做好,現在來看看代碼,我把對支付寶的調用都封裝到了一個工具類中:

package com.avie.ltd.utils; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; import com.alipay.api.DefaultAlipayClient; import com.alipay.api.internal.util.AlipaySignature; import com.alipay.api.request.AlipayTradePagePayRequest; import com.alipay.api.request.AlipayTradeRefundRequest; import com.avie.ltd.config.AlipayConfig; public class PayUtil { /** * * @param outTradeNo 商戶訂單號,商戶網站訂單系統中唯一訂單號,必填 對應繳費記錄的orderNo * @param totalAmount 付款金額,必填 * @param subject 主題 * @param body 商品描述,可空 * @return */ public static String alipay(String outTradeNo,String totalAmount,String subject,String body) { //獲得初始化的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); try { alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\"," + "\"total_amount\":\""+ totalAmount +"\"," + "\"subject\":\""+ subject +"\"," + "\"timeout_express\":\""+ Constants.TIMEOUT_EXPRESS +"\"," + "\"body\":\""+ body +"\"," + "\"qr_pay_mode\":\""+ Constants.QR_PAY_MODE +"\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); //請求 String result; result = alipayClient.pageExecute(alipayRequest).getBody(); System.out.println("*********************\n返回結果為:"+result); return result; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } /** * 支付寶退款接口 * @param outTradeNo * @param tradeNo * @param refundAmount * @param refundReason * @param out_request_no 標識一次退款請求,同一筆交易多次退款需要保證唯一,如需部分退款,則此參數必傳 * @return */ public static String aliRefund(String outTradeNo,String tradeNo,String refundAmount,String refundReason,String out_request_no) { //獲得初始化的AlipayClient AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type); //設置請求參數 AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest(); alipayRequest.setReturnUrl(AlipayConfig.return_url); alipayRequest.setNotifyUrl(AlipayConfig.notify_url); try { alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\"," + "\"trade_no\":\""+ tradeNo +"\"," + "\"refund_amount\":\""+ refundAmount +"\"," + "\"refund_reason\":\""+ refundReason +"\"," + "\"out_request_no\":\""+ out_request_no +"\"}"); //請求 String result; //請求 result = alipayClient.execute(alipayRequest).getBody(); System.out.println("*********************\n返回結果為:"+result); return result; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } /** * 支付寶的驗簽方法 * @param req * @return */ public static boolean checkSign(HttpServletRequest req) { Map<String, String[]> requestMap = req.getParameterMap(); Map<String, String> paramsMap = new HashMap<>(); requestMap.forEach((key, values) -> { String strs = ""; for(String value : values) { strs = strs + value; } System.out.println(("key值為"+key+"value為:"+strs)); paramsMap.put(key, strs); }); //調用SDK驗證簽名 try { return AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); } catch (AlipayApiException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("*********************驗簽失敗********************"); return false; } } }

 

這個工具類一共有三個靜態方法。 
alipay:支付寶的下單接口 
aliRefund:支付寶的退款方法 
checkSign:支付寶的驗簽方法

先來講alipay這個方法,當我們需要下單的時候,需要在業務邏輯代碼中調用該工具類的該方法。該方法需要傳入的參數如下:

outTradeNo: 商戶訂單號,商戶網站訂單系統中唯一訂單號,必填 。需要保證商戶端唯一。 
totalAmount :付款金額,必填 
subject:主題 
body:商品描述,可空

都是一些商品屬性的基本參數,一般都是根據我們具體的業務邏輯去設置。進入方法,第一句話:

AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
  • 1

這句話主要是初始化一個DefaultAlipayClient,這個類的初始化構造器需要傳很多參數,從左往右依次為:支付寶的網關,商戶的appid,商戶的私鑰,傳參的格式,傳參的字符集,商戶的公鑰,商戶的簽名類型。這里都把這些參數封裝進了AlipayConfig這個類里面,來看看AlipayConfig這個類:

package com.avie.ltd.config; import java.io.FileWriter; import java.io.IOException; /* * *類名:AlipayConfig *功能:基礎配置類 *詳細:設置帳戶有關信息及返回路徑 *修改日期:2017-04-05 *說明: *以下代碼只是為了方便商戶測試而提供的樣例代碼,商戶可以根據自己網站的需要,按照技術文檔編寫,並非一定要使用該代碼。 *該代碼僅供學習和研究支付寶接口使用,只是提供一個參考。 */ public class AlipayConfig { //↓↓↓↓↓↓↓↓↓↓請在這里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ // 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號 public static String app_id = "你的APPID"; // 商戶私鑰,您的PKCS8格式RSA2私鑰 public static String merchant_private_key = "你的商戶私鑰"; // 支付寶公鑰,查看地址:https://openhome.alipay.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。 public static String alipay_public_key = "你的支付寶公鑰"; // 服務器異步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 public static String notify_url = "你的異步通知頁面"; // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 public static String return_url = "你的回調頁面"; // 簽名方式 public static String sign_type = "RSA2"; // 字符編碼格式 public static String charset = "utf-8"; // 支付寶網關 public static String gatewayUrl = "https://openapi.alipay.com/gateway.do"; // 支付寶網關 public static String log_path = "C:\\"; //↑↑↑↑↑↑↑↑↑↑請在這里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ /** * 寫日志,方便測試(看網站需求,也可以改成把記錄存入數據庫) * @param sWord 要寫入日志里的文本內容 */ public static void logResult(String sWord) { FileWriter writer = null; try { writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt"); writer.write(sWord); } catch (Exception e) { e.printStackTrace(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } }

 

這個類其實很簡單,就是存儲了一些支付所需的公鑰啊,私鑰啊等參數,方便同意管理和使用。代碼往下走AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();就是初始化一個阿里封裝的request,后面幾句就是設置這個request要傳入的參數,把回調函數地址,外部訂單好,金額都設置到request里面。然后執行alipayClient.pageExecute(alipayRequest).getBody();這個方法,即可向支付寶發起一個下單請求,支付寶返回給我們的是一個字符串,這個字符串實際上是一個form表單。現在,我們寫個簡單的方法來測試以下,代碼如下:

package com.avie.itd;

import com.avie.ltd.utils.PayUtil;

public class Test { public static void main(String[] args) { String str = PayUtil.alipay("2313131", "0.01", "hehe", "haha"); System.out.println(str); } }

 

測試方式非常簡單,不需要弄什么運行環境或者一大堆依賴,就寫個main方法,調用我的PayUtil的alipay方法,傳入自己隨便編的參數,右鍵運行即可。如果基本的參數配置都沒有錯,那么你的控制台會打印出如下結果:

這里寫圖片描述

看到了嗎,返回的結果實際上是一個表單加上一個javascript腳本,腳本的目的在於提交表單。所以在實際開發中,你只需要拿到這個返回結果,把結果傳給前端,前端把用jquery把這段代碼放入一個div即可。表單自動提交,然后你就會跳轉到支付寶的支付頁面了。

那么到這里就完了嗎?肯定還沒有,支付完成后,支付寶會將支付結果推送到我們自己的業務系統中,因此我們需要為支付寶寫個異步通知的接口。先來看代碼:

package com.avie.ltd.controller; import java.io.IOException; import java.util.SortedMap; import java.util.TreeMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.avie.ltd.entity.AliReturnPayBean; import com.avie.ltd.service.TbPaymentRecordsService; import com.avie.ltd.utils.JaxbUtil; import com.avie.ltd.utils.PayUtil; import com.avie.ltd.utils.wxUtil.UnifiedOrderRespose; import com.thoughtworks.xstream.XStream; import net.sf.json.JSONObject; @Controller @RequestMapping(value = "/returnPay") public class ReturnController { private static Logger logger = LoggerFactory.getLogger(ReturnController.class); @Autowired private TbPaymentRecordsService tbPaymentRecordsService; /** * 支付寶回調的接口 * * @param uuid * @return * @throws IOException */ @RequestMapping(value = "/aliReturnPay", method = RequestMethod.POST) public void returnPay(HttpServletResponse response, AliReturnPayBean returnPay, HttpServletRequest req) throws IOException { response.setContentType("type=text/html;charset=UTF-8"); logger.info("****************************************支付寶的的回調函數被調用******************************"); if (!PayUtil.checkSign(req)) { logger.info("****************************************驗簽失敗*******************************************"); response.getWriter().write("failture"); return; } if (returnPay == null) { logger.info("支付寶的returnPay返回為空"); response.getWriter().write("success"); return; } logger.info("支付寶的returnPay" + returnPay.toString()); if (returnPay.getTrade_status().equals("TRADE_SUCCESS")) { logger.info("支付寶的支付狀態為TRADE_SUCCESS"); tbPaymentRecordsService.aliPaySuccess(returnPay); } response.getWriter().write("success"); } }

 

首先需要注意的是,這個類只能被@Controller注釋修飾,不能用@RestController,因為@RestController會將該類中所有方法的返回值自動轉為json格式,而此處支付寶的返回值不需要json格式。這里因為線上環境不能debug,我打印了大量的日志以監控該方法的運行情況。在支付的回調方法中,首先要做的就是驗證簽名,所以剛進入方法首先調用了PayUtil.checkSign(req)這個驗證簽名的方法,我們來看看這個checkSign(req)里面是怎么寫的:

/** * 支付寶的驗簽方法 * @param req * @return */ public static boolean checkSign(HttpServletRequest req) { Map<String, String[]> requestMap = req.getParameterMap(); Map<String, String> paramsMap = new HashMap<>(); requestMap.forEach((key, values) -> { String strs = ""; for(String value : values) { strs = strs + value; } System.out.println(("key值為"+key+"value為:"+strs)); paramsMap.put(key, strs); }); //調用SDK驗證簽名 try { return AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); } catch (AlipayApiException e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("*********************驗簽失敗********************"); return false; } }

 

首先我們先看最下面: AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);這句話是調用支付寶給我們封裝的驗證簽名的方法,右鍵指上去,會發現該方法的描述是這個樣子的:

boolean com.alipay.api.internal.util.AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String signType) throws AlipayApiException
  • 1

看到Map

package com.avie.ltd.entity; import java.io.Serializable; public class AliReturnPayBean implements Serializable{ /** * */ private static final long serialVersionUID = 1L; /** * 開發者的app_id */ private String app_id; /** * 商戶訂單號 */ private String out_trade_no; /** * 簽名 */ private String sign; /** * 交易狀態 */ private String trade_status; /** * 支付寶交易號 */ private String trade_no; /** * 交易的金額 */ private String total_amount; public String getTotal_amount() { return total_amount; } public void setTotal_amount(String total_amount) { this.total_amount = total_amount; } public String getApp_id() { return app_id; } public void setApp_id(String app_id) { this.app_id = app_id; } public String getOut_trade_no() { return out_trade_no; } public void setOut_trade_no(String out_trade_no) { this.out_trade_no = out_trade_no; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } public String getTrade_status() { return trade_status; } public void setTrade_status(String trade_status) { this.trade_status = trade_status; } public String getTrade_no() { return trade_no; } public void setTrade_no(String trade_no) { this.trade_no = trade_no; } @Override public String toString() { return "AliReturnPayBean [app_id=" + app_id + ", out_trade_no=" + out_trade_no + ", sign=" + sign + ", trade_status=" + trade_status + ", trade_no=" + trade_no + "]"; } }

 

 

將返回參數封裝在實體bean中,這樣springmvc會利用反射機制自動將相關參數映射進實體bean里面,省去了我們自己再去解析參數的麻煩。后面那句returnPay.getTrade_status().equals(“TRADE_SUCCESS”)是得到支付寶中trade_status這個參數,在支付寶的接口文檔中,若這個參數等於TRADE_SUCCESS,則說明支付是成功的,然后我就會調用tbPaymentRecordsService.aliPaySuccess(returnPay);。這句代碼就是具體的業務邏輯代碼了,對成功返回的參數進行處理,由於每個人業務邏輯都不一樣,我就不再贅述了。你們只需將這局代碼替換成你們的業務邏輯代碼即可。

這樣,支付下單的流程就走通了。當然我還有一個退款的接口沒講。這個接口其實和下單接口大同小異,我也寫了相關注釋。就請各位自行閱讀,我就不做解釋了。

那這次支付寶的調用就先寫到這里,下次我還會寫一些關於微信的支付接口,喜歡的小伙伴可以點波關注哦。

支付寶支付接口的調用

 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/zoroduyu/article/details/79825880

應公司業務要求,需要調用支付寶的支付接口進行支付的操作,於是將整個調用過程用博客形式記錄下來,以供以后使用。

本次調用支付寶采用的是電腦支付,官方文檔頁面如下:

這里寫圖片描述

電腦端調用支付寶,流程很簡單,在頁面有一個立即支付的按鈕,點擊進入商戶的后台,商戶的后台將支付所需的參數傳給支付寶,支付寶返回給商戶一個字符串形式的form表單,商戶將這個form表單傳給前台,前台對表單進行提交即可跳轉到支付包頁面,用戶在支付寶頁面支付完成后,支付寶會先調取我們的通知接口進行支付結果通知。然后跳轉到我們傳給支付包的回調頁面。這就是電腦端調用支付寶的整個流程。

要調用支付寶的接口,首先需要下載支付寶的sdk。這里給出官方的下載地址: 
支付寶sdk下載地址。下載下來的是一個zip包,里面文件如下:

這里寫圖片描述

這四個jar包文件如下: 
alipay-sdk-java-3.0.0.jar┈┈┈┈┈┈┈支付寶SDK編譯文件jar 
alipay-sdk-java-3.0.0-source.jar┈┈┈ 支付寶SDK源碼文件jar 
commons-logging-1.1.1.jar┈┈┈┈┈┈SDK依賴的日志jar 
commons-logging-1.1.1-sources.jar┈┈SDK依賴的日志源碼jar 
項目中需要引入的是alipay-sdk-java-3.0.0.jar和commons-logging-1.1.1.jar。對於commons-logging-1.1.1.jar,可以直接在pom文件中添加依賴:

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.1</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

對於alipay-sdk-java-3.0.0.jar,目前maven倉庫沒有該依賴,只能手動添加。首先將alipay-sdk-java-3.0.0.jar放入D盤的根目錄下,然后運行mvn命令:

 mvn install:install-file -DgroupId=com.alipay -DartifactId=sdk-java -Dversion=3.0.0 -Dpackaging=jar -Dfile=alipay-sdk-java-3.0.0.jar
  • 1

此命令會把支付寶的jar包打包到maven本地倉庫下,然后在pom文件中引用:

<dependency>
          <groupId>com.alipay</groupId>
          <artifactId>sdk-java</artifactId>
          <version>3.0.0</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

即可完成支付寶jar包的導入。

前面准備工作已經做好,現在來看看代碼,我把對支付寶的調用都封裝到了一個工具類中:

package com.avie.ltd.utils;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.avie.ltd.config.AlipayConfig;

public class PayUtil {


    /** * * @param outTradeNo 商戶訂單號,商戶網站訂單系統中唯一訂單號,必填 對應繳費記錄的orderNo * @param totalAmount 付款金額,必填 * @param subject 主題 * @param body 商品描述,可空 * @return */
    public static String alipay(String outTradeNo,String totalAmount,String subject,String body) {
        //獲得初始化的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);
                try {               
                alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\"," 
                        + "\"total_amount\":\""+ totalAmount +"\"," 
                        + "\"subject\":\""+ subject +"\"," 
                        + "\"timeout_express\":\""+ Constants.TIMEOUT_EXPRESS +"\"," 
                        + "\"body\":\""+ body +"\"," 
                        + "\"qr_pay_mode\":\""+ Constants.QR_PAY_MODE +"\"," 
                        + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");                                                                                                                                                               

                //請求
                String result;

                result = alipayClient.pageExecute(alipayRequest).getBody();
                System.out.println("*********************\n返回結果為:"+result);
                return result;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return null;
                }
    }

    /** * 支付寶退款接口 * @param outTradeNo * @param tradeNo * @param refundAmount * @param refundReason * @param out_request_no 標識一次退款請求,同一筆交易多次退款需要保證唯一,如需部分退款,則此參數必傳 * @return */
    public static String aliRefund(String outTradeNo,String tradeNo,String refundAmount,String refundReason,String out_request_no) {
        //獲得初始化的AlipayClient
                AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);

                //設置請求參數
                AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
                alipayRequest.setReturnUrl(AlipayConfig.return_url);
                alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
                try {               
                    alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\"," 
                            + "\"trade_no\":\""+ tradeNo +"\"," 
                            + "\"refund_amount\":\""+ refundAmount +"\"," 
                            + "\"refund_reason\":\""+ refundReason +"\"," 
                            + "\"out_request_no\":\""+ out_request_no +"\"}");                                                                                                                                                               

                //請求
                String result;

                //請求
                result = alipayClient.execute(alipayRequest).getBody();
                System.out.println("*********************\n返回結果為:"+result);
                return result;
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    return null;
                }
    }

    /** * 支付寶的驗簽方法 * @param req * @return */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        requestMap.forEach((key, values) -> {
              String strs = "";
              for(String value : values) {
              strs = strs + value;
              }
              System.out.println(("key值為"+key+"value為:"+strs));
              paramsMap.put(key, strs);
            });

        //調用SDK驗證簽名
        try {
            return  AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************驗簽失敗********************");
            return false;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122

這個工具類一共有三個靜態方法。 
alipay:支付寶的下單接口 
aliRefund:支付寶的退款方法 
checkSign:支付寶的驗簽方法

先來講alipay這個方法,當我們需要下單的時候,需要在業務邏輯代碼中調用該工具類的該方法。該方法需要傳入的參數如下:

outTradeNo: 商戶訂單號,商戶網站訂單系統中唯一訂單號,必填 。需要保證商戶端唯一。 
totalAmount :付款金額,必填 
subject:主題 
body:商品描述,可空

都是一些商品屬性的基本參數,一般都是根據我們具體的業務邏輯去設置。進入方法,第一句話:

AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
  • 1

這句話主要是初始化一個DefaultAlipayClient,這個類的初始化構造器需要傳很多參數,從左往右依次為:支付寶的網關,商戶的appid,商戶的私鑰,傳參的格式,傳參的字符集,商戶的公鑰,商戶的簽名類型。這里都把這些參數封裝進了AlipayConfig這個類里面,來看看AlipayConfig這個類:

package com.avie.ltd.config;

import java.io.FileWriter;
import java.io.IOException;

/* * *類名:AlipayConfig *功能:基礎配置類 *詳細:設置帳戶有關信息及返回路徑 *修改日期:2017-04-05 *說明: *以下代碼只是為了方便商戶測試而提供的樣例代碼,商戶可以根據自己網站的需要,按照技術文檔編寫,並非一定要使用該代碼。 *該代碼僅供學習和研究支付寶接口使用,只是提供一個參考。 */

public class AlipayConfig {

//↓↓↓↓↓↓↓↓↓↓請在這里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    // 應用ID,您的APPID,收款賬號既是您的APPID對應支付寶賬號
    public static String app_id = "你的APPID";

    // 商戶私鑰,您的PKCS8格式RSA2私鑰
    public static String merchant_private_key = "你的商戶私鑰";

    // 支付寶公鑰,查看地址:https://openhome.alipay.com/platform/keyManage.htm 對應APPID下的支付寶公鑰。
    public static String alipay_public_key = "你的支付寶公鑰";

    // 服務器異步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
    public static String notify_url = "你的異步通知頁面";

    // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
    public static String return_url = "你的回調頁面";

    // 簽名方式
    public static String sign_type = "RSA2";

    // 字符編碼格式
    public static String charset = "utf-8";

    // 支付寶網關
    public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";

    // 支付寶網關
    public static String log_path = "C:\\";


//↑↑↑↑↑↑↑↑↑↑請在這里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

    /** * 寫日志,方便測試(看網站需求,也可以改成把記錄存入數據庫) * @param sWord 要寫入日志里的文本內容 */
    public static void logResult(String sWord) {
        FileWriter writer = null;
        try {
            writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
            writer.write(sWord);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

這個類其實很簡單,就是存儲了一些支付所需的公鑰啊,私鑰啊等參數,方便同意管理和使用。代碼往下走AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();就是初始化一個阿里封裝的request,后面幾句就是設置這個request要傳入的參數,把回調函數地址,外部訂單好,金額都設置到request里面。然后執行alipayClient.pageExecute(alipayRequest).getBody();這個方法,即可向支付寶發起一個下單請求,支付寶返回給我們的是一個字符串,這個字符串實際上是一個form表單。現在,我們寫個簡單的方法來測試以下,代碼如下:

package com.avie.itd;

import com.avie.ltd.utils.PayUtil;

public class Test {

    public static void main(String[] args) {

        String str = PayUtil.alipay("2313131", "0.01", "hehe", "haha");
        System.out.println(str);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

測試方式非常簡單,不需要弄什么運行環境或者一大堆依賴,就寫個main方法,調用我的PayUtil的alipay方法,傳入自己隨便編的參數,右鍵運行即可。如果基本的參數配置都沒有錯,那么你的控制台會打印出如下結果:

這里寫圖片描述

看到了嗎,返回的結果實際上是一個表單加上一個javascript腳本,腳本的目的在於提交表單。所以在實際開發中,你只需要拿到這個返回結果,把結果傳給前端,前端把用jquery把這段代碼放入一個div即可。表單自動提交,然后你就會跳轉到支付寶的支付頁面了。

那么到這里就完了嗎?肯定還沒有,支付完成后,支付寶會將支付結果推送到我們自己的業務系統中,因此我們需要為支付寶寫個異步通知的接口。先來看代碼:

package com.avie.ltd.controller;

import java.io.IOException;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.avie.ltd.entity.AliReturnPayBean;
import com.avie.ltd.service.TbPaymentRecordsService;
import com.avie.ltd.utils.JaxbUtil;
import com.avie.ltd.utils.PayUtil;
import com.avie.ltd.utils.wxUtil.UnifiedOrderRespose;
import com.thoughtworks.xstream.XStream;

import net.sf.json.JSONObject;

@Controller
@RequestMapping(value = "/returnPay")
public class ReturnController {

    private static Logger logger = LoggerFactory.getLogger(ReturnController.class);
    @Autowired
    private TbPaymentRecordsService tbPaymentRecordsService;

    /** * 支付寶回調的接口 * * @param uuid * @return * @throws IOException */
    @RequestMapping(value = "/aliReturnPay", method = RequestMethod.POST)
    public void returnPay(HttpServletResponse response, AliReturnPayBean returnPay, HttpServletRequest req)
            throws IOException {
        response.setContentType("type=text/html;charset=UTF-8");
        logger.info("****************************************支付寶的的回調函數被調用******************************");
        if (!PayUtil.checkSign(req)) {
            logger.info("****************************************驗簽失敗*******************************************");
            response.getWriter().write("failture");
            return;
        }
        if (returnPay == null) {
            logger.info("支付寶的returnPay返回為空");
            response.getWriter().write("success");
            return;
        }
        logger.info("支付寶的returnPay" + returnPay.toString());
        if (returnPay.getTrade_status().equals("TRADE_SUCCESS")) {
            logger.info("支付寶的支付狀態為TRADE_SUCCESS");
            tbPaymentRecordsService.aliPaySuccess(returnPay);
        }
        response.getWriter().write("success");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

首先需要注意的是,這個類只能被@Controller注釋修飾,不能用@RestController,因為@RestController會將該類中所有方法的返回值自動轉為json格式,而此處支付寶的返回值不需要json格式。這里因為線上環境不能debug,我打印了大量的日志以監控該方法的運行情況。在支付的回調方法中,首先要做的就是驗證簽名,所以剛進入方法首先調用了PayUtil.checkSign(req)這個驗證簽名的方法,我們來看看這個checkSign(req)里面是怎么寫的:

/** * 支付寶的驗簽方法 * @param req * @return */
    public static boolean checkSign(HttpServletRequest req) {
        Map<String, String[]> requestMap = req.getParameterMap();
        Map<String, String> paramsMap = new HashMap<>();
        requestMap.forEach((key, values) -> {
              String strs = "";
              for(String value : values) {
              strs = strs + value;
              }
              System.out.println(("key值為"+key+"value為:"+strs));
              paramsMap.put(key, strs);
            });

        //調用SDK驗證簽名
        try {
            return  AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println("*********************驗簽失敗********************");
            return false;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

首先我們先看最下面: AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);這句話是調用支付寶給我們封裝的驗證簽名的方法,右鍵指上去,會發現該方法的描述是這個樣子的:

boolean com.alipay.api.internal.util.AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String signType) throws AlipayApiException
  • 1

看到Map

package com.avie.ltd.entity;

import java.io.Serializable;

public class AliReturnPayBean implements Serializable{

    /** * */
    private static final long serialVersionUID = 1L;

    /** * 開發者的app_id */
    private String app_id;

    /** * 商戶訂單號 */
    private String out_trade_no;

    /** * 簽名 */
    private String sign;

    /** * 交易狀態 */
    private String trade_status;

    /** * 支付寶交易號 */
    private String trade_no;

    /** * 交易的金額 */
    private String total_amount;

    public String getTotal_amount() {
        return total_amount;
    }

    public void setTotal_amount(String total_amount) {
        this.total_amount = total_amount;
    }

    public String getApp_id() {
        return app_id;
    }

    public void setApp_id(String app_id) {
        this.app_id = app_id;
    }

    public String getOut_trade_no() {
        return out_trade_no;
    }

    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getTrade_status() {
        return trade_status;
    }

    public void setTrade_status(String trade_status) {
        this.trade_status = trade_status;
    }

    public String getTrade_no() {
        return trade_no;
    }

    public void setTrade_no(String trade_no) {
        this.trade_no = trade_no;
    }

    @Override
    public String toString() {
        return "AliReturnPayBean [app_id=" + app_id + ", out_trade_no=" + out_trade_no + ", sign=" + sign
                + ", trade_status=" + trade_status + ", trade_no=" + trade_no + "]";
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

將返回參數封裝在實體bean中,這樣springmvc會利用反射機制自動將相關參數映射進實體bean里面,省去了我們自己再去解析參數的麻煩。后面那句returnPay.getTrade_status().equals(“TRADE_SUCCESS”)是得到支付寶中trade_status這個參數,在支付寶的接口文檔中,若這個參數等於TRADE_SUCCESS,則說明支付是成功的,然后我就會調用tbPaymentRecordsService.aliPaySuccess(returnPay);。這句代碼就是具體的業務邏輯代碼了,對成功返回的參數進行處理,由於每個人業務邏輯都不一樣,我就不再贅述了。你們只需將這局代碼替換成你們的業務邏輯代碼即可。

這樣,支付下單的流程就走通了。當然我還有一個退款的接口沒講。這個接口其實和下單接口大同小異,我也寫了相關注釋。就請各位自行閱讀,我就不做解釋了。

那這次支付寶的調用就先寫到這里,下次我還會寫一些關於微信的支付接口,喜歡的小伙伴可以點波關注哦。


免責聲明!

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



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