微信支付開發h5調用

這兩天作微信支付開發。碰到大坑。糾結死我了。好不容作完。前端

後臺java:直接上代碼:注意區分先後端的變量大小寫。。。java

@RequestMapping(value = "/index")
    public Model  index(@RequestParam(value = "openid", required = true) String openid ,Model model,HttpServletRequest request) throws Exception{
        logger.info("************openid***********爲:"+openid);
        //獲取prepayid
        Map<String ,String > map=new HashMap<String,String>();
        WeiXinConfig wcf=weiXinBaseService.getWeiXinConfig();
         String nonceStr=UUID.randomUUID().toString().substring(0, 32);
         
        oauthService.shareFactory(request);
        String appid=wcf.getAppid();
         long timestamp = System.currentTimeMillis() / 1000;
        map.put("appid", appid );
        map.put("mch_id", WebConfig.get("pay.mch_id"));
        map.put("nonce_str",nonceStr);
        map.put("body",  WebConfig.get("pay.body"));
        map.put("out_trade_no", payWxUtil.orderNum());
        map.put("total_fee", WebConfig.get("pay.price"));
        map.put("spbill_create_ip",request.getRemoteAddr());
        map.put("notify_url", WebConfig.get("hostAddress")+request.getContextPath()+"/babyShow/payInfo/info");
        map.put("trade_type", "JSAPI");
        map.put("openid", openid);
        String paySign=SignUtil.getPayCustomSign(map,WebConfig.get("pay.key"));
        map.put("sign",paySign);
        String xml=    CommonUtil.ArrayToXml(map);
        String prepayid=    payWxUtil.getPrepayid(xml);
        logger.info("prepareid*****************************="+prepayid);
       //封裝h5頁面調用參數
        Map<String ,String > signMap=new HashMap<String ,String >();
        signMap.put("appId", appid);
        logger.info("appId="+appid);
        signMap.put("timeStamp", timestamp+"");
        logger.info("timeStamp="+timestamp);
        signMap.put("package", "prepay_id="+prepayid);
        logger.info("package="+"prepay_id="+prepayid);
        signMap.put("signType", "MD5");
        logger.info("singType="+"MD5");
        signMap.put("nonceStr", nonceStr);
        logger.info("nonceStr="+nonceStr);
        model.addAttribute("paytimestamp", timestamp);
        model.addAttribute("paypackage", "prepay_id="+prepayid);
        model.addAttribute("paynonceStr", nonceStr);
        model.addAttribute("paysignType", "MD5");
        String paySign2=SignUtil.getPayCustomSign(signMap,WebConfig.get("pay.key"));
        model.addAttribute("paySign",paySign2 );
        logger.info("paySign="+paySign2);
        return model;
        
    }

以上代碼獲取openid須要根據網頁受權來獲取。這裏就很少講了。主要講講獲取prepayid和生成h5頁面所需參數,git

這裏面比較麻煩的就是簽名的獲取json

查看方法SignUtil.getPayCustomSign(signMap,WebConfig.get("pay.key"))後端

代碼以下api

  /**
     * 獲取支付所需簽名
     * @param ticket
     * @param timeStamp
     * @param card_id
     * @param code
     * @return
     * @throws Exception
     */
    public static String getPayCustomSign(Map<String, String> bizObj,String key) throws Exception {
        
        String bizString = CommonUtil.FormatBizQueryParaMap(bizObj,
                false);
        logger.info(bizString);
        return MD5SignUtil.sign(bizString, key);
    }
   

其中CommonUtil.FormatBizQueryParaMap是用來作字典排序的。有參考了網上的例子。就沒單獨作。微信

public static String FormatBizQueryParaMap(Map<String, String> paraMap,
            boolean urlencode) throws Exception {

        String buff = "";
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(
                    paraMap.entrySet());

            Collections.sort(infoIds,
                    new Comparator<Map.Entry<String, String>>() {
                        public int compare(Map.Entry<String, String> o1,
                                Map.Entry<String, String> o2) {
                            return (o1.getKey()).toString().compareTo(
                                    o2.getKey());
                        }
                    });

            for (int i = 0; i < infoIds.size(); i++) {
                Map.Entry<String, String> item = infoIds.get(i);
                //System.out.println(item.getKey());
                if (item.getKey() != "") {
                    
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlencode) {
                        val = URLEncoder.encode(val, "utf-8");

                    }
                    buff += key + "=" + val + "&";

                }
            }

            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
        return buff;
    }

   

