博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微信公众号支付总结
阅读量:5860 次
发布时间:2019-06-19

本文共 7367 字,大约阅读时间需要 24 分钟。

hot3.png

微信公众号支付总结大致可以分为三步, 第一步获取用户授权,第二步调用统一下单接口获取预支付id,第三步H5调起微信支付的内置JS进行支付

注意:

不得不提的是,每个公众号(公众平台),每一个APP(开放平台), 如果要进行微信支付得单独进行开通微信支付功能。开通成功后会为每一个公众号,APP 分配一个商户号。最开始没有搞清楚这层关系,导致出现类似“appid与商户号没有关联”,授权时没有“scope 权限”这样的问题。

获取用户授权

String wxaccessUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?";            String uri = wxaccessUrl+"appid="+ConstantUtil.JS_APP_ID+"&redirect_uri="+URLEncoder.encode(vo.getRedirectUri(),"UTF-8")+"&response_type="+vo.getResponseType()+"&scope="+vo.getScope()+"&state="+vo.getState();            logger.debug("authorize uri: "+uri);            return "redirect:"+uri;

因为统一下单接口需要用户的openid,所以需要进行用户授权,这里只需要获取到最基本的用户openid就行了。redirectUri 是授权之后跳转到后台的地址,需要进行urlencode。这里存在一个疑问,就是微信授权之后跳转回来的地址栏地址还是授权的地址,但是网页的内容已经是我们自己的网页了。这样在第三步进行支付时,会导致配置的微信支付目录不正确,因此我这里授权跳转回来之后又进行了一次跳转,通过redirect 来保证网址在微信支付中配置的目录中。

授权之后微信会在链接上加上code ,拿上这个我们再进行授权的第二步:获取用户的openid.我把这一步写在一个jsp中。

code.jsp

String code = request.getParameter("code");    String openid="";    String accessCodeUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + ConstantUtil.JS_APP_ID + "&secret="+ConstantUtil.APP_SECRET+"&code=" + code + "&grant_type=authorization_code";    if (code == null) out.println("用户授权失败。");    HttpPost post = new HttpPost(accessCodeUrl);    HttpResponse resp = HttpClients.createDefault().execute(post);    if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {        InputStream inputStream = resp.getEntity().getContent();        byte[] buff = new byte[1024];        int len;        ByteArrayOutputStream bout = new ByteArrayOutputStream();        while ((len = inputStream.read(buff)) != -1) {            bout.write(buff, 0, len);        }        JSONObject result = JSON.parseObject(new String(bout.toByteArray()));        openid = (String) result.get("openid");        if (result.containsKey("errcode")){            logger.error("wx access error code:"+result.get("errmsg"));        }    } else {        out.println("用户授权失败。");    }

这个页面包含到需要进行支付的页面中。code是从后台传过来的。

toPay.do 跳转到需要支付的页面toPay.jsp

order = URLEncoder.encode(request.getParameter("order"), "UTF-8");//从微信跳转过来,有中文的话需要进行url 编码            String uri = "/wechat/activity/toPay.jsp?rid=" + request.getParameter("rid") + "&pid=" + request.getParameter("pid")+                    "&sn="+request.getParameter("sn")+"&amount="+request.getParameter("amount")+"&order="+order+                    "&code="+request.getParameter("code")+"&showwxpaytitle=1";            logger.debug(uri);            return "redirect:"+uri;

toPay.jsp需要配置到微信的支付目录中。(这里要说一下的是关于服务器的端口号最好是弄成80端口,如果还用到微信其他的js sdk 功能,会现invalid signature之类的错误)

统一下单

点击支付之后再向后发送下单请求。

将这一步获取到的openid 传给后台,

PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);//获取prepayid的请求类            ClientRequestHandler clientHandler = new ClientRequestHandler(request, response);//返回客户端支付参数的请求类            prepayReqHandler.setParameter("appid", ConstantUtil.JS_APP_ID);            prepayReqHandler.setParameter("openid", payVO.getOpenid());            prepayReqHandler.setParameter("body", snInfo.get("name").toString()); //商品描述            prepayReqHandler.setParameter("device_info", "WEB"); //商品描述            prepayReqHandler.setParameter("mch_id", ConstantUtil.JS_MCH_ID);            String noncestr = WXUtil.getNonceStr();            prepayReqHandler.setParameter("nonce_str", noncestr);            prepayReqHandler.setParameter("notify_url", getServerUrl(request, notify_url)); //接收微信通知的URL            prepayReqHandler.setParameter("out_trade_no", out_trade_no); //商家订单号            prepayReqHandler.setParameter("spbill_create_ip", request.getRemoteAddr()); //订单生成的机器IP,指用户浏览器端IP            prepayReqHandler.setParameter("total_fee", "" + (int) (((Float) snInfo.get("amount")) * 100)); //商品金额,以分为单位            prepayReqHandler.setParameter("trade_type", "JSAPI");            //生成获取预支付签名            String sign = prepayReqHandler.createSHA1Sign(ConstantUtil.JS_APP_KEY);            //增加非参与签名的额外参数            prepayReqHandler.setParameter("sign", sign);            String gateUrl = ConstantUtil.GATEURL;            prepayReqHandler.setGateUrl(gateUrl);            //获取prepayId            String prepayid = prepayReqHandler.sendPrepay();

PrepayIdRequestHandler 这个类可以在微信的demo 找到。
这里的签名需要一个api key,同样的,每个appid 对应一个key,这个key 需要在微信支付的系统中去设置,不在公众号里面设置。

获取到prepayid 之后,将参数传给前台页面。

//输出参数列表                clientHandler.setParameter("appId", ConstantUtil.JS_APP_ID);                clientHandler.setParameter("nonceStr", noncestr);                clientHandler.setParameter("package", "prepay_id="+prepayid);                clientHandler.setParameter("timeStamp", "" + System.currentTimeMillis() / 1000);//秒                clientHandler.setParameter("signType", "MD5");                //生成签名                sign = clientHandler.createSHA1Sign(ConstantUtil.JS_APP_KEY);                clientHandler.setParameter("paySign", sign);                Map map = clientHandler.getMapBody();                return success(map);

调起支付

function onBridgeReady() {                                WeixinJSBridge.invoke(                                        'getBrandWCPayRequest', {                                            "appId": data.appId,     //公众号名称,由商户传入                                            "timeStamp": data.timeStamp,         //时间戳,                                            "nonceStr": data.nonceStr, //随机串                                            "package": data.package,                                            "signType": data.signType,         //微信签名方式:                                            "paySign": data.paySign //微信签名                                        },                                        function (res) {                                            if (res.err_msg == "get_brand_wcpay_request:ok") {                                                //支付成功后最好是到后台进行查询一下订单的状态,确保服务器后台相关的业务都已经执行成功。                                            }     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。                                            else if(res.err_msg =='get_brand_wcpay_request:cancel'){                                                                                            }                                            else{                                                showTip("支付失败。");                                            }                                        }                                );                            }                            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();                            }

这一部分可以放在你的ajax success部分中进行。

后记

进行微信开发,主要是不好调试。

  1. 需要将网页链接通过你的公众号发到你的微信,然后在微信中打开链接。
  2. 尽量把代码写在jsp 中,避免写在class 中频繁重启。
  3. 碰到签名错误,可以在微信提供的签名工具中验证,如果是签名没有错,那就是算法没有错,传的参数不对了。比如app key 不对。
如果有其他的朋友有相关的问题,可以留言给我。我尽量帮大家解决,避免大家跳入微信的坑中。

转载于:https://my.oschina.net/qzzsunly/blog/495072

你可能感兴趣的文章
NIO案例
查看>>
log4j的MDC
查看>>
OCR文字识别可以帮助PDF文档处理吗
查看>>
ABBYY FineReader 12 识别文档语言有哪些
查看>>
BarTender打印额外字符的方法
查看>>
Mysql 错误日志
查看>>
iOS开发 使用Xcode自带的Leaks:动态的检测内存泄露
查看>>
ubuntu faience图标推荐
查看>>
扫雷(windows xp winmine)内存读取
查看>>
grails使用经验笔记
查看>>
nagios+centreon总结之第一章——nagios+centreon简介
查看>>
Iptables
查看>>
Postman全局变量
查看>>
MySQL命令行工具
查看>>
sed awk第2讲: sed基本用法(视频)
查看>>
1个拥有很多编辑器的网站
查看>>
机器学习库初探之MXnet
查看>>
session监听在线用户
查看>>
python 创建虚拟环境机
查看>>
报错: java.security.KeyStoreException: java.security
查看>>