前置配置:
我们先要去接入微信支付,这个网上有很多的教程。注意几个关键的参数即可:
mch_id:商户id,也就是商户号。需要入驻成商户
appid:服务号的appid,需要做关联操作。
证书:主要用于涉及资金回滚接口使用,在下图api安全中设置获得。
apiKey:注意这个不是上面服务号的appSecret,是微信支付商户后台设置的密钥,这个设置后无法再查看,只能重置,请保存好。使用版本是v2就设置v2即可(我这里使用的v2接口),v3看使用情况设置。如下图
一、SDK下载与配置
1. 首先我们去微信支付的微信文档中心下载SDK,如下图,选择自己的开发语言,我这里使用的Java
2. 下载好的SDK,可以看到微信的SDK是java源码,我们将其复制进我们的工程。代码结构如如下所示
然后我们需要做的就是复写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环境下,我做了如下配置:
其中变量参数均配置在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(我这里不是广告,你们可以用自己觉得不错的内网穿透工具),可以使用它免费的隧道。
6. 回调详细参考:支付回调通知文档,注意在处理完自身业务逻辑时,需要返回微信文档所说明的参数,用以告知微信,通知成功,否则微信会多次尝试回调。
三 、测试沙箱
1. 值得注意的是,微信的沙箱测试比较有讲究,并不是随意金额,金额都是测试用例所规定的金额,才能成功,否则会返回错误信息:沙箱支付金额(xxx)无效,请检查需要验收的case,我们可以在微信沙箱最底部,下载对应的用例
2. 下载好对应的测试用例,我们就可以使用测试用例的金额,进行对应的测试。注意我们这里的native(原生)支付,第一步获取到二维码后,并不需要真正的去微信扫码支付,微信后台会直接支付成功并回调你的回调接口。