超详细微信支付SDK开发并对接沙箱测试

前置配置:

我们先要去接入微信支付,这个网上有很多的教程。注意几个关键的参数即可: 

mch_id:商户id,也就是商户号。需要入驻成商户

appid:服务号的appid,需要做关联操作。

证书:主要用于涉及资金回滚接口使用,在下图api安全中设置获得。

apiKey:注意这个不是上面服务号的appSecret,是微信支付商户后台设置的密钥,这个设置后无法再查看,只能重置,请保存好。使用版本是v2就设置v2即可(我这里使用的v2接口),v3看使用情况设置。如下图


商户后台


设置密钥



一、SDK下载与配置

1. 首先我们去微信支付的微信文档中心下载SDK,如下图,选择自己的开发语言,我这里使用的Java


微信SDK下载

2. 下载好的SDK,可以看到微信的SDK是java源码,我们将其复制进我们的工程。代码结构如如下所示


微信支付SDK代码结构

 然后我们需要做的就是复写WXPayConfig这个抽象类,用来配置微信支付的基础信息,如appid,mch_id等,如上图我的实现类为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;

        //这里我们提供一个配置类的构造函数,因为在对接微信支付沙箱时,appid和商户id都是正式环境的,只          //有这个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. 配置好后,我们在业务代码中使用的是WXPay这个类,进行接口请求的。如果是非spring环境下,我们需要自己创建这个对象,构造函数中,不可缺少的就是WXPayConfig这个类,上面我们已经写了这个抽象类的子类,我们创建即可。在springboot环境下,我做了如下配置:


bean配置

其中变量参数均配置在application.properties中,通过@value注解注入,用以在不同环境下注入不同的参数。证书路径就根据自己的证书存放位置配置即可。



二 、开始对接沙箱

1. 微信支付主要是支付下单,也就是微信所描述的统一下单接口,无论哪种支付都是必要的。我们这里以Native支付方式为例子。我们这里使用的是模式二进行开发。时序流程:native(原生)支付模式二时序,详细官方api请参考:微信支付api,我们在工程中使用微信SDK进行请求,它帮我们做了如下的事情:(1)通过配置加入参数appid,mch_id , (2) 自动生成随机字符串  (3) 通过配置的apiKey生成sign签名 (4)需要证书的接口,自动加上我们配置的证书  (5)将返回的xml解析为map

2. 在统一下单接口,我们仅仅需要传递如下参数,参数在文档中有详细的说明,参数传递具体需要参考接口文档,这里仅作最简单的演示。注意:这里的total_fee金额单位为分,类型为int,


人民币元和分互相转换


统一下单传参

3. 调用接口


调用统一下单

4. 处理返回结果,这里你需要参考文档api和自身的业务逻辑进行相关的处理,我这里不再赘述。

5. 在前面SDK下载与配置的第三步,我们配置了notify_url,我们需要去完成回调接口的实现,注意这个接口需要暴露在公网,本地开发,可以借助内网穿透实现,我这里使用了ngrok(我这里不是广告,你们可以用自己觉得不错的内网穿透工具),可以使用它免费的隧道。


回调demo


回调一定要验证签名

6. 回调详细参考:支付回调通知文档,注意在处理完自身业务逻辑时,需要返回微信文档所说明的参数,用以告知微信,通知成功,否则微信会多次尝试回调。

三 、测试沙箱

 1. 值得注意的是,微信的沙箱测试比较有讲究,并不是随意金额,金额都是测试用例所规定的金额,才能成功,否则会返回错误信息:沙箱支付金额(xxx)无效,请检查需要验收的case,我们可以在微信沙箱最底部,下载对应的用例


测试下载用例

2. 下载好对应的测试用例,我们就可以使用测试用例的金额,进行对应的测试。注意我们这里的native(原生)支付,第一步获取到二维码后,并不需要真正的去微信扫码支付,微信后台会直接支付成功并回调你的回调接口。



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容