微信支付对接【踩坑实录】
公众号支付
必备条件
- 拥有一个认证过的公众号
- 公众号开通微信支付
注意点
- timestamp参数js使用的是小写,后台签名使用的是timeStamp(大写S)
- 签名算法必须使用MD5,并且下单的签名算法也必须是MD5(微信的demo sdk留下一个巨大的坑,判定Sandbox环境使用MD5,其他环境使用HMACSHA256)这个地方我改了sdk代码,写死MD5
- timestamp时间戳规则,这里是精确到秒,不是毫秒
环境配置
- 公众号配置
在公众号设置-功能设置,配置网页授权域名,JS接口安全域名,业务域名
- 微信商品平台,支付配置
- 普通商户在产品中心-开发配置中设置支付授权目录
- 服务商在服务商功能-特约商户管理中设置支付授权目录
页面开发
- 页面JS授权
$.getJSON(_ctx+'/wx/outh/sign?url=' + encodeURIComponent(location.href.split('#')[0]), function (res) {
wx.config({
debug: false,
appId: res.appId,
timestamp: res.timestamp,
nonceStr: res.nonceStr,
signature: res.signature,
jsApiList: [
'chooseWXPay'
]
});
});
- 后台下单及参数签名
WxpayVo wxpayVo=new WxpayVo();
//注意:这里的时间戳是秒,不是毫秒
String timestamp = String.valueOf(System.currentTimeMillis()/1000);
String nonceStr = RandomUtils.generateString(8);
String appId = Config.instance().getAppid();
//这里不是公众号的密钥,而是微信商户平台的密钥
String appSecret = DictUtil.getValue("wxpay_info", "private_key");
wxpayVo.setAppId(appId);
wxpayVo.setNonceStr(nonceStr);
wxpayVo.setTimestamp(timestamp);
wxpayVo.setSignType("MD5");
String packageStr ="prepay_id="+order.getAuthCode();
wxpayVo.setPrepayId(packageStr);
Map<String, String> params = new HashMap<String, String>();
// Step1:准备签名参数,注意参数大小写
params.put("nonceStr", nonceStr);
params.put("timeStamp", timestamp);
params.put("appId", appId);
params.put("package", packageStr);
params.put("signType", "MD5");
// Step签名
String paySign = Signature.getSign(params,appSecret);
logger.info(paySign);
wxpayVo.setPaySign(paySign);
- 唤起支付窗口
$('#btn_topup').on('click',function(){
$.getJSON(_ctx+'/wx/pay/unifiedorder',{totalAmount:$('#totalAmount').val()}, function (res) {
console.log('chooseWXPay',res);
wx.chooseWXPay({
appId:res.appId,
timestamp: res.timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: res.nonceStr, // 支付签名随机串,不长于 32 位
package: res.prepayId, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: res.paySign, // 支付签名
success: function (res) {
// 支付成功后的回调函数
console.log('success',res);
},
fail: function(res) {
//接口调用失败时执行的回调函数。
console.log('fail',res);
}
});
});
});