java 支付寶支付 手機(jī)網(wǎng)站支付結(jié)果異步通知

對(duì)于手機(jī)網(wǎng)站支付產(chǎn)生的交易,支付寶會(huì)根據(jù)原始支付API中傳入的異步通知地址notify_url,通過POST請(qǐng)求的形式將支付結(jié)果作為參數(shù)通知到商戶系統(tǒng)。
支付寶開發(fā)文檔:https://docs.open.alipay.com/203/105286/

這邊博客講的1.8后臺(tái)通知支付結(jié)果 notify_url

image.png
這個(gè)環(huán)節(jié)的業(yè)務(wù)邏輯處理為:收到支付寶的回調(diào)結(jié)果通知,先進(jìn)行簽名校驗(yàn),如果簽名校驗(yàn)結(jié)果是對(duì)的,然后進(jìn)行自己的業(yè)務(wù)邏輯處理(比如輯比如更新訂單支付信息成功,保存交易流水,修改訂單狀態(tài));

當(dāng)然支付寶的官方文檔還推薦在驗(yàn)簽通過之后還需要查詢這個(gè)支付單號(hào)在支付寶服務(wù)器的支付結(jié)果是否為成功,以這個(gè)結(jié)果為準(zhǔn);然后再進(jìn)行支付成功后的業(yè)務(wù)邏輯處理。主要是為了防止數(shù)據(jù)篡改和數(shù)據(jù)的冪等性處理。

項(xiàng)目中的具體代碼實(shí)現(xiàn):

controller層的處理:

    /**
     * @param request:
     * @param response:
     * @return java.lang.String
     * @Description 支付寶回調(diào)
     * @Author huangkeyuan
     * @Date 16:24 2019-12-11
     */
    @PostMapping("notify")
    @ApiOperation("支付寶支付回調(diào),修改訂單支付狀態(tài)")
    public String aliPayCertNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Map<String, String> returnMap = new HashMap<>();
        //獲取支付寶POST過來反饋信息轉(zhuǎn)換為Entry
        Set<Map.Entry<String, String[]>> entries = request.getParameterMap().entrySet();
        // 遍歷
        for (Map.Entry<String, String[]> entry : entries) {
            String key = entry.getKey();
            StringBuffer value = new StringBuffer("");
            String[] val = entry.getValue();
            if (null != val && val.length > 0) {
                for (String v : val) {
                    value.append(v);
                }
            }
            returnMap.put(key, value.toString());
        }

        log.info("支付寶支付回調(diào),{}", returnMap.toString());

        return paymentService.aliPayCertNotify(returnMap);
    }

service層中的處理:

 /**
     * @param requestParams : 回調(diào)參數(shù)
     * @return java.lang.String
     * @Description 支付寶回調(diào)(公鑰證書方式)
     * @Author huangkeyuan
     * @Date 16:34 2019-12-09
     */
    @PostMapping("alipay/notify")
    @Override
    public String aliPayCertNotify(@RequestParam Map<String, String> requestParams) {

        log.info(">>>支付寶回調(diào)參數(shù):" + requestParams.toString());

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

        try {
            // 獲取支付寶的支付key
            boolean flag = aliPayService.checkSignature(requestParams);

            if (flag) {
                log.info(">>>支付寶回調(diào)簽名認(rèn)證成功");
                //商戶訂單號(hào)
                String out_trade_no = requestParams.get("out_trade_no");
                //交易狀態(tài)
                String trade_status = requestParams.get("trade_status");
                //交易金額
                String amount = requestParams.get("total_amount");

                //支付寶交易號(hào)
                String trade_no = requestParams.get("trade_no");

                if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
                    log.info("支付寶回調(diào)支付成功,trade_status:{}", trade_status);
                    /**
                     * 自己的業(yè)務(wù)處理
                     */
                    
                    // 執(zhí)行支付成功后的商城業(yè)務(wù)邏輯比如更新訂單支付信息成功,保存交易流水,修改訂單狀態(tài)

                    mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SUCCESS_CODE, PaymentStatusCode.ALI_PAY_NOTIFY_SUCCESS_MESSAGE, logMap);
                    // 修改訂單狀態(tài)成功
                    log.info("支付寶支付回調(diào)修改訂單、支付狀態(tài)成功,結(jié)果碼:" + trade_status + ",支付單號(hào):" + out_trade_no + "支付寶支付單號(hào):" + trade_no);

                } else {
                    log.error("沒有處理支付寶回調(diào)業(yè)務(wù),支付寶交易狀態(tài):{},params:{}", trade_status, requestParams);
                    mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_RESPONSE_VALIDATION_ERRORB_CODE,
                            PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_RESPONSE_VALIDATION_ERRORB_MESSAGE, logMap);
                }
            } else {
                log.info("支付寶回調(diào)簽名認(rèn)證失敗,signVerified=false, params:{}", requestParams);
                mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_CODE,
                        PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_MESSAGE, logMap);

                return "failure";
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            log.info("支付寶回調(diào)簽名認(rèn)證失敗,signVerified=false, params:{}", requestParams);
            mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_CODE,
                    PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_MESSAGE, logMap, e);
            return "failure";
        }
        return "success";//請(qǐng)不要修改或刪除
    }

third-party-service中的處理

/**
     * @param requestParams :
     * @return boolean
     * @Description 收到支付寶的成功回調(diào)之后驗(yàn)證簽名是否正確
     * @Author huangkeyuan
     * @Date 17:01 2019-12-12
     */
    @PostMapping("check/signature")
    @Override
    public boolean checkSignature(Map<String, String> requestParams) {
        try {
            String alipaypublickey = this.getAlipayPublicKey(aliPayConfig.getALIPAY_CERT_PATH());
            log.info("讀取服務(wù)器的支付寶公鑰證書,{}", alipaypublickey);
            //切記alipaypublickey是支付寶的公鑰,請(qǐng)去open.alipay.com對(duì)應(yīng)應(yīng)用下查看。
            boolean flag = AlipaySignature.rsaCheckV1(requestParams, alipaypublickey, aliPayConfig.getCHARSET(),
                    aliPayConfig.getSIGN_TYPE());

            return flag;
        } catch (Exception e) {
            return false;
        }
    }

遇到的問題

直接打印支付寶返回的參數(shù)是這樣的:

支付寶回調(diào)參數(shù):{gmt_create=[Ljava.lang.String;@362e073d, charset=[Ljava.lang.String;@1445a60e, seller_email=[Ljava.lang.String;@20f2aa67, subject=[Ljava.lang.String;@30c863fd, sign=[Ljava.lang.String;@76198d36, body=[Ljava.lang.String;@4fd5202d, buyer_id=[Ljava.lang.String;@7a410a22, invoice_amount=[Ljava.lang.String;@965491c, notify_id=[Ljava.lang.String;@33af053b, fund_bill_list=[Ljava.lang.String;@551d8f2b, notify_type=[Ljava.lang.String;@27ff9fb0, trade_status=[Ljava.lang.String;@4f11ffa, receipt_amount=[Ljava.lang.String;@4fbc4482, buyer_pay_amount=[Ljava.lang.String;@76e1ee89, app_id=[Ljava.lang.String;@2d38edfa, sign_type=[Ljava.lang.String;@21ba2968, seller_id=[Ljava.lang.String;@c0ff189, gmt_payment=[Ljava.lang.String;@7563d327, notify_time=[Ljava.lang.String;@1fdeb74c, version=[Ljava.lang.String;@6f5f3cb6, out_trade_no=[Ljava.lang.String;@1c2f1b6d, total_amount=[Ljava.lang.String;@77be0924, trade_no=[Ljava.lang.String;@1db0b448, auth_app_id=[Ljava.lang.String;@b1c81c4, buyer_logon_id=[Ljava.lang.String;@6f8c07b9, point_amount=[Ljava.lang.String;@68fcd445}

需要通過這樣數(shù)據(jù)處理才能轉(zhuǎn)換成我們常用的map結(jié)構(gòu),方便項(xiàng)目中數(shù)據(jù)分析和使用

Map<String, String> returnMap = new HashMap<>();
        //獲取支付寶POST過來反饋信息轉(zhuǎn)換為Entry
        Set<Map.Entry<String, String[]>> entries = request.getParameterMap().entrySet();
        // 遍歷
        for (Map.Entry<String, String[]> entry : entries) {
            String key = entry.getKey();
            StringBuffer value = new StringBuffer("");
            String[] val = entry.getValue();
            if (null != val && val.length > 0) {
                for (String v : val) {
                    value.append(v);
                }
            }
            returnMap.put(key, value.toString());
        }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容