安裝
pip install python-alipay-sdk
生成密鑰文件
openssl
生成私鑰javascript
genrsa -out app_private_key.pem 2048
ctr + d退出前端
ls 查看生成的私鑰文件java
cat app_private_key.pem
生成公鑰python
rsa -in app_private_key.pem -pubout -out app_public_key.pem
能夠在另外一個終端ls查看git
私鑰保存在程序中,公鑰放到支付寶中github
cat app_public_key.pem
把上面的公鑰放到支付寶的沙箱應用的查看公鑰中,除去上下的修飾json
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtL8j5quexGUn5dGTdO76 vx+yfkpOQFkTymk1FALj0FSWucrM7u8+8O5DJtbRI+Skt9tGRNU/ZjG6IlQUBzmM xIB3b0I3I5GCg2ZaFWmqblzcqo3RZ9aC+kOX9h3o/xeaq5aemwRsPxezJoFmF38f 6YwR8YIWWnqsFw93MWahbeSt02qnZPwKnq41zUSV/iPogUubLud2D7Dg+cgREfm8 pflbTL4utt41PU7O+tbGUet9fQKpliTESs7Gda/IMZf9KtbBKQCjxiVKiLHcMQje 0FcaaYWtyEebE02E4qIqnHRUklKExj1/mQfXQsum0wO6+EQPuN9VSQUaAMSfqQiq
把家目錄中的私鑰放到程序中的orders應用中後端
把支付寶的公鑰複製到程序中api
在orders應用中新建一個文件alipay_public_key.pemapp
將公鑰的內容複製保存到一個文本文件中(alipay_pubilc_key.pem),注意須要在文本的首尾添加標記位(-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----) ,形如:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzkXJrjPbdu2DdCygEChuLzuBq0Hhvp2SOoe4LzPR0LyKcQF3TM/5O/K5YlNuspeZgMqm+mNLmpp6ahfo6RrMSrnZ9f5jN81mz7ZAIe7PAG0Fj1lTzkBNLu2Ab2NVgkHT9wf/Qgug+Vef4bSVyVdED9cCxsZq76BdSKHKoSufts1YK8QzEg7oX4f/FcRyo1afuqXl2HV+LSTstw0nLq9VkaOawP5bewTg4L7yIIjsb+RLDO7mwTOe3HoGxmWOTU+EIJk2AWqaQWAIGpRQrQZ54T/B8K0wcuGsTt6Ru5Z2XcGvZ6Mk1drQsZ6u1AuOPIvlR7FM8+azGbQmADLevseYOwIDAQAB -----END PUBLIC KEY-----
用戶經過支付寶完成提交訂單
支付寶接口文檔 https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
前端的頁面以下所示:
由於後端要向支付寶發送請求,須要向支付寶傳遞的參數有
訂單的編號
訂單的金額
因此前端須要向後端傳送這兩個參數,由於後端能夠根據訂單的編號找到訂單的信息表,因此訂單的金額能夠不傳,只需傳送訂單的標號便可,
後端會給前端返回一個支付寶的頁面地址,能夠引導用戶在這個頁面付款
前端的js代碼:
必須是待支付的狀態,纔會發送請求
<script type="text/javascript"> $('.oper_btn').click(function() { var order_id = $(this).attr("order_id"); var order_status = $(this).attr("order_status"); order_status = parseInt(order_status); if (1 == order_status) { // 表示待支付 var req_data ={ order_id:order_id, csrfmiddlewaretoken: "{{ csrf_token }}" } $.post('/orders/pay', req_data, function(data){ if ( 1 == data.code ) { // 用戶未登陸 location.href = "/users/login"; } else if (0 == data.code ) { // 發起支付請求成功,跳轉的地址 window.open(data.url); } else { alert(data.message); } }); } });
後端視圖業務邏輯
用戶必須是登錄的狀態,經過繼承自定義的裝飾器
1 接受前端傳送的訂單編號
2 判斷編號是否爲空
爲空返回缺乏訂單的編號
3 經過(訂單的編號,用戶,支付的方式,支付的狀態),獲取訂單的信息表
沒查到返回訂單有誤
下面睡固定的寫法
4 構建alipay支付工具對象(固定)
alipay = AliPay( appid=settings.ALIPAY_APPID, # 沙箱模式中的appid app_notify_url=None, # 默認回調url app_private_key_path=os.path.join(settings.BASE_DIR, "apps/orders/app_private_key.pem"), alipay_public_key_path=os.path.join(settings.BASE_DIR, "apps/orders/alipay_public_key.pem"), # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰, sign_type="RSA2", # RSA 或者 RSA2 debug=True # 默認False, 沙箱模式配置爲true )
5 藉助alipay對象向支付寶發起支付請求 電腦網站支付,須要跳轉到https://openapi.alipaydev.com/gateway.do? + order_string (固定)
order_string = alipay.api_alipay_trade_page_pay( out_trade_no=order_id, # 訂單編號 total_amount=str(order.total_amount), # 訂單金額 subject="每天生鮮%s" % order_id, # 訂單描述信息 return_url=None, # 訂單成功返回的信息 notify_url=None # 可選, 不填則使用默認notify url )
6返回 電腦網站支付,須要跳轉到https://openapi.alipaydev.com/gateway.do? + order_string
在orders.models中的OrderInfo類中添加如下的屬性,表示訂單的狀態
ORDER_STATUS_ENUM = { "UNPAID": 1, "UNSEND": 2, "UNRECEIVED": 3, "UNCOMMENT": 4, "FINISHED": 5 }
在orders.models中的OrderInfo類中添加如下的屬性,表示支付方式的序號
PAY_METHODS_ENUM = { "CASH": 1, "ALIPAY": 2 }
在settiing中添加訪問支付寶的網址和支付寶的沙箱模式中的id
# 支付寶的網址 ALIPAY_URL = "https://openapi.alipaydev.com/gateway.do" ALIPAY_APPID = "2016081600258081"
代碼以下:
![](http://static.javashuo.com/static/loading.gif)
class PayView(LoginRequiredJsonMixin, View): """支付寶支付視圖""" def post(self, request): # 訂單編號 order_id order_id = request.POST.get("order_id") if not order_id: return JsonResponse({"code": 2, "message": "缺失訂單編號"}) # 獲取訂單信息 try: order = OrderInfo.objects.get(order_id=order_id, user=request.user, status=OrderInfo.ORDER_STATUS_ENUM["UNPAID"], pay_method=OrderInfo.PAY_METHODS_ENUM["ALIPAY"]) except OrderInfo.DoesNotExist: return JsonResponse({"code": 3, "message": "訂單信息錯誤"}) # 構建alipay支付工具對象 alipay = AliPay( appid=settings.ALIPAY_APPID, # 沙箱模式中的appid app_notify_url=None, # 默認回調url app_private_key_path=os.path.join(settings.BASE_DIR, "apps/orders/app_private_key.pem"), alipay_public_key_path=os.path.join(settings.BASE_DIR, "apps/orders/alipay_public_key.pem"), # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰, sign_type="RSA2", # RSA 或者 RSA2 debug=True # 默認False, 沙箱模式配置爲true ) # 藉助alipay對象,向支付寶發起支付請求 # 電腦網站支付,須要跳轉到https://openapi.alipaydev.com/gateway.do? + order_string order_string = alipay.api_alipay_trade_page_pay( out_trade_no=order_id, # 訂單編號 total_amount=str(order.total_amount), # 訂單金額 subject="每天生鮮%s" % order_id, # 訂單描述信息 return_url=None, notify_url=None # 可選, 不填則使用默認notify url ) # 返回json數據 alipay_url = settings.ALIPAY_URL + "?" + order_string return JsonResponse({"code": 0, "message": "發起支付成功", "url": alipay_url})
配置url
url('^pay$', views.PayView.as_view(), name="pay"),
當用戶點擊待支付按鈕,就能夠完成支付了
檢查支付的結果
這個是沒有公網,須要本身去向支付寶發送請求詢問支付成功仍是失敗
前端js的代碼以下:
紅色區域表示新增的代碼 :支付成功從新加載頁面,失敗顯示失敗的信息
<script type="text/javascript">
$('.oper_btn').click(function() {
var order_id = $(this).attr("order_id");
var order_status = $(this).attr("order_status");
order_status = parseInt(order_status);
// 只有待支付的狀態才能夠點擊
if (1 == order_status) {
// 表示待支付
var req_data ={
order_id:order_id,
csrfmiddlewaretoken: "{{ csrf_token }}"
}
$.post('/orders/pay', req_data, function(data){
if ( 1 == data.code ) {
// 用戶未登陸
location.href = "/users/login";
} else if (0 == data.code ) {
// 發起支付請求成功
window.open(data.url);
// 向後端發起查詢支付狀態的請求
$.get("/orders/check_pay?order_id="+order_id, function (resp_data) {
if (0 == resp_data) {
// 支付成功
location.reload();
} else {
alert(resp_data.message);
}
});
} else {
alert(data.message);
}
});
} else if (4 == order_status) {
location.href = ("/orders/comment/" + order_id);
}
});
</script>
後端視圖業務邏輯
支付寶開發者文檔 https://openhome.alipay.com/developmentDocument.htm
後端視圖的業務邏輯
1 用戶必須是登錄的狀態,
2 經過get請求的方式接受用戶傳送過來的訂單編號
若是訂單的編號不存在,返回訂單信心缺乏
3 經過訂單的(編號,用戶,交易的狀態是否爲待支付和支付的方式是否爲支付寶),查詢對應的訂單信息表
若是不存在,返回訂單信息錯誤
4 經過whileTrue循環遍歷查詢用戶交易的狀態
若是交易的狀態碼爲10000和交易的狀態爲TRADE_SUCCESS說明交易成功,把支付寶的交易號保存在訂單信息表的trade_id,訂單的狀態設爲待評價,返回給前端
若是交易的狀態碼爲40004(表示支付寶還沒生成訂單)或者交易的狀態碼爲10000而且交易的狀態爲用戶待支付(WAIT_BUYER_PAY),延遲10scontinue
else 返回支付失敗
完整的代碼以下:
![](http://static.javashuo.com/static/loading.gif)
class CheckPayStatusView(LoginRequiredJsonMixin, View): """檢查支付結果""" def get(self, request): order_id = request.GET.get("order_id") if not order_id: return JsonResponse({"code": 2, "message": "缺乏訂單號"}) # 獲取訂單信息 try: order = OrderInfo.objects.get(order_id=order_id, user=request.user, status=OrderInfo.ORDER_STATUS_ENUM["UNPAID"], pay_method=OrderInfo.PAY_METHODS_ENUM["ALIPAY"]) except OrderInfo.DoesNotExist: return JsonResponse({"code": 3, "message": "訂單信息錯誤"}) # 構建alipay支付工具對象 alipay = AliPay( appid=settings.ALIPAY_APPID, # 沙箱模式中的appid app_notify_url=None, # 默認回調url app_private_key_path=os.path.join(settings.BASE_DIR, "apps/orders/app_private_key.pem"), alipay_public_key_path=os.path.join(settings.BASE_DIR, "apps/orders/alipay_public_key.pem"), # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰, sign_type="RSA2", # RSA 或者 RSA2 debug=True # 默認False, 沙箱模式配置爲true ) # 藉助alipay工具查詢支付結果 while True: response = alipay.api_alipay_trade_query(order_id) code = response.get("code") trade_status = response.get("trade_status") if code == "10000" and trade_status == "TRADE_SUCCESS": # 表示用戶支付成功 order.trade_id = response.get("trade_no") # 支付寶的交易標號 order.status = OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"] # 設置訂單狀態爲待評價 order.save() return JsonResponse({"code": 0, "message": "支付成功"}) elif code == "40004" or (code == "10000" and trade_status == "WAIT_BUYER_PAY"): # 表示支付寶訂單還沒建立好, 或者用戶還未支付 time.sleep(10) continue else: return JsonResponse({"code": 4, "message": "支付失敗"})
配置url路徑
url('^check_pay$', views.CheckPayStatusView.as_view(), name="check_pay"),