zoukankan      html  css  js  c++  java
  • DAY 86 luffy05

    1 课程详情页面
    -播放器组件
    2 课程章节接口
    -所有课程章节全拿回来(过滤:按课程id过滤)
    3 支付宝支付
    -生成公钥私钥,把公钥配置在支付宝上---》生成一个支付宝公钥
       -支付宝公钥,自己的私钥,放到了项目中
       -API,没有提供sdk,第三方的sdk
       -安装,安装步骤扣代码
      -生成一个对象(一堆参数)
           -调用对象的方法生成支付连接(一堆参数),需要拼连接地址
           -拿到连接地址就可以打开支付宝,付款了
           -两个回调
          -get回调,调前端(传回很多参数),当vue挂载时候,也向后端发送一个请求,携带数据
               -post回调,以它为准,修改订单状态
              -如果刚支付成功,服务挂掉(24小时以内只要启动服务即可,支付宝会发送8次回调)
           -基于sdk封装包
          -

    1 支付接口

    1 post请求---》携带数据什么样
    {courses:[1,2,3],subject:'订单标题',pay_type:'1',total_amount:'199'}
       
       
    2 视图类
    -自动生成路由,新增类
       -重写create方法
       -写序列化类
      -validate中校验
       -5个步骤(在serializer的validate)
      -校验钱是否正确
           -生成订单号(uuid,分布式id的生成)
           -获取当前登录用户(request.user)
           -生成支付链接(context)
           -入库前准备(把user,订单号放到字典中)
      -入库(重写create方法)
      -入两个库

    1.1 视图类

    class PayView(GenericViewSet, CreateModelMixin):
       # class PayView(ViewSetMixin,CreateAPIView):
       # 认证类,权限类
       authentication_classes = [JSONWebTokenAuthentication]
       permission_classes = [IsAuthenticated,]
       queryset = Order.objects.all()
       serializer_class = OrderModelSerializer

       def create(self, request, *args, **kwargs):
           serializer = self.get_serializer(data=request.data, context={'request': request})
           # OrderModelSerializer(data=request.data,context={'request':request})
           serializer.is_valid(raise_exception=True)
           self.perform_create(serializer)
           # serializer.save()
           pay_url = serializer.context['pay_url']
           return APIResponse(pay_url=pay_url)

     

     

    1.2 序列化类

    class OrderModelSerializer(serializers.ModelSerializer):
       # courses:[1,2,3]
       # 转换成courses:[obj1,obj2,obj3]
       courses = serializers.PrimaryKeyRelatedField(queryset=Course.objects.all(), many=True)

       class Meta:
           model = Order
           fields = [
               'courses',
               'subject',
               'pay_type',
               'total_amount'
          ]

       def _check_money(self, attrs):
           # 校验钱是否合法
           total_amount = attrs.get('total_amount')
           total = 0
           for course in attrs.get('courses'):
               total += course.price
           if total_amount == total:
               return total_amount
           else:
               raise ValidationError('钱不对')

       def _get_trade_no(self):
           trade_no = str(uuid.uuid4()).replace('-', '')
           return trade_no

       def _get_user(self):
           return self.context['request'].user

       def _get_pay_url(self, subject, trade_no, total_amount):
           from luffyapi.libs.alpay import alipay

           res = alipay.api_alipay_trade_page_pay(
               subject=subject,
               out_trade_no=trade_no,
               total_amount=float(total_amount),  # 转成float类型
               return_url=settings.RETURN_URL,
               notify_url=settings.NOTIFY_URL
          )

           pay_url = pay_settings.GATEWAY + res  # 支付链接
           self.context['pay_url'] = pay_url

       def _pre_model(self, attrs, user, total_amount, trade_no):
           attrs['user'] = user
           attrs['total_amount'] = total_amount
           attrs['out_trade_no'] = trade_no
           # courses需要pop出来,但是不着急

       def validate(self, attrs):
           # -校验钱是否正确
           total_amount = self._check_money(attrs)
           # -生成订单号(uuid,分布式id的生成)
           trade_no = self._get_trade_no()
           # -获取当前登录用户(request.user)
           user = self._get_user()
           # -生成支付链接(context)
           self._get_pay_url(attrs['subject'], trade_no, total_amount)
           # -入库前准备(把user,订单号放到字典中)
           self._pre_model(attrs, user, total_amount, trade_no)
           return attrs

       def create(self, validated_data):
           courses = validated_data.pop('courses')
           # 存订单表
           order = Order.objects.create(**validated_data)

           # 存订单详情表
           for course in courses:
               OrderDetail.objects.create(order=order, course=course, price=course.price, real_price=course.price)

           return order

     

    1.2 路由

    router=SimpleRouter()

    router.register('pay',views.PayView,'pay')
    urlpatterns = [

       path('', include(router.urls)),

    ]

     

    2 支付前端

    2.2 get回调参数

    charset=utf-8&
    out_trade_no=36c931b5e7a44cf6a8bd5187862e8fca&
    method=alipay.trade.page.pay.return&
    total_amount=39.00&
    sign=d4KoJ4LIPap%2BmqEGTsfjVMYbml3ndl21vDgkxL0J1Zc2K1LM2Qll7yecg6nuYziwPB0EAo4dnirIBZI7%2F%2BV0zF%2BgB0l0ck%2FIYm4JfMrC1FSAL6wlSHX%2FfxRskFAsUHx%2BIvQ%2FNR6%2FK01KJ7zThRLzn3aC8%2B8gYRn1i3UagZQgKpt%2FwTWnw3jG1Gqsg7C54uW%2Fon7%2FYM3yCTLtxTIhm5vNqSy6ommqLIM%2FkVD0RpU487hQI56Nw4j1t%2F%2FXhHS7TqqTnbg0xRXIY%2FBFbFrw7QwF0JZYpvo0zE5qDugGEWsk%2BiCOmIs0bh6VJPavTHL3%2BO5rEba4F79Lpq8RvxykdoptVw%3D%3D&
    trade_no=2021051722001430480501699313&
    auth_app_id=2016092000554611&version=1.0&
    app_id=2016092000554611&sign_type=RSA2&
    seller_id=2088102176466324&
    timestamp=2021-05-17%2012%3A21%3A30

    2.2 前端

                buy_now(course) {
                   //判断是否登录了
                   let token = this.$cookies.get('token')
                   if (!token) {
                       this.$message({
                           message: '您没有登录',
                           type: 'warning',
                      })
                       return
                  }
                   //向后端发送请求
                   // this.$http.post(this.$BASE_URL + 'order/pay/', data = {}, header = {})
                   this.$http({
                           headers: {
                               'Authorization': `jwt ${token}`
                          },
                           method: 'post',
                           url: this.$BASE_URL + 'order/pay/',
                           data: {
                               "courses": [course.id], "subject": course.name, "pay_type": "1", "total_amount": course.price
                          }
                      }
                  ).then(res => {
                       console.log(res.data)
                       if (res.data.code == 100) {
                           open(res.data.pay_url, '_self') //在当前页面中打开一个连接
                      }
                  })


              },

    2.3 支付成功前端

    <template>
       <div class="pay-success">
           <!--如果是单独的页面,就没必要展示导航栏(带有登录的用户)-->
           <Header/>
           <div class="main">
               <div class="title">
                   <div class="success-tips">
                       <p class="tips">您已成功购买 1 门课程!</p>
                   </div>
               </div>
               <div class="order-info">
                   <p class="info"><b>订单号:</b><span>{{ result.out_trade_no }}</span></p>
                   <p class="info"><b>交易号:</b><span>{{ result.trade_no }}</span></p>
                   <p class="info"><b>付款时间:</b><span><span>{{ result.timestamp }}</span></span></p>
               </div>
               <div class="study">
                   <span>立即学习</span>
               </div>
           </div>
       </div>
    </template>

    <script>
       import Header from "@/components/Header"

       export default {
           name: "Success",
           data() {
               return {
                   result: {},
              };
          },
           created() {
               // url后拼接的参数:?及后面的所有参数 => ?a=1&b=2
               // console.log(location.search);

               // 解析支付宝回调的url参数
               let params = location.search.substring(1);  // 去除? => a=1&b=2
               let items = params.length ? params.split('&') : [];  // ['a=1', 'b=2']
               //逐个将每一项添加到args对象中
               for (let i = 0; i < items.length; i++) {  // 第一次循环a=1,第二次b=2
                   let k_v = items[i].split('=');  // ['a', '1']
                   //解码操作,因为查询字符串经过编码的
                   if (k_v.length >= 2) {
                       // url编码反解
                       let k = decodeURIComponent(k_v[0]);
                       this.result[k] = decodeURIComponent(k_v[1]);
                       // 没有url编码反解
                       // this.result[k_v[0]] = k_v[1];
                  }

              }
               // 解析后的结果
               // console.log(this.result);


               // 把地址栏上面的支付结果,再get请求转发给后端
               this.$http({
                   url: this.$BASE_URL + '/order/success/' + location.search,
                   method: 'get',
              }).then(response => {
                   console.log(response.data);
                   alert(response.data.msg)
              }).catch(() => {
                   console.log('支付结果同步失败');
              })
          },
           components: {
               Header,
          }
      }
    </script>

    <style scoped>
      .main {
           padding: 60px 0;
           margin: 0 auto;
            1200px;
           background: #fff;
      }

      .main .title {
           display: flex;
           -ms-flex-align: center;
           align-items: center;
           padding: 25px 40px;
           border-bottom: 1px solid #f2f2f2;
      }

      .main .title .success-tips {
           box-sizing: border-box;
      }

      .title img {
           vertical-align: middle;
            60px;
           height: 60px;
           margin-right: 40px;
      }

      .title .success-tips {
           box-sizing: border-box;
      }

      .title .tips {
           font-size: 26px;
           color: #000;
      }


      .info span {
           color: #ec6730;
      }

      .order-info {
           padding: 25px 48px;
           padding-bottom: 15px;
           border-bottom: 1px solid #f2f2f2;
      }

      .order-info p {
           display: -ms-flexbox;
           display: flex;
           margin-bottom: 10px;
           font-size: 16px;
      }

      .order-info p b {
           font-weight: 400;
           color: #9d9d9d;
           white-space: nowrap;
      }

      .study {
           padding: 25px 40px;
      }

      .study span {
           display: block;
            140px;
           height: 42px;
           text-align: center;
           line-height: 42px;
           cursor: pointer;
           background: #ffc210;
           border-radius: 6px;
           font-size: 16px;
           color: #fff;
      }
    </style>

     

    3 支付成功两个回调接口

    from rest_framework.views import  APIView
    from .models import Order
    class SuccessView(APIView):
    def get(self,request,*args,**kwargs):
    # 去订单表查询该订单的状态
    out_trade_no=request.query_params.get('out_trade_no')
    # 校验这个数据是什么状态
    try:
    Order.objects.get(out_trade_no=out_trade_no,order_status=1)
    return APIResponse(msg='已经支付')
    except Exception as e:
    return APIResponse(code=101,msg='请稍后刷新该页面再看')


    def post(self,request,*args,**kwargs):
    # 支付宝回调,数据在哪?
    # 取出支付宝回调返回的数据,在request.data中
    # 验证签名
    # 修改订单状态
    # 告诉支付宝成功
    try:
    print(request.data)
    result_data = request.data.dict()
    out_trade_no = result_data.get('out_trade_no')
    signature = result_data.pop('sign')
    from luffyapi.libs import alpay
    result = alpay.alipay.verify(result_data, signature)
    if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
    # 完成订单修改:订单状态、流水号、支付时间
    # Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1,trade_no=result_data.get('trade_no'),pay_time=result_data.get('timestamp'))
    Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)
    # 完成日志记录
    logger.warning('%s订单支付成功' % out_trade_no)
    return Response('success')
    else:
    logger.error('%s订单支付失败' % out_trade_no)
    except:
    pass
    return Response('failed')

     

    4 阿里云服务器购买

    1 内网穿透
    -花钱的花生壳
    -免费的。。。
    -ngrok.exe http 8000
    -生成一个域名,访问域名就能访问到你的本地的8000
    -自己写
    2 项目调整
    -前端
    -后端
    -nginx+uwsgi+django
    -uwsgi不能获取静态资源
    -动静分离
    3 宝塔
    -python2+django写了一个项目

    3 购买服务器
    -使用ssh连接(xshell,finallshell。。。)
    -http://www.hostbuf.com/t/988.html
    -ssh root@地址 # 输入密码即可

    4 上传前端项目的命令
    -cd /
    -mkdir soft
    -cd soft
    -yum install lrzsz -y # 上传下载软件
    -从本地把前端项目拖到服务器 /soft
    -yum install unzip -y # 解压zip的软件
    -unzip dist.zip
    -看到前端项目解压了

    5 拉去后端项目
    -yum update -y
    -yum -y groupinstall "Development tools" # 包含了git
    -yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel psmisc libffi-devel
    -git clone https://gitee.com/liuqingzheng/luffy_api_s16.git
    -在soft路径下,移动到 /soft/project/luffyapi
    -mv luffy_api_s16 project/luffyapi
    -到小luffyapi文件夹下创建static文件夹
    -mkdir static

     

    5 安装mysql

    # 下载rpm包
    wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm

    # 安装mysql57
    yum -y install mysql57-community-release-el7-10.noarch.rpm
    yum -y install mysql-community-server

    # 3 启动mysql57并查看启动状态
    systemctl start mysqld # 启动mysql服务端
    systemctl status mysqld # 查看mysqld的状态

    # 4查看默认密码并登录
    grep "password" /var/log/mysqld.log
    mysql -uroot -p
    # 5 修改密码: ,Uhfd*<;f3hp
    # 修改root用户密码为 lqz123?
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'Lqz12345?';

     

    6 安装redis

    # 下载redis-5.0.5源码包
    wget http://download.redis.io/releases/redis-5.0.5.tar.gz

    # 解压
    tar -xf redis-5.0.5.tar.gz

    # 进入目标文件
    cd redis-5.0.5

    # 编译源码
    make

    # 复制环境到指定路径完成安装
    cp -r redis-5.0.5 /usr/local/redis

    # 配置redis可以后台启动:修改下方内容(你不加也可以)
    vim /usr/local/redis/redis.conf

    daemonize yes

    # 完成配置修改
    esc
    :wq

    # 建立软连接
    ln -s /usr/local/redis/src/redis-server /usr/bin/redis-server
    ln -s /usr/local/redis/src/redis-cli /usr/bin/redis-cli

    # 后台运行redis
    >: cd /usr/local/redis
    >: redis-server ./redis.conf

    # 客户端连接测试redis环境
    >: redis-cli
    ctrl + c

    # 关闭redis服务
    >: pkill -f redis -9

     

    7 安装python(centos 7.9 可以不装了)

    # 下载  Python3.6.7
    wget https://www.python.org/ftp/python/3.6.7/Python-3.6.7.tar.xz

    # 解压安装包
    tar -xf Python-3.6.7.tar.xz

    # 进入目标文件
    cd Python-3.6.7

    # 配置安装路径:/usr/local/python3
    ./configure --prefix=/usr/local/python3

    # 编译并安装
    make && make install

    # 建立软连接:终端命令 python3,pip3
    ln -s /usr/local/python3/bin/python3.6 /usr/bin/python3.6.7
    ln -s /usr/local/python3/bin/pip3.6 /usr/bin/pip3.6.7

    # 删除安装包与文件:
    rm -rf Python-3.6.7
    rm -rf Python-3.6.7.tar.xz

    # centos 7.9默认自带3.6

     

    8 安装虚拟环境

    1 pip源的修改,如果是阿里云,就不用了
    2 安装uwsgi
    pip3.6.7 install uwsgi
    ln -s /usr/local/python3/bin/uwsgi /usr/bin/uwsgi
    ps aux|grep 进程名 # 查看进程


    # 安装依赖
    pip3.6.7 install virtualenv
    pip3.6.7 install virtualenvwrapper

    # 建立虚拟环境软连接
    ln -s /usr/local/python3/bin/virtualenv /usr/bin/virtualenv

    # 配置虚拟环境:填入下方内容(用户环境变量,root)
    vim /root/.bash_profile
    # vim ~/.bash_profile
    VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3.6.7
    source /usr/local/python3/bin/virtualenvwrapper.sh

    # 退出编辑状态
    esc

    # 保存修改并退出
    :wq

    # 更新配置文件内容
    source ~/.bash_profile

    # 虚拟环境默认根目录:~/.virtualenvs
    # 创建虚拟环境
    mkvirtualenv luffy # 创建路飞虚拟环境
    deactivate # 退出虚拟环境
    workon # 列出所有虚拟环境
    workon luffy # 进入到路飞虚拟环境

     

    9 安装Nginx


    # 下载nginx1.13.7
    wget http://nginx.org/download/nginx-1.13.7.tar.gz

    # 解压安装包
    tar -xf nginx-1.13.7.tar.gz

    # 进入目标文件
    cd nginx-1.13.7

    # 配置安装路径:/usr/local/nginx
    ./configure --prefix=/usr/local/nginx

    # 编译并安装
    make && make install

    # 建立软连接:终端命令 nginx
    ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx

    # 删除安装包与文件:
    >: cd ~
    >: rm -rf nginx-1.13.7
    >: rm -rf nginx-1.13.7.tar.xz

    # 测试Nginx环境,服务器运行nginx,本地访问服务器ip
    nginx
    服务器绑定的域名 或 ip:80

    # 相关命令
    启动
    nginx

    关闭nginx
    nginx -s stop

    重启nginx
    nginx -s reload

    查看端口,强行关闭
    ps -aux|grep nginx
    kill <pid:进程编号>

     

    10 前端部署

    # 配置nginx配置文件(访问80端口,直接返回前端页面)
    cd /usr/local/nginx/conf
    mv nginx.conf nginx.conf.bak
    vim nginx.conf

    events {
    worker_connections 1024;
    }
    http {
    include mime.types;
    default_type application/octet-stream;
    sendfile on;
    server {
    listen 80;
    server_name 127.0.0.1; # 改为自己的域名,没域名修改为127.0.0.1:80
    charset utf-8;
    location / {
    root /soft/dist; # html访问路径
    index index.html; # html文件名称
    try_files $uri $uri/ /index.html; # 解决单页面应用刷新404问题
    }
    }
    }

    # 保存退出

    # 重启nginx
    nginx -s reload

     

    11 后端部署

    #1  进入到后端项目的路径
    #2 把当前代码更新到最新
    git pull origin master
    #3 进入虚拟环境
    workon luffy
    #4 安装依赖
    pip install -r requirements.txt
    #5 如果装mysqlclient报错
    yum install mysql-devel
    yum install python-devel
    #yum install python36-devel
    pip install mysqlclient

    #6 虚拟环境中也要装uwsgi
    pip install uwsgi

    # 7 使用uwsgi跑django项目(写一个uwsgi的配置文件),项目根路径下
    vim luffyai.xml

    <uwsgi>
    <socket>127.0.0.1:8080</socket>
    <chdir>/soft/project/luffyapi/</chdir>
    <module>luffyapi.wsgi</module>
    <processes>4</processes>
    <daemonize>uwsgi.log</daemonize>
    </uwsgi>

    # 8 配置nginx 转发动态请求
    vim /usr/local/nginx/conf/nginx.conf
    server {
    listen 8000;
    server_name 127.0.0.1;
    charset utf-8;
    location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:8080;
    uwsgi_param UWSGI_SCRIPT luffyapi.wsgi;
    uwsgi_param UWSGI_CHDIR /soft/project/luffyapi/;
    }
    }

    # 数据库设置(创建用户,创建库,迁移数据)
    mysql -uroot -p
    # 创建库
    create database luffy default charset=utf8;

    # 创建用户,授权
    grant all privileges on luffy.* to 'luffy'@'%' identified by 'Luffy123?';
    grant all privileges on luffy.* to 'luffy'@'localhost' identified by 'Luffy123?';
    flush privileges;

    # 退出mysql
    >: quit;

    # 表迁移
    # 必须在luffy环境下
    python manage_pro.py makemigrations
    python manage_pro.py migrate

    python manage_pro.py createsuperuser
    # 亚洲上海,在windows上没问题,linux上 Shanghai 必须大写
    # 收集静态文件的配置,必须在迁移后在解开

    # 把之前的数据导入(把之前的数据导入)

    # 启动uwsgi,重启nginx
    nginx -s reload
    uwsgi -x luffy.xml

    # 收集静态文件(取消配置文件中的static的配置--最后一行)
    python manage_pro.py collectstatic
    # 使用nginx 转发静态文件(动静分离)
    # 动态请求---》uwsgi
    # 静态请求---》直接取拿静态文件
    vim /usr/local/nginx/conf/nginx.conf

    location /static {
    alias /soft/project/luffyapi/luffyapi/static;
    }

    nginx -s reload

    # 后台管理的地址是
    http://101.133.166.126:8000/admin/
  • 相关阅读:
    iTerm2分屏快捷键
    k8s中运维/测试常用的命令整理(随时更新)
    httpRunner自动化测试用例使用笔记
    Git学习笔记-快速上手(mac系统)
    RBAC权限控制逻辑笔记
    CPS中有关CICD的配置
    LDAP中filter的使用
    Docker初级入门
    C语言 实现 HashTable
    从三个线程 排队打印 , 到 多个线程打印
  • 原文地址:https://www.cnblogs.com/DEJAVU888/p/14894017.html
Copyright © 2011-2022 走看看