• 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原创文章,未经博主允许不得转载,如有问题请直接回复或者加群。
  • 相关阅读:
    精妙Sql语句
    TSQL是否有循环语句?类似C语言的for?如何查看有哪些用户连接到服务器上?如何强制其退出?
    Tools1.4
    Set Up1.2
    Getting Started1.0
    Start Developing iOS Apps Today1.1
    Language1.5
    Jump Right In1.3
    编译器错误信息: CS0246: 找不到类型或命名空间名称“Discuz”(是否缺少 using 指令或程序集引用?)
    ashx文件无法访问
  • 原文地址:https://www.cnblogs.com/phil_jing/p/15615881.html
Copyright © 2020-2023  润新知