其中MD5SignUtil.sign(bizString, key)方法以下網絡

public static String sign(String content, String key)
            throws Exception{
        String signStr = "";
        signStr = content + "&key=" + key;

        return MD5Util.MD5(signStr).toUpperCase();

    }
其中MD5Util.MD5(signStr)方法以下
    public final static String MD5(String s) {
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};       
        try {
            byte[] btInput = s.getBytes();
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
       }
    }
CommonUtil.ArrayToXml(map)方法以下

public static String ArrayToXml(Map<String, String> arr) {
        String xml = "<xml>";
        
        Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<String, String> entry = iter.next();
            String key = entry.getKey();
            String val = entry.getValue();
            if (IsNumeric(val)) {
                xml += "<" + key + ">" + val + "</" + key + ">";

            } else
                xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
        }

        xml += "</xml>";
        return xml;
    }
public static boolean IsNumeric(String str) {
        if (str.matches("\\d *")) {
            return true;
        } else {
            return false;
        }
    }
 
 

 

 

發送請求到微信獲取prepayid代碼以下app

public static String URL="https://api.mch.weixin.qq.com/pay/unifiedorder";
    @SuppressWarnings("deprecation")
    public  JSONObject getPrepayJson(String xml){
        HttpClient httpClient = new HttpClient(new HttpClientParams(),new SimpleHttpConnectionManager(true) ); 
        InputStream is = null;
         PostMethod method=null;
        try {
            String url =URL;
             method = HttpClientUtils.postMethod(url);
             method.setRequestBody(xml);
            httpClient.executeMethod(method);
            //讀取響應
             is = method.getResponseBodyAsStream();
            JSONObject o =Xml2JsonUtil.xml2JSON(is);
            return o;
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(method!=null){
                method.releaseConnection();
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
        return null;
    }
    public  String getPrepayid(String xml){
        try {
            JSONObject jo=getPrepayJson(xml);
            JSONObject element=jo.getJSONObject("xml");
            String prepayid=((JSONArray)element.get("prepay_id")).get(0).toString();
            return prepayid;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public  String orderNum(){
        String chars = "0123456789";
        String order = System.currentTimeMillis()+"";
        String res = "";
        for (int i = 0; i < 19; i++) {
            Random rd = new Random();
            res += chars.charAt(rd.nextInt(chars.length() - 1));
        }
        order+=res;
        return order;
    }

xml轉json方法Xml2JsonUtil.xml2JSON(is);。摘自網絡dom

 /** 
         * 轉換一個xml格式的字符串到json格式 
         *  
         * @param xml 
         *            xml格式的字符串 
         * @return 成功返回json 格式的字符串;失敗反回null 
         */  
        @SuppressWarnings("unchecked")  
        public static  JSONObject xml2JSON(InputStream is) {  
            JSONObject obj = new JSONObject();  
            try {  
                SAXReader sb = new SAXReader();  
                Document doc = sb.read(is);
                Element root = doc.getRootElement();  
                obj.put(root.getName(), iterateElement(root));  
                return obj;  
            } catch (Exception e) {  
                log.error("傳入XML後轉換JSON出現錯誤===== Xml2JsonUtil-->xml2JSON============>>",e);  
                return null;  
            }  
        }  

 /** 
         * 一個迭代方法 
         *  
         * @param element 
         *            : org.jdom.Element 
         * @return java.util.Map 實例 
         */  
        @SuppressWarnings("unchecked")  
        private static Map  iterateElement(Element element) {  
            List jiedian = element.elements() ;
            Element et = null;  
            Map obj = new HashMap();  
            List list = null;  
            for (int i = 0; i < jiedian.size(); i++) {  
                list = new LinkedList();  
                et = (Element) jiedian.get(i);  
                if (et.getTextTrim().equals("")) {  
                    if (et.elements().size() == 0)  
                        continue;  
                    if (obj.containsKey(et.getName())) {  
                        list = (List) obj.get(et.getName());  
                    }  
                    list.add(iterateElement(et));  
                    obj.put(et.getName(), list);  
                } else {  
                    if (obj.containsKey(et.getName())) {  
                        list = (List) obj.get(et.getName());  
                    }  
                    list.add(et.getTextTrim());  
                    obj.put(et.getName(), list);  
                }  
            }  
            return obj;  
        }  

 

 

 

 

 

服務端基本這麼多

前端被微信和我本身挖了大坑,整整搞了兩天,擦

先是看的微信文檔jssdk文檔(開始埋坑。。)

頁面引入js

加入

    wx.config({
        debug: false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。
        appId: '${appid}', // 必填,公衆號的惟一標識
        timestamp: '${timestamp}', // 必填,生成簽名的時間戳
        nonceStr: '${nonceStr}', // 必填,生成簽名的隨機串
        signature: '${signature}',// 必填,簽名,見附錄1
        jsApiList: [
            'chooseWXPay'
        ] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2
        
    });

 

嗯。配置好了。若是傳入jsconfig的參數。。。

而後看到jssdk裏面有發送一個微信支付請求?

嗯加進去

 
 
function pay(){
        wx.chooseWXPay({
            timestamp: ${paytimestamp}, // 支付簽名時間戳,注意微信jssdk中的全部使用timestamp字段均爲小寫。但最新版的支付後臺生成簽名使用的timeStamp字段名需大寫其中的S字符
            nonceStr: '${paynonceStr}', // 支付簽名隨機串,不長於 32 位
            package: '${paypackage}', // 統一支付接口返回的prepay_id參數值,提交格式如:prepay_id=***)
            signType: '${paysignType}', // 簽名方式,默認爲'SHA1',使用新版支付需傳入'MD5'
            paySign: '${paySign}', // 支付簽名
            success: function (res) {
                alert("支付成功");
                // 支付成功後的回調函數
            }
        });
    }
 
 

 

 

而後發佈,執行調試。。尼瑪。怎麼樣都支付不了。一下子報訂單信息錯誤、一下子報簽名錯誤。。。找了N多資料均不對

後來想啊。大不了用商戶平臺提供的文檔寫接口什麼的。因而加入了代碼

      function onBridgeReady(){
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
                   "appId" : "${appid}",     //公衆號名稱,由商戶傳入     
                    "timeStamp":"${paytimestamp}",         //時間戳,自1970年以來的秒數     
                    "nonceStr" : "${paynonceStr}", //隨機串     
                    "package" : "${paypackage}",     
                    "signType" : "${paysignType}",         //微信簽名方式:     
                    "paySign" : "${paySign}" //微信簽名 
               },
                function(res){
                   alert(res.err_msg);  // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返
 
               }
           ); 
         }
    function pay2(){  
        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();
         }
     }

發佈調試。。。仍是不對。。兩個按鈕pay()和pay2()均不對。pay方法仍是一下子訂單信息錯誤一下子簽名錯誤。pay2()方法則一直報簽名錯誤。。。尼瑪。吧經歷放後臺簽名。。怎麼改都不行。簽名明明對的啊。能夠獲取prepayid的。爲毛封裝h5參數時就出錯了呢。。。折騰啊。。。搞了N久。。就尼瑪不對。。。後來一個小錯誤pay方法js報錯了。。結果pay2方法確能夠執行了。。。吧pay的js報錯去了以後pay2又不能用了。。我擦。。哥有預感。。難道兩種方式衝突了??因而我把config和pay方法刪除了再試試。。。尼瑪果真能夠了。不能加入config和pay。。。果真能夠了。。。我擦。折騰的。。微信啃爹啊。第一種方式沒法用有沒有,誤導人啊。。。正確結果就是商品平臺的文檔使用方法js以下:

      function onBridgeReady(){
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest', {
                   "appId" : "${appid}",     //公衆號名稱,由商戶傳入     
                    "timeStamp":"${paytimestamp}",         //時間戳,自1970年以來的秒數     
                    "nonceStr" : "${paynonceStr}", //隨機串     
                    "package" : "${paypackage}",     
                    "signType" : "${paysignType}",         //微信簽名方式:     
                    "paySign" : "${paySign}" //微信簽名 
               },
                function(res){
                   alert(res.err_msg);  // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功後返
 
               }
           ); 
         }
    function pay(){  
        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();
         }
     }

 

至此。終於把微信支付搞定了。留着博客。防止後人走彎路(config裏面不能加入chooseWXPay方法。。切記)

相關文章
相關標籤/搜索