微信公众号支付开发
公众号支付是用户在微信中打开商户的web页面,商户在web页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付(注意,一定要在微信内置浏览器中才能调起JSAPI接口,否则,在别的浏览器就使用h5支付)。主要的应用场景有:用户通过消息或者扫描二维码在微信内打开网页时,调用微信支付完成下单购买的流程。我的支付场景是:微信扫描二维码进入商户页面,用户选购商品后,点击结算按钮,发起和完成微信支付。
开发前预览:
一、业务流程:
如上图所示,公众号支付的关键是:
1. 手机购物页面点击支付后,商户后台系统调用 统一支付api,从微信支付系统得到prepay_id,然后再返回给手机网页端。统一支付api示例(本质就是要获取这11个参数,并且打包成xml格式):
<xml>
<appid>wxc2dd87f529b7c03d</appid>
<mch_id>1226642802</mch_id>
<nonce_str>b0297ea9f0224281b8a7f6108460ff69</nonce_str>
<sign>C66A22EE56E8790C8439FA7B954E26F3</sign>
<body>显示的名字</body>
<out_trade_no>ba5af810300c449c89c75002572a87fe</out_trade_no>
<total_fee>1</total_fee> //这里的单位默认是分
<spbill_create_ip>58.246.221.142</spbill_create_ip>
<notify_url>http://weixin-yyb.xmhl.com.cn/paymentNotice/o9Wu3jrYnv0Bz0V7NNwd_JVO3uEE</notify_url>
<trade_type>JSAPI</trade_type>
<openid>o9Wu3jrYnv0Bz0V7NNwd_JVO3uEE</openid>
</xml>
2. 手机网页端得到prepay_id和其他参数后,调用JSAPI进行微信支付。微信支付系统会把支付结果异步通知给商户后台系统
开发前准备:
一、设置支付目录
在微信商户平台上设置公众号支付目录:商户平台 --> 产品中心 --> 开发配置。该目录必须是最终发起 统一下单api的具体url。另外,在商户平台上,还需要设置密匙key,并记录下来,生成统一下单接口的sign的时候需要用到。
二、设置授权域名
公众号支付时,统一下单接口中要求必传用户openid,而获取openid则需要在公众号设置获取openid的域名,只有被设置过的域名或者它的子域名才能有效的获取openid。注意,需要把红框中的txt文件下载下来,然后放在项目中,使得当你用浏览器访问 网页授权域名/MP_verify_fr6both2Ht9CbiPd.txt时,可以返回里面的数据,只有这样才能设置网页授权域名成功。
开始开发:
使用公众号支付主要分成两步:
1. 在后台服务器上调用统一下单api,获得订单的预支付id---prepay_id
2. 把prepay_id传到客户端的微信内置浏览器,调用微信支付提供的JSAPI接口调起微信支付模块完成支付。
步骤 1 首先得到11个必需参数,打包成xml格式,然后发送给https://api.mch.weixin.qq.com/pay/unifiedorder。这11个参数中,最关键和最难的是openid的获取。获得openid具体参考微信网页授权https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 。因为我的应用不需要用户的用户名、电话号码之类的信息,只需要openid来作为账号名和发起微信公众号支付,所以只需要以snsapi_base为scope发起的静默网页授权,用户无感知。具体流程:
1. 生成 服务器地址加上设备id组成的 二维码
2. 手机微信扫描二维码, 访问服务器,携带设备id参数
@RequestMapping("/QRcode/{devId}")
public ModelAndView ScanQRCode(HttpServletRequest request,@PathVariable String devId) throws IOException {
System.out.println("new client scan QRcode!");
devToipMaps.put(devId, ip);
String codeUrl = "redirect:" + WXPayUtil.createUrlForCode(devId);
return new ModelAndView(codeUrl);
}
3. 重定向 到 微信服务器,获取code:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI/devId&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
注意: 正确理解重定向的含义,服务器先返回重定向URL给客户端,客户端再发起对这个URL的访问,所以发起端还是客户的手机微信端。另外,再构造这个重定向URL时,里面的redirect_uri参数增加“/devId”,使得微信服务器重定向到我们的服务器时,可以知道获得的这个code是针对哪个设备发起的。还有,redirect_uri的uri需要进行encode
4. 带着code参数,重定向 到 我们的服务器,获取openid
我们的服务器利用得到的code,向微信服务器发起请求:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
返回值包括access_token和openid。到此,我们就得到我们最需要的openid,另外请求的发起端仍然是手机微信端。
5. 根据这个openid,来判断用户具体情况,返回手机端具体的购物页面或者管理员页面或其他逻辑
6. 用户选购完商品后,点击结算请求。服务器接收到请求后,打包JSAPI所需要的参数,发送给页面
7. 页面调用微信支付提供的JSAPI接口调起微信支付模块完成支付
8. 页面显示支付结果,服务器异步接收到微信服务发送的支付结果,根据支付情况增加业务逻辑
注: 本文重点描述微信公众号支付的流程和原理,具体代码网上有很多教程。