微信公众号支付总结

微信公众号支付总结大致可以分为三步, 第一步获取用户授权,第二步调用统一下单接口获取预支付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 不对。

如果有其他的朋友有相关的问题,可以留言给我。我尽量帮大家解决,避免大家跳入微信的坑中。

时间: 2024-10-10 08:51:55

微信公众号支付总结的相关文章

2017-9月微信公众号支付-Java详解

微信支付源代码 在此之前,先C麻瓜藤N遍,MD官方文档一半正确一半错误.言归正传, 微信支付整体流程:微信授权登录商户的公众号--微信支付的公众号配置--统一下单--微信js调起支付页面--输入密码支付--支付成功,异步回调URL处理商户的相应业务 一.业务场景: 先看一下支付的业务场景:用户使用微信登录商户页面,点击支付按钮,调起微信支付,选择付款卡号,输入密码,完成支付,如图: 场景十分简单,不过步骤比较多,稍不注意就掉坑里了. 二.微信公众号支付的配置准备: 1)调用公众号支付,首先你得有

微信公众号支付开发全过程 --JAVA

按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的,还配了图.我还要再说一遍. 用户点击一个支付按钮-->{后台一大推处理}-->用户看到了一个输入密码的界面,包含金额等一些信息-->用户输入密码后出来一个支付成功的页面(这部分流程都是微信自己完成的,我们什么都不用做)-->返回系统自己的页面(总不能让用户一直看着一个支付完成的页面吧

微信公众号支付H5调用支付详解

最近项目需要微信支付,然后看了下微信公众号支付,,虽然不难,但是细节还是需要注意的,用了大半天时间写了个demo,并且完整的测试了一下支付流程,下面分享一下微信公众号支付的经验. 一.配置公众号微信支付 需要我们配置微信公众号支付地址和测试白名单. 比如:支付JS页面的地址为 http://www.xxx.com/shop/pay/ 那此处配置www.xxx.com/shop/pay/ 二.开发流程 借用微信公众号支付api(地址 http://pay.weixin.qq.com/wiki/do

ASP.NET MVC 微信公众号支付,微信公众平台配置

微信公众号支付,首先要登录微信公众号进行配置: 第一步:配置网页授权域名 点击上图的修改则出现下面截图:进行修改(配置)网页授权的域名 第二步:配置支付授权目录 注意:支付授权目录的配置: 假设域名为:www.linjie.com 1.如果支付的页面在网站的根目录下,则配置格式为: http://域名/    例子:http://www.linjie.com/ 2.如果支付页面在网站的某个文件夹下,需要精确到文件夹:配置格式为:http://域名/文件夹名称/   例子支付页面在order文件下

使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发

概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很方便的快速完成微信公众号支付的开发. 关于Magicodes.WeChat.SDK MAGICODES.WECHAT.SDK为心莱团队封装的轻量级微信SDK,现已全部开源,开源库地址为:https://github.com/xin-lai/Magicodes.WeChat.SDK 更多介绍,请关注后

微信公众号支付 js api java版本

说起来.微信支付真是一堆坑. 居然官网都没有java版本的完整代码. 就算是php版本的.还都有错误.且前后各种版本.各种文档一大堆....不停的误导开发人员. 花了一天半时间.总算实现了微信公众号支付.和pc端的微信扫码支付.其他不说了.直接给思路 本人做的是微信V3版本的微信支付.微信的官方文档中.提供的demo 只有一些工具类.这些类还是很有作用的. https://mp.weixin.qq.com/paymch/readtemplate?t=mp/business/course3_tmp

微信公众号支付--错误记录

微信公众号支付调用统一下单接口时,微信返回的数据一定要二次组装再给前台,否则会有问题的,正确示范如下: /** * 获取weixin支付的返回信息 * @param payOrderId * @return */ @Override public String getPayInfo(String payOrderId,String openid,String orderType) { //返回结果 String res = ""; double total_fee_money = 0;

thinkphp整合系列之微信公众号支付

thinkphp整合系列之微信公众号支付 白俊遥 2016-07-17 11:26:52 PHP thinkphp 公众号支付是指在微信app中访问的页面通过js直接调起微信支付:因此页面必须是在微信中打开的:示例项目:https://github.com/baijunyao/thinkphp-bjyadmin一:设置域名登录微信公众平台:微信支付中设置支付授权目录:把域名改为自己的:注意最后是有一个斜线的 / 设置授权域名:二:导入sdk/ThinkPHP/Library/Vendor/Wei

微信公众号支付踩坑记

前两周做微信H5支付,在浏览器端用的,天真地以为app挂到公众号中也能用,结果不行>"<|||| ,只好再对接一次公众号支付,微信的支付对接下来总体感觉就是封装地不如支付宝,文档不完善,坑贼多.本文会主要关注对接过程中所遇到的问题,以及部分实现代码. 1.介绍 公众号支付(JSAPI支付)是指用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块来完成支付,适用于在公众号.朋友圈.聊天窗口等微信内完成支付的场景.注意公众号支付必须在微信环境