Django1.11配合uni-app发起微信支付的实现

Django1.11配合uni-app发起微信支付!

经过三天的断断续续的奋战,我终于是干动了微信支付。为了以后不忘记,现在来一篇教程,来来来,开干!!!

一、准备阶段

1、准备阶段我们需要去微信官网申请一个小程序或者公众号。获得AppID和AppSecret。

2、去微信商户平台 成为商家,开通JSAPI用来获得商户号和自己配置的钥匙。然后再商户平台上面绑定小程序appid。

(点击下面图片进入官方链接!)

在配置里面配置一个自己的key,需要记住后台开发的时候需要!

关联后即可在小程序管理页面开通微信支付!

到此,准备阶段完成!

二、梳理流程

在这里我大概写一下流程:首先我们在前端发起微信登陆,此时微信会给我们返回一个openid,这个openid一定要留存在某一个位置。然后前段发起微信支付,向后端发送数据请求,后端对结合前段的数据向微信方面发送一个请求,请求相关数据,得到相关数据之后把数据发送给前段,前段收到数据,利用微信接口再向微信指定连接发送请求,微信返回请求,即可!这个就是全流程,很多人肯定已经懵了。没事,咱一步一步来,别步子跨大了——扯到蛋了!

以上就是数据处理阶段大概流程!

三、代码实现

0、用户登录根据用户code获取openid

uni.login({
          provider: 'weixin',
          success: function(loginRes) {
            let code = loginRes.code;
            if (!_this.isCanUse) {
              //非第一次授权获取用户信息
              uni.getUserInfo({
                provider: 'weixin',
                success: function(infoRes) {
                        //获取用户信息后向调用信息更新方法
                  _this.nickName = infoRes.userInfo.nickName; //昵称
                  _this.avatarUrl = infoRes.userInfo.avatarUrl; //头像
                    _this.updateUserInfo();//调用更新信息方法
                }
              });
            }

            //2.将用户登录code传递到后台置换用户SessionKey、OpenId等信息
            uni.request({
              url: 'http://127.0.0.1:8000/users/',
              data: {
                code: code,
              },
              method: 'GET',
              header: {
                'content-type': 'application/json'
              },
              success: (res) => {
                console.log(res.data)
                if ( res.data.state== 1001) {
                  console.log("新注册的用户!")
                  _this.OpenId = res.data.openid;
                } else{
                  _this.OpenId = res.data.openid;
                  console.log("注册过的用户!开始设置本地缓存!")
                  console.log(res.data[0].id)
                  if ( res.data[0].id ) {
                    //这里获得登陆状态,然后根据登陆状态来改变用户按钮信息!!!!
                  } else{

                  };
                  _this.user_id = res.data[0].id
                  uni.setStorage({
                    key: 'user',
                    data: res.data,
                    success: function () {
                      console.log('设置缓存成功');
                    }
                  });
                  // _this.gotoshopping()
                  // uni.reLaunch({//信息更新成功后跳转到小程序首页
                  //   url: '/pages/shopping/shopping'
                  // });
                }
                //openId、或SessionKdy存储//隐藏loading
                uni.hideLoading();
              }
            });
          },
        });
if request.GET.get("code"):
      ret = {"state": 1000}
      code = request.GET.get("code")

      url = "https://api.weixin.qq.com/sns/jscode2session"
      appid = "xxxxxxxxxxxxx"
      secret = "xxxxxxxxxxxxxxxxxxxxx"

      # url一定要拼接,不可用传参方式
      url = url + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code"
      import requests
      r = requests.get(url)
      print("======", r.json())
      openid = r.json()['openid']
      user = users.objects.filter(openid=openid).all()
      if not user:
        ret["state"] = 1001
        ret["msg"] = "用户第一次登陆"
        ret["openid"] = openid
        return Response(ret)
      else:
        serializer = self.get_serializer(user, many=True)
        return Response(serializer.data)

1、首先需要创建一个confige.py的配置文件!然后写路由,让前端找到“门”在哪里!

config.py

# 微信支付的配置参数
client_appid = 'xxxxxxxxxxxxxx' # 小程序appid
client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx' # 小程序secret

