微信扫码支付4-支付回调

一、准备

1、配置ngrok

将ngrok映射到本地8170端口,并启动

2、添加工具类

在common_util中添加工具类StreamUtils.java

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
ApiWeixinPayController

@Autowired
private WeixinPayProperties weixinPayProperties;

@Autowired
private OrderService orderService;

/**
     * 支付回调:注意这里是【post】方式
     */
@PostMapping("callback/notify")
public String wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

    System.out.println("callback/notify 被调用");
    
    // 获得通知结果
    ServletInputStream inputStream = request.getInputStream();
    String notifyXml = StreamUtils.inputStream2String(inputStream, "utf-8");
    System.out.println("xmlString = " + notifyXml);
    
    // 定义响应对象
    HashMap<String, String> returnMap = new HashMap<>();
    
    // 签名验证:防止伪造回调
    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() == 1){
                    returnMap.put("return_code", "SUCCESS");
                    returnMap.put("return_msg", "OK");
                    String returnXml = WXPayUtil.mapToXml(returnMap);
                    response.setContentType("text/xml");
                    log.warn("通知已处理");
                    return returnXml;
                }else{
                    // 更新订单支付状态,并返回成功响应
                    orderService.updateOrderStatus(notifyMap);
                    returnMap.put("return_code", "SUCCESS");
                    returnMap.put("return_msg", "OK");
                    String returnXml = WXPayUtil.mapToXml(returnMap);
                    response.setContentType("text/xml");
                    log.info("支付成功,通知已处理");
                    return returnXml;
                }
            }
        }
    }
    
    // 校验失败,返回失败应答
    returnMap.put("return_code", "FAIL");
    returnMap.put("return_msg", "");
    String returnXml = WXPayUtil.mapToXml(returnMap);
    response.setContentType("text/xml");
    log.warn("校验失败");
    return returnXml;
}

2、更新订单状态

更新订单支付状态并记录支付日志,将微信返回的支付结果全部记录进数据库的json字段中

接口:OrderService

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

实现:OrderServiceImpl

@Autowired
private PayLogMapper payLogMapper;

@Transactional(rollbackFor = Exception.class)
@Override
public void updateOrderStatus(Map<String, String> map) {

    //更新订单状态
    String orderNo = map.get("out_trade_no");
    Order order = this.getOrderByOrderNo(orderNo);
    order.setStatus(1);//支付成功
    baseMapper.updateById(order);
    
    //记录支付日志
    PayLog payLog = new PayLog();
    payLog.setOrderNo(orderNo);
    payLog.setPayTime(new Date());
    payLog.setPayType(1);//支付类型
    payLog.setTotalFee(Long.parseLong(map.get("total_fee")));//总金额(分)
    payLog.setTradeState(map.get("result_code"));//支付状态
    payLog.setTransactionId(map.get("transaction_id"));
    payLog.setAttr(new Gson().toJson(map));
    payLogMapper.insert(payLog);
}
posted @ 2020-11-01 15:33  碧水云天4  阅读(385)  评论(0编辑  收藏  举报