微信公衆號支付

公衆號支付


 

      公衆號支付是用戶在微信中打開商戶的H5頁面,商戶在H5頁面經過調用微信支付提供的JSAPI接口調起微信支付模塊完成支付。應用場景有:php

    1. ◆ 用戶在微信公衆帳號內進入商家公衆號,打開某個主頁面,完成支付
    2. ◆ 用戶的好友在朋友圈、聊天窗口等分享商家頁面鏈接,用戶點擊連接打開商家頁面,完成支付
    3. ◆ 將商戶頁面轉換成二維碼,用戶掃描二維碼後在微信瀏覽器中打開頁面後完成支付

      微信開發者文檔連接地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1html


開發流程  


 

  第一步:

  你得明白本身須要作的微信支付是什麼一個需求,具體的場景規劃是什麼。前端

  第二步:

  打開微信公衆號支付開發文檔,查看一下具體的開發步驟,在上面都有一一的介紹的,不過記得是微信商戶平臺(pay.weixin.qq.com)java

  第三步:

  這個圖主要介紹了微信的開發流程,我以爲這個得看懂了,纔好開發,對從此的設計什麼的,有很大的幫助,腦子裏有一個大體支付的概念輪廓。ajax

  

  第四步:  

  微信提供的SDK,本身在仔細琢磨一下,結合上面一系列的步驟,很快就知道如何去操做了,關鍵須要認真去閱讀微信提供的SDK源碼,瞭解深刻其中。json

  多去注意查看一下微信支付文檔提供的參數列表看看其中你的一些定義,一些坑就出如今其中。  api

  還有我以爲一切支付都在統一下單的地方出現的變化,須要好好設計這裏面的邏輯,會讓支付系統變得更加的靈活多變,適合之後的擴展。瀏覽器