Mch_id = 'xxxxxxxxxxx' # 商户号
Mch_key = 'xxxxxxxxxxxxxxxxxxx' # 商户Key
order_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder' # 订单地址

url.py

router = routers.DefaultRouter()
router.register("users", views.UsersViewSet)
router.register("goods", views.GoodsViewSet)
router.register("comments", views.CommentsViewSet)
router.register("payOrder", views.OrdersViewSet) #这个就是微信支付的接口

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include(router.urls)),

]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

view.py

class OrdersViewSet(viewsets.ModelViewSet):
  queryset = Order.objects.all()
  serializer_class = OrderModelSerializer

  def create(self, request, *args, **kwargs):
    if request.data.get("user_id"):
      from goods.wxpay.wxpay import payOrder
      data = payOrder(request)
      print(data)
      return Response(data)
    else:
      serializer = self.get_serializer(data=request.data)
      serializer.is_valid(raise_exception=True)
      self.perform_create(serializer)
      headers = self.get_success_headers(serializer.data)
      return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

  def perform_create(self, serializer):
    serializer.save()

  def get_success_headers(self, data):
    try:
      return {'Location': str(data[api_settings.URL_FIELD_NAME])}
    except (TypeError, KeyError):
      return {}

2、然后创建逻辑文件,获取数据请求数据返回数据!

wxpay.py

# -*- coding: utf-8 -*-
from .config import client_appid, client_secret, Mch_id, Mch_key, order_url
import hashlib
import datetime
import xml.etree.ElementTree as ET
import requests
from ..models import users

# 生成签名的函数
def paysign(appid, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee):
  ret = {
    "appid": appid,
    "body": body,
    "mch_id": mch_id,
    "nonce_str": nonce_str,
    "notify_url": notify_url,
    "openid": openid,
    "out_trade_no": out_trade_no,
    "spbill_create_ip": spbill_create_ip,
    "total_fee": total_fee,
    "trade_type": 'JSAPI'
  }
  print(ret)
  # 处理函数,对参数按照key=value的格式,并按照参数名ASCII字典序排序
  stringA = '&'.join(["{0}={1}".format(k, ret.get(k)) for k in sorted(ret)])
  stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key)
  sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()
  print(sign.upper())
  return sign.upper()

# 生成随机字符串
def getNonceStr():
  import random
  data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
  nonce_str = ''.join(random.sample(data, 30))
  return nonce_str

# 生成商品订单号
def getWxPayOrdrID():
  date = datetime.datetime.now()
  # 根据当前系统时间来生成商品订单号。时间精确到微秒
  payOrdrID = date.strftime("%Y%m%d%H%M%S%f")

  return payOrdrID

# 获取全部参数信息,封装成xml
def get_bodyData(openid, client_ip, price):
  body = 'Mytest' # 商品描述
  notify_url = 'https://127.0.0.1:8000/payOrder/' # 支付成功的回调地址 可访问 不带参数
  nonce_str = getNonceStr() # 随机字符串
  out_trade_no = getWxPayOrdrID() # 商户订单号
  total_fee = str(price) # 订单价格 单位是 分

  # 获取签名
  sign = paysign(client_appid, body, Mch_id, nonce_str, notify_url, openid, out_trade_no, client_ip, total_fee)

  bodyData = '<xml>'
  bodyData += '<appid>' + client_appid + '</appid>' # 小程序ID
  bodyData += '<body>' + body + '</body>' # 商品描述
  bodyData += '<mch_id>' + Mch_id + '</mch_id>' # 商户号
  bodyData += '<nonce_str>' + nonce_str + '</nonce_str>' # 随机字符串
  bodyData += '<notify_url>' + notify_url + '</notify_url>' # 支付成功的回调地址
  bodyData += '<openid>' + openid + '</openid>' # 用户标识
  bodyData += '<out_trade_no>' + out_trade_no + '</out_trade_no>' # 商户订单号
  bodyData += '<spbill_create_ip>' + client_ip + '</spbill_create_ip>' # 客户端终端IP
  bodyData += '<total_fee>' + total_fee + '</total_fee>' # 总金额 单位为分
  bodyData += '<trade_type>JSAPI</trade_type>' # 交易类型 小程序取值如下:JSAPI
  bodyData += '<sign>' + sign + '</sign>'
  bodyData += '</xml>'

  return bodyData

