使用uniapp 打包成h5发起微信公众号支付,总共大概有以下的步骤
1 跳转到微信支付中心再跳回我们页面 此时会在url上带上code
2 使用得到的code 调用我们后台获取到发起支付所需要的相关参数
3 发起支付并支付后 回调我们后台,在回调方法中处理我们业务例如 充值会员
4 告诉微信不要再回调了,微信为了确保业务处理 同一个支付会一直回调 所以在回调方法中结束时需要在回应微信 同时我们的方法也要避免多次调用而重复处理的麻烦
前端代码
<script>
//#ifdef H5
let jweixin = require('jweixin-module');
//#endif
export default {
data() {
return {
code: "",
}
},
created() {
// 首次进入就去跳转微信中心并跳回来 获取到code 后面发起支付时需要
this.getWechatCode()
},
onLoad() {
},
methods: {
//发起支付
pay() {
let self = this;
//通过code 调用我们的后台获取发起支付所需的相关参数
Server.get("/scan/wxorder", {
'code': self.code,
'id': reportid, // reportid为业务处理所需相关参数 我们自定义的 后面微信回调时会在传回来
}, {
success: (response) => {
self.timeStamp = response.data.data.timeStamp;
self.nonceStr = response.data.data.nonceStr;
self.paySign = response.data.data.paySign;
self.package = response.data.data.package;
jweixin.config({
//debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: self.appid, // 必填,公众号的唯一标识
timestamp: self.timeStamp, // 必填,生成签名的时间戳
nonceStr: self.nonceStr, // 必填,生成签名的随机串
signature: self.paySign, // 必填,签名,见附录1
jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
jweixin.ready(function() {
jweixin.checkJsApi({
jsApiList: ['chooseWXPay'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res) {
console.log('checkjsapi Success')
console.log(res);
},
fail: function(res) {
console.log('res')
console.log(res);
}
});
jweixin.chooseWXPay({
timestamp: self
.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: self.nonceStr, // 支付签名随机串,不长于 32 位
package: self
.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: self.paySign, // 支付签名
success: function(res) {
//这里就是支付成功的前端处理 业务操作不建议在这里处理,可能用户会关掉等因素造成未处理的情况发生
},
cancel: function(res) {
self.modelcontent = '支付取消';
self.modeltitle = "提示";
self.modelshow = true;
},
fail: function(res) {
self.modelcontent = '支付失败';
self.modeltitle = "提示";
self.modelshow = true;
}
});
});
jweixin.error(function(res) {
console.log('error')
console.log(res)
self.modelcontent = '支付失败';
self.modeltitle = "提示";
self.modelshow = true;
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
/*alert("config信息验证失败");*/
});
},
warnings: (response) => {
/* self.modelcontent = response;
self.modeltitle = "警告";
self.modelshow = true; */
},
error: (response) => {
self.modelcontent = response;
self.modeltitle = "错误";
self.modelshow = true;
},
});
},
// 在url上获取查询字符串
getQueryVariable(variable) {
let query = window.location.search.substring(1)
let vars = query.split('&')
for (let i = 0; i < vars.length; i++) {
let pair = vars[i].split('=')
if (pair[0] == variable) {
return pair[1]
}
}
return false
},
// 获取微信code
getWechatCode() {
let tcode = this.getQueryVariable('code')
console.log("获取code到的:" + tcode)
if (tcode) {
this.code = tcode
} else {
this.getSystemInfo()
}
},
// 获取系统参数配置,并获取微信授权
getSystemInfo() {
let that = this
let redirect_uri = encodeURIComponent(window.location.href.split('?')[0])
//跳转到微信中心 并再跳回来 再次回来后url上会多上code信息
//#ifdef H5
window.location.href =
'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' +
that.appid +
'&redirect_uri=' +
redirect_uri +
'&response_type=code&scope=snsapi_base&state=1#wechat_redirect'
//#endif
},
}
}
</script>
后端代码
通过code获取发起支付所需相关信息
@GetMapping("/wxorder")
public JrsfReturn wxorder(@RequestParam String code) throws Exception {
MyWXConfig config = new MyWXConfig();
WXPay wxpay = new WXPay(config);
String appid = wxappid;
String secret = wxsecret;
String result = restTemplate.getForObject("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code", String.class);
JSONObject jsonObject = JSONObject.parseObject(result);
String openId = jsonObject.getString("openid");
if (StringUtils.isBlank(openId)) {
return JrsfReturn.error();
}
Map<String, String> data = new HashMap<String, String>();
data.put("body", "会员");
data.put("out_trade_no", DateUtil.dateToStr("yyyyMMddHHmmssSSS", new Date()));
data.put("total_fee", "0.01");
data.put("spbill_create_ip", EvCommonTool.getIpAddress());
data.put("notify_url", wxnotifyUrl); //回调地址
data.put("trade_type", "JSAPI");
data.put("openid", openId);
Map<String, Object> payInfo = new HashMap<>();//微信回调地址时 会回传给我们这里可以带上处理业务相关参数
payInfo.put("userId", "1");
payInfo.put("level", "1");
payInfo.put("months", 1);
data.put("attach", JSONObject.toJSONString(payInfo));
Map<String, String> resp = wxpay.unifiedOrder(data);
if (StringUtils.isNotBlank(resp.get("prepay_id"))) {
String prepay_id = resp.get("prepay_id"); //预支付id
Map<String, String> payMap = new HashMap<String, String>();
payMap.put("appId", appid);
payMap.put("timeStamp", String.valueOf(System.currentTimeMillis()));
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, config.getKey());
payMap.put("paySign", paySign);
return JrsfReturn.okData(payMap);
} else {
return JrsfReturn.error();
}
}
MyWXConfig类
import com.alipay.api.internal.util.file.IOUtils;
import com.github.wxpay.sdk.WXPayConfig;
import org.springframework.core.io.ClassPathResource;
import java.io.*;
public class MyWXConfig implements WXPayConfig {
private byte[] certData;
public MyWXConfig() throws Exception {
ClassPathResource classPathResource = new ClassPathResource("apiclient_cert.p12");
InputStream certStream = classPathResource.getInputStream();
this.certData = IOUtils.toByteArray(certStream);
certStream.read(this.certData);
certStream.close();
}
@Override
public String getAppID() {
return "wx120a18c636fd8718";
}
@Override
public String getMchID() {
return "1614696304";
}
@Override
public String getKey() {
return "MIIEvQIBADANBgkqhkiG9w0BAQEFAASC";
}
@Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
@Override
public int getHttpConnectTimeoutMs() {
return 8000;
}
@Override
public int getHttpReadTimeoutMs() {
return 10000;
}
}
回调方法
@PostMapping("/wx/notifyUrl")
public String wxNotifyUrl(HttpServletRequest request, HttpServletResponse response) {
//System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");
InputStream is = null;
try {
is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)
String xml = WXPayUtil.inputStream2String(is, "UTF-8");
Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转map
if (notifyMap.get("return_code").equals("SUCCESS")) {
if (notifyMap.get("result_code").equals("SUCCESS")) {
String ordersSn = notifyMap.get("out_trade_no");//商户订单号
String attach = notifyMap.get("attach");
//之前在获取支付信息时填入的
JSONObject jsonObject = JSONObject.parseObject(attach);
/*以下是自己的业务处理------仅做参考*/
}
}
//告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可
response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
评论区