主要代碼


 

  這裏我主要用的是微信的SDK,我用的是最新的SDK,已經修改好7月3號的微信XXE漏洞,其實也就添加一個類,修改一些東西,沒啥大改動。安全

  主要思路:服務器

  根據微信網頁受權獲取用戶的Openid,配置參數,將參數轉換爲xml格式,經過微信專門接口發給微信,微信在返回給你一系列的東西,能夠從其中獲取有用的。

  一、微信網頁受權(若是用戶在微信客戶端中訪問第三方網頁,公衆號能夠經過微信網頁受權機制,來獲取用戶基本信息,進而實現業務邏輯。),由於在開發文檔中說了,只要trade_type=JSAPI時(即公衆號支付),此參數必傳,此參數爲微信用戶在商戶對應appid下的惟一標識。能夠查看這個文檔https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842      

  原理:通過網頁受權獲取openid,成功則再從新加載這個地址,獲取到openid用session存起來,這個只是我的思路,能夠根據我的需求去改造。 

  代碼:

  public String toWXPublic(String spbill_create_ip, String out_trade_no, int total_fee, Model model, HttpServletResponse response, HttpServletRequest request) throws Exception {
        JSONObject jsonObject = WXPayUtil.getAccessToken(request, response);
        if (jsonObject == null) {
            try {
                String encodeURL = URLEncoder.encode(PayConfigUtil.PROJECT_URL + "/toWXPublic?out_trade_no=" + out_trade_no + "&total_fee=" + total_fee + "&spbill_create_ip=" + spbill_create_ip, "UTF-8");
                String redirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + PayConfigUtil.APP_ID + "&redirect_uri=" + encodeURL + "&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
                response.sendRedirect(redirectUrl);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }   
        log.info("openid get Success:" + jsonObject.getString("openid"));
        request.getSession().setAttribute("openid", jsonObject.getString("openid"));
     
        model.addAttribute("out_trade_no", out_trade_no);
        model.addAttribute("total_fee", total_fee);
        model.addAttribute("spbill_create_ip", spbill_create_ip);
        return "/wxPublicPay";
    }

  

  二、吊起統一下單 URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder,主要獲取prepay_id=123456789參數。

   原理:經過Ajax請求獲取必要的參數,代碼中一些類和參數工具能夠根據SDK,自行配置一下,主要爲了獲得prepay_id

   代碼:

   public Map<String, String> wxPublicPay(Unifiedorder unifiedorder) throws Exception {
        String appid = PayConfigUtil.APP_ID;
        String mch_id = PayConfigUtil.MCH_ID;
        String key = PayConfigUtil.API_KEY;
        //微信統一下單
        HashMap<String, String> data = new HashMap<>();
        data.put("body", "Sales business");
        data.put("out_trade_no", unifiedorder.getOut_trade_no());
        data.put("appid", appid);
        data.put("mch_id", mch_id);
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("total_fee", unifiedorder.getTotal_fee() + "");
        data.put("spbill_create_ip", unifiedorder.getSpbill_create_ip());
        data.put("notify_url", PayConfigUtil.NOTIFY_URL);
        data.put("trade_type", "JSAPI");
        data.put("openid", unifiedorder.getOpenid());
        data.put("sign", WXPayUtil.generateSignature(data, key, WXPayConstants.SignType.HMACSHA256));
        Map<String, String> r = wxPay.unifiedOrder(data);
        HashMap<String, String> packageParams = new HashMap<>();
        packageParams.put("appId", appid);
        packageParams.put("nonceStr", WXPayUtil.generateNonceStr());
        packageParams.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
        //用於後續接口調用中使用,該值有效期爲2小時
        packageParams.put("package", "prepay_id=" + r.get("prepay_id"));
        packageParams.put("signType", "HMAC-SHA256");
        String sign = WXPayUtil.generateSignature(packageParams, key, WXPayConstants.SignType.HMACSHA256);
        packageParams.put("paySign", sign);
        log.info("| packageParams: " + packageParams);
        return packageParams;
    }

  

  三、經過JS調用微信提供的jweixin-1.2.0.js      WeixinJSBridge , 在微信瀏覽器裏面打開H5網頁中執行JS調起支付。接口輸入輸出數據格式爲JSON。

   在這裏我以爲須要注意一下total_fee這個參數,你不能之前端js這個的total_fee這總金額爲標準,須要一塊兒他的方式傳輸,根據你的需求來設置,你要是隻是測試就隨便了。

<script>
    var out_trade_no="${out_trade_no}";
    var total_fee="${total_fee}";
    var spbill_create_ip="${spbill_create_ip}";
    $(function(){

        $("#totalFee").text(parseFloat(total_fee).toFixed(2)/100);
        $('#payBtn').click(function(){
            $.ajax({
                url : "/wxPublicPay",
                type : "post",
                data :{
                    "out_trade_no":out_trade_no,
                    "spbill_create_ip":spbill_create_ip
                },
                dataType : 'json',
                success : function(msg) {
                    if (msg.result_code == 0){
                        pay(msg.data)
                    }
                },
                error : function(data) {
                    alert("服務器異常")
                }
            })
        });
        //吊起支付
        function pay(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);
            }

        }
        //開始支付
        function onBridgeReady(data){
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
                    "appId" : data.appId,     //公衆號名稱,由商戶傳入
                    "timeStamp": data.timeStamp+"",         //時間戳,自1970年以來的秒數
                    "nonceStr" : data.nonceStr, //隨機串
                    "package" : data.package,
                    "signType" : data.signType,         //微信簽名方式:
                    "paySign" : data.paySign    //微信簽名
                },
                function(res){
                    if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                        alert("支付成功");  // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返回    ok,但並不保證它絕對可靠。
                        window.location.href="/wechatPaySucess?total_fee="+total_fee;
                    }else if (res.err_msg == "get_brand_wcpay_request:cancel")  {
                        alert("已取消支付");
                    }else{
                        //支付失敗
                        alert(res.err_msg)
                    }
                }
            );
        }
    })
