超詳細微信支付SDK開發(fā)并對接沙箱測試

前置配置:

我們先要去接入微信支付,這個網(wǎng)上有很多的教程。注意幾個關鍵的參數(shù)即可:?

mch_id:商戶id,也就是商戶號。需要入駐成商戶

appid:服務號的appid,需要做關聯(lián)操作。

證書:主要用于涉及資金回滾接口使用,在下圖api安全中設置獲得。

apiKey:注意這個不是上面服務號的appSecret,是微信支付商戶后臺設置的密鑰,這個設置后無法再查看,只能重置,請保存好。使用版本是v2就設置v2即可(我這里使用的v2接口),v3看使用情況設置。如下圖


商戶后臺


設置密鑰



一、SDK下載與配置

1. 首先我們去微信支付的微信文檔中心下載SDK,如下圖,選擇自己的開發(fā)語言,我這里使用的Java


微信SDK下載

2. 下載好的SDK,可以看到微信的SDK是java源碼,我們將其復制進我們的工程。代碼結構如如下所示


微信支付SDK代碼結構

?然后我們需要做的就是復寫WXPayConfig這個抽象類,用來配置微信支付的基礎信息,如appid,mch_id等,如上圖我的實現(xiàn)類為WXPayConfigImpl,具體代碼如下:

import lombok.extern.slf4j.Slf4j;

import org.springframework.core.io.ClassPathResource;

import java.io.InputStream;

import java.util.HashMap;

import java.util.Map;

/**

* @Descrption :

* @Author: zoujie

* @Date: 2020-4-15

*/

@Slf4j

public class WXPayConfigImpl extends WXPayConfig{

private StringweChatAppId;

? ? private String mchId;

? ? private String apiKey;

? ? private WXPayConstants.SignTypesignType;

? ? private StringcertPath;

? ? public WXPayConfigImpl(String weChatAppId,String mchId,String apiKey,String certPath,boolean useSandbox)? {

? ? ? ?this.weChatAppId = weChatAppId;

? ? ? ? this.mchId = mchId;

? ? ? ? this.apiKey = apiKey;

? ? ? ? this.certPath = certPath;

? ? ? ? //這里我們提供一個配置類的構造函數(shù),因為在對接微信支付沙箱時,appid和商戶id都是正式環(huán)境的,只? ? ? ? ? //有這個apiKey是需要通過接口獲取的,下面我通過getSandboxSignKey()方法獲取,具體查看下面方法? ? ? ? ? //代碼,詳細說明請參考:微信支付沙箱

? ? ? ? this.apiKey = useSandbox ? getSandboxSignKey() : apiKey;?

? ? ? ? this.signType = useSandbox ? WXPayConstants.SignType.MD5 : WXPayConstants.SignType.HMACSHA256;

? ? ? ? log.info("微信支付配置已加載:weChatAppId=[{}],mchId=[{}],apiKey=[{}],signType=[{}]",this.weChatAppId,this.mchId,this.apiKey,this.signType);

? ? }

@Override

? ? public StringgetAppID() {

return weChatAppId;

? ? }

@Override

? ? public StringgetMchID() {

return mchId;

? ? }

@Override

? ? public StringgetKey() {

return apiKey;

? ? }

@Override

? ? public InputStreamgetCertStream() {

ClassPathResource resource =new ClassPathResource(certPath);

? ? ? ? try {

return resource.getInputStream();

? ? ? ? }catch (Exception e) {

log.error("未成功加載classpath路徑下[{}]的證書",certPath);

? ? ? ? }

return null;

? ? }

@Override

? ? public IWXPayDomain getWXPayDomain() {

return new IWXPayDomain() {

@Override

? ? public void report(String domain, long elapsedTimeMillis, Exception ex) {

}

@Override

? ? public DomainInfogetDomain(WXPayConfig config) {

return new DomainInfo(WXPayConstants.DOMAIN_API,true);

? ? }

};

? ? }

/**

? ? * 關閉自動上報

? ? * @return

? ? */

? ? @Override

? ? public boolean shouldAutoReport() {

return false;

? ? }

public WXPayConstants.SignTypegetSignType(){

return this.signType;

? ? }

//獲取沙箱的apiKey

//接口說明:獲取接口

private String getSandboxSignKey() {

try {

log.info("當前配置為使用沙箱對接,準備獲取沙箱signKey");

? ? ? ? ? ? WXPay wxPay =new WXPay(this,false,true);

? ? ? ? ? ? Map params =new HashMap();

? ? ? ? ? ? params.put("mch_id", this.getMchID());

? ? ? ? ? ? params.put("nonce_str", WXPayUtil.generateNonceStr());

? ? ? ? ? ? params.put("sign", WXPayUtil.generateSignature(params, this.getKey()));

? ? ? ? ? ? String strXML = wxPay.requestWithoutCert("/sandboxnew/pay/getsignkey",

? ? ? ? ? ? ? ? ? ? params, this.getHttpConnectTimeoutMs(), this.getHttpReadTimeoutMs());

? ? ? ? ? ? Map result = WXPayUtil.xmlToMap(strXML);

? ? ? ? ? ? System.out.println("retrieveSandboxSignKey:" + result);

? ? ? ? ? ? if ("SUCCESS".equals(result.get("return_code"))) {

String sandboxSignkey = result.get("sandbox_signkey");

? ? ? ? ? ? ? ? log.info("獲取sandbox_signkey=[{}]", sandboxSignkey);

? ? ? ? ? ? ? ? return sandboxSignkey;

? ? ? ? ? ? }else {

log.info("獲取sandbox_signkey失?。篬{}]",result.get("return_msg"));

? ? ? ? ? ? }

return null;

? ? ? ? }catch (Exception e) {

log.error("獲取sandbox_signkey異常:[{}]",e.getLocalizedMessage());

? ? ? ? ? ? e.printStackTrace();

return null;

? ? ? ? }

}

}

3. 配置好后,我們在業(yè)務代碼中使用的是WXPay這個類,進行接口請求的。如果是非spring環(huán)境下,我們需要自己創(chuàng)建這個對象,構造函數(shù)中,不可缺少的就是WXPayConfig這個類,上面我們已經寫了這個抽象類的子類,我們創(chuàng)建即可。在springboot環(huán)境下,我做了如下配置:


bean配置

其中變量參數(shù)均配置在application.properties中,通過@value注解注入,用以在不同環(huán)境下注入不同的參數(shù)。證書路徑就根據(jù)自己的證書存放位置配置即可。



二 、開始對接沙箱

1. 微信支付主要是支付下單,也就是微信所描述的統(tǒng)一下單接口,無論哪種支付都是必要的。我們這里以Native支付方式為例子。我們這里使用的是模式二進行開發(fā)。時序流程:native(原生)支付模式二時序,詳細官方api請參考:微信支付api,我們在工程中使用微信SDK進行請求,它幫我們做了如下的事情:(1)通過配置加入?yún)?shù)appid,mch_id , (2) 自動生成隨機字符串? (3) 通過配置的apiKey生成sign簽名 (4)需要證書的接口,自動加上我們配置的證書? (5)將返回的xml解析為map

2. 在統(tǒng)一下單接口,我們僅僅需要傳遞如下參數(shù),參數(shù)在文檔中有詳細的說明,參數(shù)傳遞具體需要參考接口文檔,這里僅作最簡單的演示。注意:這里的total_fee金額單位為分,類型為int,


人民幣元和分互相轉換


統(tǒng)一下單傳參

3. 調用接口


調用統(tǒng)一下單

4. 處理返回結果,這里你需要參考文檔api和自身的業(yè)務邏輯進行相關的處理,我這里不再贅述。

5. 在前面SDK下載與配置的第三步,我們配置了notify_url,我們需要去完成回調接口的實現(xiàn),注意這個接口需要暴露在公網(wǎng),本地開發(fā),可以借助內網(wǎng)穿透實現(xiàn),我這里使用了ngrok(我這里不是廣告,你們可以用自己覺得不錯的內網(wǎng)穿透工具),可以使用它免費的隧道。


回調demo


回調一定要驗證簽名

6. 回調詳細參考:支付回調通知文檔,注意在處理完自身業(yè)務邏輯時,需要返回微信文檔所說明的參數(shù),用以告知微信,通知成功,否則微信會多次嘗試回調。

三 、測試沙箱

?1. 值得注意的是,微信的沙箱測試比較有講究,并不是隨意金額,金額都是測試用例所規(guī)定的金額,才能成功,否則會返回錯誤信息:沙箱支付金額(xxx)無效,請檢查需要驗收的case,我們可以在微信沙箱最底部,下載對應的用例


測試下載用例

2. 下載好對應的測試用例,我們就可以使用測試用例的金額,進行對應的測試。注意我們這里的native(原生)支付,第一步獲取到二維碼后,并不需要真正的去微信掃碼支付,微信后臺會直接支付成功并回調你的回調接口。



最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容