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


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

經過三天的斷斷續續的奮戰,我終於是干動了微信支付。為了以后不忘記,現在來一篇教程,來來來,開干!!!

開啟探索之門

1、准備階段我們需要去微信官網申請一個小程序或者公眾號。獲得AppID和AppSecret。

2、去微信商戶平台 成為商家,開通JSAPI用來獲得商戶號和自己配置的鑰匙。然后再商戶平台上面綁定小程序appid。

(點擊下面圖片進入官方鏈接!)

在配置里面配置一個自己的key,需要記住后台開發的時候需要!

關聯后即可在小程序管理頁面開通微信支付!

到此,准備階段完成!

 

在這里我大概寫一下流程:首先我們在前端發起微信登陸,此時微信會給我們返回一個openid,這個openid一定要留存在某一個位置。然后前段發起微信支付,向后端發送數據請求,后端對結合前段的數據向微信方面發送一個請求,請求相關數據,得到相關數據之后把數據發送給前段,前段收到數據,利用微信接口再向微信指定連接發送請求,微信返回請求,即可!這個就是全流程,很多人肯定已經懵了。沒事,咱一步一步來,別步子跨大了——扯到蛋了!

以上就是數據處理階段大概流程!

0、用戶登錄根據用戶code獲取openid

 1 uni.login({
 2                     provider: 'weixin',
 3                     success: function(loginRes) {
 4                         let code = loginRes.code;
 5                         if (!_this.isCanUse) {
 6                             //非第一次授權獲取用戶信息
 7                             uni.getUserInfo({
 8                                 provider: 'weixin',
 9                                 success: function(infoRes) { 
10                           //獲取用戶信息后向調用信息更新方法
11                                     _this.nickName = infoRes.userInfo.nickName; //昵稱
12                                     _this.avatarUrl = infoRes.userInfo.avatarUrl; //頭像
13                                         _this.updateUserInfo();//調用更新信息方法
14                                 }
15                             });
16                         }
17             
18                         //2.將用戶登錄code傳遞到后台置換用戶SessionKey、OpenId等信息
19                         uni.request({
20                             url: 'http://127.0.0.1:8000/users/',
21                             data: {
22                                 code: code,
23                             },
24                             method: 'GET',
25                             header: {
26                                 'content-type': 'application/json' 
27                             },
28                             success: (res) => {
29                                 console.log(res.data)
30                                 if ( res.data.state== 1001) {
31                                     console.log("新注冊的用戶!")
32                                     _this.OpenId = res.data.openid;
33                                 } else{
34                                     _this.OpenId = res.data.openid;
35                                     console.log("注冊過的用戶!開始設置本地緩存!")
36                                     console.log(res.data[0].id)
37                                     if ( res.data[0].id ) {
38                                         //這里獲得登陸狀態,然后根據登陸狀態來改變用戶按鈕信息!!!!
39                                     } else{
40                                         
41                                     };
42                                     _this.user_id = res.data[0].id
43                                     uni.setStorage({
44                                         key: 'user',
45                                         data: res.data,
46                                         success: function () {
47                                             console.log('設置緩存成功');
48                                         }
49                                     });
50                                     // _this.gotoshopping()
51                                     // uni.reLaunch({//信息更新成功后跳轉到小程序首頁
52                                     //     url: '/pages/shopping/shopping'
53                                     // });
54                                 }
55                                 //openId、或SessionKdy存儲//隱藏loading
56                                 uni.hideLoading();
57                             }
58                         });
59                     },
60                 });
uni.login部分代碼
 1         if request.GET.get("code"):
 2             ret = {"state": 1000}
 3             code = request.GET.get("code")
 4 
 5             url = "https://api.weixin.qq.com/sns/jscode2session"
 6             appid = "xxxxxxxxxxxxx"
 7             secret = "xxxxxxxxxxxxxxxxxxxxx"
 8 
 9             # url一定要拼接,不可用傳參方式
10             url = url + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code"
11             import requests
12             r = requests.get(url)
13             print("======", r.json())
14             openid = r.json()['openid']
15             user = users.objects.filter(openid=openid).all()
16             if not user:
17                 ret["state"] = 1001
18                 ret["msg"] = "用戶第一次登陸"
19                 ret["openid"] = openid
20                 return Response(ret)
21             else:
22                 serializer = self.get_serializer(user, many=True)
23                 return Response(serializer.data)
后端處理登陸

1、首先需要創建一個confige.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'  # 訂單地址
config.py
 1 router = routers.DefaultRouter()
 2 router.register("users", views.UsersViewSet)
 3 router.register("goods", views.GoodsViewSet)
 4 router.register("comments", views.CommentsViewSet)
 5 router.register("payOrder", views.OrdersViewSet) #這個就是微信支付的接口
 6 
 7 
 8 urlpatterns = [
 9     url(r'^admin/', admin.site.urls),
10     url(r'', include(router.urls)),
11 
12 ]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
13 urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
url.py
 1 class OrdersViewSet(viewsets.ModelViewSet):
 2     queryset = Order.objects.all()
 3     serializer_class = OrderModelSerializer
 4 
 5     def create(self, request, *args, **kwargs):
 6         if request.data.get("user_id"):
 7             from goods.wxpay.wxpay import payOrder
 8             data = payOrder(request)
 9             print(data)
10             return Response(data)
11         else:
12             serializer = self.get_serializer(data=request.data)
13             serializer.is_valid(raise_exception=True)
14             self.perform_create(serializer)
15             headers = self.get_success_headers(serializer.data)
16             return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
17 
18     def perform_create(self, serializer):
19         serializer.save()
20 
21     def get_success_headers(self, data):
22         try:
23             return {'Location': str(data[api_settings.URL_FIELD_NAME])}
24         except (TypeError, KeyError):
25             return {}
view.py

2、然后創建邏輯文件,獲取數據請求數據返回數據!

# -*- 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
wxpay.py

3、前段獲取后端返回的數據給微信再次發送數據請求!(包含點擊的時候往后端發送數據處理請求)

 1 pay(){
 2                 uni.request({
 3                     url: 'http://127.0.0.1:8000/payOrder/',
 4                     method: 'POST',
 5                     header: {
 6                         'content-type': 'application/json'
 7                     },
 8                     data: {
 9                         user_id:this.user_id,
10                         price:128
11                     },
12                     success: res => {
13                         console.log("success")
14                         console.log(res.data)
15                         
16                         uni.requestPayment({
17                         provider: 'wxpay',
18                         
19                         timeStamp: res.data.timeStamp,
20                         nonceStr: res.data.nonceStr,
21                         package: 'prepay_id='+String(res.data.prepay_id),
22                         signType: 'MD5',
23                         paySign: res.data.paySign,
24                         
25                         success: function (res) {
26                             console.log('success:' + JSON.stringify(res));
27                             // 支付成功,給后台發送數據,保存訂單
28                             
29                         },
30                         fail: function (err) {
31                             console.log('fail:' + JSON.stringify(err));
32                             // 支付失敗,給后台發送數據,保存訂單
33                         }
34                         });
35 
36                         
37                         
38                     },
39                     fail: (res) => {
40                         console.log("fail")
41                         console.log(res)
42                     },
43                     complete: () => {}
44                 });
45                 
46                 
47             }
前端代碼

至此相信大家也就會了。

附上我的目錄結構

 

最后,人生苦短,我用Python!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM