最近两周实现了调用微信接口使用微信进行支付的需求,包含公众号支付及扫码支付两种方式,由于微信文档写的较为简略,现将调用微信接口进行支付流程进行记录及分享。
本文旨在对公众号支付的实现流程进行介绍,即微信用户从公众号中点击链接进入商品h5页面,选择商品后点击支付按钮后弹出微信支付页面、输入支付密码、支付成功后跳转到全部商品页面的整个过程。微信扫码支付请参看后续文章。
首先,商户需申请微信公众号、微信商户号及微信支付权限。开发过程中需参照公众号及商户平台提供如下参数:
① appid:公众号id,登录微信公众号–开发–基本配置中获得;
② mch_id:收款商家商户号;
③ APP_SECRET:第三方唯一凭证密码;
④ key:收款商户后台进行配置,登录微信商户平台–账户设置–安全设置–api安全,设置32位key值。登录微信公众号,进行开发相关设置:
① 获取用户基本信息(主要是openid)权限配置:微信公众平台–开发–接口权限–网页授权–网页授权域名(不接受IP地址,需通过ICP备案验证,不带http):
② 支付测试目录及测试白名单设置:微信公众平台–微信支付–开发配置,测试授权目录具体到最后一级。获取用户openid,OpenID是公众号一对一对应用户身份的标识:
① 微信网页授权获取用户信息文档:https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html。根据文档拼装url,引导用户在微信上点击该链接,获取用户openid等基本信息;
② 引导用户点击url(例如公众号推送该链接),形式如下:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
各个参数需替换,含义如下:
REDIRECT_URI:重定向URL,可为商品列表页面或商品页面,用户授权成功即转到该URL指向页面
scope:snsapi_base和snsapi_userinfo两种,snsapi_base为用户静默授权,snsapi_userinfo需要用户进行授权确认,可以获得更多用户信息。本文选择后者
state:重定向后会带上此参数
③ 用户授权后,重定向的页面获得code参数(若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE ),官方对于code参数的说明如下:code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
重定向页面对应controller中通过
String code = getPara("code");
获取code参数。
④ contoller中同时利用WxPayUtil中方法,调用微信接口,获取当前用户openid,将该openid存入session:setSessionAttr("openid", (WxPayUtil.getOpenIdByCode(code)).get("openid"));
用户选择商品点击付款,在商家提供h5页面确认支付对应controller中,进行统一下单,获得prepay_id(这里需要注意,订单金额转换成以分为单位)。统一下单的官方文档地址为:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
//统一下单,返回xml,用return_code判断统一下单结果,获取prepay_id等预支付成功信息 String prePayInfoXml = WxPayUtil.unifiedOrder("WxPay", userOrder.getStr("orderNo"), (entity.getBigDecimal("orderMoney").multiply(new BigDecimal(100))).intValue(), WxPayUtil.getIpAddr(getRequest()), getSessionAttr("openid").toString()); //生成包含prepay_id的map,map传入前端 map = WxPayUtil.getPayMap(prePayInfoXml); //将订单号放入map,用以支付后处理 map.put("orderNo",userOrder.getStr("orderNo"));
前端获得上一步中的map后,调用微信支付JSAPI,前端js代码如下所示:
<script type="text/javascript"> function payPublic(){ Common.AjaxSubmitBind("saveForm",function(){ saveIndex=Common.Loading("正在付款中"); },function(data){ prepay_id = data.prepay_id; paySign = data.paySign; appId = data.appId; timeStamp = data.timeStamp; nonceStr = data.nonceStr; packageStr = data.packageStr; signType = data.signType; orderNo = data.orderNo; callpay(); },function(errMsg,errCode){ Common.Alert(errMsg); }); } var prepay_id; var paySign; var appId; var timeStamp; var nonceStr; var packageStr; var signType; var orderNo; function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId" : appId, //公众号名称,由商户传入 "timeStamp" : timeStamp,