超详细微信支付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(原生)支付,第一步获取到二维码后,并不需要真正的去微信扫码支付,微信后台会直接支付成功并回调你的回调接口。



你可能感兴趣的:(超详细微信支付SDK开发并对接沙箱测试)