微信掃碼支付總結-PC端-Java(模式二)

前言

最近做的項目有對接微信支付的需求,於是開始了一個人的摸索。本文的前提是公司已經申請了商戶號和appid,設置了商戶號對應的key,即appId,mchId,key三個參數。以下爲開發步驟:

1 閱讀微信官方開發文檔

微信官方文檔鏈接:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1

這裏選擇流程更爲簡單的模式二,主要是看模式二的時序圖:

åçæ¯ä»æ¨¡å¼äºæ¶åºå¾

作爲開發者,此模式跟微信支付系統直接相關的是步驟2,步驟10,步驟11

(2)用戶確認支付後調用微信支付【統一下單API】生成預支付交易;

(10)微信支付系統通過發送異步消息通知商戶後臺系統支付結果。商戶後臺系統需回覆接收情況,通知微信後臺系統不再發送該單的支付通知。

(11)未收到支付通知的情況,商戶後臺系統調用【查詢訂單API】。

2 導入相關依賴

2.1 添加pom.xml依賴

由於採用maven開發,故在pom.xml文件加上如下依賴:

<!-- wxpay -->
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

也可以在官方開發文檔網站下載sdk和demo

2.2 maven依賴的使用

只需新建一個Java配置類,實現WXPayConfig接口,配置appId,mchId,key三個主要參數

public class WxPayConfig implements WXPayConfig {
 
    @Override
    public String getAppID() {
        return "xxxxxxxxxxxxxxxxxx";
    }
 
    @Override
    public String getMchID() {
        return "xxxxxxxxxx";
    }
 
    @Override
    public String getKey() {
        return "xxxxxxxxxxxxxxxxxxxxx";
    }
 
    /*此證書是退款才需要配置*/
    @Override
    public InputStream getCertStream() {
        return this.getClass().getResourceAsStream("/cert/apiclient_cert.p12");
    }
 
    @Override
    public int getHttpConnectTimeoutMs() {
        return 6000;
    }
 
    @Override
    public int getHttpReadTimeoutMs() {
        return 8000;
    }
}

3 調用統一下單接口

3.1 接口地址

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

// new一個新建的配置類
WxPayConfig wxPayConfig = new WxPayConfig();
// WXPay即爲maven依賴的jar包封裝好的調用官方接口的
WXPay wxPay = new WXPay(wxPayConfig);
// 調用統一下單接口
Map<String, String> returnMap = wxPay.unifiedOrder(dataMap);

3.2 此處應注意參數傳遞notify_url這個參數(在第4節會細說)

3.3 接口的返回值

根據官方文檔得知下單接口的返回值,可以判斷returnMap的屬性return_code和result_code都爲SUCCESS時,返回二維碼鏈接code_url

if(WXPayConstants.SUCCESS.equals(returnMap.get("return_code")) &&
                WXPayConstants.SUCCESS.equals(returnMap.get("result_code"))){
    return returnMap.get("code_url");
}

3.4 二維碼插件

由於項目是前後端分離,這裏使用前端插件生成qrcode,具體使用請參考http://code.ciaoca.com/javascript/qrcode/

<script type="text/javascript" src="qrcode.js"></script>
<script type="text/javascript">
// 設置參數方式
    var qrcode = new QRCode('qrcode', {
        // 只需替換這一串內容即可生成二維碼
        text: 'weixin://wxpay/bizpayurl?pr=xxxxxx',
        width: 256,
        height: 256,
        colorDark : '#000000',
        colorLight : '#ffffff',
        correctLevel : QRCode.CorrectLevel.H
    });
</script>


ps:此處也可使用zxing的工具類直接在後端生成二維碼圖片返回給前端顯示,暫不詳細展開。

4 設置支付結果通知的notify_url

開發者在調用統一下單接口時,需要傳遞notify_url給微信支付系統。使得用戶掃碼付款成功後,微信會主動調用開發者設置的接口,對支付結果進行通知,開發者可對支付結果進行判斷,並結合業務需求,實現項目業務。

4.1 使用內網穿透工具ngrok實現內網穿透

若是在本地測試開發,則需要使用內網穿透工具,方便測試

