路飛學城先後端分離項目2

 路飛學城先後端分離項目2

推薦課程的開發

需求:前端

  咱們在點擊推薦課程的時候,會有該推薦課程的詳細頁面vue

思路:python

   爲每個推薦課程標籤添加事件,從新向後臺請求數據加載頁面,可是url不會發生改變jquery

  使用router-link,由於都在在detail路由中,頁面不會從新加載,因此只要url改變,頁面不改變ios

須要說明的是,vue跟jquery不一樣,由於vue是單頁面,全部他作的只是頁面組件的重建與銷燬vuex

如若你只是改變路由的話,那麼頁面不會有變化.npm

若是你只是改變組件那麼路由不會發生變化.django

咱們開發的時候須要兩個一塊兒改變json

<template>
  <div>
    <h1>課程詳細頁面</h1>
    <div>
      <p>{{detail.course}}</p>
      <p>{{detail.img}}</p>
      <p>{{detail.level}}</p>
      <p>{{detail.slogon}}</p>
      <p>{{detail.title}}</p>
      <p>{{detail.why}}</p>
      <div>
        <ul v-for="item in detail.chapter">
          <li>{{item.name}}</li>
        </ul>
      </div>

      <div>
        <h3>推薦課程</h3>
        <ul v-for="item in detail.recommends">
          <!--<li><router-link :to="{name:'detail',params:{id:item.id}}">{{item.title}}</router-link></li>-->
          <li @click="changeDetail(item.id)">{{item.title}}</li>
        </ul>
      </div>

    </div>
  </div>
</template>

<script>
  export default {
    name: "index",
    data() {
      return {
        detail:{
          course:null,
          img:null,
          level:null,
          slogon:null,
          title:null,
          why:null,
          chapter:[],
          recommends:[],
        }
      }
    },
    mounted(){
      var id = this.$route.params.id
      this.initDetail(id)
    },
    methods:{
      initDetail(nid){
        var that = this
        this.$axios.request({
          url:'http://127.0.0.1:8000/api/v1/course/'+ nid +'/',
          method:'GET'
        }).then(function (arg) {
          if(arg.data.code === 1000){
            that.detail = arg.data.data
          }else{
            alert(arg.data.error)
          }
        })
      },
      changeDetail(id){
        this.initDetail(id)
        this.$router.push({name:'detail',params:{id:id}})
      }
    }
  }
</script>

<style scoped>

</style>

 vue中跳轉路徑方法補充:axios

this.$router.push({name:'detail',params:{id:id}})

 用戶登陸

需求:

  •   實現用戶的登陸並放置vue-cookies中
  •   而且隨機生成token,訪問須要登陸的頁面都帶着token值

思路:

  •  用戶登陸的時候先在前端獲取用戶名密碼、若是有token值,生成token,若是沒有則建立
  •    將token值和nikname返回給前端
  •    前端在vue-cookies保存token值和nikname做持久化,
  •    登陸成功則顯示nikname和註銷

前端登陸頁面

Login.vue

<template>
  <div>
    <h1>用戶登陸</h1>
    <div>
      <p>
        <input type="text" placeholder="請輸入用戶名" v-model="username">
      </p>
      <p>
        <input type="password" placeholder="請輸入密碼"  v-model="password">
      </p>
      <input type="button" value="登陸" @click="doLogin">
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        username:'',
        password:''
      }
    },
    methods:{
      doLogin(){
        var that = this
        this.$axios.request({
          url:'http://127.0.0.1:8000/api/v1/auth/',
          method:'POST',
          data:{
            user:this.username,
            pwd:this.password
          },
          headers:{
            'Content-Type':'application/json',
          }
        }).then(function (arg) {
          if (arg.data.code === 1000){
            that.$store.commit('saveToken',{token:arg.data.token,username:that.username})
          }else{
            alert(arg.data.error)
          }
        }).catch(function (arg) {
          console.log('發生錯誤')
        })
      }
    }
  }
</script>

<style scoped>

</style>

 store目錄下的store.vue

import Vue from 'vue'
import Vuex from 'vuex'
import Cookie from 'vue-cookies'

Vue.use(Vuex)

export default new Vuex.Store({
  // 組件中經過 this.$store.state.username 調用
  state: {
    username: Cookie.get("username"),  #store每次都從cookie中取值
    token:Cookie.get("token"),
  },
  mutations: {
    // 組件中經過 this.$store.commit(saveToken,參數)  調用
    saveToken: function (state, userToken) {
      state.username = userToken.username;
      state.token = userToken.token;
      Cookie.set("username", userToken.username, "20min")
      Cookie.set("token", userToken.token, "20min")

    },
    clearToken: function (state) {
      state.username = null
      state.token = null
      Cookie.remove('username')
      Cookie.remove('token')

    }
  }
})

 在store中,使用vue設置全局變量,vue-cookies保存全局變量,使其刷新後仍然存在於vue-cookies中

vuex全局變量的用法

一、建立store.js

二、main.js中   

import store from './store/store'
放到實例化裏邊

 組建中能夠經過this.$store.state.username調用

vue-cookies的下載和使用

下載

npm install vue-cookis --save

使用:

若是登陸成功,調用store的mutations方法:

關於向後臺發送數據的簡單請求和複雜請求

條件:
一、請求方式:HEAD、GET、POST
二、請求頭信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 對應的值是如下三個中的任意一個
application/x-www-form-urlencoded
multipart/form-data
text/plain

注意:同時知足以上兩個條件時,則是簡單請求,不然爲複雜請求

複雜請求處理

