Flask項目之手機端租房網站的實戰開發(十四)

說明:該篇博客是博主一字一碼編寫的,實屬不易,請尊重原創,謝謝你們!javascript

接着上一篇博客繼續往下寫 :https://blog.csdn.net/qq_41782425/article/details/86660480html

目錄java

一丶支付接口python

二丶支付寶支付後端接口編寫mysql

三丶支付寶支付測試linux

四丶獲取支付寶支付結果對訂單狀態進行修改git

五丶測試訂單支付成功後對訂單狀態的修改github

六丶測試客戶評論對訂單狀態以及訂單量的增長ajax

七丶項目優化redis


一丶支付接口

1.分析:當客戶下單後,房東須要進入客戶訂單中,將該訂單進行接單處理後,那麼在客戶的個人訂單功能中,才能對此訂單進行支付操做,當客戶點擊支付後,接入支付寶支付(這裏以支付寶爲支付方式,微信的話邏輯也是同樣)

2.支付寶開發文檔

  • step2 而後選擇支付應用下的接入文檔

  • step3 點擊所有文檔

 

 

  • step4 進入手機網站支付,查看開發說明文檔

  

3.支付寶產品流程

  • step1 用戶已安裝支付寶支付流程:

步驟1:用戶在瀏覽器中訪問商家網頁應用,選擇商品下單、確認購買,進入支付環節,選擇支付寶付款,用戶點擊去支付,以下圖1;
步驟2:進入到支付寶支付路由頁面,支付寶處理支付請求,並嘗試喚起支付寶客戶端,以下圖2;
步驟3:進入到支付寶頁面,調起支付寶支付,出現確認支付界面,以下圖3;

圖1:

圖2:

圖3:

步驟4:用戶確認收款方和金額,點擊當即支付後出現輸入密碼界面,以下圖4;
步驟5:輸入正確密碼後,支付寶端顯示支付結果,以下圖5;
步驟6:自動回跳到瀏覽器中,商家根據付款結果個性化展現訂單處理結果,以下圖6。
注意:在iOS系統中,喚起支付寶App支付完成後,不會自動回到瀏覽器或商戶App。用戶可手工切回到瀏覽器或商戶App。

圖4:

圖5:

圖6:

  • step2 用戶未安裝支付寶支付流程:

用戶未安裝支付寶支付流程
步驟1:若用戶未安裝支付寶客戶端,用戶進入到支付寶網頁收銀臺,用戶登陸支付寶帳戶,如圖7和圖8;
步驟2:登陸成功後,進入付款確認頁面,如圖9;
步驟3:用戶點擊確認付款,進入支付密碼頁面,如圖10;
步驟4:用戶輸入密碼,完成支付,展現支付結果,如圖11。

圖7:

圖8:

圖9:

圖10:

圖11:

 

 4.建立應用

  • step1 登陸支付寶,進入管理中心

  • step2 填寫入住申請

  • step3 提交後進入以下界面

  • step4 進入網頁&移動應用列表,進入支付接入

  • step5 建立應用並提交審覈,經過後,方可在線上使用 ,須要審覈,還有填寫營業執照啥的,這樣太麻煩,微信有測試環境,那麼支付寶一樣也有,沙箱就是支付寶測試環境

 

5.沙箱:這是支付寶提供開發人員測試的那麼一個環境,這個沙箱環境與線上的環境是同樣的,在沙箱環境與線上使用惟一不一樣的就是APPID,若是須要轉換爲線上的話,只須要將APPID修改成你的應用的APPID便可,程序代碼不須要做任何改變,進入支付寶沙箱,在沙箱帳號中分爲賣家信息和買家信息,帳戶餘額能夠任意充值

6.支付流程圖

7.在支付寶開發平臺中,只有JAVA PHP 以及.NET三種語言的SDK,在github上也有他人封裝好的支付寶支付的SDK

https://github.com/fzlee/alipay/blob/master/README.zh-hans.md

二丶支付寶支付後端接口編寫

