Vuejs+ElementUI搭建后臺管理系統框架

文章目錄

  • 1. Vue.js 項目創建
    • 1.1 vue-cli 安裝
    • 1.2 使用 vue-cli 創建項目
    • 1.3 文件/目錄介紹
    • 1.4 啟動 Web 服務
  • 2. 集成 Vue Router 前端路由
    • 2.1 Vue Router 是什么
    • 2.2 集成 Vue Router 方法
    • 2.3 使 Vue Router 生效
  • 3. 集成 Vuex 組件
    • 3.1 Vuex 是什么
    • 3.2 集成 Vuex 方法
    • 3.3 使 Vuex 生效
    • 3.4 Vuex 使用方式
      • 3.4.1 設置 state 值
      • 3.4.2 獲取 state 值
  • 4. 集成 ElementUI 組件
    • 4.1 Element UI 是什么
    • 4.2 集成 Element UI 方法
    • 4.3 使 ElementUI 生效
  • 5. 設計前端項目目錄結構
  • 6. layout 設計
    • 6.1 Header 部分設計
    • 6.2 Side Menu 部分設計
    • 6.3 Main Content 部分設計
      • 6.3.1 面包屑功能
    • 6.4 Footer 部分設計
  • 7. 集成 Axios 組件
    • 7.1 Axios 是什么
    • 7.2 集成 Axios 方法
    • 7.3 Axios 初始化
  • 8. 權限攔截管理設計
  • 9. 菜單后臺加載設計
  • 10. 前端路由設計
  • 11. 登錄入口設計
  • 12. Mock 數據設計
    • 12.1 Mockjs 集成方法
    • 12.2 啟用 Mockjs 服務
  • 13. 前端代理服務

1. Vue.js 項目創建

Vue.js 是一套用于構建用戶界面的漸進式框架。在使用 Vue.js 框架之前,如果您還不能靈活的使用 HTML、CSS、JavaScript 語言,如果能抽空預習一下 HTML、CSS、JavaScript 這幾門語言的用法,這樣更利于您繼續學習 Vue.js。

vue-cli 是開發 Vue.js 的一種官方標準工具,我們通過 vue-cli 4.1.2 版本(關于 vue-cli 版本問題,學習或者技術選型沒有歷史包袱時,建議使用最新版,4.1.2 是本場 Chat 時最新版本)來創建項目,當然沒有 vue-cli 也能夠使用 Vue.js 開發您的項目,但使用 vue-cli 可以更方便您使用 Vue.js 開發項目。

1.1 vue-cli 安裝

 $ yarn global add @vue/cli
  • yarn

Facebook、Google 等公司推薦的一款 JavaScript 包管理工具,類似于 Java 界的 Maven、Gradle。當然您也可以繼續使用 NPM 工具來管理 JavaScript 包。關于 Yarn 和 NPM 的對比不在此處介紹,有興趣的朋友可以在網上搜索 NPM 了解其用法。

  • global

表示將需要下載的 JavaScript 包存儲在全局目錄中。這樣我們就可以在命令行中直接使用 JavaScript 安裝包內的程序。如 Vue 命令就來源于 vue/cli 包。

  • @vue/cli

scoped packages。@ 后邊跟隨的 Vue 是 scope,cli 是包名。意思是下載 Vue 這個組織下 cli 包。

1.2 使用 vue-cli 創建項目

我們使用 vue-cli 創建名稱為 web-demo 的項目。操作命令如下所示:

 $ vue create web-demo

在創建項目的過程中,中途有一個選項操作,如下所示:

Vue CLI v4.1.2
? Please pick a preset: (Use arrow keys)
? default (babel, eslint) Manually select features 

默認選擇第一項。安心等待項目創建完成。當依賴文件下載完成后,進入項目所在目錄,目錄內文件如下所示:

README.md	babel.config.js	node_modules	
package.json	public		src		yarn.lock

1.3 文件/目錄介紹

README.md

項目介紹說明信息。

babel.config.js

Babel 是一個工具鏈,主要用于將 ECMAScript 2015+ 版本的代碼轉換為向后兼容的 JavaScript 語法,以便能夠運行在當前和舊版本的瀏覽器或其他環境中。babel.config.js 就是 babel 編輯器的配置文件。通常情況下,無需過多關注。

node_modules

項目依賴包目錄,里邊存儲了當前 Web 項目依賴的 JavaScript 包。

package.json

項目配置信息,包括依賴包信息。

public

公共文件目錄,如 HTML 文件、圖片等。

src

當前項目開發的 Vue 代碼。

yarn.lock

Yarn 工具自動生成的文件,里邊包含每個依賴文件的確切版本等信息。注意 package.json 中也指定了項目依賴 JavaScript 包的版本信息,但 package.json 中可能對于同一個 JavaScript 包指定了多個版本(范圍選擇),而 yarn.lock 存儲的是確切版本信息。

1.4 啟動 Web 服務

下邊來啟動 Web 服務,操作步驟如下所示:

 $ cd web-demo$ yarn serve

Web 服務啟動后,打開瀏覽器輸入 Web 服務地址。

 http://localhost:8080/

8080 是 Web 服務的默認端口,如果在啟動 Web 服務的時候,恰巧 8080 端口已經被占用,那么 Web 服務會默認啟用 8081 端口。Web 服務啟動成功后,至此,Vue.js 項目便創建完成。

2. 集成 Vue Router 前端路由

2.1 Vue Router 是什么

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,讓構建單頁面應用(SPA)變得易如反掌。

為什么要引入 Vue Router 呢 ?

SPA(single page application)單一頁面應用程序,即整個 Web 只有一個完整的頁面,這個頁面由非常多個組件組成。當 Web 加載時,不會一次性顯示整個頁面所有的組件,而是按需顯示局部內容,也就是部分組件。SPA 頁面中這么多個組件,究竟哪個組件要顯示,哪個組件要隱藏。為了解決這個問題,我們引入一種前端路由的工具 Vue Router。

我們給每個組件定義一個 URL,從而形成一張前端路由表。當頁面上發起請求跳轉到指定 URL 時,這個 URL 對應的組件以及這個組件引用的組件就會被顯示出來,不在這個范圍內的組件就會被隱藏。

所以:前端路由通俗地講,就是給組件取個名字,這個名字就是 URL。當頁面上發生 URL 跳轉時,顯示這個 URL 對應的組件以及這個組件引用的組件。

{ path: '/user/details', component: User 
}

上邊例子是前端路由的簡單定義。path 對應的便是 URL,component 對應的便是組件。當頁面上發生 /user/details 跳轉時,便會顯示 User 組件。

2.2 集成 Vue Router 方法

