尚品甄選電商SpringBoot-Web開發之用戶登入與角色管理
相關資源
網友整理的完整程式碼
前置作業
使用開源模板
vue3 和 element-plus UI 框架,vite 建構工具、pinia 狀態管理、vue-router 路由管理、mockjs 數據模擬,並整合了 typescript,功能由 Vue Element Admin 移植而来。
- 使用
node 16.9.0
Redis建立
原文是有一個虛擬機來放置docker,而我是直接使用windows的docker,所以在設定的時候和原文不太一樣
原文命令
各命令的解釋(來源chatgpt)
docker run
: This command is used to run a Docker container.-d
: It stands for “detached” mode, which means the container runs in the background.-p 6379:6379
: This option maps port 6379 on the host to port 6379 in the container. This allows external processes to communicate with Redis through port 6379.--restart=always
: This option specifies that the container should always restart automatically if it stops for any reason.-v redis-config:/etc/redis/config
: This option creates a volume named “redis-config” and mounts it to the “/etc/redis/config” directory inside the container. This allows you to provide custom Redis configuration files.-v redis-data:/data
: This option creates a volume named “redis-data” and mounts it to the “/data” directory inside the container. This is used to persist Redis data, allowing it to survive container restarts or deletion.--name redis
: This option assigns the name “redis” to the container.redis
: This is the name of the Docker image used to create the container. In this case, it’s the official Redis image from Docker Hub.redis-server /etc/redis/config/redis.conf
: This command instructs the Redis server to use the configuration file located at “/etc/redis/config/redis.conf” inside the container.
唯一有問題的就是redis.config
不知道要放哪,根據-v redis-config:/etc/redis/config
,是映射關係,也就是redis-config
這個volume
映射到後面那個路徑,於是我建立了一個資料夾,然後照樣建立redis.conf
,然後映射過去變為以下指令
應該要弄一個linux
系統的虛擬機,這樣會比較方便,不過教程沒有細講,所以就直接用了win10
,之後太麻煩的話就考慮全部搬到虛擬機去了
啟動的問題
直接執行會出現Getting java.lang.IllegalStateException: Logback configuration error detected error...
原因是logback
的設定檔案logback-spring.xml
裡面輸出路徑要改成自己的
用戶登入-異常處理
為了統一遇到異常(錯誤)時回傳的資訊,定義新的異常,並且建立global
異常處理器來統一管理
於是新增了GlobalExceptionHandler
裡面目前定義了異常的部分就是回傳enum
的LOGIN_ERROR
這些是原先定義好的部分
以及自訂SimonException
,定義好其constructor
,這樣被throw
的時候就可以傳入指定的值,exception
就會被拋出,因為GlobalExceptionHandler
裡已經定義好,如下
用戶登入(前端接入)
直接在vscode
的cmd
輸入npm start
可能會看到以下錯誤
實際上只是因為在workspace
,cmd
的初始位置是在上一層的資料夾,而我們需要到程式的前端資料夾內執行
使用前端記得先執行後端,這樣才能調用後端資料庫
跨域問題
前端程式,目前把請求導向port 8501
(也就是後端的port
),但是這樣會出現跨域請求的問題
解決方法: 在後端設定開啟跨域(前端也可以設定代理等等解決,不過此教程為後端導向)
先前有登入過的話可能再次開啟port 3001
會是空白的,因為沒有設定跳轉頁面,可以使用這個網址進到登入頁面
使用帳號admin
,密碼111111
登入,此時如果按照步驟來,會在控制台看到404 not found
因為還沒有設定拉取userinfo
資料的路徑
圖片驗證碼產生
這部分沒什麼問題,照著做就可以成功了,步驟如下
- 編寫後端邏輯,建立
API
- 調用
hutool
的功能建立驗證碼圖片,使用Base64
編碼 - 前端調用後端
API
,並且修改html
,Ajax
調用API
顯示圖片
圖片驗證碼驗證
在SysUserServiceImpl.java
中
- 驗證帳號密碼之前先驗證圖片驗證碼是否正確
取得當前登入用戶的資料
有兩種從request
拿到token
的方式:
同時這部分也改了好幾個前端的code
,一直出錯,最後找到原因是前端接後端的getUserInfo
API沒有寫對
這裡主要就是後端邏輯寫好,前端連一下API
就搞定
用戶登出
- 點退出登入
- 根據
header
的token
呼叫service
中的logout
方法 logout
方法直接依照token
查詢,登出時直接把token
也刪除,完成登出- 前端的部分就是呼叫後端方法
登入驗證
如何做到?
flowchart TD
A[攔截器Interceptors] --> B{當前路徑需要驗證登入}
B -->|是| C[從header嘗試取得token,並查詢redis]
B -->|否| 通過
C --> D[redis是否有用戶資訊]
D --> |是| E[取得用戶資訊,存到ThreadLocal]
D --> |否| F[不是登入狀態,回傳提示訊息]
E --> 更新redis資料過期時間
- 需要把攔截器加入到
Spring MVC
中,設定攔截的路徑
延伸文章: Java - ThreadLocal 類的使用
優化
- 把排除的路徑寫入
configuration
,減少冗長code
- 因為上面把用戶資料放入
threadLocal
,所以不需要從資料庫去撈,直接取threadLocal
的即可 - 前端: 判斷如果狀態碼是
208
(表示未登入),直接跳轉到登入頁面
把排除的路徑寫入configuration
- 寫一個
configurationProperty
並且加入到Spring
啟動檔案 - 把路徑寫入設定檔案
從threadLocal取得用戶資料
狀態碼208跳轉登入頁面
權限管理
例如:
Lucy是總經理,可以使用menu所有tabs
Mary是Sales,僅可使用商品管理menu
大致有三張表:
- 用戶表
- 角色表
- 選單表
用戶與角色是多對多關係,為了實做這個部分,需要一張角色用戶關係表(類似map
)
角色與選單也是多對多關係
小練習:
- 查詢
id
為1
的用戶的角色資料
- 查詢
id
為1
的用戶的menu
資料
這個比較複雜一點因為需要關聯三張表,把他們的id
透過關係表連接起來
準備工作
- 前端新增角色定向
router
中新增定向
- 建立角色頁面
views
中新增介面給menu
,role
以及user
- 後端角色相關
controller
,service
,mapper
建立
需要實作的功能:
- 根據角色名稱條件搜尋
- 分頁顯示
後端介面
使用pagehelper plugin
SysRoleController
: 加入findByPage
方法,並傳入三個參數(current
,limit
,sysRoleDto
),調用sysRoleService
中的findByPage
SysRoleServiceImpl
: 加入findByPage
方法,也是同樣的三個參數,設定分頁參數(起始分頁)以及根據條件搜尋資料並且封裝成pageInfo
物件並回傳
SysRoleMapper.xml
(SysRoleMapper
調用): 加入sql
語句,根據條件搜尋,如果roleName
為空就代表無條件搜尋
前端介面
修改並完善sysRole
頁面
sysRole.js
: 介面Post
請求後端資料
sysRole.vue
頁面: 修改按鈕觸發method
,並且顯示資料
總結一下上述這兩個前端與後端的操作,大致上的步驟如下:
- 用戶在頁面上輸入角色條件點
搜索
- 會觸發
sysRole.vue
的按鈕,這個按鈕會調用searchSysRole
方法(在script
裡) searchSysRole
方法會調用fetchData
fetchData
會調用sysRole.js
中的GetSysRoleListByPage
方法嘗試取得資料- 而
GetSysRoleListByPage
方法會透過api
請求後端資料 - 後端
SysRoleController
接收到請求,調用SysRoleService
的findByPage
SysRoleService
再調用SysRoleMapper
進行資料庫請求,執行sql
語句- 資料取得後
SysRoleController
再把資料傳給前端 - 前端收到資料後顯示
角色新增介面
前端的部分利用element-plus
快速構建一個彈出提示框,可以輸入角色名稱、角色Code
,並且提交
提交後通過js
請求後端,後端再通過controller->service->mapper
加入資料並回傳,如果加入成功,code
是200
,就關掉提示框,顯示添加成功並且重新載入數據以顯示更新後的
角色修改界面
基本上是和新增大同小異,以下幾點需特別注意
- 修改時彈框中顯示的數據可以使用
{...row}
,否則直接使用row
會造成邊修改,介面上的資料也會跟著修改,即便還沒提交 - 修改與添加同樣都是透過
submit
函式處理,所以可以藉由判斷sysRole
是否有id
來判斷要呼叫哪個api
- 後端部分也是比較簡單的controller->service->mapper
- 更新時要判斷每個值是否存在,否則就不更新
角色刪除功能
- 根據
id
刪除角色 - 使用邏輯刪除而非物理刪除,也就是利用
is_deleted
這個參數,刪除時把該筆資料標記為1
,代表已刪除,查詢時查找is_deleted
為0
的所有數據