zoukankan      html  css  js  c++  java
  • 微信扫码支付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);
    }
    
  • 相关阅读:
    公众号我也快看不下去了
    朋友圈我快看不下去了!
    微信5.2
    微信支付类目及费率
    ACCESS TOKEN
    关于微博认证和微信认证
    重定向
    微信公众账号支付商户接入指南
    微信公众平台开发(94) 违章查询
    [Servlet]什么是Servlet
  • 原文地址:https://www.cnblogs.com/smalldong/p/13909682.html
Copyright © 2011-2022 走看看