👏👏👏
哈喽!大家好,我是【太阳打伞】,一位热爱分享各种技术的博主!😍😍😍
⭐【太阳打伞】的创作宗旨:每一条命令都亲自执行过,每一行代码都实际运行过,每一种方法都真实实践过,每一篇文章都良心制作过。✊✊✊
⭐【太阳打伞】的博客中所有涉及命令、代码的地方,除了提供图片供大家参考,另外会在图片下方提供一份纯文本格式的命令或者代码方便大家粘贴复制直接执行命令或者运行代码。🤝🤝🤝
⭐如果你对技术有着浓厚的兴趣,欢迎关注【太阳打伞】,欢迎大家和我一起交流。😘😘😘
❤️❤️❤️感谢各位朋友接下来的阅读❤️❤️❤️
登录支付宝,打开控制台,进入研发服务
进入沙箱,生成自己的私钥,支付宝公钥
将支付宝公钥和自己私钥存放到.txt文件中
拿到自己的支付宝沙箱应用id,和 买家账号:xxxxxxxxxxxx
登录密码111111
支付密码111111,
买家账号等到支付时使用!
后端代码实现:
创建alipay.py文件
我采用的是Tornado框架实现的!!!
-
- from datetime import datetime
- from Crypto.PublicKey import RSA
- from Crypto.Signature import PKCS1_v1_5
- from Crypto.Hash import SHA256
- from urllib.parse import quote_plus
- from urllib.parse import urlparse, parse_qs
- from base64 import decodebytes, encodebytes
- import json
- from tornado import httpclient
-
-
- class AliPay:
- """
- 支付宝支付接口(PC端支付接口)
- """
-
-
- def __init__(self, appid, app_notify_url, app_private_key_path,
- alipay_public_key_path, return_url, debug=True):
- self.appid = appid
- self.app_notify_url = app_notify_url
- self.app_private_key_path = app_private_key_path
- self.app_private_key = None
- self.return_url = return_url
- with open(self.app_private_key_path) as fp:
- self.app_private_key = RSA.importKey(fp.read())
- self.alipay_public_key_path = alipay_public_key_path
- with open(self.alipay_public_key_path) as fp:
- self.alipay_public_key = RSA.importKey(fp.read())
-
- if debug is True:
- self.__gateway = "https://openapi.alipaydev.com/gateway.do"
- else:
- self.__gateway = "https://openapi.alipay.com/gateway.do"
-
- # 商户订单号out_trade_no
- def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
- biz_content = {
- "subject": subject,
- "out_trade_no": out_trade_no,
- "total_amount": total_amount,
- "product_code": "FAST_INSTANT_TRADE_PAY",
- # "qr_pay_mode":4
- }
-
- biz_content.update(kwargs)
- data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
- return self.sign_data(data)
-
-
- # 查询订单状态方法
- async def api_alipay_trade_query(self,out_trade_no=None,**kwargs):
- biz_content = {
- "out_trade_no": out_trade_no
- }
- biz_content.update(**kwargs)
-
- data = self.build_body("alipay.trade.query", biz_content)
- url = self.__gateway + "?" + self.sign_data(data)
- res = await httpclient.AsyncHTTPClient().fetch(url,method='GET',validate_cert=False,connect_timeout=30.0, request_timeout=30.0)
- res = json.loads(res.body.decode())
- return res
-
- #请求支付宝退款接口
- async def api_alipay_trade_refund(self, refund_amount, out_trade_no=None, trade_no=None, **kwargs):
- biz_content = {
- "refund_amount": refund_amount
- }
- biz_content.update(**kwargs)
- if out_trade_no:
- biz_content["out_trade_no"] = out_trade_no
- if trade_no:
- biz_content["trade_no"] = trade_no
- data = self.build_body("alipay.trade.refund", biz_content)
- url = self.__gateway + "?" + self.sign_data(data)
- res = await httpclient.AsyncHTTPClient().fetch(url,method='GET',validate_cert=False,connect_timeout=30.0, request_timeout=30.0)
- res = json.loads(res.body.decode())
- return res
-
- def build_body(self, method, biz_content, return_url=None):
- data = {
- "app_id": self.appid,
- "method": method,
- "charset": "utf-8",
- "sign_type": "RSA2",
- "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- "version": "1.0",
- "biz_content": biz_content
- }
-
- if return_url is not None:
- data["notify_url"] = self.app_notify_url
- data["return_url"] = self.return_url
-
- return data
-
- def sign_data(self, data):
- data.pop("sign", None)
- # 排序后的字符串
- unsigned_items = self.ordered_data(data)
- unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
- sign = self.sign(unsigned_string.encode("utf-8"))
- # ordered_items = self.ordered_data(data)
- quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)
-
- # 获得最终的订单信息字符串
- signed_string = quoted_string + "&sign=" + quote_plus(sign)
- return signed_string
-
- def ordered_data(self, data):
- complex_keys = []
- for key, value in data.items():
- if isinstance(value, dict):
- complex_keys.append(key)
-
- # 将字典类型的数据dump出来
- for key in complex_keys:
- data[key] = json.dumps(data[key], separators=(',', ':'))
-
- return sorted([(k, v) for k, v in data.items()])
-
- def sign(self, unsigned_string):
- # 开始计算签名
- key = self.app_private_key
- signer = PKCS1_v1_5.new(key)
- signature = signer.sign(SHA256.new(unsigned_string))
- # base64 编码,转换为unicode表示并移除回车
- sign = encodebytes(signature).decode("utf8").replace("\n", "")
- return sign
-
- def _verify(self, raw_content, signature):
- # 开始计算签名
- key = self.alipay_public_key
- signer = PKCS1_v1_5.new(key)
- digest = SHA256.new()
- digest.update(raw_content.encode("utf8"))
- if signer.verify(digest, decodebytes(signature.encode("utf8"))):
- return True
- return False
-
- def verify(self, data, signature):
- if "sign_type" in data:
- sign_type = data.pop("sign_type")
- # 排序后的字符串
- unsigned_items = self.ordered_data(data)
- message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
- return self._verify(message, signature)
-
-
-
写pay.py主文件:
- import datetime
- import logging
- import decimal
- from base import BaseHandler
- from tornado.web import url
-
- from db import UserModel,OrderModel
- from user import BaseMange
- # 充值
- from alipay import AliPay
- from utils import jwt_auth
-
- # 钱包
- class WalletHandler(BaseMange):
- """创建订单"""
-
- @jwt_auth
- async def post(self):
- _where = "model.uid == {}".format(self._cuser.id)
- orders = await self.get_all_where(OrderModel,_where)
- return self.finish({"errcode":0,"data":orders})
-
- @jwt_auth
- async def get(self):
- # 查询用户余额
- user = await self.get_one_obj(UserModel, self._cuser.id)
-
- return self.finish({'errcode': 0, 'data': user.wallet})
-
-
-
- class PayHandler(BaseMange):
- # 转跳地址
- @jwt_auth
- async def get(self):
-
- alipay = AliPay(
- appid='xxxxxxxxxx', # 你的支付宝沙箱应用的id
- app_private_key_path='./keys/app_private_2048.txt', # 你的私钥
- alipay_public_key_path='./keys/alipay_public_2048.txt', # 支付宝公钥,
- app_notify_url="http://127.0.0.1:8080/wallet", # 回调地址
- return_url='http://127.0.0.1:8080/pay',
- debug=True # 请求来到支付宝沙箱)
- )
- # 3.创建订单
- order_id = datetime.datetime.now().strftime("%Y%m%d%H%M%S") + "_%s" % self._cuser.id
- subject = self.get_argument("subject",None)
- # 订单编号
- total_amount= self.get_argument("total_amount",None)
- # res = alipay.direct_pay(subject,order_id,total_amount)
- # print(res)
- # pay_url = "https://openapi.alipaydev.com/gateway.do?"+res # 支付宝网关地址(沙箱应用)
- # return self.finish({'errcode': 0, 'data': pay_url})
-
- """创建订单"""
- try:
- # 创建订单信息
- order = {"order_id": order_id, "uid_id": self._cuser.id, "total_amount": float(total_amount)}
-
- order = await self.create(OrderModel, order)
- res = alipay.direct_pay(subject, order_id, total_amount)
- print(res)
- pay_url = "https://openapi.alipaydev.com/gateway.do?" + res # 支付宝网关地址(沙箱应用)
- # print(pay_url)
- return self.finish({'errcode': 0, 'data': pay_url})
- except Exception as e:
- logging.error("create order error, reason is %s" % e)
- return self.finish({'errcode': 1, 'msg': "交易出错!"})
-
- @jwt_auth
- async def post(self):
-
- order_id = self.get_argument("out_trade_no", None) # 订单编号
-
- _where = "(model.order_id=='{}')".format(order_id)
-
- alipay = AliPay(
- appid='xxxxxxxxxx', # 你的支付宝沙箱应用的id
- app_private_key_path='./keys/app_private_2048.txt', # 你的私钥
- alipay_public_key_path='./keys/alipay_public_2048.txt', # 支付宝公钥,
- app_notify_url="http://127.0.0.1:8080/wallet", # 回调地址
- return_url='http://127.0.0.1:8080/pay',
- debug=True # 请求来到支付宝沙箱)
- )
-
- res = await alipay.api_alipay_trade_query(out_trade_no=order_id)
- print(res)
- res = res['alipay_trade_query_response']
-
- if res['code'] == '10000':
- try:
- order = await self.get_one_where(OrderModel, _where)
-
- # 修改订单的状态
- order.trade_no = res['trade_no']
- order.total_amount = res['total_amount']
- order.status = 1
- order.record = res["send_pay_date"]
- await self.application.objects.update(order)
- user = await self.get_one_obj(UserModel, self._cuser.id)
- user.wallet = user.wallet + decimal.Decimal(res['total_amount'])
-
- await self.application.objects.update(user)
- return self.finish({'errcode': 0, 'msg': "充值成功"})
- except Exception as e:
- print(e)
-
- return self.finish({'errcode': 1, 'msg': "未找到订单交易!"})
-
- else:
- return self.finish({'errcode': 2, 'msg': "支付失败!"})
-
-
- urlpatterns = [
- url('/pay/', PayHandler),
- url('/wallet/', WalletHandler),
-
-
- ]
-
前端代码实现
我使用的是Vue.3
文件名是:wallet.vue
-
- <template>
- <div class="container">
- <a-layout>
- <a-layout-sider>
- <mymenu>mymenu>
- a-layout-sider>
- <a-layout>
-
- <h2>充值页面h2>
-
- <h3>我的钱包h3>
-
- <p>
- <a-col :span="22">
- <a-statistic title="钱包余额" :precision="2" :value= wallet />
- a-col>
- p>
-
- <div class="components-input-demo-presuffix">
- <h2>钱包充值h2>
-
- <p>请输入充值金额:
- <a-input v-model:value="value" prefix="¥" suffix="RMB" placeholder="请输入充值金额" />
- p>
- <p>
- <a-button type="primary" @click="get_pay()">支付宝充值a-button>
- <a-button type="">微信充值a-button>
- p>
- div>
- <p>用户订单表p>
- <p><table>
- <tr>
- <th>订单编号th>
- <th>创建时间th>
- <th>支付方式th>
- <th>备注th>
- <th>支付状态th>
- tr>
- <tr v-for="(j,i) in orderlist" :key="i">
- <td>{{j.order_id}}td>
- <td>{{j.create_time}}td>
- <td>{{j.pay_method}}td>
- <td>{{j.record}}td>
- <td v-if="j.status==0">待支付td>
- <td v-if="j.status==1">已支付td>
- <td v-if="j.status==3">已取消td>
- tr>
- table>p>
-
-
-
-
-
-
-
- a-layout>
- a-layout>
- div>
- template>
-
- <script>
- // 导入子组件
- import mymenu from "./mymenu.vue";
- import { message } from "ant-design-vue";
-
- export default {
- data() {
- return {
-
- collapsed: false,
- selectedKeys: ["1"],
- visible:false,
- money:'',
- id:'',
- wallet:0,
- value:50,
- orderlist:[]
-
-
-
-
-
- };
- },
-
- //声明组件
- components: {
- mymenu,
- },
- methods: {
-
- pay(id){
- this.visible = true
- // this.id = id
- },
-
-
- // 充值请求
-
- get_pay() {
- this.myaxios(this.baseurl + "pay/", "get",{"subject":"钱包充值","total_amount":this.value}).then(data => {
-
- console.log(data);
- if (data.errcode === 0) {
- window.location.href=data.data
- }
-
- });
- },
-
- get_wallet() {
- this.myaxios(this.baseurl + "wallet/", "get").then(data => {
-
- console.log(data);
- if (data.errcode === 0) {
- this.wallet = data.data
- }
-
- });
- },
-
-
-
-
- get_orderlist(){
- this.myaxios(this.baseurl + "wallet/", "post").then(data => {
-
- console.log(data);
- if (data.errcode === 0) {
- this.orderlist = data.data
- }
-
- });
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- },
- created() {
- this.get_wallet()
- this.get_orderlist()
-
-
-
- },
- mounted() {},
- };
- script>
-
-
- <style scoped>
- @import url("../assets/style.css");
- style>
充值请求:
文件名是:pay.vue
-
- <template>
- <div class="container">
- <a-layout>
- <a-layout-sider>
- <mymenu>mymenu>
- a-layout-sider>
- <a-layout>
-
- <h2>充值页面h2>
-
- a-layout>
- a-layout>
- div>
- template>
-
- <script>
- // 导入子组件
- import mymenu from "./mymenu.vue";
- import { message } from "ant-design-vue";
-
- import { createFromIconfontCN } from '@ant-design/icons-vue';
-
- const IconFont = createFromIconfontCN({
- scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js',
- });
-
- export default {
- data() {
- return {
-
- collapsed: false,
- selectedKeys: ["1"],
-
-
-
- };
- },
-
- //声明组件
- components: {
- mymenu,
- },
- methods: {
-
-
-
-
- // 充值请求
-
- check_order(){
- this.myaxios(this.baseurl + "pay/", "post",{"out_trade_no":this.$route.query.out_trade_no,"trade_no":this.$route.query.trade_no,"total_amount":this.$route.query.total_amount,"timestamp":this.$route.query.timestamp}).then(data => {
-
- console.log(data);
- if (data.errcode === 0) {
- this.$message.success(data.msg)
- window.location.href="/wallet"
- }else{
- this.$message.error(data.msg)
- window.location.href="/wallet"
- }
-
- });
- }
-
-
-
- },
- created() {
-
- this.check_order()
-
- },
- mounted() {},
- };
- script>
-
-
- <style scoped>
- @import url("../assets/style.css");
- style>
数据库内容,字段名
订单表:
用户表:记得写钱包字段哦
点击支付宝充值:
输入从沙箱获得的支付宝账号和密码。
点击确认付款!
后面还让输入支付密码!!!
钱包到账啦: