zoukankan      html  css  js  c++  java
  • wx三方支付+二维码生成

    代码实例

    • 前言

    主要介绍了微信小程序内部支付的流程,然而实际上微信小程序有一定的局限性,也就是用户范围仅限于小程序内部生态圈,在生活中真正具有广泛性、高效性、使用方便性的支付方式还得是扫码支付,扫码的优点在于推广成本低,上至钓鱼台国宾馆,下至发廊地摊都能用,打印出来就完事了,而相比其他支付方式,现金的找零及假钞问题,信用卡的办理门槛、pos机的沉没成本,就算微信可集成的h5支付和小程序支付,奈何很多老年人根本不会用小程序和手机浏览器,更别说再进行支付操作了,所以基于二维码的扫码支付的确是非常符合国情的。本次我们使用前后端分离项目Vue.js+Django来集成微信的扫码支付功能,体验一下21世纪泛用性最高的支付方式。

    1 相关操作

    1.1 注册微信公众平台

    https://mp.weixin.qq.com
    
    1.1.1 获得开发者id和秘钥
    • appid & appsecret

    1.1.2 获取微信支付接口的权限

    1.2 注册微信支付商户平台

    https://pay.weixin.qq.com/
    
    1.2.1 获取微信支付的商户号
    • 在账户信息页面

    1.3 获取微信支付接口的秘钥

    • 账户中心->api安全

    1.4 配置支付域名

    • 产品中心->开发配置页面

    1.5 相关注意事项

    1.5.1 域名

    这里不像微信小程序,小程序只能允许https协议接口,而扫码支付域名既支持https也支持http,非常方便,同时注意域名必须是一个备案域名。

    1.5.2 微信接口使用xml

    qrcode模块用来生成二维码,bs4模块用来将微信接口返回的xml解析成json,在21世纪的第二十个年头,微信接口居然还在使用原始的xml,这种反人类行为实在不能理解。

    2 业务流程说明

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

    3 Django

    3.1 需要安装的包

    pip install lxml
    pip install qrcode
    

    3.2 utils.py

    import json
    
    import qrcode
    import requests
    from django.http import HttpResponse, HttpResponseRedirect
    
    import random
    import time
    import hashlib
    
    from bs4 import BeautifulSoup
    
    def trans_xml_to_dict(data_xml):
        soup = BeautifulSoup(data_xml, features='xml')
        xml = soup.find('xml')  # 解析XML
        if not xml:
            return {}
        data_dict = dict([(item.name, item.text) for item in xml.find_all()])
        return data_dict
    
    def trans_dict_to_xml(data_dict):  # 定义字典转XML的函数
        data_xml = []
        for k in sorted(data_dict.keys()):  # 遍历字典排序后的key
            v = data_dict.get(k)  # 取出字典中key对应的value
            if k == 'detail' and not v.startswith('<![CDATA['):  # 添加XML标记
                v = '<![CDATA[{}]]>'.format(v)
            data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
        return '<xml>{}</xml>'.format(''.join(data_xml))  # 返回XML
    
    def get_sign(data_dict, key):  # 签名函数,参数为签名的数据和密钥
        params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=False)  # 参数字典倒排序为列表
        params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key
        # 组织参数字符串并在末尾添加商户交易密钥
        md5 = hashlib.md5()  # 使用MD5加密模式
        md5.update(params_str.encode())  # 将参数字符串传入
        sign = md5.hexdigest().upper()  # 完成加密并转为大写
        return sign
    
    
    def wx_pay(request):
        url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'  # 微信扫码支付接口
        key = '945bec9df3614cffb74e39aba8fbf7d7'  #
        total_fee = 1 #支付金额,单位分
        body = '123456'  # 商品描述
        out_trade_no = 'order_%s' % random.randrange(100000, 999999)  # 订单编号
        params = {
            'appid': 'wx092344a76b9979ff',  # APPID
            'mch_id': '1602932608',  # 商户号
            'notify_url': 'http://wxpay.v3u.cn/wx_back/',  # 回调地址
            'product_id': 'goods_%s' % random.randrange(100000, 999999),  # 商品编号
            'trade_type': 'NATIVE',  # 支付类型(扫码支付)
            'spbill_create_ip': '114.254.176.137',  # 发送请求服务器的IP地址
            'total_fee': total_fee,  # 订单总金额
            'out_trade_no': out_trade_no,  # 订单编号
            'body': body,  # 商品描述
            'nonce_str': 'ibuaiVcKdpRxkhJA'  # 字符串
        }
        sign = get_sign(params, key)  # 获取签名
        params.setdefault('sign', sign)  # 添加签名到参数字典
        xml = trans_dict_to_xml(params)  # 转换字典为XML
        response = requests.request('post', url, data=xml)  # 以POST方式向微信公众平台服务器发起请求
        data_dict = trans_xml_to_dict(response.content)  # 将请求返回的数据转为字典
        print(data_dict)
        qrcode_name = out_trade_no + '.png'  # 支付二维码图片保存路径
        if data_dict.get('return_code') == 'SUCCESS':  # 如果请求成功
            img = qrcode.make(data_dict.get('code_url'))  # 创建支付二维码片
            img.save('./static/upload/' + qrcode_name)  # 保存支付二维码,自己的地址,upload自己创建的
        return HttpResponse(json.dumps({'img':qrcode_name}))
    

    3.3 urls.py

    from django.urls import path, re_path
    from eventlet import serve
    
    from walletapp.utils import payment, payment_execute, wx_pay
    
    urlpatterns = [
        path('paypal/', payment),            # 支付地址
        path('execute/', payment_execute),   # 回调
        # path('refund/', payment_execute),   # 退款
        path('wx_pay/', wx_pay),             # wx支付
        re_path('^static/upload/(?P<path>.*)$', serve, {'document_root':'/static/upload/'}),
    ]
    

    4 Vue端

    4.1 payFor.vue

    <template>
        <div>
            <h1>wx</h1>
            <div>
                <a-form-item v-bind="formItemLayout" label="金额" style="200px;margin-left:650px">
                    <a-input v-model="money"/>
                </a-form-item>
        
       
                <a-form-item v-bind="tailFormItemLayout">
                    <a-button type="primary" html-type="submit" @click="submit">
                        生成二维码
                    </a-button>
                </a-form-item>
    
    
                <a-form-item v-bind="formItemLayout" label="二维码">
        
                    <img :src="src" />
    
                </a-form-item>
            </div>
        </div>
    </template>
    
    <script>
    import axios from 'axios'
    export default {
        data() {
            return {
                money:"1",
                src:"",
                formItemLayout: {
                    labelCol: {
                    xs: { span: 24 },
                    sm: { span: 8 },
                    },
                    wrapperCol: {
                    xs: { span: 24 },
                    sm: { span: 16 },
                    },
                },
                tailFormItemLayout: {
                    wrapperCol: {
                    xs: {
                        span: 24,
                        offset: 0,
                    },
                    sm: {
                        span: 16,
                        offset: 8,
                    },
                    },
                },
                dataSource: [
                        {
                        key: '0',
                        name: 'Edward King 0',
                        age: '32',
                        address: 'London, Park Lane no. 0',
                        },
                        {
                        key: '1',
                        name: 'Edward King 1',
                        age: '32',
                        address: 'London, Park Lane no. 1',
                        },
                    ],
                columns: [
                        {
                        title: 'name',
                        dataIndex: 'name',
                        },
                        {
                        title: 'age',
                        dataIndex: 'age',
                        },
                        {
                        title: 'address',
                        dataIndex: 'address',
                        },
                        {
                        title: 'operation',
                        dataIndex: 'operation',
                        scopedSlots: { customRender: 'operation' },
                        },
                    ],
                }
        },
        methods: {
                    submit:function(){
    
                        axios.get('http://127.0.0.1:1594/wallet/wx_pay/').then((result) =>{
    
                        console.log(result.data.img);
    
                        this.src = "http://127.0.0.1:1594/static/upload/"+result.data.img
    
                        })
                    },
                    onDelete(key) {
                        console.log(this.dataSource[key]);
                    }
        },
        created() {
    
        }
    }
    </script>
    
    <style scoped>
    
    </style>
    
    
  • 相关阅读:
    第四次作业—— 分析比较各种软件构建环境
    如何实现点击事件触发之后刷新还保存原值
    简单理解js闭包
    javascript中 __proto__与prorotype的理解
    原生和jQuery的ajax用法
    getElementById和querySelector方法的区别
    关于javascript闭包理解
    第二篇 进销存管理系统冲刺博客
    个人项目:WC
    自我介绍+软工五问
  • 原文地址:https://www.cnblogs.com/mapel1594184/p/14199875.html
Copyright © 2011-2022 走看看