这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
前面在《微信公众号整合JSAPI支付方式入门基础步骤》中介绍了微信JSAPI支付方式的对接基础,那么这一篇就来再做一个具体点的实现。实现一个简单的页面,把功能串通起来。
前端
界面
- 添加两个按钮,做触发授权与支付函数使用
<html>
<body>
<div>
<span>JSAPI支付</span>
<div>
<button type="button" onclick="getCode()">授权</button>
<button type="button" onclick="sendPay()">支付</button>
</div>
</div>
</body>
</html>
复制代码
功能
- 获取code:打开首页之后会去访问微信的认证地址,然后重定向到我们指定的地址上,后面会携带
code
和state
参数
// 微信客户端获取code
function getCode(){
var local = window.location.href
var code = getParam('code')
if (code) {
getOpenId(code);
} else {
// 跳转至授权地址,该地址只支持微信浏览器打开
// APPID,SCOPE需要根据自己实际情况填写
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=" + encodeURIComponent(local) + "&response_type=code&scope=SCOPE#wechat_redirect";
}
}
// 获取url中指定参数的值
function getParam(paramName) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] === paramName) {
return pair[1];
}
}
return (false);
}
复制代码
- 获取openid: 发送
code
到后端,拿到openid
// 像后端发起请求,获取openid
function getOpenId() {
const request = new XMLHttpRequest();
request.open("POST", "https://host/pay/accessToken")
// 可以通过参数携带,不一定要通过请求体
request.setRequestHeader("code", getParam("code"))
request.send()
request.onreadystatechange = function () {
// 得到响应之后调用后端接口生成预支付订单
if (request.readyState === 4 && request.status === 200) {
// 生成预支付订单
wxPayOrder(request)
}
}
}
复制代码
- 获取prepayId: 调用后端接口生成预支付订单,得到
prepayId
(具体参数参考链接:pay.weixin.qq.com/wiki/doc/ap… )
// 生成预支付订单
function wxPayOrder(request) {
const openId = request.responseText
request.open("POST", "https://host/wechatPay/wxPayOrder")
request.send(openId)
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
// 唤醒微信支付
cellBack(JSON.parse(request.responseText))
}
}
}
复制代码
- 唤醒微信支付: 生成预支付订单之后,通过JSAPI唤起微信支付,将响应结果发送到微信服务端
// 微信官方提供案例,自己加参数进行赋值
function onBridgeReady(data){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": data.appId, //公众号ID,由商户传入
"timeStamp": data.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": data.nonceStr, //随机串
"package": data.prepayId, //prepayId
"signType": data.signType, //微信签名方式:
"paySign": data.paySign //微信签名
},
function (data) {
if (data.err_msg === 'get_brand_wcpay_request:ok') {
console.log("支付成功")
} else if (data.err_msg === 'get_brand_wcpay_request:cancel') {
console.log("用户取消支付")
} else if (data.err_msg === 'get_brand_wcpay_request:fail') {
console.log("支付失败")
}
});
}
// 微信官方提供案例,自己加的 function 来做入口触发
function cellBack(data) {
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady(data);
}
}
复制代码
后端
授权
- 首页
// 定义一个入口,打开前端页面
@GetMapping("/payPage")
public String payPage(){
return "index";
}
复制代码
- 获取用户信息
@PostMapping("/accessToken")
@ResponseBody
public String accessToken(HttpServletRequest request){
String code = request.getHeader("code");
String uri = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APPID + "&secret=" + SECRET + "&code=" + code + "&grant_type=authorization_code";
String body = "";
try{
HttpRequest get = HttpUtil.createGet(uri);
HttpResponse response = get.execute();
body = response.body();
}catch (Exception e){
e.printStackTrace();
}
// 具体属性参考官网: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
AccessTokenData accessTokenData = JSONUtil.toBean(body, AccessTokenData.class);
// 将 accessToken 保存在服务端,不要发送到前端
String openid = accessTokenData.getOpenid();
accessTokens.put(openid, body);
return openid;
}
复制代码
支付
- 生成预付单
@PostMapping("/wxPayOrder")
public Object wxPayOrder(@RequestBody PayOrder payOrder) {
// 这里我是根据自己的业务需求做了封装。实际JSAPI下单参考: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
String call = InterfaceCallUtil.call(PAYMENT_URL + DEV_PAY, payOrder, PRI_KEY, PUB_KEY);
// 得将响应反序列化成对象,返回给前端(prepayId就在这里面)
WechatPaymentResParam paymentResParam = JSON.parseObject(call, WechatPaymentResParam.class);
WechatPayData payData = paymentResParam.getPayData();
payData.setAppid(APP_ID);
return payData;
}
复制代码
最后
整体的步骤还是比较简单的,先在前端这边得到用户授权之后,拿到专属的openid
,再通过openid
生成一个预支付订单,然后将结果返回给前端这边,前端通过调用微信的JSAPI来唤醒支付功能实现扣款操作。
这里有需要注意的就是支付页面需要在商户平台先设置好权限,才能正常唤醒,否则会提示没有设置权限等错误。
如果觉得文章对你有帮助,请 点赞、收藏、关注、评论 一键四连支持,你的支持就是我创作最大的动力!!!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END