Flask项目之手机端租房网站的实战开发(十四)

  • Post author:
  • Post category:其他


说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

接着上一篇博客继续往下写 :

https://blog.csdn.net/qq_41782425/article/details/86660480


目录


一丶支付接口


二丶支付宝支付后端接口编写


三丶支付宝支付测试


四丶获取支付宝支付结果对订单状态进行修改


五丶测试订单支付成功后对订单状态的修改


六丶测试客户评论对订单状态以及订单量的增加


七丶项目优化


一丶支付接口


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

转载于:https://www.cnblogs.com/cdtaogang/p/10631073.html