1.生成祕鑰文件

  • step1 在linux系統中有openssl命令,用來生成祕鑰的,進入openssl,執行genrsa -out app_private_key.pem 2048命令,生成2048字節的私鑰並保存到app_private_key.pem文件中

  • step2 生成完私鑰後,執行rsa -in app_private_key.pem -pubout -out app_public_key.pem,對應根據私鑰生成公鑰

  • step3 在終端中使用cat 查看公鑰,複製公鑰

  • step4 在沙箱中查看應用公鑰點擊修改,將剛複製的公鑰進行粘貼保存便可

  • step5 在項目文件api_1_0目錄下新建keys目錄用於保存項目所需的祕鑰,再將在linux系統中生成的app_private_key.pem拷貝到keys項目目錄下,在keys目錄下建立一個alipay_public_key.pem文件,而後在上圖中,查看支付寶公鑰,複製支付寶公鑰,將複製的支付寶公鑰粘貼到alipay_public_key.pem文件中

2.邏輯編寫 

  • step1 在api_1_0目錄下建立一個pay.py模塊,用做於支付,而後子啊__init__中導入此模塊

  • step2 定義接口路由
@api.route("/orders/<int:order_id>/payment", methods=["POST"])
@login_required
def order_pay(order_id):
    """支付寶支付"""
    pass
  • step3 獲取用戶id
user_id = g.user_id
  • step4 判斷訂單的狀態,須要知足參數中訂單id與客戶的訂單id一致,當前訂單的用戶與登陸的用戶id一致,以及訂單的狀態爲待支付
try:
    order = Order.query.filter(Order.id==order_id, Order.user_id==user_id, Order.status=="WAIT_PAYMENT").first()
except Exception as e:
    current_app.logger.error(e)
    return jsonify(errno=RET.DBERR, errmsg="數據庫異常")
  • step5 判斷訂單對象是否存在
if not order:
    return jsonify(errno=RET.NODATA, errmsg="訂單數據有誤")
  • step6 獲取應用私鑰
app_private_key_path = os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem")
app_private_key_string = open(app_private_key_path).read()
  • step7 獲取支付寶公鑰
alipay_public_key_path = os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem")
alipay_public_key_string = open(alipay_public_key_path).read()
  • step8 建立支付寶sdk工具對象
app_client = AliPay(
    appid="2016092400589177", # 沙箱的appid
    app_notify_url=None,  # 默認回調url
    app_private_key_string=app_private_key_string, # 私鑰
    # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
    alipay_public_key_string=alipay_public_key_string,
    sign_type="RSA2", # RSA 或者 RSA2
    debug = True  # 默認False
)
  • step9 手機網站支付,須要跳轉到https://openapi.alipaydev.com/gateway.do? + order_string
order_string = app_client.api_alipay_trade_wap_pay(
    out_trade_no=order.id, # 訂單編號
    total_amount=str(order.amount/100.0), # 總金額
    subject=u"愛家租房<%s>" % order.id, # 訂單標題
    return_url="http://127.0.0.1:5000/orders.html",
    notify_url=None  # 可選, 不填則使用默認notify url
)
  • step10 構造用戶跳轉的支付連接地址,並返回正確響應數據
pay_url = constants.ALIPAY_URL_PREFIX + order_string

return jsonify(errno=RET.OK, errmsg="OK", data={"pay_url":pay_url})

三丶支付寶支付測試

1.運行項目,清除瀏覽器緩存,進入http://127.0.0.1:5000/orders.html個人訂單頁面

2.在訂單編號爲5的訂單上進行點擊去支付, 而後會出現一個檢查客戶到的頁面,若是客戶端存在則會在手機上打開支付寶客戶端(注:由於這裏博主使用的是沙箱進行開發測試,因此在手機端須要安裝沙箱版的支付寶,詳細說明在開發平臺文檔中有相關說明,此支付寶只暫不支持IOS)

3.由於博主是在電腦Web上進行測試,因此當環境中沒有支付寶客戶端,那麼就會跳轉到支付寶手機網頁登陸界面,選擇支付寶帳號登陸(左圖),輸入開發平臺沙箱買家帳號(右圖)進行登陸

4.點擊下一步後,會出現房屋的編號,以及金額,與個人訂單中編號5的的訂單信息一致(左圖),點擊確認付款後,輸入支付密碼,而後出現(右圖)成功界面

 5.點擊完成後,根據return_url編寫的代碼邏輯會跳轉到http://127.0.0.1:5000/orders.html訂單頁面,此時訂單5的狀態依然顯示待支付(左圖),那是由於這一塊的邏輯還未進行編寫,當支付寶支付成功返回正確響應數據給咱們時,咱們還未在頁面中對訂單的狀態進行修改,若是此時再點擊該訂單的去支付,則會出現(右圖)頁面,而不會跳轉到訂單支付界面,此時若是點擊繼續支付,則會報錯,由於此訂單在支付寶後臺已經有對應的流水了

四丶獲取支付寶支付結果對訂單狀態進行修改

1.分析:根據代碼邏輯當客戶進行訂單支付後,支付顯示成功後,支付寶會攜帶如下參數跳轉到訂單頁面,正常來講那麼在這個頁面就應該根據支付寶返回的參數,進行處理,可是放在訂單頁面進行處理的話就比較麻煩,由於我客戶訪問個人訂單頁面時,是不須要攜帶參數的,而從個人訂單頁面去訪問支付寶支付接口時,成功支付後,返回的個人訂單頁面是攜帶了參數的,因此若是要在個人訂單頁面進行處理的話,須要進行判斷究竟是客戶訪問的仍是支付寶返回回來的這是其一,其二就是在個人訂單頁面何時讓後端去對訂單狀態進行更改,因此在個人訂單頁面進行處理的話,邏輯比較複雜,那麼最好的方式就是定義一個過渡頁面,當支付寶支付成功後,不是直接跳轉到個人訂單頁面,而是跳轉到咱們定義的過渡頁面,在這個過渡頁面確定是有支付寶發送過來的參數,那麼就在後端對訂單狀態進行修改,再跳轉到個人訂單頁面,顯示成功支付後的訂單狀態

前臺回跳參數

公共參數:

參數 類型 是否必填 最大長度 描述 示例值
app_id String 32 支付寶分配給開發者的應用ID 2016040501024706
method String 128 接口名稱 alipay.trade.wap.pay.return
sign_type String 10 簽名算法類型,目前支持RSA2和RSA,推薦使用RSA2 RSA2
sign String 256 支付寶對本次支付結果的簽名,開發者必須使用支付寶公鑰驗證簽名 詳見示例
charset String 10 編碼格式,如utf-8,gbk,gb2312等 utf-8
timestamp String 19 前臺回跳的時間,格式"yyyy-MM-dd HH:mm:ss" 2016-08-11 19:36:01
version String 3 調用的接口版本,固定爲:1.0 1.0

業務參數:

參數 類型 是否必填 最大長度 描述 示例值
out_trade_no String 64 商戶網站惟一訂單號 70501111111S001111119
trade_no String 64 該交易在支付寶系統中的交易流水號。最長64位。 2016081121001004630200142207
total_amount Price 9 該筆訂單的資金總額,單位爲RMB-Yuan。取值範圍爲[0.01,100000000.00],精確到小數點後兩位。 9.00
seller_id String 16 收款支付寶帳號對應的支付寶惟一用戶號。 以2088開頭的純16位數字 2088111111116894

2.邏輯編寫 

  • step1 在static靜態文件目錄下建立一個payComplete.html訂單支付完成頁面,將orders.html的代碼複製到此文件中,並進行修改
<div class="container">
        <div class="top-bar">
            <div class="nav-bar">
                <h3 class="page-title">支付完成</h3>
                <a class="nav-btn fl" href="/my.html"><span><i class="fa fa-angle-left fa-2x"></i></span></a>
            </div>
        </div>
        <div class="orders-con">
            <p style="font-size: 20px;margin: auto">支付已完成</p>
            <a href="orders.html" style="font-size: 18px">返回到個人訂單頁</a>
        </div>
        <div class="footer">
            <p><span><i class="fa fa-copyright"></i></span>愛家租房&nbsp;&nbsp;享受家的舒適</p>
        </div>
    </div>
  • step2 在pay.py中將return_url修改成http://127.0.0.1:5000/payComplete.html過渡頁面
return_url="http://127.0.0.1:5000/payComplete.html"
  • step3 訪問以下地址,查看此過渡頁面