這樣微信訪問馬賽克的鏈接,就相當於訪問了本地的8080端口的程序接口

4.2 配置notify_url

在項目配置文件application.properties文件或者自定義文件中配置notify_url

wechat.notify_url=http://xxxx.ngrok.xxxxx.cn/test/payNotify

4.3 新增payNotify接口,以便微信回調

controller層:提供微信回調接口

@PostMapping(value = "/payNotify")
public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setCharacterEncoding("UTF-8");
        String notify = payService.payNotify(request);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.getWriter().println(notify);
}

service層:接收處理參數,並返回指定內容給微信支付系統   

        // 返回微信格式
        private static final String RESULT_SUCCESS = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        private static final String RESULT_FAIL = "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[參數爲空]]></return_msg></xml>";
        // 異步接收到微信的支付結果
        String requestBody = getRequestBody(request);
        // 使用maven依賴工具類對結果進行轉化
        Map<String, String> map = WXPayUtil.xmlToMap(requestBody);
        LOGGER.debug("微信支付結果通知:{}",requestBody);
        // 返回成功
        if(!WXPayConstants.SUCCESS.equals(map.get("return_code"))){
            LOGGER.error("支付失敗");
            return RESULT_FAIL;
        }
        // 簽名
        String sign = map.get("sign");
        // 業務結果
        String result_code = map.get("result_code");
        // 商戶訂單號
        String out_trade_no = map.get("out_trade_no");
        // 訂單金額
        String total_fee = map.get("total_fee");
        // 微信支付訂單號
        String transaction_id = map.get("transaction_id");
 
        // 1,驗證簽名是否正確
        WxPayConfig config = new WxPayConfig();
        String signature = WXPayUtil.generateSignature(map, config.getKey());
        LOGGER.info("重新生成的簽名:{}",signature);
        if(!signature.equals(sign)){
            LOGGER.info("簽名驗證失敗");
            return RESULT_FAIL;
        }
 
        LOGGER.info("驗籤成功");
        // 驗證支付金額和訂單金額是否一致,此處省略代碼
        // ...
        // 驗證通過,則返回成功結果
        return RESULT_SUCCESS;

獲取request輸入流,解析參數 

/**
     * 接收微信傳過來的結果
     * @param request req
     * @return String格式
     * @throws IOException
     */
    private String getRequestBody(HttpServletRequest request) throws IOException {
        ServletInputStream inputStream = request.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder inputLine = new StringBuilder();
        String line;
        try {
            while ((line = reader.readLine())!=null){
                inputLine.append(line);
            }
        } catch (Exception e){
            LOGGER.debug(e.getMessage());
            e.printStackTrace();
        } finally {
            reader.close();
            inputStream.close();
        }
        return inputLine.toString();
    }

4.4 注意事項

微信回調此處有坑,微信回調是定時重試地調用,若因爲網絡原因或者其他因素,可能導致即使是返回成功了,也會不斷調用回調接口,廢話不多說,上代碼:

        // 1獲取訂單號,查詢該訂單在商戶系統中的訂單狀態
        Map<String, Object> order = orderInfoMapper.queryOrder(out_trade_no);
        // 2判斷訂單是否支付成功,成功則直接返回
        Integer statu = Integer.parseInt(order.get("statu") + "");
        // 1爲已支付
        if(1 == statu){
            LOGGER.info("該訂單已支付,訂單號爲:{}",out_trade_no);
            return RESULT_SUCCESS;
        }

5 查詢訂單狀態接口調用

接口鏈接:https://api.mch.weixin.qq.com/pay/orderquery

參照api文檔,傳遞參數直接調用:

/**
     * 查詢訂單
     * @param dataMap 數據參數
     * @return 返回結果集合
     * @throws Exception 異常
     */
    public static Map<String,String> queryOrder(Map<String,String> dataMap) throws Exception {
        WxPayConfig wxPayConfig = new WxPayConfig();
        WXPay wxPay = new WXPay(wxPayConfig);
        Map<String, String> orderQuery = wxPay.orderQuery(dataMap);
        return orderQuery;
    }

6 退款接口

退款接口需下載證書,並配置證書路徑,未完待續...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章