首先進入我們在第一步中創建的項目 web-demo 目錄中。然后使用 Yarn 工具在線下載 vue-router 包,執行下邊命令如下所示:

yarn add vue-router

vue-router 包下載完成后,將會被存儲到當前項目 node_modules 目錄下。

2.3 使 Vue Router 生效

Vue Router 引入項目后,使用 Vue.use(plugin) 方法添加插件。在 main.js 內導入 Vue Router 對象關聯前端路由組件。

// main.js
import Vue from 'vue'
import VueRouter from 'vue-router';
import router from '@/router/router.js'Vue.use(VueRouter);new Vue({router,store,render: h => h(App),
}).$mount('#app')

3. 集成 Vuex 組件

3.1 Vuex 是什么

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。SPA 由多個組件組成,組件與組件之間需要共享狀態時,怎么來實現呢?瀏覽器上常見的幾種存儲方式如下所示:

  • HTML5 的 localStorage。主要通過本地存儲的方式存儲數據,瀏覽器關閉后,數據仍在在本地。
  • HTML5 的 sessionStorage。主要通過會話保存數據,當瀏覽器關閉后,數據丟失。
  • Cookies。每次 HTTP 請求時,都會將 Cookies 信息發送給服務端。Cookies 存儲大小有限制,否則每次 HTTP 請求發送給服務器的數據會占用過多帶寬。
  • Vuex 通過內存存儲數據。頁面刷新時,state 狀態丟失

localStorage、sessionStorage 更多的時候用于頁面之間數據傳遞。Cookies 更多用于存儲 Web 前端與后臺服務端之間的數據。Vuex 更適合于組件之間的狀態管理。上述幾種存儲方式可在一個項目中同時存在,主要取決于需求,不同的場合,選用不同的數據存儲方式。

Vuex 模塊核心概念如下所示:

  • State 存儲的狀態變量;
  • Getter 獲取狀態變量;
  • Mutation 修改狀態變量的值;
  • Action 提供入口方法,修改存儲狀態的值;
  • Module 狀態模塊化管理,即我們將幾百個狀態分布到多個文件中,每個文件中對應的是一個模塊。

修改狀態的流程:action -> mutation -> state 修改狀態。

獲取狀態的流程:getter -> state 獲取狀態。

3.2 集成 Vuex 方法

使用 Yarn 工具在線下載 Vuex 包,下載命令如下所示:

yarn add vuex

Vuex 包下載完成后,將會被存儲到當前項目 node_modules 目錄下。

3.3 使 Vuex 生效

Vuex 組件引入項目后,使用 Vue.use(plugin) 方法添加插件。在 main.js 導入 Vuex 的對象來關聯狀態管理組件。

// main.js
import Vue from 'vue'
import store from '@/store/index.js';Vue.use(Vuex);new Vue({router,store,render: h => h(App),
}).$mount('#app')

3.4 Vuex 使用方式

3.4.1 設置 state 值

this.$store.dispatch({action 名字},{state 新的值})

第一個參數是 action 中定義的方法。第二個參數是 state 新的值。如我們需要調整 height 這個變量的值為 100px。假設 action 中定義了一個方法 autoHeight。則使用命令如下所示:

this.$store.dispatch('authHeight', '100px')

3.4.2 獲取 state 值

通過 mapGetters 方法獲取到 state 中 height 這個變量,或者從 data 中讀取 clientHeight 變量。

import { mapGetters } from "vuex";export default {computed: {// 從 vuex 中獲取瀏覽器高度,實時更新,保持左側菜單欄高度與瀏覽器高度一致,保持垂直方向 100% 高度...mapGetters(["height"])},data(){return {// 從 vuex 讀取 state 狀態的第二種方式clientHeight: this.$store.getters.height}},
}

4. 集成 ElementUI 組件

4.1 Element UI 是什么

Element,一套為開發者、設計師和產品經理準備的基于 Vue 2.0 的桌面端組件庫。這個庫集成了大量漂亮的組件,如選擇框組件、彈框組件、輸入框組件、按鈕組件等等。集成了 ElementUI 后,可以方便我們更快的開發出更漂亮的 Web 頁面。

4.2 集成 Element UI 方法

使用 Yarn 工具在線下載 element-ui 包,下載命令如下所示:

yarn add element-ui

element-ui 包下載完成后,將會被存儲到當前項目 node_modules 目錄下。

4.3 使 ElementUI 生效

使用 Vue.use(plugin) 方法添加插件,將 ElementUI 添加到項目中。

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';Vue.use(ElementUI, {size: 'small' // set element-ui default size
});

5. 設計前端項目目錄結構

項目目錄結構:

-- public
-- src
---- api
---- assets
---- components
------ layout
------ pagination
------ Breadcrumb.vue
---- layout
------ BaseLayout.vue
------ EmptyRouter.vue
---- mock
------ mock.js
------ data
---- router
---- store
---- utils
---- views
---- App.vue
---- main.js
---- permission.js

6. layout 設計

在前端頁面開發時,第一步先規劃整體布局,如將整個 Web 劃分為幾個大的區域,每個區域負責特定的顯示。我們將后臺管理系統劃分為如下四個部分,分別是:

  • Header 頭部信息顯示欄
  • Side Menu 左側菜單顯示欄目
  • Main Content 內容顯示區域
  • Footer 頁腳顯示信息

6.1 Header 部分設計

頭部顯示欄主要顯示整個系統重要信息,如 LOGO 信息、主菜單信息、登錄用戶信息,以及其他重要信息。實現 Header 部分代碼如下所示:

<template><div class="wisrc-header"><el-row><el-col :span="24"><!-- Logo 顯示--><Logo /><!--一級主菜單區域--><MainMenu /><!-- 右側工具欄(包含用戶登錄信息) --><Tools /></el-col></el-row></div>
</template><script>
import Logo from "@/components/layout/Logo.vue";
import MainMenu from "@/components/layout/MainMenu.vue";
import Tools from "@/components/layout/Tools.vue";export default {name: "WisrcHeader",components: {Logo,MainMenu,Tools}
};
</script><style scoped>
.wisrc-header {height: 60px;width: 100%;text-align: left;padding: 0px;line-height: 60px;background-color: rgb(84, 92, 100);color: #ffffff;
}
</style>

6.2 Side Menu 部分設計

Side Menu 部分由兩個組件組成,分別是:

  • Side.vue
  • SideChildrenMenu.vue

Side 組件主要實現左側菜單欄主要布局,建構一個緊靠瀏覽器左側,且橫向寬度為 260 像素,垂直方向自適應瀏覽器高度的區域。布局構建完成后,通過嵌套 SideChildrenMenu 組件顯示具體的菜單信息。Side 組件的代碼如下所示:

<template><div class="wisrc-side"><el-menudefault-active="2":style="{height: (height-60)+'px'}"class="wisrc-side-menu"background-color="#545c64"text-color="#fff"active-text-color="#ffd04b"><el-scrollbar style="height: 100%"><SideChildrenMenu  v-bind:children="sideMenuList" /></el-scrollbar></el-menu></div>
</template><script>import { mapGetters } from "vuex";
import { getMenu } from '@/api/menu.js';
import SideChildrenMenu from '@/components/layout/SideChildrenMenu.vue';export default {name: "wisrc-side",computed: {// 從 vuex 中獲取瀏覽器高度,實時更新,保持左側菜單欄高度與瀏覽器高度一致,保持垂直方向 100% 高度...mapGetters(["height"])},components: {SideChildrenMenu},data() {return {sideMenuList: [],};},methods: {openPage(url) {this.$router.push(url);}, },mounted(){// 定時獲取后臺菜單信息getMenu().then(resp => {this.sideMenuList = resp})}
};
</script><style scoped>
.wisrc-side {width: 260px;height: 100%;float: left;text-align: left;
}
.wisrc-side-menu {overflow-y: auto;
}
.el-scrollbar__wrap {overflow-x: hidden;
}
</style>

SideChildrenMenu 組件用來渲染樹形層級菜單。樹形菜單采用遞歸渲染的方式實現,即在 SideChildrenMenu 組件內嵌套使用組件自身,從而實現遞歸渲染樹形菜單的效果。Vue.js 中組件采用遞歸時,該組件一定要設置 name 屬性。否則遞歸無效。

SideChildrenMenu 組件的代碼實現如下所示:

<template>
<div><div v-for="(item, index) in children" :key="index"><!-- 目錄菜單 --><el-submenu v-if="item.menuType == 1" :index="index"><!-- 目錄菜單名稱 --><template slot="title"><i :class="item.iconClass"></i><span>{{item.menuName}}</span></template><!-- 目錄下子菜單 --><SideChildrenMenu  v-bind:children="item.children" /></el-submenu><!-- 葉子菜單 --><el-menu-item v-if="item.menuType == 2" :index="item.menuId" @click="openPage(item.path)">{{item.menuName}}</el-menu-item></div>
</div>
</template><script>
export default {props: ["children"],name: 'SideChildrenMenu',methods: {openPage(url) {this.$router.push(url);}}
}
</script>

自此,左側菜單組件開發完畢,我們通過 Axios 組件向后臺服務發起請求,獲取左側菜單欄信息。菜單信息數據格式見下邊 9.1 節。

6.3 Main Content 部分設計

Main Content 用來渲染具體的業務信息。例如當我們在左側菜單欄點擊打開“字段管理”頁面,字段管理頁在前端路由表中配置了相應的組件 Column.vue。也就是點擊“字段管理”頁面,將會打開 Column.vue 組件以及這個組件中引入的其他組件。那問題來了, 待顯示的組件在哪里顯示呢?

答案就是 <router-view></router-view>

我們在 Main Content 中加入了 <router-view></router-view> DOM 元素。當左側菜單欄點擊打開“字段管理”頁面后,其對應的組件 Column.vue 將會在 Main Content 中 <router-view></router-view> DOM 元素內顯示。

<template><div><el-card><Breadcrumb></Breadcrumb></el-card><div class="wisrc-content" :style="{height: (height-138)+'px'}"><section style="overflow: auto !important"><transition name="fade" mode="out-in"><keep-alive><el-cardstyle="overflow: auto !important; text-align: left":style="{height: (height-140)+'px'}"><router-view></router-view></el-card></keep-alive></transition></section></div></div>
</template>
<script>
import { mapGetters } from "vuex";
import Breadcrumb from "@/components/Breadcrumb";export default {name: "WisrcContent",components: {Breadcrumb},computed: {...mapGetters(["height"])}
};
</script><style scoped>
.wisrc-content {margin-left: 260px;border: #f6f3f3 solid 1px;background-color: #f6f3f3;overflow-y: auto;padding: 6px 6px;
}
</style>

通過使用 <router-view></router-view> 渲染待刷新顯示的內容,實現了局部頁面刷新的功能。如果沒有 <router-view></router-view>,那么前端路由還能渲染出來嗎?

答案是:不行,router-view 就像是個容器,沒有容器,待顯示的組件無處安放。

6.3.1 面包屑功能

此處的面包屑不是吃了一半的面包渣渣。面包屑導航(Breadcrumbs)是一種基于網站層次信息的顯示方式。前端路由往往由多層路由組成,在頁面跳轉過程中,可能點著點著就不知道現在處于哪個頁面中(除非每個頁面中都設計了標題)。引入面包屑導航功能后,我們可以很方便的知道當下所在的頁面。面包屑實現方式如下所示:

<template><div><el-breadcrumb separator="/"><el-breadcrumb-item :to="{ path: '/' }">首頁</el-breadcrumb-item><el-breadcrumb-itemv-for="(item,index) in breadcrumb":to="{path: item.path}":key="index">{{item.title}}</el-breadcrumb-item></el-breadcrumb></div>
</template>
<script>
export default {data() {return {breadcrumb: []};},watch: {$route(to) {// 監聽路由跳轉,每次發生路由跳轉時,$route 中的值都會發生變化。// to.matched 用來獲取匹配成功的路由信息,const routers = to.matched;this.breadcrumb = [];if (routers && routers.length > 0) {for (let i = 1; i < routers.length; i++) {this.breadcrumb.push({title: routers[i].meta.title,path: routers[i].path});}}}}
};
</script>

前端路由往往由多個層級組成,例如現在有如下幾個路由信息:

  • /modeller
  • /modeller/column
  • /modeller/column/add

路由 /modeller/column/add 的上一層級路由是 /modeller/column,/modeller/column 的上一層路由是 /modeller。 當我們跳轉到 /modeller/column/add 時,這個組件的所有直系父組件都會被顯示。所以 to.matched 返回上邊三個值。我們通過這三個返回值,便可描繪出路由的層級結構。從而生成面包屑導航。

6.4 Footer 部分設計

Footer 主要顯示一些版權信息,沒有具體的業務邏輯。此部分通常位于系統底部,實現代碼如下所示:

<template><div class="wisrc-footer"><el-footer style="margin-left: -260px; font-size: 12px">Copyright ? 2019 基于 Vue.js + ElementUI 后臺管理系統</el-footer></div>
</template>
<script>
export default {name: "WisrcFooter"
};
</script><style scoped>
.wisrc-footer {position: fixed;text-align: center;width: 100%;height: 24px;line-height: 24px;bottom: 0px;background-color: #f6f4f4;border-top: #cccccc solid 1px;margin-left: 260px;
}
</style>

7. 集成 Axios 組件

7.1 Axios 是什么

Axios 是一個基于 Promise 的 HTTP 庫。HTTP 庫提供了瀏覽器通過 HTTP 協議與后臺服務通信的能力。由于網絡帶寬、后臺服務等可能存在不穩定的情況,所以有時候請求后臺服務很快,有時候請求后臺服務很慢,那當服務請求很慢時,前端是否有必要卡著不動,等待請求完成呢?

如果 Web 頁面卡著不動,那用戶體驗一定很糟糕。眾所周知 JavaScript 運行在單線程上,現在很多語言都講究多線程、高并發,從而實現任務異步處理。那么單線程運行的 JavaScript 怎么來實現異步處理呢?主要有兩種方法:

  • 基于事件監聽實現異步處理
  • 基于回調函數實現異步處理

基于事件監聽實現異步處理存在一定的限制,HTML 事件屬性有范圍,如 Window 事件、Form 事件、Keyboard 事件、Mouse 事件、Media 事件。當異步處理的業務不在 HTML 事件屬性范圍內時,將無法使用事件監聽來實現異步處理任務。

基于回調函數的異步處理,將會吞噬掉 return 值。常見的回調函數使用方法是:將需要執行的任務放進 setInterval 或 setTimeout 內來實現任務異步處理。


setTimeout(function(){// 異步處理任務,5秒后執行console.log("異步處理任務執行");
},5000)setInterval(function(){// 異步處理任務,每 5 秒執行一次console.log("每 5 秒鐘執行一次異步處理任務");
}, 5000)

由于 setInterval 和 setTimeout 無法保證執行順序,所以,當項目中大量使用回調函數時,幾十個不知道順序的任務即將執行,不知道哪個先運行,哪個后運行,誰又在誰前邊運行,這樣對于后期代碼維護,將會是一場巨大的災難。

有沒有辦法既能實現異步處理,又能解決順序問題呢?

Axios 庫有一個非常有效的特性,就是支持 Promise API。使用 Promise 既能實現任務的異步處理,又能實現任務的順序執行。Promise 將多個需要異步處理的任務隊列化,隊列有效的保證了任務執行的有序性。隊列中的異步任務順序執行,上一個任務的執行返回值作為下一個異步任務的輸入值,這樣又解決了異步任務吞噬 return 返回值的問題。

但與傳統的函數調用使用 return 返回值不同的是,Promise 使用 resolve 函數傳遞正確處理的返回值,使用 reject 函數傳遞錯誤處理的返回值。舉個例子:

function asyncDemo(){return new Promise((resolve, reject) => {axios.get('/api/demo').then(response => {if (response) {// 請求 API 成功,將返回結果傳遞到下一個任務resolve('請求 API 成功');} else {// 請求 API 失敗,終止異步處理任務reject('請求 API 失敗')}})})
}// 運行異步處理任務
asyncDemo().then(response => {// 請求成功后,上一個任務通過 resolve 函數傳遞的參數作為當前的輸入console.log(response);// 輸出信息是: 請求 API 成功
}).then(error => {// 請求 API 失敗,上一個任務通過 reject 函數傳遞的參數作為當前的輸入console.log(error)// 輸出信息是: 請求 API 失敗
)

7.2 集成 Axios 方法

使用 Yarn 工具在線獲取 Axios 包,并安裝到當前項目中。

yarn add axios

Axios 包下載好之后,被存放到當前項目 node_modules 目錄中。

7.3 Axios 初始化

項目中使用 Axios 組件請求 API 服務,通常需要設置一些統一處理邏輯,如異常信息全局處理、token 信息注入等等。那么如何初始化 Axios 組件呢?代碼示例如下所示:

// utils/request.js
import axios from 'axios';
import { Message } from 'element-ui';// 設置遠程服務器 IP 地址
// axios.defaults.baseURL = process.env.VUE_APP_BASE_API;// 設置請求遠程服務器時攜帶的 token 值信息
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;// 設置 POST 方法請求時默認的請求頭信息
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';// 攔截請求發生前,可以在此修改請求參數
axios.interceptors.request.use(config => {return config;
}, error => {Message.error(error)
})// 攔截請求完成后,可以全局處理異常信息
axios.interceptors.response.use(response => {if (response && response.status == 200) {if (response.data.statusCode == "200") {// 請求成功return response.data.data;} else {Message.error(response.data.statusMessage)return false;}}Message.error('請求API失敗');
}, error => {Message.error(error)return false;
})
  • axios.interceptors.request:瀏覽器向后臺服務發起請求之前的處理邏輯。
  • axios.interceptors.response:瀏覽器向后臺服務發起請求之后,攔截響應值,判斷是否存在異常,如果存在異常,攔截處理結果,提示請求錯誤信息。如果請求成功,則將請求結果返回給具體的發起請求的函數。

8. 權限攔截管理設計

管理系統通常會針對不同的用戶開發不同的權限,如超級管理員可以使用管理系統中所有的功能,財務部門只能使用財務相關的功能,人事部門只能使用員工管理相關功能。為了實現這個需求,我們在設計后臺管理系統中需要引入權限管理功能。

權限管理通常分為幾個形式:

  • API 權限控制
  • 數據權限控制
  • 前端頁面權限控制
  • 頁面按鈕權限控制

API 權限控制

通常 API 的權限管理在后臺進行,后臺服務的入口處會攔截所有的請求,當用戶發起 API 請求后,校驗用戶是否被授予訪問這個 API 的權限,用戶被授權,則允許訪問,若用戶未被授權,則用戶被拒絕訪問。

數據權限控制

數據權限往往基于角色、崗位等維度進行管理。往往針對的是數據的訪問控制,如哪些角色、崗位的用戶能夠訪問哪些數據。這塊的權限控制往往由后臺服務控制。

前端頁面權限控制

前端頁面權限,指用戶登錄系統之后,哪些頁面可見,哪些頁面不可見。與數據權限有一點相似之處。通常前端讀取后臺服務關于用戶的權限信息后,在渲染菜單的時候,將無權限的菜單屏蔽。

頁面按鈕權限控制

頁面按鈕控制權限,指用戶打開頁面之后,哪些頁面按鈕可見,哪些頁面按鈕不可見。通常前端讀取后臺服務關于用戶的權限信息后,在渲染頁面的時候,將用戶沒有權限的按鈕屏蔽。

用戶在瀏覽器中打開頁面后,怎么在每個頁面中都加入校驗,用來攔截判斷用戶是否有權限訪問這個頁面呢?

  • 在每個頁面中加入判斷,校驗用戶是否登錄
  • 全局校驗用戶是否登錄

在每個頁面中加入判斷用戶是否登錄的代碼,顯然這種方式對于業務的侵入太大,過于笨拙,顯然不適合。那么怎么設置全局的用戶登錄校驗呢?

Vue Router 導航守衛功能。導航守衛主要在如下幾個階段來攔截請求。分別是:

  • beforeEach 全局前置守衛,在導航路由觸發前攔截
  • beforeRouteUpdate
  • beforeEnter
  • beforeRouteEnter
  • beforeResolve
  • afterEach

上述幾種導航守衛,我們使用 beforeEach 實現登錄校驗的判斷。實現代碼如下所示:

import router from '@/router/router.js';
import store from '@/store/index.js';function checkLogin() {// todo 校驗用戶是否登錄,以及用戶 token 令牌是否過期return !store.getters.loginStatus;
}// @param to 到哪里去,跳轉到哪個路由
// @param from 從哪里來,從哪個路由跳轉過來的
// @param next 執行跳轉
router.beforeEach((to, from, next) => {// 判斷用戶是否登錄,// 如果用戶已經登錄,執行 next() 方法,// 如果用戶未登錄,則跳轉到登錄頁面if (to.path != '/login' && checkLogin()) {next({ path: '/login' })} else {next()}})

每次觸發路由導航時,都會執行這個判斷邏輯,當發現用戶未登錄,或登錄的 token 失效后,將會被引導進入登錄頁面。注意一定要判斷目標地址是否為登錄地址,否則出現死循環

checkLogin 方法現在只是讀取了保存在 vuex 中的用戶登錄狀態,這種處理方式并適合生產環境。主要原因是:在瀏覽器執行 F5 刷新時,Vuex 存儲的狀態值會丟失,那么用戶又要重新登錄。

通常生產環境中,會將 token 信息存儲到 Cookies 中,登錄狀態存儲在 Vuex 中,判斷用戶是否登錄要結合 Cookies 中的 token 與 Vuex 中的登錄狀態一起判斷。如用戶登錄狀態為 false 時,從 Cookies 中讀取用戶 token 值,向后臺服務請求驗證 token 有效性,如果 token 有效,則設置 Vuex 中用戶登錄狀態為 true,然后跳轉到目標路由地址。否則跳轉到登錄頁面。

9. 菜單后臺加載設計

字段介紹

  • menuId 菜單編碼,每個菜單必須對應一個唯一的菜單編碼。
  • menuName 菜單名稱。
  • menuType 菜單類型。1 表示目錄類型,2 表示葉子菜單,目錄類型菜單,表示其下還有菜單信息,葉子類型菜單,表示達到樹底部。
  • path 前端路由值,葉子菜單被點擊時,將會跳轉到該路由。目錄菜單設置 path 值將會被忽略。
  • iconCLass 目錄類型菜單前邊的小圖標。
  • children 表示目錄類型菜單下的子菜單信息。

假設我們要創建一個目錄菜單,目錄菜單下邊掛載兩個葉子菜單,菜單數據格式如下所示:

{menuId: "1-1",menuType: 1,menuName: '業務規則',iconClass: 'el-icon-location',children: [{menuId: "1-1-1",menuType: 2,menuName: '數據集管理',path: '/modeller',},{menuId: "1-1-2",menuType: 2,menuName: '內容管理',path: '/modeller',}]
}

Web 中向后臺請求菜單信息的方式:

// api/menu.js
import axios from "axios"export function getMenu(){return axios.get('/menu')
}

10. 前端路由設計

前端路由,粗魯的解釋,就是給組件取個名字,這個名字采用 URL 的形式來命名。前端路由格式如下所示:

      path: '/foo',name: 'foo',component: Foo,meta: { title: 'foo' }children: [{path: '/foo',name: 'foo',component: Foo,meta: { title: 'foo' }}]
  • path 路由地址
  • name 路由名稱
  • component 路由對應的組件
  • meta 路由元數據,如路由標簽等
  • children 子路由信息

定義好路由信息后,我們在程序中便可以調用路由跳轉方法進行路由切換操作。具體方法如下所示:

// 字符串
router.push('/foo')// 對象
router.push({ path: '/foo' })// 命名的路由
router.push({ name: 'foo', params: { userId: '123' }})// 帶查詢參數,變成 /register?plan=private
router.push({ path: '/foo', query: { plan: 'private' }})

在 HTML 頁面元素中實現路由跳轉的方法:

<router-link to="/foo">Go to Foo</router-link>

在瀏覽歷史記錄中切換跳轉方法:

router.go(n)
// n 表示第幾個歷史記錄,n 必須是整數

前端路由往往嵌套多層。下邊我們來模擬一個復雜的場景,構建路由信息,詳細路由表如下所示:

import VueRouter from "vue-router"
import BaseLayout from '@/layout/BaseLayout'
import EmptyLayout from '@/layout/EmptyRouter'
import Dashboard from '@/views/Dashboard'
import Login from '@/views/Login'import Modeller from '@/views/modeller/Modeller'
import ModelUpdate from '@/views/modeller/ModelUpdate'
import ModelColumn from '@/views/modeller/column/ModelColumn'
import ModelColumnUpdate from '@/views/modeller/column/ModelColumnUpdate'// 前端路由表
const routes = [{path: '',component: EmptyLayout,redirect: 'dashboard',children: [{path: '/login',component: Login,name: 'login',meta: {title: '登錄'}}]
}, {path: '',component: BaseLayout,redirect: 'dashboard',children: [{path: 'dashboard',component: Dashboard,name: 'dashboard',meta: {title: '首頁'}}]
}, {path: '/',component: BaseLayout,children: [{path: 'modeller',component: Modeller,meta: {title: '數據集管理'}}, {path: 'modeller',component: EmptyLayout,meta: {title: '數據集管理'}, children: [{path: 'add',name: 'add',component: ModelUpdate,meta: {title: '新增數據集',}}, {path: 'column',name: 'column',component: ModelColumn,meta: {title: '字段管理'}}, {path: 'column',component: EmptyLayout,meta: {title: '字段管理'},children: [{path: 'add',name: 'modeller-column-add',component: ModelColumnUpdate,meta: {title: '新增字段'}}]}]}]
}]var router = new VueRouter({scrollBehavior: () => ({ y: 0 }),routes
})export default router;

路由組件之間嵌套層級比較多,例如當用戶請求 /modeller/column 時,頁面渲染順序是:

  • 先打開 BaseLayout 組件;
  • 然后在這個組件中找到 <router-view></router-view>
  • 接著在打開 EmptyLayout 組件,EmptyLayout 組件被嵌入 BaseLayout 組件的 <router-view></router-view> 內;
  • 最后打開 ModelColumn 組件,此時 ModelColumn 的上級組件即 EmptyLayout 組件內查找 <router-view></router-view>,然后將 ModelColumn 組件嵌入到 EmptyLayout 組件的 <router-view></router-view> 內。

前端路由定義時,如果路由中包含了 children 屬性,那么這個組件內一定帶有 <router-view></router-view> DOM 元素 ,否則 children 內的組件無處安放。我們可以查看一下整個項目的入口組件 App.vue。里邊就是一個 <router-view></router-view>

<!--App.vue--><template><div id="app"><router-view></router-view></div>
</template><script>
export default {name: "app",methods: {autoHeight() {// 初始化瀏覽器高度this.$store.dispatch("autoHeight");}},beforeCreate() {this.$store.dispatch("autoHeight");},mounted() {window.onresize = () => {// 瀏覽器this.autoHeight();};}
};
</script><style>
#app {font-family: "Avenir", Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}
body {padding: 0px;margin: 0px;
}
</style>

11. 登錄入口設計

登錄入口主要負責接收用戶賬號和密碼,校驗用戶身份。當用戶身份校驗通過后,進入系統。現在流行的登錄方式非常多。常見的幾種登錄方式如下所示:

  • 微信掃碼登錄
  • 支付寶掃碼登錄
  • 手機驗證碼登錄
  • 用戶賬號密碼登錄
  • 微博授權登錄

上邊的幾種登錄方式,從技術實現的角度來看,主要為下邊幾種:

賬號密碼登錄

最常見的登錄方式是用戶賬號密碼登錄。后臺校驗用戶賬號和密碼是否正確,如果正確,則返回有效的 token 信息, Web 端上攜帶 token 信息請求后臺服務。

短信驗證碼登錄

Web 端向后臺服務發起請求獲取短信驗證碼,短信運營商將驗證碼發送到用戶手機上。用戶通過手機號 + 短信驗證碼請求后臺短信登錄接口。后臺服務使用手機號 + 短信驗證碼到短信運營商(或者自己開發的驗證接口)請求驗證,如果驗證通過,則用戶使用短信登錄成功,后臺服務向 Web 端下發 token 信息,Web 端攜帶 token 信息進入系統。

二維碼掃碼登錄

實質上是通過手機上已經登錄的賬號來獲取新的登錄令牌。二維碼通常分為活碼和靜態碼表。

  • 靜態碼是將文字信息翻譯成二維碼,這種二維碼存儲信息量有限,且不能動態改變。如我們將 hello 這個單詞做成一個靜態的二維碼。這樣不論是誰來掃描,得到的都是 hello 這個詞。
  • 活碼是將一個 URL 地址做成二維碼。掃描二維碼時得到這個 URL 地址,然后跳轉到這個 URL 地址獲取真正的內容。

掃碼登錄的常見流程如下(大概流程,中間省略一些驗證細節):

  • Web 頁面上選擇掃碼登錄,Web 上顯示出二維碼,此時的二維碼中包含一個唯一 ID 信息,且這個 ID 信息會被記錄到后臺服務中。
  • APP 上(假設這個 APP 是自己公司開發,且支持掃碼登錄功能)掃描二維碼,讀取到二維碼中包含的內容(包含了第一步中的唯一 ID)。
  • APP 點擊確認登錄,此時手機 APP 向后臺發送自己的登錄信息(也就是 APP
    掃碼登錄的前提是 APP 在手機上已經登錄),并帶上第二步讀取到的唯一 ID 信息。
  • 后臺服務收到用戶在手機上的登錄信息以及唯一 ID 信息。后臺服務開始校驗用戶登錄信息是否有效,如果有效,則修改服務端存儲的唯一 ID 對應的狀態為 true。
  • Web 端通過唯一 ID 查詢到后臺服務對應的狀態為 true 時,后臺返回新的登錄 token 信息。此時 Web 端攜帶 token 信息進入系統。

第三方授權登錄

第三方授權也是一種比較常見的登錄方式,如微博賬號登錄、微信賬號登錄、QQ 賬號登錄等等。第三方授權登錄流程是:

  • 用戶點擊第三方授權登錄請求,跳轉到微博、QQ、微信的登錄頁面。微博、QQ、微信校驗用戶登錄信息,如果用戶登錄信息校驗通過,則回調我們的后臺服務地址,告訴我們的服務器授權登錄成功,并返回 token 信息給我們的后臺服務;
  • 我們的服務獲取到 token 信息后,可以根據這個 token 與微博、QQ或微信建立綁定關系。如果此時的 token 權限過大,則后臺服務可以根據這個 token 來操作用戶微博、QQ、微信部分功能(一些小網站上,建議不要輕易在上邊使用進行第三方授權的方式登錄,萬一不法網站獲取到權限過大的授權,此時可能存在信息泄露的風險)。
  • 我們的服務器收到微博、QQ或微信的回調后。我們的后臺服務生成的 token 信息,并下發給 Web 端,Web 端攜帶我們服務器下發的 token 信息進入系統。

下邊我們來實現一個簡單的賬號密碼登錄頁面,示例代碼如下所示:

<template><div><el-row style="margin-top: 80px;"><el-col :span="8" :offset="8"><el-form><el-form-item prop="username" label="用戶名:"><el-input name="username" v-model="username" placeholder="用戶賬號" /></el-form-item><el-form-item prop="password" label="密碼"><el-input type="password" name="passwrod" v-model="password" placeholder="用戶密碼" /></el-form-item></el-form><el-button @click="loginSubmit">&nbsp;&nbsp;</el-button></el-col></el-row></div>
</template>
<script>import { login } from '@/api/login.js';export default {name: "login",data() {return {username: "admin",password: "123456"};},methods: {loginSubmit() {login(this.username, this.password).then(resp => {if (resp) {// 修改登錄狀態this.$store.dispatch('loginStatus', true);this.$router.push('/dashboard')}});}}
};
</script>

當用戶在 Web 上輸入用戶名和密碼后,點擊登錄按鈕。此時將會執行 loginSubmit 方法。這個方法負責調用后臺服務登錄接口。登錄成功后跳轉到系統首頁。

12. Mock 數據設計

當我們在開發前端 Web 服務時,可能對應的后臺服務尚未開發完成,此時,我們可以借助于 Mock 服務來模擬后臺服務,當 Web 端使用 Axios 向后臺服務發起請求時,請求將會被 Mock 服務攔截,Mock 服務返回預先定義的數據。當后臺服務開發完成后,只需關閉對應的 Mock 服務,此時請求將會被轉發到真正的后臺服務。所以,Mock 服務給我們開發前端 Web 提供了擋板功能,在后臺服務尚未開發完成的情況下,通過使用 Mock 服務,從而保障前端開發進度。

12.1 Mockjs 集成方法

使用 Yarn 工具在線下載 mockjs 工具包。下載命令如下所示:

yarn add mockjs

mockjs 包下載完成后,將會被存儲在當前項目 node_modules 目錄下。

12.2 啟用 Mockjs 服務

// mock/mock.js
import Mock from 'mockjs'const mock_source = ['biz.js', 'sys.js']function load(mock_source) {for (let i = 0; i < mock_source.length; i++) {let file = import('./data/' + mock_source[i])file.then(content => {if (content && content.default) {// 找到目標initMock(content.default)}})}
}function initMock(rules) {for (let [rule, resp] of Object.entries(rules)) {const element = rule.split(" ")if (element && element.length == 2) {const rtype = element[0].trim()const rurl = element[1].trim()Mock.mock(rurl, rtype.toLowerCase(), resp)} else {Mock.mock(rule, resp)}}
}if (mock_source && mock_source.length > 0) {load(mock_source)
}

注意事項

Mock 服務啟動需要時間,有可能首頁打開時,Mock 服務尚未啟動,可能出現請求 Mock 服務時出現 404 的情況。比如從 Mock 服務中加載菜單信息。如果加載菜單的時候,Mock 服務未初始化完成,則很有可能請求菜單時出現 404。

解決辦法:在 Mock 數據初始化完成后,將 Mock 服務狀態保存到 store 中存儲。

在 store 中 定義 Mock 服務初始化狀態的變量,變量名稱為 mockInitFinished,變量定義方式如下所示:

// store/modules/basic.js
const basic = {state: {// mock 服務初始化狀態mockInitFinished: false,},mutations: {MOCK_INIT_FINISHED: (state, status) => {// mock 初始化完成state.mockInitFinished = status;},},actions: {mockInitFinished({ commit }, status) {// 修改 mock 服務初始化狀態為已完成commit('MOCK_INIT_FINISHED', status)},}
}export default basic;

當我們初始化 Mock 服務完成后,通過如下方式更新 store 中 Mock 服務的狀態為 true。具體方式如下所示:

// mock/mock.js
import store from '@/store/index.js';if (mock_source && mock_source.length > 0) {load(mock_source)// 將 Mock 狀態保存到 store 中存儲。store.dispatch('mockInitFinished', true)
}

從后臺 API 獲取菜單信息方法修改成如下所示:

	// components/layout/Side.vue// 定時獲取后臺菜單信息const timer = setInterval(()=> {if (this.mockInitFinished){getMenu().then(resp => {this.sideMenuList = respclearInterval(timer)})}},1000)

setInterval 方法每隔一個固定的頻率執行一次任務。上邊的代碼中,我們每隔 1 秒鐘獲取一次后臺 API 中的菜單信息。為什么要在此使用定時循環執行的方式獲取菜單信息呢? 主要原因是 Mock 服務啟動可能晚于我們在 Side 組件中查詢后臺 API /menu 的時間,這樣必然會出現請求 404 的錯誤。

為了解決這個問題,我們可以通過引入定時器,每隔 1 秒鐘定時查詢一次 Mock 服務的狀態,當 Mock 服務啟動后,再去請求獲取 Mock 服務的數據。如果我們請求的是真實的后臺環境,那么我們就沒必要引入 setinterval 這種方式來查詢后臺服務的菜單信息

Mock 服務初始化完成后,我們開始根據具體的 API 需求編寫 Mock 服務。比如編寫一個菜單查詢的 Mock 服務。詳細信息如下所示:

// mock/data/sys.js
const menu = {'GET /menu': {statusCode: "200", statusMessage: "succcess", data: [{menuId: "2",menuType: 1,menuName: '系統管理',iconClass: 'el-icon-location',children: [{menuId: "2-1",menuType: 2,menuName: '數據集管理',path: '/modeller',},{menuId: "2-2",menuType: 2,menuName: '內容管理',path: '/modeller',}]},{menuId: "3-1",menuType: 2,menuName: '數據集管理',path: '/modeller',}]}
}export default menu;

13. 前端代理服務

在前后端分離模式開發中,后臺服務往往部署在某一個 K8s 集群中,Web 與后臺服務可能不在一個網絡(尤其是開發階段),此時 Web 跨域請求后臺服務可能出現跨域失敗的問題。可以通過設置前端代理的方式來解決這個問題。

在項目根目錄創建 vue.config.js 文件。然后添加如下代碼:

// vue.config.js
module.exports = {devServer: {port: 8080,proxy: {'/': {// process.env.VUE_APP_BASE_API 替換成對應的后臺服務地址target: process.env.VUE_APP_BASE_API,changeOrigin: true,secure: false,pathRewrite: {'^/': '/'}}}}
}

Web 端通過 Axios 發起后臺服務請求,都會被轉發到 process.env.VUE_APP_BASE_API 這個地址,通過設置 changeOrigin 為 true,有效的解決跨域請求失敗的問題。

本篇 Chat 代碼地址

https://github.com/hzwy23/vue-admin

Vue.js 官方網站地址

https://cn.vuejs.org/

Vue Cli 官網網站地址

https://cli.vuejs.org/zh/

Vue Router 官方網站地址

https://router.vuejs.org/zh/

Vuex 官方網站地址

https://vuex.vuejs.org/zh/

Element UI 官方網站地址

https://element.eleme.cn/#/zh-CN

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165173.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165173.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165173.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2023全球數字貿易創新大賽-人工智能元宇宙-4-10

目錄 競賽感悟: 創業的話 好的項目 數字工廠,智慧制造:集群控制的安全問題

dlv 安裝與使用

dlv 安裝 第一步&#xff1a; # git clone https://github.com/go-delve/delve # cd delve # make install 第二步&#xff1a; # ln -s /root/go/bin/dlv /usr/local/bin/dlv 第三步&#xff1a; # dlv version Delve Debugger Version: 1.21.2 Build: d6f215b27b6d8a4e4…

Excel中出現“#NAME?”怎么辦?(文本原因)

excel 單元格出現 #NAME? 錯誤的原因有二&#xff1a; 函數公式輸入不對導致 #NAME? 錯誤。 在單元格中字符串的前面加了號&#xff0c;如下圖中的--GoJG7sEe6RqgTnlUcitA&#xff0c;本身我們想要的是--GoJG7sEe6RqgTnlUcitA&#xff0c;但因為某些不當的操作在前面加了號&…

vue+SpringBoot的圖片上傳

前端VUE的代碼實現 直接粘貼過來element-UI的組件實現 <el-uploadclass"avatar-uploader"action"/uploadAvatar" //這個action的值是服務端的路徑&#xff0c;其他不用改:show-file-list"false":on-success"handleAvatarSuccess"…

萬界星空科技商業開源MES/免費MES/低代碼MES

萬界星空科技商業開源MES可以提供包括制造數據管理、計劃排程管理、生產調度管理、庫存管理、質量管理、人力資源管理、工作中心/設備管理、工具工裝管理、采購管理、成本管理、項目看板管理、生產過程控制、底層數據集成分析、上層數據集成分解等管理模塊&#xff0c;打造一個…

141.【Git版本控制-本地倉庫-遠程倉庫-IDEA開發工具全解版】

Git-深入挖掘 (一)、Git分布式版本控制工具1.目標2.概述(1).開發中的實際常見(2).版本控制器的方式(3).SVN (集中版本控制器)(4).Git (分布版本控制器)(5).Git工作流程圖 (二)、Git安裝與常用命令1.Git環境配置(1).安裝Git的操作(2).Git的配置操作(3).為常用的指令配置別名 (可…

element中el-switch的v-model自定義值

一、問題 element中的el-switch的值默認都是true或false&#xff0c;但是有些時候后端接口該字段可能是0或者1&#xff0c;如果說再轉換一次值&#xff0c;那就有點太費力了。如下所示&#xff1a; <template><el-switchinactive-text"否"active-text&quo…

【Seata源碼學習 】篇四 TM事務管理器是如何開啟全局事務

TM發送 單個或批量 消息 以發送GlobalBeginRequest消息為例 TM在執行攔截器鏈路前將向TC發送GlobalBeginRequest 消息 io.seata.tm.api.DefaultGlobalTransaction#begin(int, java.lang.String) Overridepublic String begin(String applicationId, String transactionServi…

操作系統發展過程--單道批處理系統、多道批處理系統、分時系統、實時系統

一、單道批處理系統 計算機早期&#xff0c;為了能提高利用率&#xff0c;需要盡量保持系統的連續運行&#xff0c;即在處理完一個作業之后&#xff0c;緊接著處理下一個作業&#xff0c;以減少機器的空閑等待時間 1.單道批處理系統的處理過程 為了實現對作業的連續處理&…

51單片機應用從零開始(七)·循環語句(if語句,swtich語句)

51單片機應用從零開始&#xff08;一&#xff09;-CSDN博客 51單片機應用從零開始&#xff08;二&#xff09;-CSDN博客 51單片機應用從零開始&#xff08;三&#xff09;-CSDN博客 51單片機應用從零開始&#xff08;四&#xff09;-CSDN博客 51單片機應用從零開始&#xff08;…

數倉成本下降近一半,StarRocks 存算分離助力云覽科技業務出海

成都云覽科技有限公司傾力打造了鳳凰瀏覽器&#xff0c;專注于為海外用戶提供服務&#xff0c;公司致力于構建一個全球性的數字內容連接入口&#xff0c;為用戶帶來更為優質、高效、個性化的瀏覽體驗。 作為數據驅動的高科技公司&#xff0c;從數據中挖掘價值一直是公司核心任務…

【Spring進階系列丨第四篇】學習Spring中的Bean管理(基于xml配置)

前言 在之前的學習中我們知道&#xff0c;容器是一個空間的概念&#xff0c;一般理解為可盛放物體的地方。在Spring容器通常理解為BeanFactory或者ApplicationContext。我們知道spring的IOC容器能夠幫我們創建對象&#xff0c;對象交給spring管理之后我們就不用手動去new對象。…

基于單片機的智能藍牙避障循跡小車

智能小車循跡與避障運動控制系統的設計 摘 要:本設計主要由STC89C52單片機來進行控制&#xff0c;通過輸入輸出兩個端口控制驅動模塊來調節電機的工作狀態。本設計預利用機器視覺&#xff0c;通過識別條帶狀路標實現自主導航且利用超聲波模塊實時檢測距離以實現避障功能&…

vue3 webSocket 封裝及使用

vue3 webSocket 封裝及使用 封裝 import { ref, onUnmounted } from vue; interface SocketOptions {heartbeatInterval?: number;reconnectInterval?: number;maxReconnectAttempts?: number; }class Socket {url: string;ws: WebSocket | null null;opts: SocketOption…

【Docker】從零開始:9.Docker命令:Push推送倉庫(Docker Hub,阿里云)

【Docker】從零開始&#xff1a;9.Docker命令:Push推送倉庫 知識點1.Docker Push有什么作用&#xff1f;2.Docker倉庫有哪幾種2.1 公有倉庫2.2 第三方倉庫2.3 私有倉庫2.4 搭建私有倉庫的方法有哪幾種 3.Docker公有倉庫與私有倉庫的優缺點對比 Docker Push 命令標準語法操作參數…

openEuler 22.03 LTS x86_64 cephadm 部署ceph18.2.0 未完成 筆記

環境 準備三臺虛擬機 10.47.76.94 node-1 10.47.76.95 node-2 10.47.76.96 node-3 下載cephadm [rootnode-1 ~]# yum install cephadm Last metadata expiration check: 0:11:31 ago on Tue 21 Nov 2023 10:00:20 AM CST. Dependencies resolved. Package …

酷開系統 | 酷開科技聚焦價值人群 助力營銷增長

2023年&#xff0c;是消費復蘇回暖的一年&#xff0c;市場中充溢著大量品牌重啟增長的機遇與實例。品牌商期望能夠把握住市場趨勢&#xff0c;通過營銷獲得確定性的業績提升&#xff0c;并在未來收獲長期穩定的增長。作為數字媒介的代表之一&#xff0c;OTT大屏營銷的屬性和價值…

Vue學習之路------指令

Vue指令 vue會根據不同的指令&#xff0c;針對標簽實現不同的功能 指令:帶有v-前綴的特殊標簽屬性 1&#xff1a;v-html&#xff1a;指令 <div v-html"msg"></div> 2&#xff1a;v-show 作用&#xff1a;控制元素顯示隱藏 語法&#xff1a;v-show&quo…

【SpringMVC】 對請求的不同響應

前言 本文學習如何運用不同的注解來返回不同的響應. 1.返回靜態頁面Controller 返回index.html頁面 Controller 和 RestController的區別 controller 只有加上這個注解,Spring才會幫我們管理這個代碼.后續我們訪問時才能訪問到. RestController 等同于 Controller ResponseBo…

UML建模圖文詳解教程01——Enterprise Architect的安裝與使用

版權聲明 本文原創作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Enterprise Architect概述 官方網站&#xff1a;https://www.sparxsystems.cn/products/ea/&#xff1b;圖示如下&#xff1a; Enterprise Architect是一個全功能的、基于…