http://127.0.0.1:5000/payComplete.html?charset=utf-8&out_trade_no=5&method=alipay.trade.wap.pay.return&total_amount=2544.00&sign=U%2Fl06mjzgZwNEdXo0ePmldLIE6wuMZ4qo2PgyDf4Q%2BRZh1b0KdBqaRkckEBZ136Zyr283FzBlNOMprucQcjH6E9i1Df0ZVRx9HJAm54yN6n%2F1ENFpSOG9znILGbGj%2BV9v%2F0efrcUIvBnYgMIHvp2rBJ8ygRjnhQlTC0q5TVafJQ9OHt%2BX9Ae5F7yiJsb%2B8MVoaG6CDSxqy6MpT2JG7h14alKF6At%2BiJVCN6lbs9RCHZgABabTLDgHbkjJWusElCbi6NEzR%2FHvu9ANSz9onb0RmiyfZ35hwVNw1EATKTsdM47TwYxHxHv%2BFS0gFXdDsQnCYpsH%2F0SCL6aqjK%2Fj1r9eg%3D%3D&trade_no=2019013122001459890500811871&auth_app_id=xxx&version=1.0&app_id=xxx&sign_type=RSA2&seller_id=xxx&timestamp=2019-01-31+10%3A47%3A16

  • step4  在pay.py模塊中定義接口路由,用於保存訂單支付結果
# /api_v1.0/order/payment
@api.route("/order/payment", methods=["PUT"])
def save_order_payment_result():
    """保存訂單支付結果"""
    pass
  • step5 獲取支付寶支付成功返回的響應參數並轉換爲字典格式數據
alipay_dict = request.form.to_dict()
  • step6 對支付寶的數據進行分離 將簽名參數sign提取出去並獲取值
alipay_sign = alipay_dict.pop("sign")
  • step7 獲取應用私鑰和支付寶公鑰
# 獲取應用私鑰
app_private_key_path = os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem")
app_private_key_string = open(app_private_key_path).read()
# 獲取支付寶公鑰
alipay_public_key_path = os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem")
alipay_public_key_string = open(alipay_public_key_path).read()
  • step8 建立支付寶sdk工具對象
app_client = AliPay(
    appid="2016092400589177",  # 沙箱的appid
    app_notify_url=None,  # 默認回調url
    app_private_key_string=app_private_key_string,  # 應用私鑰
    # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
    alipay_public_key_string=alipay_public_key_string, # 支付寶公鑰
    sign_type="RSA2",  # RSA 或者 RSA2
    debug=True  # 默認False
)
  • step9 經過支付寶sdk工具對象中的verify方法驗證支付寶返回的響應參數中剔除sign參數後,剩餘參數與響應參數中的sign值是否一致,若是肯定參數是支付寶的,返回True,不然返回false
result = app_client.verify(alipay_dict, alipay_sign)
  • step10 驗證正確則修改數據庫的訂單狀態信息,最後返回正確響應
if result:
    # 獲取請求中的參數
    order_id = alipay_dict.get("out_trade_no")  # 訂單號
    trade_no = alipay_dict.get("trade_no")  # 支付寶的流水號
    try:
        # 查詢並修改該訂單的狀態以及在支付寶中的交易流水號
        Order.query.filter_by(id=order_id).update({"status": "WAIT_COMMENT", "trade_no": trade_no})
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()

return jsonify(errno=RET.OK, errmsg="OK")

3.更新數據庫ih_order_info表字段,增長trade_no字段

說明:由於當初在建立數據庫時,未設置訂單對應的支付寶交易流水號的字段,因此這裏進行一個更新

  • step1 在models.py中找到Order類,添加此字段
trade_no = db.Column(db.String(128)) # 支付寶交易流水號
  • step2 生成遷移文件並對數據庫進行更新操做

  • step3 查看數據庫ih_order_info表結構,添加trade_no字段成功

4.在payComplete.html中編寫js代碼,向後端/api/v1.0/order/payment接口發送請求,並攜帶支付寶支付成功返回的參數

<script type="text/javascript">
    function getCookie(name) {
        var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
        return r ? r[1] : undefined;
    }
    // 獲取支付寶返回的url中的參數,並經過substr方法從去掉第一個元素?,由於返回的url參數是以鍵值對方式進行構造的,因此這裏是以請求體數據進行發送給後端接口
    var alipayData = document.location.search.substr(1);
    $.ajax({
        url: "/api/v1.0/order/payment",
        type: "put",
        data: alipayData,
        headers: {
            "X-CSRFToken": getCookie("csrf_token")
        }
    })
</script>

 五丶測試訂單支付成功後對訂單狀態的修改

1.運行項目,清除頁面緩存,刷新網頁,進入個人訂單(左圖),由於前面測試支付時,對訂單編號爲5的訂單已經支付成功,因此對應的在支付寶後臺中已經造成了此訂單編號爲5的交易號,因此這裏需從數據庫中將該訂單的編號進行修改,這裏修改成100(右圖)

update ih_order_info set id= 100 where id = 5;

2.而後將訂單編號爲100的訂單進行支付(左圖),點擊確認付款後,支付寶顯示成功後,則跳轉到payComplete.html頁面,在此頁面中點擊返回個人訂單頁,此訂單狀態爲發表評價(右圖),按理說當訂單支付成功後,該訂單狀態顯示爲已支付,等待用戶退房或者完成住宿後,纔會出現待評價,這個邏輯被直接省掉了,在此項目中用戶一旦支付成功則該訂單顯示發表評價

 3.第一次使用支付寶支付接口的朋友們,通常不知道支付寶會收取手續費的,那麼博主就帶你們看看支付寶的手續費是多少

  • step1 修改個人訂單中訂單標號爲1的訂單,將編號改成101,來進行測試,這個房屋以前博主測試過電腦網頁支付接口,因此是須要進行編號修改的

  • step2 查看螞蟻金服開放平臺---沙箱帳號中商家的帳戶餘額爲2009144.81,測試訂單的金額爲4112,沒有手續費的狀況下,客戶支付此單後,商家的帳戶餘額就應該爲2013256.81

  • step3  支付編號爲101的訂單,下面展現支付流程圖

 

  • step4 點擊返回到個人訂單頁後,訂單標號爲101的訂單顯示爲能夠發表評價

  •  step5 在step2時,若是沒有支付寶不收取手續費的狀況下,客戶在支付4112元訂單後,商家的帳戶餘額應該爲2013256.81元,那麼此時在商家信息看看商家的帳戶餘額究竟是不是這麼多錢,結果發現商家的餘額是2013232.14元

  • step6 計算下支付寶的收費需收取比例是多少,原來是千分之6,仍是比較多的

六丶測試客戶評論對訂單狀態以及訂單量的增長

1.對訂單編號爲100的訂單(左圖),點擊發表評論按鈕,彈出評論框(右圖)

 

2.點擊肯定按鈕後,該訂單的狀態變成已完成,顯示客戶評論

 

3.查看數據庫房屋信息表ih_user_info,訂單量order_count值從0變成1,代碼邏輯當訂單狀態變成已完成則order_count加1

 

七丶項目優化

1.解決csrf_token缺失的bug,INFO csrf.py:251 The CSRF token is missing.,在用戶進行退出時,不將session數據所有清除,須要將csrf_token的數據保存到session中

# 在清除session數據時,先從session中獲取csrf_token的值
csrf_token = session.get("csrf_token")
session.clear()
# 當session數據清除完後 再設置session中的csrf_token的值,這樣能夠解決csrf_token缺失的bug
session["csrf_token"] = csrf_token

2.數據庫優化:

a. 表結構設計  擴展  查詢的快慢
    三範式  https://www.zhihu.com/question/24696366
    設計的時候就考慮可能會用到的查詢,爲方便查詢而設計,好比用空間換時間,適當增長冗餘字段節省查詢開銷

b. 建索引   主鍵  惟一(unique)  索引(key   index)  (外鍵)
    http://www.jianshu.com/p/2b541c028157
    提高 查詢速度  複合索引  where k1     k2   k3  k4
    下降   增刪改

c. sql語句優化
    使用索引 注意關鍵字順序 最左原則  where

    不要select *

    能使用聯合查詢,不使用嵌套(子查詢)

    select  from tbl_a a inner join tbl_b b on a.field=b.filed where b.=

    select from tbl_a where filed=(select field from tbl_b where b.=)

    能不使用聯合查詢,儘可能不用聯合查詢

    外鍵 cascade 級聯 (維護外鍵有額外開銷,影響性能)  數據量大的時候,再也不使用外鍵

    使用分析工具分析效率低的sql語句   慢查詢工具
    https://flyerboy.github.io/2016/12/23/mysql_slow/
    https://yemengying.com/2016/05/24/mysql-tuning/

d. 緩存
    redis memcached

e. 讀寫分離
    主從熱備份       主(寫   增刪改)  從(查)

f. 分庫分表  水平分庫分表
    http://www.infoq.com/cn/articles/key-steps-and-likely-problems-of-split-table  

相關文章
相關標籤/搜索