微信支付回調通知實現

一 準備

1 配置ngrok

將ngrok映射到本地8170端口,並啓動

2 添加工具類

在common_util中添加工具類StreamUtils

package com.atguigu.guli.service.trade.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class StreamUtils {
    private static int _buffer_size = 1024;
    /**
     * InputStream流轉換成String字符串
     * @param inStream InputStream流
     * @param encoding 編碼格式
     * @return String字符串
     */
    public static String inputStream2String(InputStream inStream, String encoding){
        String result = null;
        ByteArrayOutputStream outStream = null;
        try {
            if(inStream != null){
                outStream = new ByteArrayOutputStream();
                byte[] tempBytes = new byte[_buffer_size];
                int count = -1;
                while((count = inStream.read(tempBytes, 0, _buffer_size)) != -1){
                    outStream.write(tempBytes, 0, count);
                }
                tempBytes = null;
                outStream.flush();
                result = new String(outStream.toByteArray(), encoding);
                outStream.close();
            }
        } catch (Exception e) {
            result = null;
        } finally {
            try {
                if(inStream != null) {
                    inStream.close();
                    inStream = null;
                }
                if(outStream != null) {
                    outStream.close();
                    outStream = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }
}

二 支付回調

1 回調方法

該鏈接是通過【統一下單API】中提交的參數notify_url設置,如果鏈接無法訪問,商戶將無法接收到微信通知。

參考文檔:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8

2 控制器

/**
* 功能描述:微信回調通知
*
* @author cakin
* @date 2021/1/13
* @param request 請求
* @return response 響應
*/
@PostMapping("callback/notify")
public String wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
    log.info("\n callback/notify 被調用");
    ServletInputStream inputStream = request.getInputStream();
    String notifyXml = StreamUtils.inputStream2String(inputStream, "utf-8");
    log.info("\n notifyXml = \n " + notifyXml);
    // 驗籤:驗證簽名是否正確
    if (WXPayUtil.isSignatureValid(notifyXml, weixinPayProperties.getPartnerKey())) {
        // 解析返回結果
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml);
        // 判斷支付是否成功
        if ("SUCCESS".equals(notifyMap.get("result_code"))) {
            // 金額校驗
            String totalFee = notifyMap.get("total_fee"); //支付結果返回的訂單金額
            String outTradeNo = notifyMap.get("out_trade_no");//訂單號
            Order order = orderService.getOrderByOrderNo(outTradeNo);//查詢本地訂單
            // 校驗返回的訂單金額是否與商戶側的訂單金額一致
            if (order != null && order.getTotalFee().intValue() == Integer.parseInt(totalFee)) {
                // 接口調用的冪等性:無論接口被調用多少次,最後所影響的結果都是一致的
                if (order.getStatus() == 0) {
                    // 更新訂單狀態
                    orderService.updateOrderStatus(notifyMap);
                }
                // 支付成功:給微信發送我已接收通知的響應
                // 創建響應對象
                Map<String, String> returnMap = new HashMap<>();
                returnMap.put("return_code", "SUCCESS");
                returnMap.put("return_msg", "OK");
                String returnXml = WXPayUtil.mapToXml(returnMap);
                response.setContentType("text/xml");
                log.info("支付成功,通知已處理");
                return returnXml;
            }
        }
    }

    // 創建響應對象:微信接收到校驗失敗的結果後,會反覆的調用當前回調函數
    Map<String, String> returnMap = new HashMap<>();
    returnMap.put("return_code", "FAIL");
    returnMap.put("return_msg", "");
    String returnXml = WXPayUtil.mapToXml(returnMap);
    response.setContentType("text/xml");
    log.info("校驗失敗");
    return returnXml;
}

3 服務層

接口

void updateOrderStatus(Map<String, String> notifyMap);

實現

@Transactional(rollbackFor = Exception.class)
@Override
public void updateOrderStatus(Map<String, String> notifyMap) {
    // 更新訂單狀態
    String outTradeNo = notifyMap.get("out_trade_no");
    Order order = this.getOrderByOrderNo(outTradeNo);
    order.setStatus(1);//支付成功
    baseMapper.updateById(order);
    // 記錄支付日誌
    PayLog payLog = new PayLog();
    payLog.setOrderNo(outTradeNo);
    payLog.setPayTime(new Date());
    payLog.setPayType(1);//支付類型:微信支付
    payLog.setTotalFee(Long.parseLong(notifyMap.get("total_fee")));
    payLog.setTradeState(notifyMap.get("result_code"));
    payLog.setTransactionId(notifyMap.get("transaction_id"));
    payLog.setAttr(new Gson().toJson(notifyMap));
    payLogMapper.insert(payLog);
    //更新課程銷量
    eduCourseService.updateBuyCountById(order.getCourseId());
}

 

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