微信掃碼支付功能實現(java版)

微信支付接入方式總共分爲四種:公衆號支付、APP支付、掃碼支付和刷卡支付。其中掃碼支付最符合公司當前業務場景,掃碼支付有兩種接入方式(請參考掃碼支付開發步驟),本文選擇模式二方式接入掃碼支付功能。 php

  模式二接入方式分爲兩個步驟:生成二維碼圖片和編寫支付回調接口。下面分別詳細闡述這兩個步驟: java

一、生成二維碼圖片

  二維碼圖片其實是對一個預交易的url進行編碼而生成的,所以要想獲得二維碼圖片,必須先獲得這個預交易的url,消費者掃描二維碼圖片後打開的網址連接就是這個url。那如何獲得這個url呢?調用微信支付統一下單API。調用該API的各參數這裏不贅述了,文檔寫的很詳細。下面先貼上示例代碼: api

/**
 * 獲取微信支付二維碼圖片
 * @param userId 當前用戶ID,用來看成商戶訂單號,防止重複支付
 * @return
 */
public BufferedImage getWeChatPaymentImage(Integer userId) {
    HashMap<String, String> paramMap = new HashMap<>();
    paramMap.put("appid", "xxxxxxxxxxxx"); //appid:每一個公衆號都有一個appid
    paramMap.put("mch_id", "11111111111"); //商戶號:開通微信支付後分配
    //隨機數
    paramMap.put("nonce_str", RandomUtil.getRandomString(32, RandomUtil.LETTER_AND_NUMBER_RANGE));  
    paramMap.put("body", "香辣烤翅"); //商品描述
    //商戶訂單號:用戶id + 「|」 + 隨機16位字符
    paramMap.put("out_trade_no", userId + "|" + RandomUtil.getRandomString(16, RandomUtil.LETTER_AND_NUMBER_RANGE)); 
    paramMap.put("total_fee", 1000); //金額必須爲整數  單位爲分
    paramMap.put("spbill_create_ip", PaymentUtil.localIp()); //本機的Ip
    paramMap.put("notify_url", this.notifyUrl); //支付成功後,回調地址
    paramMap.put("trade_type", "NATIVE"); //交易類型
    paramMap.put("product_id", "100001"); // 商戶根據本身業務傳遞的參數 當trade_type=NATIVE時必填
    //根據微信簽名規則,生成簽名。隨機參數能夠在商戶後臺管理系統中進行設置。
    paramMap.put("sign", PaymentUtil.getSignature(paramMap, "beGPax3F1EtxxxxxxofcerMRqNvt9XJ2"));

    String xmlData = PaymentUtil.mapToXml(paramMap);//把參數轉換成XML數據格式

    String codeUrl = getCodeUrl(xmlData);   //獲取二維碼連接

    return PaymentUtil.encodeQrcode(codeUrl);   //將二維碼連接信息編碼成二維碼圖片,用BufferedImage對象表示

}

/**
 * 獲取二維碼連接
 * @param xmlData
 * @return
 */
private String getCodeUrl(String xmlData) {
    String resXml = HttpUtil.postData(WX_PAYMENT_API_URL, xmlData);
    String code_url = "";
    Map<String, Object> map;
    try {
        map = PaymentUtil.getMapFromXML(resXml);
        Object returnCode = map.get("return_code");
        if(PaymentUtil.SUCCESS.equals(returnCode)) {
            Object resultCode = map.get("result_code");
            if(PaymentUtil.SUCCESS.equals(resultCode)) {
                code_url = map.get("code_url").toString();
            }
        }
    } catch (Exception e) {
        return "";
    }

    return code_url;
}

  getWeChatPaymentImage方法中有4個參數須要特別說明,這4個都是調用統一下單API須要的參數。appid是每個公衆號都有的惟一標識,登陸公衆號便可看到;mch_id,即商戶號,只有開通微信支付功能以後纔有;參數簽名sign的隨機數能夠經過商戶後臺設置,務必保證設置的隨機數與代碼中的一致,不然API調用報錯:簽名錯誤;最後一個特別要說明的參數是:notify_url,回調接口地址,也是本文接下來的闡述主題,請讀者繼續往下看。 微信

二、編寫回調接口

  回調接口是幹嗎的呢?微信支付完成以後,會自動調用該接口,反饋這次支付的結果。舉個例子:現有一個訂單,支付狀態爲未支付,掃碼支付以後,微信後臺自動調用自定義的回調接口,將支付結果信息傳遞回來,接口方法經過判斷支付結果參數,修改訂單的支付狀態。支付結果反饋形式參考:支付結果通用通知。下面是回調接口示例代碼: app

public void wechatPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
    String ret = "";

    // 解析結果存儲在HashMap
    Map<String, String> map = new HashMap<String, String>();
    InputStream inputStream = request.getInputStream();
    // 讀取輸入流
    SAXReader reader = new SAXReader();
    Document document = reader.read(inputStream);
    // 獲得xml根元素
    Element root = document.getRootElement();
    // 獲得根元素的全部子節點
    List<Element> elementList = root.elements();

    // 遍歷全部子節點
    for (Element e : elementList)
        map.put(e.getName(), e.getText());

    // 釋放資源
    inputStream.close();
    inputStream = null;

    Map<String, String> retMap = new HashMap<String, String>();

    String returnCode = map.get("return_code");
    if("SUCCESS".equals(returnCode)) {
        String resultCode = map.get("result_code");
        String outTradeNo = map.get("out_trade_no");
        if("SUCCESS".equals(resultCode)) {
            //下面爲業務邏輯處理:若是支付成功,則修改該用戶的付費狀態,更新付費時間。
            String[] temp = StringUtils.split(outTradeNo, "|");
            Integer userId = Integer.parseInt(temp[0]);
            UcUser ucUser = new UcUser();
            ucUser.setId(userId);
            ucUser.setIsPay(1);
            ucUser.setPayTime(new Date());
            ucUserManager.updateUserPayment(ucUser);

            retMap.put("return_code", "SUCCESS");
            retMap.put("return_msg", "OK");
            log.info("支付成功!out_trade_no:" + outTradeNo + ", result_code:" + resultCode);
        } else {
            String errCode = map.get("err_code");
            log.error("支付失敗!out_trade_no:" + outTradeNo + ",result_code:" + resultCode + ", err_code:" + errCode);
            retMap.put("return_code", returnCode);
            retMap.put("return_msg", resultCode);
        }
    } else {
        String returnMsg = map.get("return_msg");
        retMap.put("return_code", returnCode);
        retMap.put("return_msg", returnMsg);
        log.error("支付通訊失敗!" + returnMsg);
    }

    ret = PaymentUtil.mapToXml(retMap);

    response.getWriter().print(ret);
}

  回調接口必須經過request.getInputStream()方法獲取支付返回的結果參數,最後使用response.getWriter().print()方法將xml形式的處理結果直接輸出,返回給微信後臺。 dom

  至此,微信掃碼支付功能已完整實現,感謝各位的耐心閱讀,謝謝! post

文章做者: xiaohui249
本文連接: http://javatech.wang/index.php/archives/84/ 版本全部 ©轉載時必須以連接形式註明做者和原始出處
相關文章
相關標籤/搜索