微信支付回调通知实现

一 准备

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());
}

 

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