1. 程式人生 > >微信支付(三) - 非同步通知並且查詢支付結果

微信支付(三) - 非同步通知並且查詢支付結果

要知道,app呼叫支付後,微信會發送一個非同步通知給後臺,同時後臺需要呼叫查詢微信後臺這筆訂單的支付結果以及金額,這是一個並行操作,需要注意的是微信後臺收到的金額和訂單金額需要進行比對,為了防止釣魚,所以這個查詢是有必要的,必須匹配:收到的到賬金額 >= 訂單金額(我有一哥們他們的app是沒有這步操作的,支付了不論是否成功訂單直接往下走,這樣是不對滴...)

好吧,來看一下程式碼,非同步通知地址需要自己配置好,在生成預付單的時候就得傳過去

// TODO 通知回撥地址
    @Value("${WXPAY_NOTIFYURL}")
    private String notifyUrl;

這個地址就是自己的webservice,也就是你的某個rest-controller

複製程式碼

@RequestMapping("/notice")
    public void notice(HttpServletRequest request, HttpServletResponse response) throws IOException {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        String result = new String(outSteam.toByteArray(), "utf-8");
        Map<String, String> map = null;
        try {
            map = XMLUtil.doXMLParse(result);
        } catch (JDOMException e) {
            e.printStackTrace();
        }

        // 此處呼叫訂單查詢介面驗證是否交易成功
        WXOrderQuery wxpayResult = reqOrderQueryResult(map);
        boolean isSucc = wxpayResult.isSuccess();
        
        // 支付成功,商戶處理後同步返回給微信引數
        PrintWriter writer = response.getWriter();
        if (!isSucc) {
            // 支付失敗, 記錄流水失敗
            System.out.println("===============支付失敗==============");
        } else {
            orderService.doWXPayNotice(wxpayResult);
            System.out.println("===============付款成功,業務處理完畢==============");
            
            // 通知微信已經收到訊息,不要再給我發訊息了,否則微信會8連擊呼叫本介面
            String noticeStr = setXML("SUCCESS", "");
            writer.write(noticeStr);
            writer.flush();
        }
        
        String noticeStr = setXML("FAIL", "");
        writer.write(noticeStr);
        writer.flush();
    }

    public static String setXML(String return_code, String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";
    }

複製程式碼

複製程式碼

/**
     * 目前用的這個介面
     * @Description: 查詢通知的結果bean
     * @param map
     * @return
     * 
     * @author lc
     * @date 2016年12月8日 上午11:04:52
     */
    public WXOrderQuery reqOrderQueryResult(Map<String, String> map) {
        WXOrderQuery orderQuery = new WXOrderQuery();
        orderQuery.setAppid(map.get("appid"));
        orderQuery.setMch_id(map.get("mch_id"));
        orderQuery.setTransaction_id(map.get("transaction_id"));
        orderQuery.setOut_trade_no(map.get("out_trade_no"));
        orderQuery.setNonce_str(map.get("nonce_str"));
        String payFlowId = map.get("attach");
        orderQuery.setAttach(payFlowId);
        
        //此處需要金鑰PartnerKey,此處直接寫死,自己的業務需要從持久化中獲取此金鑰,否則會報簽名錯誤
        orderQuery.setPartnerKey(WXPayContants.partnerKey);
        
        Map<String, String> orderMap = orderQuery.reqOrderquery();
        //此處新增支付成功後,支付金額和實際訂單金額是否等價,防止釣魚
        if (orderMap.get("return_code") != null && orderMap.get("return_code").equalsIgnoreCase("SUCCESS")) {
            if (orderMap.get("trade_state") != null && orderMap.get("trade_state").equalsIgnoreCase("SUCCESS")) {
                // 查詢訂單(交易流水的實際金額),判斷微信收到的錢和訂單中的錢是否等額
                SpPayFlowCargoSource payFlow = spPayFlowCargoSourceService.getPayFlowById(payFlowId);
                String total_fee = map.get("total_fee");
                orderQuery.setPayFlow(payFlow);
                Integer db_fee = payFlow.getFee().multiply(new BigDecimal(100)).intValue();
                if (Integer.parseInt(total_fee) == db_fee) {
                    orderQuery.setSuccess(true);
                    return orderQuery;
                }
            }
        }
        orderQuery.setSuccess(false);
        return orderQuery;
    }

複製程式碼

到這一步,就能判斷金額到底對不對,對了那麼久成功支付,訂單進行下一步流程~

再次強調,一定要防止釣魚,另外非同步呼叫的時候需要去檢視你的訂單或者交易流水是否已經成功了,成功就沒有必要繼續走,直接return就行,因為微信

會多次非同步通知,主要還是看你的介面怎麼設計了

 (附:微信非同步通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒)