java實現微信支付之掃碼支付


本文直接從代碼調用微信掃碼支付講起。賬號配置,參數生成等請參考官方文檔:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1

微信掃碼支付。簡單來說,就是你把微信支付需要的信息,生成到二維碼圖片中。通過微信掃一掃,發起支付。我們需要做的就是二件事:

一是:按照微信掃碼支付規則生成二維碼信息.

二是:微信沒有提供生成二維碼圖片的接口。需要我們自己把二維碼信息生成到二維碼圖片中。

1.模式選擇:

微信掃碼支付,有兩種模式,文檔中有介紹。第二種模式,微信接口會返回二維碼信息給我們。而第一種模式則需要我們自己去生成二維碼信息。會有些麻煩。尤其 是參數大小寫,還有簽名的問題,容易出錯。總的來說第二種模式比第一種模式簡單。所有我采用的是第二種模式,比較通用。京東與攜程亦用的是第二種模式。

2.調用統一下單接口獲取帶有二維碼信息的url:(模式二)

模式二的微信掃碼支付,需要先調用微信的統一下單接口,生成預交易單。(參數傳遞與接收都是XML 數據格式。)

正確調用后,會返回含有交易標示ID,和二維碼鏈接的URL。

 

3.實現掃碼支付(模式二)

 

  private static String APPID = "";  

  private static String MCHID= "";
  private static String KEY= "";
  private static String APPSECRET= "";
  private static String body= "";
  private static String notify_url= "";    //回調地址。測試回調必須保證外網能訪問到此地址

  /**   * 統一下單接口 * 微信二維碼支付 * @param params * @return */ public String weixin_pay(String out_trade_no,String product_id) { JSONObject retJson = new JSONObject(); try { String currTime = PayCommonUtil.getCurrTime(); String strTime = currTime.substring(8, currTime.length()); String strRandom = PayCommonUtil.buildRandom(4) + ""; String nonce_str = strTime + strRandom;      //生成隨機字符串 JSONObject requestObj = JSONObject.fromObject(params); // 正式上線的時候價格根據訂單id查詢 String order_price = "1"; // 價格 注意:價格的單位是分 SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); packageParams.put("appid", APPID); packageParams.put("mch_id", MCHID); packageParams.put("nonce_str", nonce_str); packageParams.put("body", body); packageParams.put("out_trade_no", out_trade_no); packageParams.put("total_fee", order_price); packageParams.put("spbill_create_ip", "用戶端ip"); packageParams.put("notify_url", notify_url); packageParams.put("trade_type", "NATIVE"); packageParams.put("product_id", product_id); Calendar nowTime = Calendar.getInstance(); packageParams.put("time_start", DateFormatUtil.formatDate( nowTime.getTime(), "yyyyMMddHHmmss")); nowTime.add(Calendar.MINUTE, requestObj.getInt("expire_time")); packageParams.put("time_expire", DateFormatUtil.formatDate( nowTime.getTime(), "yyyyMMddHHmmss")); String sign = PayCommonUtil.createSign("UTF-8", packageParams, KEY); packageParams.put("sign", sign);        //加密 String requestXML = PayCommonUtil.getRequestXml(packageParams); logger.info("支付請求:" + requestXML); long startTime=System.currentTimeMillis(); String resXml = HttpRequest.postData( "https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML); long endTime=System.currentTimeMillis(); Integer execute_time = (int) ((endTime-startTime)/1000); logger.info("支付結果:" + resXml); Map map = XMLUtil.doXMLParse(resXml); JSONObject reportParams = new JSONObject(); reportParams.put("url", "https://api.mch.weixin.qq.com/pay/unifiedorder"); reportParams.put("execute_time", execute_time); reportParams.put("return_code", map.get("return_code").toString()); reportParams.put("return_msg", map.get("return_msg").toString()); reportParams.put("result_code", map.get("result_code").toString()); if (map.get("err_code") != null) { reportParams.put("err_code", map.get("err_code").toString()); reportParams.put("err_code_des", map.get("err_code_des").toString()); } reportParams.put("out_trade_no", out_trade_no); //交易保障 report(reportParams.toString()); if (map.get("return_code").toString().equals("SUCCESS") && map.get("result_code").toString().equals("SUCCESS")) { String urlCode = (String) map.get("code_url");          //微信二維碼短鏈接 retJson.put("code", 0); retJson.put("message", "下單成功."); retJson.put("data", urlCode); } else { retJson.put("code", 1); retJson.put("message", map.get("err_code_des").toString()); retJson.put("data", ""); } return retJson.toString(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } }

 

 

4.支付工具類

public class PayCommonUtil {
    
    public static Logger log = LoggerFactory.getLogger(PayCommonUtil.class);
    
    /**
     * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。
     * @return boolean
     */  
    public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  
        StringBuffer sb = new StringBuffer();  
        Set es = packageParams.entrySet();  
        Iterator it = es.iterator();  
        while(it.hasNext()) {  
            Map.Entry entry = (Map.Entry)it.next();  
            String k = (String)entry.getKey();  
            String v = (String)entry.getValue();  
            if(!"sign".equals(k) && null != v && !"".equals(v)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
          
        sb.append("key=" + API_KEY);  
          
        //算出摘要  
        String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();  
          
        //System.out.println(tenpaySign + "    " + mysign);  
        return tenpaySign.equals(mysign);  
    }  
 
    /**
     * @author
     * @date 2016-4-22
     * @Description:sign簽名
     * @param characterEncoding
     *            編碼格式
     * @param parameters
     *            請求參數
     * @return
     */  
    public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  
        StringBuffer sb = new StringBuffer();  
        Set es = packageParams.entrySet();  
        Iterator it = es.iterator();  
        while (it.hasNext()) {  
            Map.Entry entry = (Map.Entry) it.next();  
            String k = (String) entry.getKey();  
            String v = "";
            try {
                v = (String) entry.getValue();
            } catch (Exception e) {
                // TODO: handle exception
                v = entry.getValue() + "";
            }
             
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
        sb.append("key=" + API_KEY);  
        String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
        return sign;  
    }  
 
    /**
     * @author
     * @date 2016-4-22
     * @Description:將請求參數轉換為xml格式的string
     * @param parameters
     *            請求參數
     * @return
     */  
    public static String getRequestXml(SortedMap<Object, Object> parameters) {  
        StringBuffer sb = new StringBuffer();  
        sb.append("<xml>");  
        Set es = parameters.entrySet();  
        Iterator it = es.iterator();  
        while (it.hasNext()) {  
            Map.Entry entry = (Map.Entry) it.next();  
            String k = (String) entry.getKey();
            String v = "";
            try {
                v = (String) entry.getValue();
            } catch (Exception e) {
                // TODO: handle exception
                v = entry.getValue() + "";
            }
             
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {  
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");  
            } else {  
                sb.append("<" + k + ">" + v + "</" + k + ">");  
            }  
        }  
        sb.append("</xml>");  
        return sb.toString();  
    }  
 
    /**
     * 取出一個指定長度大小的隨機正整數.
     *  
     * @param length
     *            int 設定所取出隨機數的長度。length小於11
     * @return int 返回生成的隨機數。
     */  
    public static int buildRandom(int length) {  
        int num = 1;  
        double random = Math.random();  
        if (random < 0.1) {  
            random = random + 0.1;  
        }  
        for (int i = 0; i < length; i++) {  
            num = num * 10;  
        }  
        return (int) ((random * num));  
    }  
 
    /**
     * 獲取當前時間 yyyyMMddHHmmss
     *  
     * @return String
     */  
    public static String getCurrTime() {  
        Date now = new Date();  
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");  
        String s = outFormat.format(now);  
        return s;  
    }  
    
    
    public static JSONObject httpsRequestToJsonObject(String requestUrl,
            String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        try {
            StringBuffer buffer = httpsRequest(requestUrl, requestMethod,
                    outputStr);
            jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error("連接超時:" + ce.getMessage());
        } catch (Exception e) {
            log.error("https請求異常:" + e.getMessage());
        }
        return jsonObject;
    }

    private static StringBuffer httpsRequest(String requestUrl,
            String requestMethod, String output)
            throws NoSuchAlgorithmException, NoSuchProviderException,
            KeyManagementException, MalformedURLException, IOException,
            ProtocolException, UnsupportedEncodingException {
        URL url = new URL(requestUrl);
        HttpsURLConnection connection = (HttpsURLConnection) url
                .openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setRequestMethod(requestMethod);
        if (null != output) {
            OutputStream outputStream = connection.getOutputStream();
            outputStream.write(output.getBytes("UTF-8"));
            outputStream.close();
        }
        // 從輸入流讀取返回內容
        InputStream inputStream = connection.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(
                inputStream, "utf-8");
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String str = null;
        StringBuffer buffer = new StringBuffer();
        while ((str = bufferedReader.readLine()) != null) {
            buffer.append(str);
        }
        bufferedReader.close();
        inputStreamReader.close();
        inputStream.close();
        inputStream = null;
        connection.disconnect();
        return buffer;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM