1. 程式人生 > >手摸手,帶你用vue擼後臺 系列二(登入許可權篇)

手摸手,帶你用vue擼後臺 系列二(登入許可權篇)

前言

拖更有點嚴重,過了半個月才寫了第二篇教程。無奈自己是一個業務猿,每天被我司的產品虐的死去活來,之前又病了一下休息了幾天,大家見諒。

進入正題,做後臺專案區別於做其它的專案,許可權驗證與安全性是非常重要的,可以說是一個後臺專案一開始就必須考慮和搭建的基礎核心功能。我們所要做到的是:不同的許可權對應著不同的路由,同時側邊欄也需根據不同的許可權,非同步生成。這裡先簡單說一下,我實現登入和許可權驗證的思路。

  • 登入:當用戶填寫完賬號和密碼後向服務端驗證是否正確,驗證通過之後,服務端會返回一個token,拿到token之後(我會將這個token存貯到cookie中,保證重新整理頁面後能記住使用者登入狀態),前端會根據token再去拉取一個user_info的介面來獲取使用者的詳細資訊(如使用者許可權,使用者名稱等等資訊)。

  • 許可權驗證:通過token獲取使用者的role,動態根據使用者的role算出其相應有許可權的路由,通過router.addRoutes動態掛載路由。

上述所有的資料和操作都是通過vuex全域性管理控制的。接下來,我們一起手摸手一步一步實現這個系統。

登入篇

首先我們不管什麼許可權,來實現最基礎的登入功能。

隨便找一個空白頁面擼上兩個input的框,一個是登入賬號,一個是登入密碼。再放置一個登入按鈕。我們將登入按鈕上綁上click事件,點選登入之後向服務端提交賬號和密碼進行驗證。
這就是一個最簡單的登入頁面。如果你覺得還要寫的更加完美點,你可以在向服務端提交之前對賬號和密碼做一次簡單的校驗。

詳細程式碼

click事件觸發登入操作

this.$store.dispatch('LoginByEmail', this.loginForm).then(() => {
  this.$router.push({ path: '/' }); //登入成功之後重定向到首頁
}).catch(err => {
  this.$message.error(err); //登入失敗提示錯誤
});

action

LoginByEmail({ commit }, userInfo) {
  const email = userInfo.email.trim();
  return new Promise
((resolve, reject) => { loginByEmail(email, userInfo.password).then(response => { const data = response.data; Cookies.set('Token', response.data.token); //登入成功後將token儲存在cookie之中 commit('SET_TOKEN', data.token); commit('SET_EMAIL', email); resolve(); }).catch(error => { reject(error); }); }); }

登入成功後,服務端會返回一個token(該token的是一個能唯一標示使用者身份的一個key),之後我們將token儲存在本地cookie之中,這樣下次開啟頁面或者重新整理頁面的時候能記住使用者的登入住在那臺,不用再去登入頁面重新登入了。

ps:為了保證安全性,我司現在後臺所有token有效期(Expires/Max-Age)都是Session,就是當瀏覽器關閉了就丟失了。重新開啟遊覽器都需要重新登入驗證,後端也會在每週固定一個時間點重新重新整理token,讓後臺使用者全部重新登入一次,確保後臺使用者不會因為電腦遺失或者其它原因被人隨意使用賬號。

獲取使用者資訊

使用者登入成功之後,我們會在全域性鉤子router.beforeEach中攔截路由,判斷是否已獲得token,在獲得token之後我們就要去獲取使用者的基本資訊了

//router.beforeEach
if (store.getters.roles.length === 0) { // 判斷當前使用者是否已拉取完user_info資訊
  store.dispatch('GetInfo').then(res => { // 拉取user_info
    const roles = res.data.role;
    next();//resolve 鉤子
  })

就如前面所說的,我只在本地儲存了一個使用者的token,並沒有儲存別的使用者資訊(如使用者許可權,使用者名稱等)。有些人問過為什麼不把一些其它的使用者資訊也存一下?主要出於如下的考慮:
假設我把使用者許可權和名字也存在了本地,但我這時候用另一臺電腦登入修改了自己的使用者名稱,之後再用這臺存有之前使用者資訊的電腦登入,它預設會去讀取本地cookie的名字,並不會去拉去新的使用者資訊。所以現在的策略是頁面會先從cookie中檢視是否存有token,沒有,就走一遍上一部分的流程重新登入,如果有token,就會去拉取user_info,保證使用者資訊是最新的。
當然如果是做了單點登入得功能的話,使用者資訊儲存在本地也是可以的。但你一臺電腦登入時,另一臺會被提下線,所以總會重新登入獲取最新的內容。

但從程式碼層面我建議還是把login和get_user_info兩件事分開比較好,在這個後端全面微服務的年代,後端同學也想寫優雅的程式碼~

許可權篇

先說一說我許可權控制的主體思路,前端會有一份路由表,它表示了每一個路由可訪問的許可權。當用戶登入之後,通過token獲取使用者的role,動態根據使用者的role算出其相應有許可權的路由,再通過router.addRoutes動態掛載路由。但這些控制都只是頁面級的,說白了前端再怎麼做許可權控制都不是絕對安全的,後端的許可權驗證是逃不掉的。
我司現在就是前端來控制頁面級的許可權,不同許可權的使用者顯示不同的側邊欄和能進入不同的頁面(也做了少許按鈕級別的許可權控制),後端則會驗證每一個涉及請求的操作,驗證其是否有該操作的許可權,每一個後臺的請求不管是get還是post都會讓前端在請求header裡面攜帶使用者的token,後端會根據該token來驗證使用者是否有許可權執行該操作。

許可權前端or後端來控制?

有很多人表示他們公司的路由表是於後端根據使用者的許可權動態生成的,我司不採取這種方式的原因如下:

  • 專案不斷的迭代你會異常痛苦,前端新開發一個頁面還要讓後端配一下路由和許可權,讓我們想了曾經前後端不分離,被後端支配的那段恐怖時間了。

  • 其次,就拿我司的業務來說,雖然後端的確也是有許可權驗證的,但它的驗證其實是針對業務來劃分的,比如超級編輯可以釋出文章,而實習編輯只能編輯文章不能釋出,但對於前端來說不管是超級編輯還是實習編輯都是有許可權進入文章編輯頁面的。所以前端和後端許可權的劃分是不太一致。

  • 還有一點是就vue2.2.0之前非同步掛載路由是很麻煩的一件事!不過好在官方也出了新的api,雖然本意是來解決ssr的痛點的。。。

addRoutes

在之前通過後端動態返回前端路由一直很難做的,因為vue-router必須是要vue在例項化之前就掛載上去的,不太方便動態改變。不過好在vue2.2.0以後新增了router.addRoutes

Dynamically add more routes to the router. The argument must be an Array using the same route config format with the routes constructor option.

有了這個我們就可相對方便的做許可權控制了。(樓主之前在許可權控制也走了不少歪路,可以在專案的commit記錄中看到,重構了很多次,最早沒用addRoute整個許可權控制程式碼裡都是各種if/else的邏輯判斷,程式碼相當的耦合和複雜)

具體實現

1.建立vue例項的時候將vue-router掛載,但這個時候vue-router掛載一些登入或者不用許可權的公用的頁面。
2.當用戶登入後,獲取用role,將role和路由表每個頁面的需要的許可權作比較,生成終端使用者可訪問的路由表。
3.呼叫router.addRoutes(store.getters.addRouters)新增使用者可訪問的路由。
4.使用vuex管理路由表,根據vuex中可訪問的路由渲染側邊欄元件。

router.js

首先我們實現router.js路由表,這裡就拿前端控制路由來舉例(後端的也差不多,稍微改造一下就好了)

// router.js
import Vue from 'vue';
import Router from 'vue-router';

import Login from '../views/login/';
const dashboard = resolve => require(['../views/dashboard/index'], resolve);
//使用了vue-routerd的[Lazy Loading Routes
](https://router.vuejs.org/en/advanced/lazy-loading.html)

//所有許可權通用路由表 
//如首頁和登入頁和一些不用許可權的公用頁面
export const constantRouterMap = [
  { path: '/login', component: Login, hidden: true //hidden為自定義屬性,側邊欄那章會纖細解釋},
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    name: '首頁',
    children: [{ path: 'dashboard', component: dashboard }]
  },
]

//例項化vue的時候只掛載constantRouter
export default new Router({
  routes: constantRouterMap
});

//非同步掛載的路由
//動態需要根據許可權載入的路由表 
export const asyncRouterMap = [
  {
    path: '/permission',
    component: Layout,
    redirect: '/permission/index',
    name: '許可權測試',
    meta: { role: ['admin','super_editor'] }, //頁面需要的許可權
    children: [
    { 
        path: 'index',
        component: Permission,
        name: '許可權測試頁',
        meta: { role: ['admin','super_editor'] }  //頁面需要的許可權
    }]
  },
  { path: '*', redirect: '/404', hidden: true }
];

這裡我們根據vue-router官方推薦的方法通過meta標籤來標示改頁面能訪問的許可權有哪些。如meta: { role: ['admin','super_editor'] }表示該頁面只有admin和超級編輯才能有資格進入。
注意事項:這裡有一個需要非常注意的地方就是404頁面一定要最後載入,如果放在constantRouterMap一同聲明瞭404,後面的所以頁面都會被攔截到404,詳細的問題見addRoutes when you've got a wildcard route for 404s does not work

main.js

關鍵的main.js

// main.js
router.beforeEach((to, from, next) => {
  if (store.getters.token) { // 判斷是否有token
    if (to.path === '/login') {
      next({ path: '/' });
    } else {
      if (store.getters.roles.length === 0) { // 判斷當前使用者是否已拉取完user_info資訊
        store.dispatch('GetInfo').then(res => { // 拉取info
          const roles = res.data.role;
          store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可訪問的路由表
            router.addRoutes(store.getters.addRouters) // 動態新增可訪問路由表
            next(to.path); // hack方法 確保addRoutes已完成
          })
        }).catch(err => {
          console.log(err);
        });
      } else {
        next() //當有使用者許可權的時候,說明所有可訪問路由已生成 如訪問沒許可權的全面會自動進入404頁面
      }
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登入白名單,直接進入
      next();
    } else {
      next('/login'); // 否則全部重定向到登入頁
    }
  }
});

這裡的router.beforeEach也結合了上一章講的一些登入邏輯程式碼。


上面一張圖就是在使用addRoutes方法之前的許可權判斷,非常的繁瑣,因為我是把所有的路由都掛在了上去,所有我要各種判斷當前的使用者是否有許可權進入該頁面,各種if/else的巢狀,維護起來相當的困難。但現在有了addRoutes之後就非常的方便,我只掛載了使用者有許可權進入的頁面,沒許可權,路由自動幫我跳轉的404,省去了不少的判斷。

這裡還有一個小hack的地方,就是router.addRoutes之後的next()可能會失效,因為可能next()的時候路由並沒有完全add完成,好在查閱文件發現

next('/') or next({ path: '/' }): redirect to a different location. The current navigation will be aborted and a new one will be started.

這樣我們就可以簡單的通過next(to)巧妙的避開之前的那個問題了。

store/permission.js

就來就講一講GenerateRoutes Action

// store/permission.js
import { asyncRouterMap, constantRouterMap } from 'src/router';

function hasPermission(roles, route) {
  if (route.meta && route.meta.role) {
    return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    return true
  }
}

const permission = {
  state: {
    routers: constantRouterMap,
    addRouters: []
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers;
      state.routers = constantRouterMap.concat(routers);
    }
  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const { roles } = data;
        const accessedRouters = asyncRouterMap.filter(v => {
          if (roles.indexOf('admin') >= 0) return true;
          if (hasPermission(roles, v)) {
            if (v.children && v.children.length > 0) {
              v.children = v.children.filter(child => {
                if (hasPermission(roles, child)) {
                  return child
                }
                return false;
              });
              return v
            } else {
              return v
            }
          }
          return false;
        });
        commit('SET_ROUTERS', accessedRouters);
        resolve();
      })
    }
  }
};

export default permission;

這裡的程式碼說白了就是幹了一件事,通過使用者的許可權和之前在router.js裡面asyncRouterMap的每一個頁面所需要的許可權做匹配,最後返回一個該使用者能夠訪問路由有哪些。

側邊欄

最後一個涉及到許可權的地方就是側邊欄,不過在前面的基礎上已經很方便就能實現動態顯示側邊欄了。這裡側邊欄基於element-ui的NavMenu來實現的。

<template>
    <el-menu :unique-opened='true' mode="vertical" theme="dark" :default-active="$route.path">
        <template v-for="item in permission_routers" v-if="!item.hidden">
            <el-submenu :index="item.name" v-if="!item.noDropdown">
                <template slot="title">
                    <wscn-icon-svg :icon-class="item.icon||'wenzhang1'" /> {{item.name}}
                </template>
                <router-link v-for="child in item.children" :key="child.path" v-if="!child.hidden" class="title-link" :to="item.path+'/'+child.path">
                    <el-menu-item :index="item.path+'/'+child.path">
                        {{child.name}}
                    </el-menu-item>
                </router-link>
            </el-submenu>
            <router-link v-if="item.noDropdown&&item.children.length>0" :to="item.path+'/'+item.children[0].path">
                <el-menu-item :index="item.path+'/'+item.children[0].path">
                    <wscn-icon-svg :icon-class="item.icon||'geren1'" /> {{item.children[0].name}}
                </el-menu-item>
            </router-link>
        </template>
    </el-menu>
</template>
<script>
    import { mapGetters } from 'vuex';

    export default {
      name: 'Sidebar',
      computed: {
        ...mapGetters([
          'permission_routers'
        ])
      }
    }
</script>

說白了就是遍歷之前算出來的permission_routers,通過vuex拿到之後動態v-for渲染而已。不過這裡因為有一些業務需求所以加了很多判斷
比如我們在定義路由的時候會加很多引數

  • icon : the icon show in the sidebar

  • hidden : if hidden:true will not show in the sidebar

  • redirect : if redirect:noredirect will not redirct in the levelbar

  • noDropdown : if noDropdown:true will not has submenu

  • meta : { role: ['admin'] } will control the page role

這裡僅供參考,而且當前demo只支援兩級選單,如需要請大家自行改造,來打造滿足自己業務需求的側邊欄。

側邊欄高亮問題:很多人在群裡問為什麼自己的側邊欄不能跟著自己的路由高亮,其實很簡單,element-ui官方已經給了default-active所以我們只要

:default-active="$route.path"

default-active一直指向當前路由就可以了,就是這麼簡單

按鈕級別許可權控制

有很多人一直在問關於按鈕級別粒度的許可權控制怎麼做。我司現在是這樣的,真正需要按鈕級別控制的地方不是很多,現在是通過獲取到使用者的role之後,在前端用v-if手動判斷來區分不同許可權對應的按鈕的。理由前面也說了,我司顆粒度的許可權判斷是交給後端來做的,每個操作後端都會進行許可權判斷。而且我覺得其實前端真正需要按鈕級別判斷的地方不是很多,如果一個頁面有很多種不同許可權的按鈕,我覺得更多的應該是考慮產品層面是否設計合理。當然你強行說我想做按鈕級別的許可權控制,你也可以參照路由層面的做法,搞一個操作許可權表。。。但個人覺得有點多此一舉。

axios攔截器

這裡再說一說axios吧,雖然在上一篇系列文章中簡單介紹過,不過這裡還是要在嘮叨一下。如上文所說,我司服務端對每一個請求都會驗證許可權,所以這裡我們針對業務封裝了一下請求。首先我們通過request攔截器在每個請求頭裡面塞入token,好讓後端進行許可權驗證。並建立一個respone攔截器,當服務端返回特殊的狀態碼,我們統一做如沒許可權或者token失效的操作。

import axios from 'axios';
import { Message } from 'element-ui';
import store from '../store';
// import router from '../router';

// 建立axios例項
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 5000                  // 請求超時時間
});

// request攔截器
service.interceptors.request.use(config => {
  // Do something before request is sent
  if (store.getters.token) {
    config.headers['X-Token'] = store.getters.token; // 讓每個請求攜帶token--['X-Token']為自定義key 請根據實際情況自行修改
  }
  return config;
}, error => {
  // Do something with request error
  console.log(error); // for debug
  Promise.reject(error);
})

// respone攔截器
service.interceptors.response.use(
  response => response
  /**
  * 下面的註釋為通過response自定義code來標示請求狀態,當code返回如下情況為許可權有問題,登出並返回到登入頁
  * 如通過xmlhttprequest 狀態碼標識 邏輯可寫在下面error中
  */
  // const code = response.data.code;
  // // 50014:Token 過期了 50012:其他客戶端登入了 50008:非法的token
  // if (code === 50008 || code === 50014 || code === 50012) {
  //   Message({
  //     message: res.message,
  //     type: 'error',
  //     duration: 5 * 1000
  //   });
  //   // 登出
  //   store.dispatch('FedLogOut').then(() => {
  //     router.push({ path: '/login' })
  //   });
  // } else {
  //   return response
  // }
  ,
  error => {
    console.log('err' + error);// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 5 * 1000
    });
    return Promise.reject(error);
  }
)

export default service;

兩步驗證

文章一開始也說了,後臺的安全性是很重要的,簡簡單單的一個賬號+密碼的方式是很難保證安全性的。所以我司的後臺專案都是用了兩步驗證的方式,之前我們也嘗試過使用基於google-authenticator或者youbikey這樣的方式但難度和操作成本都比較大。後來還是準備藉助騰訊爸爸,這年代誰不用微信。。。安全性騰訊爸爸也幫我做好了保障。
樓主建議兩步驗證要支援多個渠道不要只微信或者QQ,前段時間QQ第三方登入就出了bug,官方兩三天才修好的,害我背了鍋/(ㄒoㄒ)/~~ 。

這裡的兩部驗證有點名不副實,其實就是賬號密碼驗證過之後還需要一個繫結的第三方平臺登入驗證而已。
寫起來也很簡單,在原有登入得邏輯上改造一下就好。

this.$store.dispatch('LoginByEmail', this.loginForm).then(() => {
  //this.$router.push({ path: '/' });
  //不重定向到首頁
  this.showDialog = true //彈出選擇第三方平臺的dialog
}).catch(err => {
  this.$message.error(err); //登入失敗提示錯誤
});

登入成功之後不直接跳到首頁而是讓使用者兩步登入,選擇登入得平臺。
接下來就是所有第三方登入一樣的地方通過OAuth2.0授權。這個各大平臺大同小異,大家自行查閱文件,不展開了,就說一個微信授權比較坑的地方。注意你連引數的順序都不能換,不然會驗證不通過。具體程式碼,同時我也封裝了openWindow方法大家自行看吧。
當第三方授權成功之後都會跳到一個你之前有一個傳入redirect——uri的頁面

如微信還必須是你授權賬號的一級域名。所以你授權的域名是vue-element-admin.com,你就必須重定向到vue-element-admin.com/xxx/下面,所以你需要寫一個重定向的服務,如vue-element-admin.com/auth/redirect?a.com 跳到該頁面時會再次重定向給a.com。

所以我們後臺也需要開一個authredirect頁面:程式碼。他的作用是第三方登入成功之後會預設跳到授權的頁面,授權的頁面會再次重定向回我們的後臺,由於是spa,改變路由的體驗不好,我們通過window.opener.location.href的方式改變hash,在login.js裡面再監聽hash的變化。當hash變化時,獲取之前第三方登入成功返回的code與第一步賬號密碼登入之後返回的uid一同傳送給服務端驗證是否正確,如果正確,這時候就是真正的登入成功。

 created() {
     window.addEventListener('hashchange', this.afterQRScan);
   },
   destroyed() {
     window.removeEventListener('hashchange', this.afterQRScan);
   },
   afterQRScan() {
     const hash = window.location.hash.slice(1);
     const hashObj = getQueryObject(hash);
     const originUrl = window.location.origin;
     history.replaceState({}, '', originUrl);
     const codeMap = {
       wechat: 'code',
       tencent: 'code'
     };
     const codeName = hashObj[codeMap[this.auth_type]];
     this.$store.dispatch('LoginByThirdparty', codeName).then(() => {
       this.$router.push({
         path: '/'
       });
     });
   }

到這裡涉及登入許可權的東西也差不多講完了,這裡樓主只是給了大家一個實現的思路(都是樓主不斷摸索的血淚史),每個公司實現的方案都有些出入,請大家結合自己實際需求來一起擼一個後臺吧~

佔坑

常規佔坑,這裡是手摸手,帶你用vue擼後臺系類
完整專案地址:vue-element-admin
系類文章一:手摸手,帶你用vue擼後臺 系列一(基礎篇)
系類文章三:手摸手,帶你用vue擼後臺 系列三(實戰篇)
相應廣大需求 建了一個qq群 591724180 方便大家交流
下一次開始會講一些實際元件的使用方法和element-ui的一些心得。

相關推薦

vue後臺 系列(登入許可權)

前言 拖更有點嚴重,過了半個月才寫了第二篇教程。無奈自己是一個業務猿,每天被我司的產品虐的死去活來,之前又病了一下休息了幾天,大家見諒。 進入正題,做後臺專案區別於做其它的專案,許可權驗證與安全性是非常重要的,可以說是一個後臺專案一開始就必須考慮和搭建的基礎核心功能

【轉】vue後臺 系列(登錄權限)

userinfo ogr abort 變化 再次 狀態碼 quest -o 監聽 前言 拖更有點嚴重,過了半個月才寫了第二篇教程。無奈自己是一個業務猿,每天被我司的產品虐的死去活來,之前又病了一下休息了幾天,大家見諒。 進入正題,做後臺項目區別於做其它的項目,權限驗證與

vue實現後臺管理許可權系統及頂欄三級選單顯示

手摸手,帶你用vue實現後臺管理許可權系統及頂欄三級選單顯示 效果演示地址 專案demo展示 重要功能總結 許可權功能的實現 許可權路由思路: 根據使用者登入的roles資訊與路由中配置的roles資訊進行比較過濾,生成可以訪問的路由表,並通過router.addRoutes(store.gett

Hexo部落格()之配置主題

[原文地址](https://blog.limeichao.cn/article/fdc79fa4.html) 在上一篇部落格[手摸手帶你用Hexo擼部落格(一)](https://www.cnblogs.com/big0range/p/14204956.html)中主要介紹了部落格的初步搭建 今天我們繼續講

合理的姿勢使用 webpack 4(上)

(點選上方公眾號,可快速關注)作者:華爾街見聞技術團隊 - 花褲衩segmentfault.co

Hexo部落格(三)之新增評論系統

[原文地址](https://boke.limeichao.cn/article/7885e224.html) 注: 筆者採用的是butterfly主題, 主題內建整合評論系統 ## butterfly主題開啟評論 開啟評論需要在comments-use中填寫你需要的評論。 以Valine為例 ``

手把手從無到有vue進行專案實戰 系列(cdn、gzip效能加速

相關連結: 一、前言 在系列一中桃子叔叔介紹了使用iview-cli構建專案框架並基於框架進行的相關改造,主要包括: 路徑規範 dev-server配置 啟用熱更新 封裝axios 解決跨域 二、問題 經過以上的改造,已經能夠滿足基本生產開發的需求了

寫Struts深入原始碼中心解析

個人剖析,不喜勿噴 掃碼關注公眾號,不定期更新干活 在此申明本博文並非原創,原文:http://blog.csdn.net/lenotang/article/details/3336623,本文章是在此文章基礎上進行優化。也談不上優化,只是加上了點自己的想法 jar包準備 為什麼會用到這兩個j

golang--深入簡出golang的反射一個公用後臺查詢方法

一些基本方法 本篇不會介紹反射的基本概念和原理等,會從每個常用的方法入手,講解一些基本和進階用法,反射不太適合在業務層使用,因為會幾何倍的降低執行速度,而且用反射做出來的程式健壯度不高,一旦一個環節沒有處理好就會直接panic,影響程式的執行,但是在後臺上使用還是很適合的,可以極大的降低程式碼量,從繁複的增刪

Android檢視繪製流程完全解析一步步深入瞭解View()

在上一篇文章中,我帶著大家一起剖析了一下LayoutInflater的工作原理,可以算是對View進行深入瞭解的第一步吧。那麼本篇文章中,我們將繼續對View進行深入探究,看一看它的繪製流程到底是什麼樣的。如果你還沒有看過我的上一篇文章,可以先去閱讀 Android Layo

搭建前後端分離商城系統】02 VUE-CLI 腳手架生成基本專案axios配置請求、解決跨域問題

## 【手摸手,帶你搭建前後端分離商城系統】02 VUE-CLI 腳手架生成基本專案,axios配置請求、解決跨域問題。 回顧一下上一節我們學習到的內容。已經將一個 `usm_admin 後臺使用者` 表的基本增刪改查全部都完成了。並且通過`swagger` 測試了我們的介面資訊,並且順利通過測試。本節將通

實現程式碼自動部署

為什麼? 為什麼要實現自動部署? 在2個月的時間裡,一直都在忙著整理部落格,每一個程式設計師都有一個部落格夢(當然也不排除有些是沒有的),我先後使用過各種部落格系統: vuepress react-static jekyll hexo ... 這些都因為前前後後的原因,

圖解AQS的設計與實現實現一把互斥鎖!

AQS是併發程式設計中非常重要的概念,它是juc包下的許多併發工具類,如CountdownLatch,CyclicBarrier,Semaphore 和鎖, 如ReentrantLock, ReaderWriterLock的實現基礎,提供了一個基於int狀態碼和佇列來實現的併發框架。本文將對AQS框架的幾個重

淺談Java中的Condition條件佇列實現一個阻塞佇列!

條件佇列是什麼?可能很多人和我一樣答不出來,不過今天終於搞清楚了! 什麼是條件佇列 條件佇列:當某個執行緒呼叫了wait方法,或者通過Condition物件呼叫了await相關方法,執行緒就會進入阻塞狀態,並加入到對應條件佇列中。 在等待喚醒機制相關文章中我們提到了條件佇列,即當物件獲取到同步鎖之後,如果呼叫

理解Vue響應式原理

## 前言 響應式原理作為 `Vue` 的核心,使用資料劫持實現資料驅動檢視。在面試中是經常考查的知識點,也是面試加分項。 本文將會循序漸進的解析響應式原理的工作流程,主要以下面結構進行: 1. 分析主要成員,瞭解它們有助於理解流程 2. 將流程拆分,理解其中的作用 3. 結合以上的點,理解整體流程

理解Vue的Computed原理

## 前言 `computed` 在 `Vue` 中是很常用的屬性配置,它能夠隨著依賴屬性的變化而變化,為我們帶來很大便利。那麼本文就來帶大家全面理解 `computed` 的內部原理以及工作流程。 在這之前,希望你能夠對響應式原理有一些理解,因為 `computed` 是基於響應式原理進行工作。如果你對

理解Vue的Watch原理

## 前言 `watch` 是由使用者定義的資料監聽,當監聽的屬性發生改變就會觸發回撥,這項配置在業務中是很常用。在面試時,也是必問知識點,一般會用作和 `computed` 進行比較。 那麼本文就來帶大家從原始碼理解 `watch` 的工作流程,以及依賴收集和深度監聽的實現。在此之前,希望你能對響應式

YApi——在Win10環境下安裝YApi視覺化介面管理平臺

手摸手,帶你在Win10環境下安裝YApi視覺化介面管理平臺 YApi   YApi 是高效、易用、功能強大的 api 管理平臺,旨在為開發、產品、測試人員提供更優雅的介面管理服務。可以幫助開發者輕鬆建立、釋出、維護 API,YApi 還為使用者提供了優秀的互

搭建前後端分離商城系統】01 搭建基本程式碼框架、生成一個基本API

## 【手摸手,帶你搭建前後端分離商城系統】01 搭建基本程式碼框架、生成一個基本API 通過本教程的學習,將帶你從零搭建一個商城系統。 當然,這個商城涵蓋了很多流行的`知識點`和`技術核心` ### 我可以學習到什麼? - SpringBoot - 鑑權與認證、token、有關許可權的相關的內容

搭建前後端分離商城系統】03 整合Spring Security token 實現方案完成主業務登入

## 【手摸手,帶你搭建前後端分離商城系統】03 整合Spring Security token 實現方案,完成主業務登入 上節裡面,我們已經將基本的前端 `VUE + Element UI` 整合到了一起。並且通過 `axios` 傳送請求到後端API。 解決跨域問題後、成功從後端獲取到資料。 本小結