说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢你们!javascript
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/86660480html
目录java
一丶支付接口python
二丶支付宝支付后端接口编写mysql
三丶支付宝支付测试linux
五丶测试订单支付成功后对订单状态的修改github
七丶项目优化redis
1.分析:当客户下单后,房东须要进入客户订单中,将该订单进行接单处理后,那么在客户的个人订单功能中,才能对此订单进行支付操做,当客户点击支付后,接入支付宝支付(这里以支付宝为支付方式,微信的话逻辑也是同样)
2.支付宝开发文档
3.支付宝产品流程
步骤1:用户在浏览器中访问商家网页应用,选择商品下单、确认购买,进入支付环节,选择支付宝付款,用户点击去支付,以下图1;
步骤2:进入到支付宝支付路由页面,支付宝处理支付请求,并尝试唤起支付宝客户端,以下图2;
步骤3:进入到支付宝页面,调起支付宝支付,出现确认支付界面,以下图3;
图1: |
图2: |
图3: |
步骤4:用户确认收款方和金额,点击当即支付后出现输入密码界面,以下图4;
步骤5:输入正确密码后,支付宝端显示支付结果,以下图5;
步骤6:自动回跳到浏览器中,商家根据付款结果个性化展现订单处理结果,以下图6。
注意:在iOS系统中,唤起支付宝App支付完成后,不会自动回到浏览器或商户App。用户可手工切回到浏览器或商户App。
图4: |
图5: |
图6: |
用户未安装支付宝支付流程
步骤1:若用户未安装支付宝客户端,用户进入到支付宝网页收银台,用户登陆支付宝帐户,如图7和图8;
步骤2:登陆成功后,进入付款确认页面,如图9;
步骤3:用户点击确认付款,进入支付密码页面,如图10;
步骤4:用户输入密码,完成支付,展现支付结果,如图11。
图7: |
图8: |
图9: |
图10: |
图11: |
4.建立应用
5.沙箱:这是支付宝提供开发人员测试的那么一个环境,这个沙箱环境与线上的环境是同样的,在沙箱环境与线上使用惟一不一样的就是APPID,若是须要转换为线上的话,只须要将APPID修改成你的应用的APPID便可,程序代码不须要做任何改变,进入支付宝沙箱,在沙箱帐号中分为卖家信息和买家信息,帐户余额能够任意充值
6.支付流程图
7.在支付宝开发平台中,只有JAVA PHP 以及.NET三种语言的SDK,在github上也有他人封装好的支付宝支付的SDK
https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
1.生成秘钥文件
2.逻辑编写
@api.route("/orders/<int:order_id>/payment", methods=["POST"]) @login_required def order_pay(order_id): """支付宝支付""" pass
user_id = g.user_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="数据库异常")
if not order: return jsonify(errno=RET.NODATA, errmsg="订单数据有误")
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()
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 )
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 )
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.逻辑编写
<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>爱家租房 享受家的舒适</p> </div> </div>
return_url="http://127.0.0.1:5000/payComplete.html"
# /api_v1.0/order/payment @api.route("/order/payment", methods=["PUT"]) def save_order_payment_result(): """保存订单支付结果""" pass
alipay_dict = request.form.to_dict()
alipay_sign = alipay_dict.pop("sign")
# 获取应用私钥 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()
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 )
result = app_client.verify(alipay_dict, alipay_sign)
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字段
说明:由于当初在建立数据库时,未设置订单对应的支付宝交易流水号的字段,因此这里进行一个更新
trade_no = db.Column(db.String(128)) # 支付宝交易流水号
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.第一次使用支付宝支付接口的朋友们,通常不知道支付宝会收取手续费的,那么博主就带你们看看支付宝的手续费是多少
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