02-登錄頁面、動態路由、權限等模塊開發

權限模塊開發流程

  • 前端login頁面開發
  • 后端SpringSecurity配置
  • 后端login接口開發
  • 前端頁面框架搭建
  • 前端路由守衛,狀態管理開發
  • 前后端完成認證流程

開發Login頁面

  • 創建Login頁面
  • 創建router,可以跳轉到Login頁面

Login頁面

使用element-plus開發

認證功能流程

前端

  • 集成axios,并對axios進行封裝
  • 配置路由守衛
    • 對請求和響應的攔截
  • 登錄接口的調用
  • 登錄成功之后的頁面跳轉
    • 跳轉到首頁
    • 頁面就是由左側導航、頭部導航、頁面主體

后端

  • 配置SpringScurity
  • 寫登錄接口
    • 返回用戶的token、使用jwt生成token
    • 返回用戶的權限信息【路由頁面】

配置Redis

引入依賴

<!--引入redis-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>3.1.5</version>
</dependency>

配置連接

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://rm-2ze9013333m0paw8ywo.mysql.rds.aliyuncs.com:3306/daocao?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: puhe_shitianpassword: Shitian@9527data:redis:# 地址host: localhost# 數據庫索引database: 2# 密碼password: $2a$10$4NR/# 連接超時時間timeout: 10slettuce:pool:# 連接池中的最小空閑連接min-idle: 0# 連接池中的最大空閑連接max-idle: 8# 連接池的最大數據庫連接數max-active: 8# #連接池最大阻塞等待時間(使用負值表示沒有限制)max-wait: -1ms

配置Redis數據序列化

public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>{public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");private Class<T> clazz;public FastJson2JsonRedisSerializer(Class<T> clazz){super();this.clazz = clazz;}@Overridepublic byte[] serialize(T t) throws SerializationException{if (t == null){return new byte[0];}return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);}@Overridepublic T deserialize(byte[] bytes) throws SerializationException{if (bytes == null || bytes.length <= 0){return null;}String str = new String(bytes, DEFAULT_CHARSET);return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);}
}
package com.daocao.support.config.redis;import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @author 石添* @date 2023/11/15 9:31*/
@Configuration
@EnableCaching
public class RedisConfig {@Bean@SuppressWarnings(value = { "unchecked", "rawtypes" })public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);// 使用StringRedisSerializer來序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(serializer);// Hash的key也采用StringRedisSerializer的序列化方式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(serializer);template.afterPropertiesSet();return template;}@Beanpublic DefaultRedisScript<Long> limitScript() {DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();redisScript.setScriptText(limitScriptText());redisScript.setResultType(Long.class);return redisScript;}/*** 限流腳本*/private String limitScriptText() {return "local key = KEYS[1]\n" +"local count = tonumber(ARGV[1])\n" +"local time = tonumber(ARGV[2])\n" +"local current = redis.call('get', key);\n" +"if current and tonumber(current) > count then\n" +"    return tonumber(current);\n" +"end\n" +"current = redis.call('incr', key)\n" +"if tonumber(current) == 1 then\n" +"    redis.call('expire', key, time)\n" +"end\n" +"return tonumber(current);";}
}

工具類

package com.daocao.common.redis;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.*;
import java.util.concurrent.TimeUnit;/*** @author ShiTian* @date 2022/8/1 17:19*/
@Component
public class RedisCache {@Autowiredpublic RedisTemplate redisTemplate;/*** 緩存基本的對象,Integer、String、實體類等** @param key 緩存的鍵值* @param value 緩存的值*/public <T> void setCacheObject(final String key, final T value){redisTemplate.opsForValue().set(key, value);}/*** 緩存基本的對象,Integer、String、實體類等** @param key 緩存的鍵值* @param value 緩存的值* @param timeout 時間* @param timeUnit 時間顆粒度*/public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 設置有效時間** @param key Redis鍵* @param timeout 超時時間* @return true=設置成功;false=設置失敗*/public boolean expire(final String key, final long timeout){return expire(key, timeout, TimeUnit.SECONDS);}/*** 設置有效時間** @param key Redis鍵* @param timeout 超時時間* @param unit 時間單位* @return true=設置成功;false=設置失敗*/public boolean expire(final String key, final long timeout, final TimeUnit unit){return redisTemplate.expire(key, timeout, unit);}/*** 獲得緩存的基本對象。** @param key 緩存鍵值* @return 緩存鍵值對應的數據*/public <T> T getCacheObject(final String key){ValueOperations<String, T> operation = redisTemplate.opsForValue();return operation.get(key);}/*** 刪除單個對象** @param key*/public boolean deleteObject(final String key){return redisTemplate.delete(key);}/*** 刪除集合對象** @param collection 多個對象* @return*/public long deleteObject(final Collection collection){return redisTemplate.delete(collection);}/*** 緩存List數據** @param key 緩存的鍵值* @param dataList 待緩存的List數據* @return 緩存的對象*/public <T> long setCacheList(final String key, final List<T> dataList){Long count = redisTemplate.opsForList().rightPushAll(key, dataList);return count == null ? 0 : count;}/*** 獲得緩存的list對象** @param key 緩存的鍵值* @return 緩存鍵值對應的數據*/public <T> List<T> getCacheList(final String key){return redisTemplate.opsForList().range(key, 0, -1);}/*** 緩存Set** @param key 緩存鍵值* @param dataSet 緩存的數據* @return 緩存數據的對象*/public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);Iterator<T> it = dataSet.iterator();while (it.hasNext()){setOperation.add(it.next());}return setOperation;}/*** 獲得緩存的set** @param key* @return*/public <T> Set<T> getCacheSet(final String key){return redisTemplate.opsForSet().members(key);}/*** 緩存Map** @param key* @param dataMap*/public <T> void setCacheMap(final String key, final Map<String, T> dataMap){if (dataMap != null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 獲得緩存的Map** @param key* @return*/public <T> Map<String, T> getCacheMap(final String key){return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入數據** @param key Redis鍵* @param hKey Hash鍵* @param value 值*/public <T> void setCacheMapValue(final String key, final String hKey, final T value){redisTemplate.opsForHash().put(key, hKey, value);}/*** 獲取Hash中的數據** @param key Redis鍵* @param hKey Hash鍵* @return Hash中的對象*/public <T> T getCacheMapValue(final String key, final String hKey){HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 刪除Hash中的數據** @param key* @param hKey*/public void delCacheMapValue(final String key, final String hKey){HashOperations hashOperations = redisTemplate.opsForHash();hashOperations.delete(key, hKey);}/*** 獲取多個Hash中的數據** @param key Redis鍵* @param hKeys Hash鍵集合* @return Hash對象集合*/public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 獲得緩存的基本對象列表** @param pattern 字符串前綴* @return 對象列表*/public Collection<String> keys(final String pattern){return redisTemplate.keys(pattern);}
}

認證功能實現

認證功能主要由三部分組成:

  • 根據用戶名和密碼登陸,獲取返回的token保存下來
  • 攜帶token請求用戶的路由權限信息,跳轉到項目首頁
  • 通過路由守衛,實現動態路由配置

登陸

登錄方法中獲取token,將token存儲到sessionStorage中【或者pinia】。在axios請求中,獲取token,將token傳到后端

請求路由信息

后端:創建過濾器,獲取request中的token,獲取token之后,需要刷新token

獲取路由數據,根據token獲取用戶信息,根據用戶id查詢對應的權限

存儲路由數據

使用pinia進行全局存儲【localstorage存儲,sessionstorage存儲】,前提保障項目中引入pinia

路由頁面

使用vue-router路由頁面,保障項目中引入vue-router

創建核心頁面

頁面其實單頁面,所有的路由都是跳轉到同一個組件下的,只不過在main容器中,替換不同的vue文件【頁面】就可以了

核心頁面由三部分組成

  • 左側導航【Aside】
    • 樹形結構的菜單,里邊包含了菜單名以及路由信息
  • 頭部【Header】
  • 主體【Main】

可以使用element-plus實現

動態路由

兩步走:

  • 路由查詢出來之后,需要渲染動態路由結構
  • 在路由頁面的時候,可以知道頁面跳轉的位置【通過路由守衛實現】

pinia持久化

安裝持久化插件

npm install pinia-plugin-persistedstate

main.js配置

import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

store文件

export const xxxx = defineStore('xxx', {state: () => ({ ...... }),getter: {},actions: {},// 持久化persist: {enabled: true,storage: localStorage,key: 'useMenu',path: ['xxxx','xxxx']}
})

自定義icon

導入依賴

npm install fast-globnpm install vite-plugin-svg-icons

vite.config.js

// 引入path
import path from 'path'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'export default defineConfig({plugins: [vue(),createSvgIconsPlugin({iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')],symbolId: '[name]'})],resolve: {// 使用import導入文件時刻省略后綴extensions: ['.js', '.vue', '.json'],alias: {'@': fileURLToPath(new URL('./src', import.meta.url))}}
})

編寫組件

components下創建 SvgIcon\index.vue

<template><!-- svg:圖標外層容器節點,內部需要與use標簽結合使用 --><svg :style="{ width, height }"><!-- xlink:href執行用哪一個圖標,屬性值務必#icon-圖標名字 --><!-- use標簽fill屬性可以設置圖標的顏色 --><use :xlink:href="prefix + name" :fill="color"></use></svg>
</template><script setup>//接受父組件傳遞過來的參數
defineProps({//xlink:href屬性值前綴prefix: {type: String,default: "#",},//提供使用的圖標名字name: String,//接受父組件傳遞顏色color: {type: String,default: "",},//接受父組件傳遞過來的圖標的寬度width: {type: String,default: "16px",},//接受父組件傳遞過來的圖標的高度height: {type: String,default: "16px",},
})
</script><style lang="scss" scoped></style>

全局注冊,在main.js添加

import SvgIcon from '@/components/SvgIcon/index.vue';
import 'virtual:svg-icons-register';app.component('svg-icon', SvgIcon);

使用

<template #prefix>
<svg-iconv-if="form.icon"slot="prefix":name="form.icon" width="16px" height="25px"/>
</template>

使用elemet-plus的icon

頭部tabs開發

Main組件

Aside組件

配置省略后綴

在 vite.config.js文件中配置

export default defineConfig({......resolve: {extensions: ['.js','.vue','.json','.css'],alias: {'@': fileURLToPath(new URL('./src',import.meta.url))}}
})

安裝vue3 devtools插件

參考鏈接

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

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

相關文章

力扣75. 顏色分類

Problem: 75. 顏色分類 文章目錄 題目描述思路及解法復雜度Code 題目描述 思路及解法 由于題目只提供0&#xff0c;1&#xff0c;2分別代表顏色紅、白、藍&#xff0c;并按此排序&#xff0c;那么我們可以遍歷兩次數組&#xff0c;第一次將0&#xff0c;全部放到數組前面一部分…

移動 App 入侵與逆向破解技術-iOS 篇

如果您有耐心看完這篇文章&#xff0c;您將懂得如何著手進行app的分析、追蹤、注入等實用的破解技術&#xff0c;另外&#xff0c;通過“入侵”&#xff0c;將幫助您理解如何規避常見的安全漏洞&#xff0c;文章大綱&#xff1a; 簡單介紹ios二進制文件結構與入侵的原理介紹入…

軟考考試需要達到多少分才能及格?

當然是45分&#xff01;45分&#xff01;45分&#xff01;而且是各科45&#xff01; 初級和中級考兩科 綜合知識考試時長為150分鐘&#xff0c;筆試&#xff0c;選擇題&#xff08;上午9:00-11:30&#xff09; 案例分析考試時長為90分鐘&#xff0c;筆試&#xff0c;問答題&…

計算機畢業設計 | vue+springboot圖書借閱 書籍管理系統(附源碼)

1. 開發目的 實現圖書的智能化、信息化和簡單化&#xff1b;實現圖書信息的增加、刪除、修改、查找、借閱、還書、收藏的顯示操作及實時數據庫的提交和更改和對普通用戶的增、刪、改、查&#xff1b;提高圖書管理員工作信息報送及反饋的工作效率&#xff0c;減輕管理員的勞動負…

Unity組件入門篇目錄

Audio AudioChorusFilter......................................點擊導航AudioDistortionFilter..................................點擊導航AudioEchoFilter.........................................點擊導航AudioHighPassFilter..................................點擊導…

設計模式Java實現-迭代器模式

?這里是第七人格的博客?小七&#xff0c;歡迎您的到來~? &#x1f345;系列專欄&#xff1a;設計模式&#x1f345; ??本篇內容: 迭代器模式?? &#x1f371; 本篇收錄完整代碼地址&#xff1a;https://gitee.com/diqirenge/design-pattern &#x1f371; 楔子 很久…

Java Spring 中使用緩存來提高性能

在Spring框架中&#xff0c;緩存是一種用于提高應用程序性能的重要機制。通過緩存&#xff0c;可以減少對數據庫或其他外部資源的訪問次數&#xff0c;從而加快應用程序的響應速度。以下是如何在Spring中使用緩存來提高性能的詳細過程&#xff1a; 1. 引入緩存依賴 首先&…

蒼穹外賣Day06筆記(復習了jwt的加密解密和傳遞)

瘋玩了一個月&#xff0c;效率好低&#xff0c;今天開始撿起來蒼穹外賣~ 1. 為什么不需要單獨引入HttpClient的dependency&#xff1f; 因為我們在sky-common的pom.xml中已經引入了aliyun-sdk-oss的依賴&#xff0c;而這個依賴低層就引入了httpclinet的依賴&#xff0c;根據依…

C語言從頭學05——頭文件及庫文件

我們寫"Hello World!"程序時&#xff0c;一上來先寫了一句代碼&#xff1a; #include <stdio.h> 我們看上面這條代碼&#xff0c;前面有個"#"號后邊沒有";"號&#xff0c;這樣的代碼不是普通的C語言代碼&#xff0c;它屬于預處理命令。這…

代碼隨想錄算法訓練營第六天| 242. 有效的字母異位詞、349. 兩個數組的交集、202. 快樂數、1. 兩數之和

哈希表理論基礎 [LeetCode] 242. 有效的字母異位詞 [LeetCode] 242. 有效的字母異位詞 文章解釋 [LeetCode] 242. 有效的字母異位詞 視頻解釋 題目: 給定兩個字符串 s 和 t &#xff0c;編寫一個函數來判斷 t 是否是 s 的字母異位詞。 注意&#xff1a;若 s 和 t 中每個字符出…

JavaEE技術之SpringCloud(Nacos注冊中心、Nacos配置中心、Sentinel實現熔斷與限流)

文章目錄 SpringCloud Alibaba1、簡介1.1 背景1.2 Nacos主要功能1.3 Nacos和SpringBoot、SpringCloud版本選擇 2、Nacos注冊中心2.1 案例準備2.2 Nacos注冊中心下載啟動2.2.1 下載2.2.2 解壓啟動2.2.3 nacos-server訪問測試 2.3 nacos注冊中心客戶端整合2.3.1 訂單服務整合naco…

YTU 3166 共享單車 DFS 記憶化搜索

問題 D: 共享單車 題目描述 共享單車走進煙臺&#xff0c;小明決定嘗試。小明啟動共享單車 App&#xff0c;輕松地找到附近的單車。那么問題來了&#xff0c;到最近的那輛單車&#xff0c;小明大約要走多少米呢&#xff1f; 現在簡化問題。將地圖設定成一個由 100100 米的像…

【UE】仿原神實現無限道路延伸的開場效果

目錄 效果 步驟 一、無限生成磚塊 二、制作門 三、停止移動并生成門 四、進入門 效果 步驟 一、無限生成磚塊 1. 新建一個Basic關卡&#xff0c;再新建一個Pawn類&#xff0c;這里命名為“BP_MyPawn” 打開“BP_MyPawn”&#xff0c;添加一個膠囊體碰撞組件和一個攝像…

工器具管理(基于若依)

文章目錄 前言一、工器具管理項目總覽 二、入庫功能1. 前端1.1 界面展示1.2 具體操作實現1.3 js文件 2. 后端2.1 工器具信息回顯2.2 工器具入庫 三、領用功能1. 前端1.1 界面展示1.2 具體實現操作1.3 js文件 2. 后端2.1 工器具信息回顯2.2 工器具領用 遇到的問題1. 同一頁面展示…

pat乙1033-舊鍵盤打字

1測試點2&#xff1a; 輸入的字符串如果為空&#xff0c;要用getline(cin,s)&#xff0c;而不是cin>>s&#xff0c;否則程序做不了 2題目說的如果上鍵壞了那大寫字母打印不了&#xff0c;不是大寫轉小寫打印啦&#xff0c;認真讀題 3兩個for循環長這樣&#xff0c;break…

基于springboot+vue的自習室管理和預約系統(全套)

一、系統架構 前端&#xff1a;vue | element-ui | html 后端&#xff1a;springboot | mybatis-plus 環境&#xff1a;jdk1.8 | mysql | maven | nodejs 二、代碼及數據庫 三、功能介紹 01. web端-首頁1 02. web端-首頁2 03. web端-注冊 04. web端-登錄 05. w…

牛客Linux高并發服務器開發學習第六天

目錄相關函數 學習進度&#xff1a; Linux系統編程入門 06&#xff1a;59&#xff1a;42

Apollo9.0 Control模塊算法源碼學習

參考資料 Apollo控制算法_嗶哩嗶哩_bilibili

Python自動化測試 | 如何使用Robot Framework進行自動化測試?

你還在手動測試&#xff1f;不妨了解一下更高效、準確且簡單的測試方法——使用Python的Robot Framework進行自動化測試。 什么是Robot Framework&#xff1f; Robot Framework是一款開源的Python自動化測試框架&#xff0c;它基于關鍵字驅動的思想&#xff0c;具有易讀、易擴…

每日一題 城市群的數量

題目解析 城市群數量_牛客題霸_牛客網 當解決這個問題時&#xff0c;首先需要理解題目要求。題目中給出了一個城市之間的鄰接矩陣&#xff0c;矩陣中的元素表示城市之間是否直接相連。如果兩個城市直接相連&#xff0c;或者通過其他城市間接相連&#xff0c;它們就屬于同一個城…