麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 課堂 > 小程序 > 正文

微信小程序調用微信支付接口的實現方法

2020-03-21 15:58:48
字體:
來源:轉載
供稿:網友

前言:應項目要求,需要使用微信小程序做支付,寫完后告知手續費太高方案不予通過(寶寶心里苦,但寶寶不說)。此次開發在因站在巨人的肩膀上順利完成。

微信支付文檔傳送門:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3

1.開發工具:

Eclipse+Tomcat+微信web開發工具

2.開發環境:

java+maven

3.開發前準備:

3.1 所需材料

小程序的appid,APPsecret,支付商戶號(mch_id),商戶密鑰(key),付款用戶的openid。

申請接入微信商戶地址:https://pay.weixin.qq.com/static/applyment_guide/applyment_detail_miniapp.shtml

3.2 開發模式

本次開發采用的開發模式是:普通模式,適用于有自己開發團隊或外包開發商的直連商戶收款。開發者申請自己的appid和mch_id,兩者需具備綁定關系,以此來使用微信支付提供的開放接口,對用戶提供服務。

微信小程序,微信支付接口

4 開發

wx.request({   url: address + 'wxPay',   data: {     openId: openId      // amount: amount,     // openId: openId   },   header: {     'content-type': 'application/x-www-form-urlencoded' // 默認值    },   method: "POST",   success: function (res) {     console.log(res);     that.doWxPay(res.data);  },   fail: function (err) {     wx.showToast({       icon: "none",       title: '服務器異常,清稍候再試'     })   }, });   doWxPay(param) { //小程序發起微信支付 wx.requestPayment({ timeStamp: param.data.timeStamp,//記住,這邊的timeStamp一定要是字符串類型的,不然會報錯 nonceStr: param.data.nonceStr, package: param.data.package, signType: 'MD5', paySign: param.data.paySign, success: function (event) { // success console.log(event);   wx.showToast({ title: '支付成功', icon: 'success', duration: 2000 }); }, fail: function (error) { // fail console.log("支付失敗") console.log(error) }, complete: function () { // complete console.log("pay complete") } }); },

4.2 java后臺

4.2.1 PayUtil.java

private static Logger logger = Logger.getLogger(PayUtil.class);public static JSONObject wxPay(String openid,HttpServletRequest request){JSONObject json = new JSONObject();        try{            //生成的隨機字符串            String nonce_str = Util.getRandomStringByLength(32);            //商品名稱             String body = new String(WXConst.title.getBytes("ISO-8859-1"),"UTF-8");            //獲取本機的ip地址            String spbill_create_ip = Util.getIpAddr(request);            String orderNo = WXConst.orderNo;            String money = "1";//支付金額,單位:分,這邊需要轉成字符串類型,否則后面的簽名會失敗             Map<String, String> packageParams = new HashMap<String, String>();            packageParams.put("appid", WXConst.appId);            packageParams.put("mch_id", WXConst.mch_id);            packageParams.put("nonce_str", nonce_str);            packageParams.put("body", body);            packageParams.put("out_trade_no", orderNo);//商戶訂單號            packageParams.put("total_fee", money);            packageParams.put("spbill_create_ip", spbill_create_ip);            packageParams.put("notify_url", WXConst.notify_url);            packageParams.put("trade_type", WXConst.TRADETYPE);            packageParams.put("openid", openid);              // 除去數組中的空值和簽名參數            packageParams = PayUtil.paraFilter(packageParams);            String prestr = PayUtil.createLinkString(packageParams); // 把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串              //MD5運算生成簽名,這里是第一次簽名,用于調用統一下單接口            String mysign = PayUtil.sign(prestr, WXConst.key, "utf-8").toUpperCase();            logger.info("=======================第一次簽名:" + mysign + "=====================");              //拼接統一下單接口使用的xml數據,要將上一步生成的簽名一起拼接進去            String xml = "<xml version='1.0' encoding='gbk'>" + "<appid>" + WXConst.appId + "</appid>"                    + "<body><![CDATA[" + body + "]]></body>"                    + "<mch_id>" + WXConst.mch_id + "</mch_id>"                    + "<nonce_str>" + nonce_str + "</nonce_str>"                    + "<notify_url>" + WXConst.notify_url + "</notify_url>"                    + "<openid>" + openid + "</openid>"                    + "<out_trade_no>" + orderNo + "</out_trade_no>"                    + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"                    + "<total_fee>" + money + "</total_fee>"                    + "<trade_type>" + WXConst.TRADETYPE + "</trade_type>"                    + "<sign>" + mysign + "</sign>"                    + "</xml>";              System.out.println("調試模式_統一下單接口 請求XML數據:" + xml);              //調用統一下單接口,并接受返回的結果            String result = PayUtil.httpRequest(WXConst.pay_url, "POST", xml);              System.out.println("調試模式_統一下單接口 返回XML數據:" + result);              // 將解析結果存儲在HashMap中            Map map = PayUtil.doXMLParse(result);              String return_code = (String) map.get("return_code");//返回狀態碼              //返回給移動端需要的參數            Map<String, Object> response = new HashMap<String, Object>();            if(return_code == "SUCCESS" || return_code.equals(return_code)){                // 業務結果                String prepay_id = (String) map.get("prepay_id");//返回的預付單信息                response.put("nonceStr", nonce_str);                response.put("package", "prepay_id=" + prepay_id);                Long timeStamp = System.currentTimeMillis() / 1000;                response.put("timeStamp", timeStamp + "");//這邊要將返回的時間戳轉化成字符串,不然小程序端調用wx.requestPayment方法會報簽名錯誤                  String stringSignTemp = "appId=" + WXConst.appId + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=" + WXConst.SIGNTYPE + "&timeStamp=" + timeStamp;                //再次簽名,這個簽名用于小程序端調用wx.requesetPayment方法                String paySign = PayUtil.sign(stringSignTemp, WXConst.key, "utf-8").toUpperCase();                logger.info("=======================第二次簽名:" + paySign + "=====================");                  response.put("paySign", paySign);                  //更新訂單信息                //業務邏輯代碼            }              response.put("appid", WXConst.appId);            json.put("errMsg", "OK");            //json.setSuccess(true);            json.put("data", response);            //json.setData(response);        }catch(Exception e){            e.printStackTrace();            json.put("errMsg", "Failed");            //json.setSuccess(false);            //json.setMsg("發起失敗");        }        return json;    }   /**       * 簽名字符串       * @param text需要簽名的字符串       * @param key 密鑰       * @param input_charset編碼格式       * @return 簽名結果       */       public static String sign(String text, String key, String input_charset) {           text = text + "&key=" + key;           return DigestUtils.md5Hex(getContentBytes(text, input_charset));       }       /**       * 簽名字符串       * @param text需要簽名的字符串       * @param sign 簽名結果       * @param key密鑰       * @param input_charset 編碼格式       * @return 簽名結果       */       public static boolean verify(String text, String sign, String key, String input_charset) {           text = text + key;           String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));           if (mysign.equals(sign)) {               return true;           } else {               return false;           }       }       /**       * @param content       * @param charset       * @return       * @throws SignatureException       * @throws UnsupportedEncodingException       */       public static byte[] getContentBytes(String content, String charset) {           if (charset == null || "".equals(charset)) {               return content.getBytes();           }           try {               return content.getBytes(charset);           } catch (UnsupportedEncodingException e) {               throw new RuntimeException("MD5簽名過程中出現錯誤,指定的編碼集不對,您目前指定的編碼集是:" + charset);           }       }       /**       * 生成6位或10位隨機數 param codeLength(多少位)       * @return       */       public static String createCode(int codeLength) {           String code = "";           for (int i = 0; i < codeLength; i++) {               code += (int) (Math.random() * 9);           }           return code;       }       @SuppressWarnings("unused")private static boolean isValidChar(char ch) {           if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))               return true;           if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))               return true;// 簡體中文漢字編碼           return false;       }       /**       * 除去數組中的空值和簽名參數       * @param sArray 簽名參數組       * @return 去掉空值與簽名參數后的新簽名參數組       */       public static Map<String, String> paraFilter(Map<String, String> sArray) {           Map<String, String> result = new HashMap<String, String>();           if (sArray == null || sArray.size() <= 0) {               return result;           }           for (String key : sArray.keySet()) {               String value = sArray.get(key);               if (value == null || value.equals("") || key.equalsIgnoreCase("sign")                       || key.equalsIgnoreCase("sign_type")) {                   continue;               }               result.put(key, value);           }           return result;       }       /**       * 把數組所有元素排序,并按照“參數=參數值”的模式用“&”字符拼接成字符串       * @param params 需要排序并參與字符拼接的參數組       * @return 拼接后字符串       */       public static String createLinkString(Map<String, String> params) {           List<String> keys = new ArrayList<String>(params.keySet());           Collections.sort(keys);           String prestr = "";           for (int i = 0; i < keys.size(); i++) {               String key = keys.get(i);               String value = params.get(key);               if (i == keys.size() - 1) {// 拼接時,不包括最后一個&字符                   prestr = prestr + key + "=" + value;               } else {                   prestr = prestr + key + "=" + value + "&";               }           }           return prestr;       }       /**       *       * @param requestUrl請求地址       * @param requestMethod請求方法       * @param outputStr參數       */       public static String httpRequest(String requestUrl,String requestMethod,String outputStr){           // 創建SSLContext           StringBuffer buffer = null;           try{           URL url = new URL(requestUrl);           HttpURLConnection conn = (HttpURLConnection) url.openConnection();           conn.setRequestMethod(requestMethod);           conn.setDoOutput(true);           conn.setDoInput(true);           conn.connect();           //往服務器端寫內容           if(null !=outputStr){               OutputStream os=conn.getOutputStream();               os.write(outputStr.getBytes("utf-8"));               os.close();           }           // 讀取服務器端返回的內容           InputStream is = conn.getInputStream();           InputStreamReader isr = new InputStreamReader(is, "utf-8");           BufferedReader br = new BufferedReader(isr);           buffer = new StringBuffer();           String line = null;           while ((line = br.readLine()) != null) {           buffer.append(line);           }           br.close();        }catch(Exception e){               e.printStackTrace();           }        return buffer.toString();    }         public static String urlEncodeUTF8(String source){           String result=source;           try {               result=java.net.URLEncoder.encode(source, "UTF-8");           } catch (UnsupportedEncodingException e) {               // TODO Auto-generated catch block               e.printStackTrace();           }           return result;       }     /*** 解析xml,返回第一級元素鍵值對。如果第一級元素有子節點,則此節點的值是子節點的xml數據。* @param strxml* @return* @throws JDOMException* @throws IOException*/public static Map doXMLParse(String strxml) throws Exception {  if(null == strxml || "".equals(strxml)) {    return null;    }   Map m = new HashMap();  InputStream in = String2Inputstream(strxml);  SAXBuilder builder = new SAXBuilder();  Document doc = builder.build(in);  Element root = doc.getRootElement();  List list = root.getChildren();  Iterator it = list.iterator();  while(it.hasNext()) {    Element e = (Element) it.next();    String k = e.getName();    String v = "";    List children = e.getChildren();    if(children.isEmpty()) {      v = e.getTextNormalize();    } else {      v = getChildrenText(children);  }   m.put(k, v);} //關閉流in.close(); return m;}/*** 獲取子結點的xml* @param children* @return String*/public static String getChildrenText(List children) {  StringBuffer sb = new StringBuffer();  if(!children.isEmpty()) {  Iterator it = children.iterator();  while(it.hasNext()) {    Element e = (Element) it.next();    String name = e.getName();    String value = e.getTextNormalize();    List list = e.getChildren();    sb.append("<" + name + ">");    if(!list.isEmpty()) {      sb.append(getChildrenText(list));    }    sb.append(value);    sb.append("</" + name + ">");  }}   return sb.toString();}public static InputStream String2Inputstream(String str) {  return new ByteArrayInputStream(str.getBytes());}     public static void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{  BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));        String line = null;        StringBuilder sb = new StringBuilder();        while((line = br.readLine())!=null){            sb.append(line);        }        br.close();        //sb為微信返回的xml        String notityXml = sb.toString();        String resXml = "";        System.out.println("接收到的報文:" + notityXml);          Map map = PayUtil.doXMLParse(notityXml);          String returnCode = (String) map.get("return_code");        if("SUCCESS".equals(returnCode)){            //驗證簽名是否正確            if(PayUtil.verify(PayUtil.createLinkString(map), (String)map.get("sign"), WXConst.key, "utf-8")){                /**此處添加自己的業務邏輯代碼start**/                    /**此處添加自己的業務邏輯代碼end**/                  //通知微信服務器已經支付成功                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";            }        }else{            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"                    + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";        }        System.out.println(resXml);        System.out.println("微信支付回調數據結束");          BufferedOutputStream out = new BufferedOutputStream(                response.getOutputStream());        out.write(resXml.getBytes());        out.flush();        out.close();      }

4.2.2 Util.java

/**     * Util工具類方法     * 獲取一定長度的隨機字符串,范圍0-9,a-z     * @param length:指定字符串長度     * @return 一定長度的隨機字符串     */    public static String getRandomStringByLength(int length) {        String base = "abcdefghijklmnopqrstuvwxyz0123456789";        Random random = new Random();        StringBuffer sb = new StringBuffer();        for (int i = 0; i < length; i++) {            int number = random.nextInt(base.length());            sb.append(base.charAt(number));        }        return sb.toString();    }            /**     * Util工具類方法     * 獲取真實的ip地址     * @param request     * @return     */    public static String getIpAddr(HttpServletRequest request) {        String ip = request.getHeader("X-Forwarded-For");        if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){            //多次反向代理后會有多個ip值,第一個ip才是真實ip            int index = ip.indexOf(",");            if(index != -1){                return ip.substring(0,index);            }else{                return ip;            }        }        ip = request.getHeader("X-Real-IP");        if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){            return ip;        }        return request.getRemoteAddr();     }

4.2.3 WXConst.java

//微信小程序appidpublic static String appId = "";//微信小程序appsecretpublic static String appSecret = "";//微信支付主體public static String title = "";public static String orderNo = "";//微信商戶號public static String mch_id="";//微信支付的商戶密鑰public static final String key = "";//獲取微信Openid的請求地址public static String WxGetOpenIdUrl = "";//支付成功后的服務器回調urlpublic static final String notify_url="https://api.weixin.qq.com/sns/jscode2session";//簽名方式public static final String SIGNTYPE = "MD5";//交易類型public static final String TRADETYPE = "JSAPI";//微信統一下單接口地址public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

5 可能出現的問題

5.1 商戶號

會出現一個什么異常我忘了,重置一下微信商戶密鑰就好了

5.2 中文參數

String body = new String(WXConst.title.getBytes("ISO-8859-1"),"UTF-8");

這行很重要,如果報參數索引-2異常,很可能是出現了中文,對中文進行如上處理即可通過。

5.3 invalid spbill_create_ip

使用微信web開發工具直接測試的,出現了這個問題,調試記得用真機哦。

整個小程序前后端一個人開發,測試成功上線前夕又嫌棄微信支付收取的手續費(0.6%)太高,結算周期(T+7)太長,所以就被無情拋棄了,這個月項目重啟(2018-11)和工商銀行達成一致,直接轉賬到對公賬戶,目前項目進展順利已上線。改需求請先掃碼(小聲bb)

以上所述是小編給大家介紹的微信小程序調用微信支付接口詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 亚洲网站一区 | 久久伊人国产精品 | 国产91免费看| 黄色片一区二区 | 国产午夜三级一区二区三桃花影视 | 国产精品剧情一区二区三区 | 大逼逼影院 | 亚洲精品久久久久久下一站 | 87成人免费看片 | 色屁屁xxxxⅹ在线视频 | 视频一区 中文字幕 | 韩国三级日本三级香港三级黄 | 国产亚洲在线 | 中文字幕网站在线 | 美女黄色毛片免费看 | 久久国产在线观看 | 亚洲一级片免费观看 | 2021免费日韩视频网 | 91精品国产乱码久久久久久久久 | 欧美一级性 | 午夜视频色 | 国产免费激情视频 | 亚州综合一区 | 91九色蝌蚪国产 | 九九热免费精品视频 | 毛片一级片 | 草草视频在线播放 | 久久久久国产成人免费精品免费 | 夜夜看| 久久精品久 | 少妇一级淫片免费放播放 | 小视频在线看 | 中文字幕在线观看91 | 欧美综合日韩 | 久久精品影视 | 色日本视频 | 精品一区二区在线视频 | 亚洲欧美国产视频 | 羞羞的视频免费在线观看 | 精品国产一区二区在线观看 | 日韩剧情片|