zoukankan      html  css  js  c++  java
  • Java微信支付开发之扫码支付模式二

    官方文档

    准备工作:已通过微信认证的公众号,域名可以不通过ICP备案
    借鉴了很多大神的文章,在此先谢过了
    大体过程:根据固定金额和商品的ID先生成订单,再生成二维码,客户扫一扫付款
    模式二支付的流程如下图,可以说是最简单的支付方式了

    原生支付模式二时序图

    业务流程说明:

    (1)商户后台系统根据用户选购的商品生成订单。
    (2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
    (3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
    (4)商户后台系统根据返回的code_url生成二维码。
    (5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
    (6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
    (7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
    (8)微信支付系统根据用户授权完成支付交易。
    (9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
    (10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
    (11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
    (12)商户确认订单已支付后给用户发货。

    一、生成微信支付二维码

    订单可以在订单表中新建一条数据,然后用id作为product_id

     /**
         * 扫码模式二
         *
         * @param params
         * @throws Exception
         */
        @RequestMapping("M2")
        public Map<String, Object> paytwo(HttpServletRequest request, UnifiedOrderParams params) throws Exception {
            Map<String, Object> data = new HashMap<>();
            // 商户后台系统根据用户选购的商品生成订单。
            String out_trade_no = PayHelper.createNonceStr();
            String product_id = DateUtils.getCurrentTime();// 根据自己的逻辑生成
            // int total_fee = 1; // 1分作测试
            // String attach = "支付测试";
            // String body = "微信支付-支付测试";
            String nonce_str = PayHelper.createNonceStr();
            String spbill_create_ip = HttpUtil.getRemortIP(request); // 获取IP
            UnifiedOrderParams unifiedOrderParams = new UnifiedOrderParams();
            unifiedOrderParams.setAppid(wechatAccountConfig.getAppid());// 必须
            unifiedOrderParams.setMch_id(PayConstant.MCH_ID);// 必须
            unifiedOrderParams.setOut_trade_no(out_trade_no);
            unifiedOrderParams.setBody(params.getBody());
            unifiedOrderParams.setAttach(params.getAttach());
            unifiedOrderParams.setProduct_id(product_id);// 必须
            unifiedOrderParams.setTotal_fee(params.getTotal_fee());// 必须
            unifiedOrderParams.setNonce_str(nonce_str); // 必须
            unifiedOrderParams.setSpbill_create_ip(spbill_create_ip); // 必须
            unifiedOrderParams.setTrade_type("NATIVE");// 必须
            unifiedOrderParams.setNotify_url(wechatPayConfig.getNotifyUrl()); // 异步通知URL
            // 统一下单 请求的Xml(除detail外不需要<![CDATA[product_001]]>格式)
            String unifiedXmL = PayHelper.toPayXml(unifiedOrderParams); // 签名并入util
            // log.debug("统一下单 请求的Xml"+unifiedXmL);
            // 统一下单 返回的xml(<![CDATA[product_001]]>格式)
            String unifiedResultXmL = HttpUtil.doPost(
                    wechatPayConfig.getUnifiedOrderUrl(), null, unifiedXmL);
            // log.debug("统一下单 返回的xml("+unifiedResultXmL);
            // 统一下单返回 验证签名
            if (SignatureUtil.checkValidPaySign(unifiedResultXmL, null)) {
                UnifiedOrderResult unifiedOrderResult = XmlUtil.fromXml(unifiedResultXmL,
                        UnifiedOrderResult.class);
                if (Objects.equals("SUCCESS", unifiedOrderResult.getReturn_code())
                        && Objects.equals("SUCCESS", unifiedOrderResult.getResult_code())) {
                    /**** 根据unifiedOrderResult.getCode_url()生成有效期为2小时的二维码 ****/
    
    
                    /**** 根据product_id再次支付方法自己写 ****/
                }
            } else {
                log.debug("签名验证错误");
            }
            return data;
        }

    二、完成支付并通知支付结果

    package com.phil.wechat.pay.controller;
    
    import com.phil.modules.result.ResultState;
    import com.phil.modules.util.SignatureUtil;
    import com.phil.modules.util.XmlUtil;
    import com.phil.wechat.pay.model.response.PayNotifyResult;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.io.IOUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedOutputStream;
    import java.util.Objects;
    
    /**
     * 微信支付结果通知(统一下单参数的notify_url)
     *
     * @author phil
     * @date 2017年6月27日
     */
    @RestController
    @RequestMapping("api/wxpay")
    @Slf4j
    public class WechatPayNotifyController {
    
        @RequestMapping("notify")
        public ResultState notice(HttpServletRequest request, HttpServletResponse response) throws Exception {
            ResultState resultState = new ResultState();
            log.debug("开始处理支付返回的请求");
            String resXml = ""; // 反馈给微信服务器
            String notifyXml = IOUtils.toString(request.getInputStream());// 微信支付系统发送的数据(<![CDATA[product_001]]>格式)
            log.debug("微信支付系统发送的数据" + notifyXml);
            // 验证签名
            if (SignatureUtil.checkValidPaySign(notifyXml, null)) {
                PayNotifyResult notify = XmlUtil.fromXml(notifyXml, PayNotifyResult.class);
                log.debug("支付结果 {}", notify.toString());
                if (Objects.equals("SUCCESS", notify.getResult_code())) {
                    resultState.setErrcode(0);// 表示成功
                    resultState.setErrmsg(notify.getResult_code());
                    /**** 业务逻辑 保存openid之类的 ****/
                    // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了
                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                            + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
                } else {
                    resultState.setErrcode(-1);// 支付失败
                    resultState.setErrmsg(notify.getErr_code_des());
                    log.debug("支付失败,错误信息:" + notify.getErr_code_des());
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA["
                            + notify.getErr_code_des() + "]]></return_msg>" + "</xml> ";
                }
            } else {
                resultState.setErrcode(-1);// 支付失败
                resultState.setErrmsg("签名验证错误");
                log.debug("签名验证错误");
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[签名验证错误]]></return_msg>" + "</xml> ";
            }
            try (BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream())) {
                out.write(resXml.getBytes());out.flush();
            } catch (Exception e) {
    
                log.error(e.getMessage());
            }
            return resultState;
        }
    }

    可以说这是最简单的支付方式了

    具体源码:https://github.com/philjing/my_wechat/tree/master/src/main/java/com/phil/wechat/pay

    扫一扫加群

    本文为Phil Jing原创文章,未经博主允许不得转载,如有问题请直接回复或者加群。
  • 相关阅读:
    P1121 环状最大两段子段和
    无题
    cdoj 1485 柱爷搞子串 sam treap
    自然数幂和
    Gym 100341C AVL Trees NTT
    线性筛分解质因子
    codeforces 366 Ant Man dp
    UVALive 6914 Maze Mayhem 轮廓线dp
    hdu 5790 Prefix 字典树 主席树
    莫比乌斯反演个人小结
  • 原文地址:https://www.cnblogs.com/phil_jing/p/15615881.html
Copyright © 2011-2022 走看看