</script>

  四、流程到這就差很少了,最後剩下一個是異步回調的事情了,支付完成後,微信會把相關支付結果和用戶信息發送給商戶,商戶須要接收處理,並返回應答。

  關鍵在於咱們須要去處理這個信息,並給出應答。

  

 @RequestMapping(value = "weChatReturnNotify")
    @ResponseBody
    public void wechatPaySyntony(HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            BufferedReader reader = request.getReader();
            String line = "";
            StringBuffer inputString = new StringBuffer();
            PrintWriter writer = response.getWriter();
            while ((line = reader.readLine()) != null) {
                inputString.append(line);
            }
            if (reader != null) {
                reader.close();
            }
            if (!StringUtils.isEmpty(inputString.toString())) {
                WXPayResult wxPayResult = JdomParseXmlUtils.getWXPayResult(inputString.toString());
                if ("SUCCESS".equalsIgnoreCase(wxPayResult.getReturn_code())) {
                    SortedMap<String, String> parameters = new TreeMap<String, String>();
                    parameters.put("appid", wxPayResult.getAppid());
                    parameters.put("attach", wxPayResult.getAttach());
                    parameters.put("bank_type", wxPayResult.getBank_type());
                    parameters.put("cash_fee", wxPayResult.getCash_fee() + "");
                    parameters.put("fee_type", wxPayResult.getFee_type());
                    parameters.put("is_subscribe", wxPayResult.getIs_subscribe());
                    parameters.put("mch_id", wxPayResult.getMch_id());
                    parameters.put("nonce_str", wxPayResult.getNonce_str());
                    parameters.put("openid", wxPayResult.getOpenid());
                    parameters.put("out_trade_no", wxPayResult.getOut_trade_no());
                    parameters.put("result_code", wxPayResult.getResult_code());
                    parameters.put("return_code", wxPayResult.getReturn_code());
                    parameters.put("time_end", wxPayResult.getTime_end());
                    parameters.put("total_fee", wxPayResult.getTotal_fee() + "");
                    parameters.put("trade_type", wxPayResult.getTrade_type());
                    parameters.put("transaction_id", wxPayResult.getTransaction_id());
                    log.info("| out_trade_no: " + wxPayResult.getOut_trade_no() + " | wechat Success Back params:" + parameters);
                    // 反校驗簽名
                    String sign = WXPayUtil.generateSignature(parameters, PayConfigUtil.API_KEY);
                    log.info("回調獲得的sign:"+wxPayResult.getSign());
                    log.info("回調參數的sign:"+sign);
                    //這個是判斷你的驗籤和你以前給微信傳的數據,微信服務器組合給你返回的服務器的驗籤,二者一致則表示成功。執行下一步操做
                    if (sign.equals(wxPayResult.getSign())) {
                        Map<String, String> param = new HashMap<>();
                        param.put("out_trade_no", parameters.get("out_trade_no"));
                        param.put("transaction_id", parameters.get("transaction_id"));
                        param.put("result_code", parameters.get("result_code"));
                        HttpUtil.doPost("請求url地址,通知其支付回調成功", param);
                        writer.write(HttpUtil.backWeixin("SUCCESS", "OK"));
                        log.info("| Successful callback to WeChat :" + param);
                    } else {
                        writer.write(HttpUtil.backWeixin("FAIL", "簽名失敗"));
                    }
                } else {
                    writer.write(HttpUtil.backWeixin("FAIL", wxPayResult.getReturn_msg()));
                }
                if (writer != null) {
                    writer.close();
                }
            } else {
                writer.write(HttpUtil.backWeixin("FAIL", "未獲取到微信返回的結果"));
            }
        } catch (Exception e) {
            System.err.println("微信回調錯誤!!!");
        }

    }

 

  到此處你就要去發快遞了。

  其實主要好好看一下安全性。根據微信提供的SDK,上網多看看一些坑你就知道啦,商戶平臺須要配置的東西還蠻多的。

  

 

  參考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

   轉載請註明出處:https://www.cnblogs.com/zhouguanglin/p/9283258.html

相關文章
相關標籤/搜索