python

超轻量级php框架startmvc

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

更新时间:2020-08-02 20:42:01 作者:startmvc
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: () => {}
 });
 
 
 }

至此相信大家也就会了。

附上我的目录结构

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

Django uni-app 微信支付