def xml_to_dict(xml_data):
  '''
  xml to dict
  :param xml_data:
  :return:
  '''
  xml_dict = {}
  root = ET.fromstring(xml_data)
  for child in root:
    xml_dict[child.tag] = child.text
  return xml_dict

def dict_to_xml(dict_data):
  '''
  dict to xml
  :param dict_data:
  :return:
  '''
  xml = ["<xml>"]
  for k, v in dict_data.iteritems():
    xml.append("<{0}>{1}</{0}>".format(k, v))
  xml.append("</xml>")
  return "".join(xml)

# 获取返回给小程序的paySign
def get_paysign(prepay_id, timeStamp, nonceStr):
  pay_data = {
    'appId': client_appid,
    'nonceStr': nonceStr,
    'package': "prepay_id=" + prepay_id,
    'signType': 'MD5',
    'timeStamp': timeStamp
  }
  stringA = '&'.join(["{0}={1}".format(k, pay_data.get(k)) for k in sorted(pay_data)])
  stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key)
  sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()
  return sign.upper()

# 统一下单支付接口
def payOrder(request):
  import time
  # 获取价格,和用户是谁
  price = request.data.get("price")
  user_id = request.data.get("user_id")

  # 获取客户端ip
  client_ip, port = request.get_host().split(":")

  # 获取小程序openid
  openid = users.objects.get(id=user_id).openid

  # 请求微信的url
  url = order_url

  # 拿到封装好的xml数据
  body_data = get_bodyData(openid, client_ip, price)

  # 获取时间戳
  timeStamp = str(int(time.time()))

  # 请求微信接口下单
  respone = requests.post(url, body_data.encode("utf-8"), headers={'Content-Type': 'application/xml'})

  # 回复数据为xml,将其转为字典
  content = xml_to_dict(respone.content)
  print(content)
  # 返回给调用函数的数据
  ret = {"state": 1000}
  if content["return_code"] == 'SUCCESS':
    # 获取预支付交易会话标识
    prepay_id = content.get("prepay_id")
    # 获取随机字符串
    nonceStr = content.get("nonce_str")

    # 获取paySign签名,这个需要我们根据拿到的prepay_id和nonceStr进行计算签名
    paySign = get_paysign(prepay_id, timeStamp, nonceStr)

    # 封装返回给前端的数据
    data = {"prepay_id": prepay_id, "nonceStr": nonceStr, "paySign": paySign, "timeStamp": timeStamp}
    print('=========',data)

    ret["msg"] = "成功"
    return data

  else:
    ret["state"] = 1001
    ret["msg"] = "失败"
    return ret

3、前段获取后端返回的数据给微信再次发送数据请求!(包含点击的时候往后端发送数据处理请求)

pay(){
        uni.request({
          url: 'http://127.0.0.1:8000/payOrder/',
          method: 'POST',
          header: {
            'content-type': 'application/json'
          },
          data: {
            user_id:this.user_id,
            price:128
          },
          success: res => {
            console.log("success")
            console.log(res.data)

            uni.requestPayment({
            provider: 'wxpay',

            timeStamp: res.data.timeStamp,
            nonceStr: res.data.nonceStr,
            package: 'prepay_id='+String(res.data.prepay_id),
            signType: 'MD5',
            paySign: res.data.paySign,

            success: function (res) {
              console.log('success:' + JSON.stringify(res));
              // 支付成功,给后台发送数据,保存订单

            },
            fail: function (err) {
              console.log('fail:' + JSON.stringify(err));
              // 支付失败,给后台发送数据,保存订单
            }
            });

          },
          fail: (res) => {
            console.log("fail")
            console.log(res)
          },
          complete: () => {}
        });

      }

至此相信大家也就会了。

附上我的目录结构

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • uni-app微信小程序登录并使用vuex存储登录状态的思路详解

    微信小程序注册登录思路 (这是根据自身的项目的思路,不一定每个项目都适用) 1.制作授权登录框,引导用户点击按钮 2.uni.login获取code 3.把code传给后端接口,后端返回如下数据 openid: "ogtVM5RWdfadfasdfadfadV5s" status: 1 // 状态码:status==0(该用户未注册,需调用注册接口) status==1(该用户已注册) 4.判断用户是否注册,并调用用户信息接口 (1)若已注册则提示登录成功,并调用后台给的获取用户信息的

  • uni-app之APP和小程序微信授权方法

    uni-app 介绍 uni-app 是一个使用 Vue.js 开发跨平台应用的前端框架. 适用平台:Android.iOS.微信小程序.实现了一套代码,同时发布到Android.iOS.微信小程序. 参考官方:https://uniapp.dcloud.io/ APP微信授权 检测服务商 检测手机上是否安装微信.QQ.新浪微博等. uni.getProvider({ service: 'oauth', success: function (res) { console.log(res.prov

  • 详解使用uni-app开发微信小程序之登录模块

    从微信小程序官方发布的公告中我们可获知:小程序体验版.开发版调用 wx.getUserInfo 接口,将无法弹出授权询问框,默认调用失败,需使用 <button open-type="getUserInfo"></button> 引导用户主动进行授权操作: 1.当用户未授权过,调用该接口将直接报错 2.当用户授权过,可以使用该接口获取用户信息 但在实际开发中我们可能需要弹出授权询问框,因此需要我们自己来写模拟授权弹框(主要是对<buttonopen-typ

  • 微信小程序自定义tabBar在uni-app的适配详解

    引言:此方法可用作大部分微信小程序支持,但uni-app文档中却找不到相关说明的API 需求 需要在微信小程序中,实现一个中间图标突出显示的异形导航栏. 如下图 实现方法设计 要做这种异形的导航栏,用直接在配置文件里面写list的方法肯定做不到.那么,就有以下两种可替代方法. 在每一个页面都加载一个tabBar组件,与页面同时渲染. 设置自定义tabBar,修改tabBar的样式. 优缺点分析:方法1实现起来略为简单,但是会出现代码可重用率低,降低性能,已经界面跳动等问题.方法2则是微信官方提供

  • uni app仿微信顶部导航条功能

    最近一直在学习uni-app开发,由于uniapp是基于vue.js技术开发的,只要你熟悉vue,基本上很快就能上手了. 在开发中发现uni-app原生导航栏也能实现一些顶部自定义按钮+搜索框,只需在page.json里面做一些配置即可.设置app-plus,配置编译到App平台的特定样式.dcloud平台对app-plus做了详细说明:app-plus配置,需注意 目前暂支持H5.App端,不支持小程序. 在page.json里配置app-plus即可 { "path": "

  • uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能

    最近一直在学习uni-app开发,由于uniapp是基于vue.js技术开发的,只要你熟悉vue,基本上很快就能上手了. 在开发中发现uni-app原生导航栏也能实现一些顶部自定义按钮+搜索框,只需在page.json里面做一些配置即可.设置app-plus,配置编译到App平台的特定样式.dcloud平台对app-plus做了详细说明:app-plus配置,需注意 目前暂支持H5.App端,不支持小程序. 在page.json里配置app-plus即可 { "path": "

  • Django1.11配合uni-app发起微信支付的实现

    Django1.11配合uni-app发起微信支付! 经过三天的断断续续的奋战,我终于是干动了微信支付.为了以后不忘记,现在来一篇教程,来来来,开干!!! 一.准备阶段 1.准备阶段我们需要去微信官网申请一个小程序或者公众号.获得AppID和AppSecret. 2.去微信商户平台 成为商家,开通JSAPI用来获得商户号和自己配置的钥匙.然后再商户平台上面绑定小程序appid. (点击下面图片进入官方链接!) 在配置里面配置一个自己的key,需要记住后台开发的时候需要! 关联后即可在小程序管理页

  • PHP开发APP端微信支付功能

    用PHP开发APP端微信支付的一点个人心得 最近因为公司需求,要开发APP端上的微信支付,看了微信文档,感觉还不错,没有遇到太大的坑,需要注意的点不算太多. 写一个记事文档,作为备忘录. APP支付流程 从上面的图片中,可以看出来,需要注意的流程是一共是3部分: 第一部分:调用下单API,返回预支付订单,签名之后再返回信息(4.5.6.7) 第二部分:异步通知(15.16) 第三部分:最后的判断支付结果 最需要注意的就是第一部分:调用下单API,返回预支付订单,签名之后再返回信息 微信文档中有详

  • PHP实现 APP端微信支付功能

    前面已经写了手机APP支付宝支付,今天再把手机APP微信支付补上,前期的准备工作在这里就不多说了,可以参考微信支付开发文档,一定要仔细阅读开发文档,可以让你少踩点坑:准备工作完成后就是配置参数,调用统一下单接口,支付后异步回调三部曲啦: 1.我封装好的一个支付类文件,多余的东西都去除掉了,并且把配置参数放到了这个支付类中,只需要修改Weixinpayandroid方法内的几个参数就可以直接复制使用: class Wxpayandroid { //参数配置 public $config = arr

  • Android App支付系列(一):微信支付接入详细指南(附官方支付demo)

    写在前面 一家移动互联网公司,说到底,要盈利总是需要付费用户的,自己开发支付系统显然是不明智的,国内已经有多家成熟的移动支付提供商,腾讯就是其中之一.梳理了下微信支付的接入,今天给大家分享下腾讯旗下的微信支付SDK的接入流程. 接入流程 1.申请开发者资质 地址:https://open.weixin.qq.com/ 使用公司管理者/高层帐号登录微信开放平台,进入"账号中心",进行开发者资质认证,需要填写公司资料,包括但不限于,公司注册号,公司营业执照,公司对外办公电话,公司对公银行卡

  • 微信支付开发IOS图文教程案例

    前言:下面介绍微信支付的开发流程的细节,图文并茂,你可以按照我的随笔流程过一遍代码.包你也学会了微信支付.而且支付也是面试常问的内容. 正文: 1.首先在开始使用微信支付之前,有一些东西是开发者必须要知道的,打开下面链接: https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=3_1 然后可以看到下面的页面,这个就是微信支付商户平台的开发文档,很多东西是可以查阅和了解的,在开发使用微信SDK支付功能的时候,遇到了问题也可以到这找找相关须知信

  • 微信小程序-详解微信登陆、微信支付、模板消息

    微信公众平台近日悄然开始内测微信小程序(微信公众号)功能,引来无数开发者和普通用户关注,微信支付的能力,是随着小程序的发布一并推出的,具有介绍如下: wx.login(OBJECT) 调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key).用户数据的加解密通讯需要依赖会话密钥完成. OBJECT参数说明: success返回参数说明: 示例代码: //app.js App({ onLaunch: functio

  • Android实现微信支付功能详解

    1.集成微信支付SDK: 在build.gradle中,添加如下依赖 compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+' 2.设置微信支付回调页面: 路径:项目包名.wxapi 名称:WXPayEntryActivity public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI api; @

  • springboot对接微信支付的完整流程(附前后端代码)

    展示图: 对接的完整流程如下 首先是配置 gzh.appid=公众号appid wxPay.mchId=商户号 wxPay.key=支付密钥 wxPay.notifyUrl=域名回调地址 常量: /**微信支付统一下单接口*/ public static final String unifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; public static String SUCCESSxml = &q

  • 微信小程序调用微信支付接口的实现方法

    前言:应项目要求,需要使用微信小程序做支付,写完后告知手续费太高方案不予通过(宝宝心里苦,但宝宝不说).此次开发在因站在巨人的肩膀上顺利完成. 微信支付文档传送门:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3 1.开发工具: Eclipse+Tomcat+微信web开发工具 2.开发环境: java+maven 3.开发前准备: 3.1 所需材料 小程序的appid,APPsecret,支付商户号(mch_i

随机推荐