若是是複雜請求,那麼就會先發一個options請求到服務裏進行'預檢'

詢問服務器是否容許我用post請求進行訪問.若是是options請求過來後,

給他加上一個特殊的請求頭,那麼就能夠經過了

class CORSMiddleware(MiddlewareMixin):

    def process_response(self,request,response):
        # 添加響應頭

        # 容許你的域名來獲取個人數據
        # response['Access-Control-Allow-Origin'] = "*"

        # 容許你攜帶Content-Type請求頭
        # response['Access-Control-Allow-Headers'] = "Content-Type"

        # 容許你發送DELETE,PUT
        # response['Access-Control-Allow-Methods'] = "DELETE,PUT"
        response['Access-Control-Allow-Origin'] = "*"

        if request.method == "OPTIONS":
            response['Access-Control-Allow-Headers'] = "Content-Type"
            response['Access-Control-Allow-Methods'] = "PUT,DELETE"

        return response

 使用中間件爲每次請求添加響應頭

後端登陸操做

models.py中

 

class UserInfo(models.Model):
    '''用戶表'''
    username=models.CharField(verbose_name='用戶名',max_length=32)
    password=models.CharField(verbose_name='密碼',max_length=64)
    nikname=models.CharField(max_length=32,verbose_name='暱稱')
    def __str__(self):
        return self.nikname

class Token(models.Model):
    user=models.OneToOneField('UserInfo',on_delete=models.CASCADE,verbose_name='用戶')
    token=models.CharField(max_length=128)

    def __str__(self):
        return self.user

 

 url.py

url(r'^auth/$', account.AuthView.as_view()),

 view.py中

from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import HttpResponse
from api import models
import uuid


class AuthView(APIView): def post(self,request,*args,**kwargs): """ 用戶登陸認證 :param request: :param args: :param kwargs: :return: """ ret = {'code':1000} user = request.data.get('user') pwd = request.data.get('pwd') user = models.UserInfo.objects.filter(user=user,pwd=pwd).first() if not user: ret['code'] = 1001 ret['error'] = '用戶名或密碼錯誤' else: uid = str(uuid.uuid4()) models.UserToken.objects.update_or_create(user=user,defaults={'token':uid}) ret['token'] = uid return Response(ret)

 vue-攔截器

用攔截器實現的功能:

  在須要登陸才能訪問的頁面,若是未登陸訪問就攔截下來,跳轉到登陸頁面

 

登陸成功後再跳到訪問的頁面

一、在路徑中添加   meta

 {
      path: '/news',
      name: 'news',
      component: News,
      meta:{
        requireAuth:true
      }
    },

 二、main.js中

router.beforeEach(function (to, from, next) {
  if(to.meta.requireAuth){
    // 要去的url只有登錄成功後才能訪問
    if (store.state.token) {
      next() #next表示去訪問,原本是去哪訪問就去哪訪問
    } else {
      next({name: 'login',query: {backUrl: to.fullPath}})
    }
  }else{
    next()
  }
})

 三、login中作判斷,跳轉url

 }).then(function (arg) {
          if (arg.data.code === 1000){
            that.$store.commit('saveToken',{token:arg.data.token,username:that.username})

            var url = that.$route.query.backUrl
            if(url){
              that.$router.push({path:url})
            }else{
              that.$router.push({path:'/index'})
            }

 後端認證

 

用戶獲取到後端接口,直接不登陸訪問後端的接口,

 

若是後端沒有認證的話,那麼接口的內容就會被暴露

Micro.vue

 

<template>
  <div>
    <h1>LuffyX學位:{{title}}</h1>

  </div>
</template>

<script>
  export default {
    name: "index",
    data() {
      return {
        title:null
      }
    },
    mounted(){
      this.initMicro()
    },
    methods:{
      initMicro(){
        var that = this
        this.$axios.request({
          url:'http://127.0.0.1:8000/api/v1/micro/',
          method:'GET',
          params:{
            token:this.$store.state.token
          }
        }).then(function (arg) {
          if(arg.data.code === 1000){
            that.title = arg.data.title
          }
        })

      }
    }
  }
</script>

<style scoped>

</style>

 

 url.py

 url(r'^micro/$', course.MicroView.as_view()),

 auth認證

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from api import models

class LuffyAuth(BaseAuthentication):

    def authenticate(self, request):
        token = request.query_params.get('token')
        obj = models.UserToken.objects.filter(token=token).first()
        if not obj:
            raise AuthenticationFailed({'code':1001,'error':'認證失敗'})
        return (obj.user.user,obj)

 view.py中使用

class MicroView(APIView):
    authentication_classes = [LuffyAuth,]

    def get(self,request,*args,**kwargs):
        ret = {'code':1000,'title':'微職位'}
        return Response(ret)

 API的統一存放

當你寫了不少API後,你就會發現你本身不知道寫了哪些路由,

那麼若是有人問你要接口的時候你可能會找好久.那麼咱們將api的路由

統一放到vue的store裏

  放在api的store裏有什麼好處?

  • 查找的時候變的方便,只要在store裏查找就能夠
  • 發送axios請求的時候能夠在store裏獲取
const store = new Vuex.Store({
  state: {
    apiList:{
     Course:'http://127.0.0.1:8000/api/v2/course/',
      CourseDetail:'http://127.0.0.1:8000/api/v2/course/',
      Login:'http://127.0.0.1:8000/api/v2/login/',
      Micro:'http://127.0.0.1:8000/api/v2/micro/',

    }

  },

 

相關文章
相關標籤/搜索