• 微信小程序支付实现流程


    基本流程

    用户操作流程

    image

    小程序流程

    image

    整体支付流程

    image

    代码实现

    创建订单

    创建订单,主要是前端将订单的信息提交到后端。但是在创建订单之前还有一些准备工作要做:

    1. 获取用户数据GetUserInfo
    2. 获取用户授权,获得token
    3. 创建订单

    使用buttongetUserInfo 获得的用户信息,再使用wx.login(Object object)得到code(用户登录凭证),session_key,获得后就可以在后台下发token用以对用户操作进行验证。

    登录流程时序:
    image

    bindGetUserInfo的回调方法返回的参数示例:

    encryptedData: "NC9d+PEDLe6SPdjskdlfjslkjdfsljflksdjfklsdjfsdqwqz"
    errMsg: "getUserInfo:ok"
    iv: "2fNiyg133zyP5X9hOHS6Og=="
    rawData: "{"nickName":"1024","gender":1,"language":"zh_CN","city":"","province":"","country":"Croatia","avatarUrl":"https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIradvotK0Q7XAK7bs06ZZidHLxdlscmaZZXwQrr5S7hhNS98CB2p4kL5nWuohlQel1vm2X2kFygozA/112"}"
    signature: "d4d9c2cff76bd348f1d9125216b53c7493e11da4"
    
    const { encryptedData, rawData, iv, signature } = e.detail;
    const { code } = await login();
    const loginParams = { encryptedData, rawData, iv, signature, code };
    
    // 将小程序端拿到的用户信息提交到后端
    // 后端调用微信的auth.code2Session接口
    // 就能获得openid,session_key,unionid等内容
    // 用以预付单的创建,及安全验证
    const {token} = await request({ url: "/users/wxlogin", data: loginParams, method: "post" });
    

    获取token后将其添加在请求头的Authorization字段中。然后发送请求,后端程序将订单内容保存,然后将进行预支付。

    // orderParams 中是订单商品信息
    const header = { Authorization: token }
    const { order_number } = await request({ url: "order/submit", method: "POST", data: orderParams, header})
    

    wx.login()
    auth.code2Session

    预支付

    此时小程序端将订单编号发送给后端预支付接口,然后接口将会返回必要的支付参数。

    // 发起预支付接口 添加content-type才能成功
    const { pay } = await request({ url: "/my/orders/req_unifiedorder", method: "POST", data: { order_number }, header: { "content-type": "application/x-www-form-urlencoded" } });
    

    此时后端服务器,会先判断订单是否是待支付的状态,若是则需要将以下参数提交到
    image
    统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
    参数说明:接口参数说明
    请求微信下单接口成功后,则会返回prepay_id,可以进行封装后,返回后续支付要的参数。

    java随机数生成:

    // 获取随机字符
    public static String getRandomNum(Integer num) {
            String base = "0123456789";
            Random random = new Random();
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < num; i++) {
                int number = random.nextInt(base.length());
                sb.append(base.charAt(number));
            }
            return sb.toString();
        }
    
    String randomStr = getRandomNum(18).toUpperCase();
    

    签名生成的通用步骤如下:

    第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

    特别注意以下重要规则:

    ◆ 参数名ASCII码从小到大排序(字典序);
    ◆ 如果参数的值为空不参与签名;
    ◆ 参数名区分大小写;
    ◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
    ◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
    第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。 注意:密钥的长度为32个字节。

    ◆ key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

    Java签名工具类:

    public static String arraySign(Map < Object, Object > params, String paySignKey)
    {
        boolean encode = false;
        Set < Object > keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for(Object key: keys)
        {
            if(first)
            {
                first = false;
            }
            else
            {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if(null != value)
            {
                valueString = value.toString();
            }
            if(encode)
            {
                try
                {
                    temp.append(URLEncoder.encode(valueString, "UTF-8"));
                }
                catch(UnsupportedEncodingException e)
                {
                    e.printStackTrace();
                }
            }
            else
            {
                temp.append(valueString);
            }
        }
        temp.append("&key=");
        temp.append(paySignKey);
        System.out.println(temp.toString());
        String packageSign = MD5.getMessageDigest(temp.toString());
        return packageSign;
    }
    String sign = arraySign(parame, "商户key");
    

    发起支付

    使用wx.requestPayment(OBJECT)发起支付

    // 发起微信支付
    wx.requestPayment(pay)
    

    需要参数如下,在请求预支付接口后由服务端返回:
    image

    查询订单

    请求后端的查询接口,进行查询:

    // 查询订单状态
    const res = await request({ url: "/my/orders/chkOrder", method: "POST", data: { order_number } });
    

    微同商城支付逻辑分析

    image

    参考和补充

    1. 微信支付开发文档
    2. 微同商城Gitee
    3. 微信小程序登录换取token
    4. 微信小程序登录 + 基于token的身份验证
  • 相关阅读:
    (拿来主义) SpringCloud | 第四篇: 断路器(Hystrix)
    (拿来主义) SpringCloud | 第三篇: 服务消费者(Feign)
    (拿来主义) SpringCloud | 第二篇: 服务消费者(rest+ribbon)
    (拿来主义) SpringCloud | 第一篇: 服务的注册与发现(Eureka)
    (拿来主义-10) Spring Boot中使用Swagger2构建强大的RESTful API文档(五)
    (拿来主义-9) Spring Boot构建RESTful API与单元测试(四)
    (拿来主义-8) Spring Boot属性配置文件详解(三)
    (拿来主义-7) Spring Boot工程结构推荐(二)
    springMVC配置文件路径问题
    实现可用的插件系统
  • 原文地址:https://www.cnblogs.com/flytree/p/14772303.html
Copyright © 2020-2023  润新知