调用微信支付api实现用户扫描二维码支付订单

1 开发流程

微信支付开发流程

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。

(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;

(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。

(4)商户后台系统根据返回的code_url生成二维码。

(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。

(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。

(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。

(8)微信支付系统根据用户授权完成支付交易。

(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。

(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。

(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。

(12)商户确认订单已支付后给用户发货。

下载微信SDK

微信没有提供maven仓库坐标,因此我们必须下载使用

微信SDK下载,点击下载java对应的SDK,然后安装到maven的本地仓库中。
进入下载好的SDK的项目目录,然后打开黑窗口,输入命令:

mvn source:jar install -Dmaven.test.skip=true

在pom.xml中引入

<dependency> 
	<groupId>com.github.wxpay</groupId> 
	<artifactId>wxpay-sdk</artifactId>
 	<version>3.0.9</version> 
</dependency>

WXPay工具

微信SDK提供了一个统一的微信支付工具类:WXPay:
在这里插入图片描述
com.github.wxpay.sdk.WXPay类下提供了对应的方法:
在这里插入图片描述

生成支付链接

根据微信提供的WXPay类编写了一个支付工具类PayUtils

import com.github.wxpay.sdk.PayConfig;
import com.github.wxpay.sdk.WXPay;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付工具类
 */
public class PayUtils {

    private static WXPay wxPay;

    // 支付成功回调地址
    private static String notifyUrl = "http://xxx.com/test/PayNotify";

    // 初始化微信支付
    static {
        try {
            PayConfig payConfig = new PayConfig();
            payConfig.setAppID("wxXXXX"); // 公众账号ID
            payConfig.setMchID("XXXXX");// 商户号
            payConfig.setKey("XXXXXX");// 生成签名的密钥
            wxPay = new WXPay(payConfig);
        } catch (Exception e) {
            // e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    // 生成微信订单支付 url
    public static String createOrder(String orderId, Integer totalPay) {
        Map<String, String> data = new HashMap<>();
        // 商品描述
        data.put("body", "商品支付");
        // 订单号
        data.put("out_trade_no", orderId);
        //金额,单位是分
        data.put("total_fee", totalPay.toString());
        //调用微信支付的终端IP
        data.put("spbill_create_ip", "127.0.0.1");
        //回调地址
        data.put("notify_url", notifyUrl);
        // 支付有效时间10分钟
        Date now = new Date();
        Date now_10 = new Date(now.getTime() + 600000); //10分钟后的时间
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//可以方便地修改日期格式
        String nowTime_10 = dateFormat.format(now_10);
        data.put("time_expire", nowTime_10);
        // 交易类型为扫码支付
        data.put("trade_type", "NATIVE");

        // 利用wxPay工具,完成下单
        Map<String, String> result = null;
        try {
            result = wxPay.unifiedOrder(data);
        } catch (Exception e) {
            throw new RuntimeException("微信下单失败", e);
        }
        // 校验业务状态
        checkResultCode(result);

        // 下单成功,获取支付链接
        String url = result.get("code_url");
        if (StringUtils.isBlank(url)) {
            throw new RuntimeException("微信下单失败,支付链接为空");
        }
        return url;
    }

    // 检查业务状态
    public static void checkResultCode(Map<String, String> result) {
        String resultCode = result.get("result_code");
        if ("FAIL".equals(resultCode)) {
            throw new RuntimeException("【微信支付】微信支付业务失败");
        }
    }
}

下单并生成支付链接

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("createOrder")
    public String createOrder() throws Exception {
        String orderId = UUID.randomUUID().toString();
        orderId = orderId.substring(orderId.length()-33,orderId.length()-1);
        Integer totalPay = 1;
        String payUrl = PayUtils.createOrder(orderId, totalPay);
        return payUrl;
    }
}

前端通过调用这个节课就可以生成一个微信支付的订单链接,
然后使用qrcode.js生成一个微信支付的二维码.

pay.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../img/asset-favico.ico">
    <title>支付页面</title>
    <script src="../plugins/vue/vue.js"></script>
    <script src="../plugins/vue/axios-0.18.0.js"></script>
    <script src="../js/qrious.js"></script>
    <script src="../js/qrcode.js"></script>
    <!--<script>
        var id = getUrlParam("id");
    </script>-->
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div id="app" class="app">
    <!-- 页面内容 -->
    <center><h1>请扫描下方二维码进行支付!</h1></center>
    <hr>
    <div class="contentBox" style="width: 100%">
        <!--<img alt="" id="qrcode" style="height: 50%;width: 50%;">-->
        <img alt="" id="qrious" style="height: 30%;width: 30%;display: block;margin:0 auto;">
    </div>
</div>
</body>
<script>
    var vue = new Vue({
        el: '#app',
        data: {
            payUrl: ''
        },
        created() {
            // alert(id);
            axios.get('/test/createOrder').then(res => {
                if (res.status === 200) {
                    // alert("111")
                    console.log(res)
                    this.payUrl = res.data;
                    // 生成二维码
                    // new QRCode(document.getElementById("qrcode"), this.payUrl)
                    new QRious({
                        element: document.getElementById('qrious'),
                        level: 'L',
                        // 注意级别越高可能会影响到识别度
                        size: 300,
                        value: this.payUrl
                    })
                }
            })
        }
    });
</script>
<script>
    // 生成二维码
    new QRious({
        element: document.getElementById('qrious'),
        level: 'L',
        // 注意级别越高可能会影响到识别度
        size: 300,
        value: '${payUrl}'
    })
</script>
</html>

支付结果通知

http://localhost:8080/test/PayNotify这个地址是在支付成功后的异步结果通知。官网介绍如下:
支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。
所以,此处的地址必须是一个外网可访问地址,而且我们要定义好回调的处理接口。

内网穿透

此处我们肯定不能写:http://localhost:8080/travel/pay/notify,这个域名是本地,是不被外网识别的。可以通过内网穿透来实现。

内网穿透的目的是:让外网能访问你本地的应用,例如在外网打开你本地http://127.0.0.1指向的Web站点。

使用natapp实现内网穿透

使用的natapp得到的域名,设置指向到 PayUtils工具类的支付成功回调地址。
在这里插入图片描述

支付结果通知API

支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。
对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)
注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
特别提醒:商户系统对于支付结果通知的内容一定要做 签名验证,并校验返回的订单金额是否与商户侧的订单金额一致 ,防止数据泄漏导致出现“假通知”,造成资金损失。

支付完成后,微信服务会自动向 http://localhost:8080/test/PayNotify 地址发起POST请求,请求参数是xml格式:

在这里插入图片描述
通信成功,会返回下面信息:
在这里插入图片描述
编写回调api: /test/PayNotify

@PostMapping("PayNotify")
    public void PayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

// 1.接收请求参数(xml)
        ServletInputStream in = request.getInputStream();
        // 2.将xml转为java对象
        XmlMapper xmlMapper = new XmlMapper();
        Map param = xmlMapper.readValue(in, Map.class);
        // 3.调用orderService,修改订单状态
//        orderService.updateState(param);
        // 4.返回微信平台,接收成功..
        HashMap<String, String> result = new HashMap<>();
        result.put("return_code", "SUCCESS");
        result.put("return_msg", "OK");
        // 将map转为xml
        String xml = xmlMapper.writeValueAsString(result);
        response.setContentType("application/xml;charset=utf-8");
        response.getWriter().write(xml);



//        return "yyy";
    }

支付状态查询

当用户扫码支付成功,会自动调用回调接口,从而修改订单状态,完成订单支付。
可以在 /test/PayNotify 的第三步修改用户支付的该订单的支付状态pay_status为已支付;然后在页面的payOrder() 支付成功后调用this.isPay(),会采用定时任务,不断查询订单支付的状态:

<script>
    var vue = new Vue({
        el: '#app',
        data: {
            payUrl: '',
            orderNo: ''
        },
        methods: {
            payOrder() {
                axios.get('/order/createPayOrder/' + this.orderNo).then(res => {
                    if (res.status === 200) {
                        // alert("111")
                        console.log(res)
                        this.payUrl = res.data.data;
                        // 生成二维码
                        // new QRCode(document.getElementById("qrcode"), this.payUrl)
                        new QRious({
                            element: document.getElementById('qrious'),
                            level: 'L',
                            // 注意级别越高可能会影响到识别度
                            size: 300,
                            value: this.payUrl
                        });
                        this.isPay()
                    }
                })
            },
            isPay() {
                // 开启定时任务,查询付款状态
                let num = setInterval(function () {
                    // let url = '/order/isPay/'+this.orderNo;
                    axios.get('/order/isPay/' + this.orderNo).then(res => {
                        console.log(res.data)
                        if (res.data.flag && res.data.data === '1') {
                            alert("支付成功")
                            window.location.href = "/pages/pay-success.html";
                        }
                    })
                }, 5000);
                // 同时设置一个定时任务,10分钟后,终止查询,认为付款失败
                setTimeout(function () {
                    clearInterval(num);
                    alert("支付失败")
                    window.location.href = "/pages/pay-fail.html";
                }, 600000)

            }
        },
        created() {
            // alert(orderNo);
            this.orderNo = orderNo;
            this.payOrder()
        }
    });
</script>

每隔5秒就会查询一次,为了防止用户一直不支付的情况,又设置了一个定时任务,10分钟后跳转到支付失败页面

@GetMapping("/isPay/{orderNo}")
    public Result isPay(@PathVariable("orderNo") String orderNo){

        String isPay = orderService.isPay(orderNo);
        return new Result(true,"",isPay);
    }
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生成微信支付二维码可以通过以下步骤: 1. 调用微信支付接口生成预支付订单,获取到预支付订单号。可以通过微信支付官方提供的API实现这一步骤。 2. 将预支付订单号作为参数,调用微信支付接口生成支付二维码,获取到支付二维码的url。可以使用微信支付官方提供的“统一下单接口”来实现这一步骤。 3. 在后端将支付二维码的url返回给前端,前端展示二维码供用户扫描。 以下是生成微信支付二维码的代码示例(使用Node.js): ```javascript const request = require('request'); const crypto = require('crypto'); const querystring = require('querystring'); // 微信支付API密钥,需要在微信商户平台设置 const key = 'your_wechat_pay_api_key'; // 微信支付统一下单接口URL const unifiedOrderUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; function generateUnifiedOrder(params) { // 按照微信支付要求对参数进行签名 const signParams = Object.assign({}, params, {key}); const signString = querystring.stringify(signParams); const hash = crypto.createHash('md5'); const sign = hash.update(signString, 'utf8').digest('hex').toUpperCase(); // 组装请求参数 const requestData = Object.assign({}, params, {sign}); // 发送请求 request({ url: unifiedOrderUrl, method: 'POST', body: requestData, json: true }, function(err, response, body) { if (err) { console.error(err); return; } // 解析响应数据 const { return_code, result_code, code_url } = body; if (return_code === 'SUCCESS' && result_code === 'SUCCESS') { // 支付二维码URL const qrCodeUrl = code_url; console.log(qrCodeUrl); } else { console.error('生成支付二维码失败'); } }); } // 调用生成支付二维码函数,传入必要的参数 generateUnifiedOrder({ appid: 'your_wechat_appid', mch_id: 'your_wechat_mch_id', nonce_str: Math.random().toString(36).substr(2, 15), body: '商品描述', out_trade_no: '订单号', total_fee: 1, // 单位为分 spbill_create_ip: '用户IP地址', notify_url: '支付结果通知地址', trade_type: 'NATIVE' // 生成扫码支付二维码 }); ``` 以上代码演示了如何调用微信支付API生成支付二维码。需要注意的是,这里只是演示了生成支付二维码的过程,具体实现还需要根据实际情况进行调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值