營銷型網(wǎng)站建設(shè)的注意事項灰色行業(yè)推廣平臺
瑞吉外賣-Day02
課程內(nèi)容
完善登錄功能
新增員工
員工信息分頁查詢
啟用/禁用員工賬號
編輯員工信息
1. 完善登錄功能
1.1 問題分析
前面我們已經(jīng)完成了后臺系統(tǒng)的員工登錄功能開發(fā),但是目前還存在一個問題,接下來我們來說明一個這個問題, 以及如何處理。
1). 目前現(xiàn)狀
用戶如果不登錄,直接訪問系統(tǒng)首頁面,照樣可以正常訪問。

2). 理想效果
上述這種設(shè)計并不合理,我們希望看到的效果應(yīng)該 是,只有登錄成功后才可以訪問系統(tǒng)中的頁面,如果沒有登錄, 訪問系統(tǒng)中的任何界面都直接跳轉(zhuǎn)到登錄頁面。

那么,具體應(yīng)該怎么實現(xiàn)呢?
可以使用我們之前講解過的 過濾器、攔截器來實現(xiàn),在過濾器、攔截器中攔截前端發(fā)起的請求,判斷用戶是否已經(jīng)完成登錄,如果沒有登錄則返回提示信息,跳轉(zhuǎn)到登錄頁面。
1.2 思路分析

過濾器具體的處理邏輯如下:
A. 獲取本次請求的URI
B. 判斷本次請求, 是否需要登錄, 才可以訪問
C. 如果不需要,則直接放行
D. 判斷登錄狀態(tài),如果已登錄,則直接放行
E. 如果未登錄, 則返回未登錄結(jié)果
如果未登錄,我們需要給前端返回什么樣的結(jié)果呢? 這個時候, 我們可以去看看前端是如何處理的 ?

1.3 代碼實現(xiàn)
1). 定義登錄校驗過濾器
自定義一個過濾器 LoginCheckFilter 并實現(xiàn) Filter 接口, 在doFilter方法中完成校驗的邏輯。 那么接下來, 我們就根據(jù)上述分析的步驟, 來完成具體的功能代碼實現(xiàn):
AntPathMatcher 拓展:
介紹: Spring中提供的路徑匹配器 ;
通配符規(guī)則:
2). 開啟組件掃描
需要在引導(dǎo)類上, 加上Servlet組件掃描的注解, 來掃描過濾器配置的@WebFilter注解, 掃描上之后, 過濾器在運行時就生效了。
@ServletComponentScan 的作用:
在SpringBoot項目中, 在引導(dǎo)類/配置類上加了該注解后, 會自動掃描項目中(當(dāng)前包及其子包下)的@WebServlet , @WebFilter , @WebListener 注解, 自動注冊Servlet的相關(guān)組件 ;
1.4 功能測試
代碼編寫完畢之后,我們需要將工程重啟一下,然后在瀏覽器地址欄直接輸入系統(tǒng)管理后臺首頁,然后看看是否可以跳轉(zhuǎn)到登錄頁面即可。我們也可以通過debug的形式來跟蹤一下代碼執(zhí)行的過程。
對于前端的代碼, 也可以進行debug調(diào)試。
F12打開瀏覽器的調(diào)試工具, 找到我們前面提到的request.js, 在request.js的響應(yīng)攔截器位置打上斷點。
2. 新增員工
2.1 需求分析
后臺系統(tǒng)中可以管理員工信息,通過新增員工來添加后臺系統(tǒng)用戶。點擊[添加員工]按鈕跳轉(zhuǎn)到新增頁面,如下:
當(dāng)填寫完表單信息, 點擊"保存"按鈕后, 會提交該表單的數(shù)據(jù)到服務(wù)端, 在服務(wù)端中需要接受數(shù)據(jù), 然后將數(shù)據(jù)保存至數(shù)據(jù)庫中。
2.2 數(shù)據(jù)模型
新增員工,其實就是將我們新增頁面錄入的員工數(shù)據(jù)插入到employee表。employee表中的status字段已經(jīng)設(shè)置了默認(rèn)值1,表示狀態(tài)正常。
需要注意,employee表中對username字段加入了唯一約束,因為username是員工的登錄賬號,必須是唯一的。
2.3 程序執(zhí)行流程
在開發(fā)代碼之前,我們需要結(jié)合著前端頁面發(fā)起的請求, 梳理一下整個程序的執(zhí)行過程:
A. 點擊"保存"按鈕, 頁面發(fā)送ajax請求,將新增員工頁面中輸入的數(shù)據(jù)以json的形式提交到服務(wù)端, 請求方式POST, 請求路徑 /employee
B. 服務(wù)端Controller接收頁面提交的數(shù)據(jù)并調(diào)用Service將數(shù)據(jù)進行保存
C. Service調(diào)用Mapper操作數(shù)據(jù)庫,保存數(shù)據(jù)
2.4 代碼實現(xiàn)
在EmployeeController中增加save方法, 用于保存用戶員工信息。
A. 在新增員工時, 按鈕頁面原型中的需求描述, 需要給員工設(shè)置初始默認(rèn)密碼 123456, 并對密碼進行MD5加密。
B. 在組裝員工信息時, 還需要封裝創(chuàng)建時間、修改時間,創(chuàng)建人、修改人信息(從session中獲取當(dāng)前登錄用戶)。
2.5 功能測試
代碼編寫完畢之后,我們需要將工程重啟, 完畢之后直接訪問管理系統(tǒng)首頁, 點擊 "員工管理" 頁面中的 "添加員工" 按鈕, 輸入員工基本信息, 然后點擊 "保存" 進行數(shù)據(jù)保存, 保存完畢后, 檢查數(shù)據(jù)庫中是否錄入員工數(shù)據(jù)。
當(dāng)我們在測試中,添加用戶時, 輸入了一個已存在的用戶名時,前端界面出現(xiàn)錯誤提示信息:
而此時,服務(wù)端已經(jīng)報錯了, 報錯信息如下:
出現(xiàn)上述的錯誤, 主要就是因為在 employee 表結(jié)構(gòu)中,我們針對于username字段,建立了唯一索引,添加重復(fù)的username數(shù)據(jù)時,違背該約束,就會報錯。但是此時前端提示的信息并不具體,用戶并不知道是因為什么原因造成的該異常,我們需要給用戶提示詳細(xì)的錯誤信息 。
2.6 全局異常處理
2.6.1 思路分析
要想解決上述測試中存在的問題,我們需要對程序中可能出現(xiàn)的異常進行捕獲,通常有兩種處理方式:
A. 在Controller方法中加入 try...catch 進行異常捕獲
形式如下:
如果采用這種方式,雖然可以解決,但是存在弊端,需要我們在保存其他業(yè)務(wù)數(shù)據(jù)時,也需要在Controller方法中加上try...catch進行處理,代碼冗余,不通用。
B. 使用異常處理器進行全局異常捕獲
采用這種方式來實現(xiàn),我們只需要在項目中定義一個通用的全局異常處理器,就可以解決本項目的所有異常。
2.6.2 全局異常處理器
在項目中自定義一個全局異常處理器,在異常處理器上加上注解 @ControllerAdvice,可以通過屬性annotations指定攔截哪一類的Controller方法。 并在異常處理器的方法上加上注解 @ExceptionHandler 來指定攔截的是那一類型的異常。
異常處理方法邏輯:
指定捕獲的異常類型為 SQLIntegrityConstraintViolationException
解析異常的提示信息, 獲取出是那個值違背了唯一約束
組裝錯誤信息并返回
所屬包: com.itheima.reggie.common
注解說明:
上述的全局異常處理器上使用了的兩個注解 @ControllerAdvice , @ResponseBody , 他們的作用分別為:
@ControllerAdvice : 指定攔截那些類型的控制器;
@ResponseBody: 將方法的返回值 R 對象轉(zhuǎn)換為json格式的數(shù)據(jù), 響應(yīng)給頁面;
上述使用的兩個注解, 也可以合并成為一個注解 @RestControllerAdvice
2.6.3 測試
全局異常處理器編寫完畢之后,我們需要將項目重啟, 完畢之后直接訪問管理系統(tǒng)首頁, 點擊 "員工管理" 頁面中的 "添加員工" 按鈕。當(dāng)我們在測試中,添加用戶時, 輸入了一個已存在的用戶名時,前端界面出現(xiàn)如下錯誤提示信息:
3. 員工分頁查詢
3.1 需求分析
系統(tǒng)中的員工很多的時候,如果在一個頁面中全部展示出來會顯得比較亂,不便于查看,所以一般的系統(tǒng)中都會以分頁的方式來展示列表數(shù)據(jù)。而在我們的分頁查詢頁面中, 除了分頁條件以外,還有一個查詢條件 "員工姓名"。
請求參數(shù)
搜索條件: 員工姓名(模糊查詢)
分頁條件: 每頁展示條數(shù) , 頁碼
響應(yīng)數(shù)據(jù)
總記錄數(shù)
結(jié)果列表
3.2 程序執(zhí)行流程
3.2.1 頁面流程分析
在開發(fā)代碼之前,需要梳理一下整個程序的執(zhí)行過程。
A. 點擊菜單,打開員工管理頁面時,執(zhí)行查詢:
B. 搜索欄輸入員工姓名,回車,執(zhí)行查詢:
1). 頁面發(fā)送ajax請求,將分頁查詢參數(shù)(page、pageSize、name)提交到服務(wù)端
2). 服務(wù)端Controller接收頁面提交的數(shù)據(jù), 并組裝條件調(diào)用Service查詢數(shù)據(jù)
3). Service調(diào)用Mapper操作數(shù)據(jù)庫,查詢分頁數(shù)據(jù)
4). Controller將查詢到的分頁數(shù)據(jù), 響應(yīng)給前端頁面
5). 頁面接收到分頁數(shù)據(jù), 并通過ElementUI的Table組件展示到頁面上
3.2.2 前端代碼介紹
1). 訪問員工列表頁面/member/list.html時, 會觸發(fā)Vuejs中的鉤子方法, 在頁面初始化時調(diào)用created方法
從上述的前端代碼中我們可以看到, 執(zhí)行完分頁查詢, 我們需要給前端返回的信息中需要包含兩項 : records 中封裝結(jié)果列表, total中封裝總記錄數(shù) 。
而在組裝請求參數(shù)時 , page、pageSize 都是前端分頁插件渲染時的參數(shù);
2). 在getMemberList方法中, 通過axios發(fā)起異步請求
axios發(fā)起的異步請求會被聲明在 request.js 中的request攔截器攔截, 在其中對get請求進行進一步的封裝處理
最終發(fā)送給服務(wù)端的請求為 : GET請求 , 請求鏈接 /employee/page?page=1&pageSize=10&name=xxx
3.3 代碼實現(xiàn)
3.3.1 分頁插件配置
當(dāng)前我們要實現(xiàn)的分頁查詢功能,而在MybatisPlus要實現(xiàn)分頁功能,就需要用到MybatisPlus中提供的分頁插件,要使用分頁插件,就要在配置類中聲明分頁插件的bean對象。
3.3.2 分頁查詢實現(xiàn)
在上面我們已經(jīng)分析了,頁面在進行分頁查詢時, 具體的請求信息如下:
請求 | 說明 |
請求方式 | GET |
請求路徑 | /employee/page |
請求參數(shù) | page , pageSize , name |
那么查詢完畢后我們需要給前端返回什么樣的結(jié)果呢?
在上述我們也分析了, 查詢返回的結(jié)果數(shù)據(jù)data中應(yīng)該封裝兩項信息, 分別為: records 封裝分頁列表數(shù)據(jù), total 中封裝符合條件的總記錄數(shù)。 那么這個時候, 在定義controller方法的返回值類型R時, 我們可以直接將 MybatisPlus 分頁查詢的結(jié)果 Page 直接封裝返回, 因為Page中的屬性如下:
那么接下來就依據(jù)于這些已知的需求和條件完成分頁查詢的代碼實現(xiàn)。 具體的邏輯如下:
A. 構(gòu)造分頁條件
B. 構(gòu)建搜索條件 - name進行模糊匹配
C. 構(gòu)建排序條件 - 更新時間倒序排序
D. 執(zhí)行查詢
E. 組裝結(jié)果并返回
具體的代碼實現(xiàn)如下:
3.4 功能測試
代碼編寫完畢之后,我們需要將工程重啟, 完畢之后直接訪問管理系統(tǒng)首頁, 默認(rèn)就會打開員工管理的列表頁面, 我們可以查看列表數(shù)據(jù)是否可以正常展示, 也可以通過分頁插件來測試分頁功能, 及員工姓名的模糊查詢功能。
在進行測試時,可以使用瀏覽器的監(jiān)控工具查看頁面和服務(wù)端的數(shù)據(jù)交互細(xì)節(jié)。 并借助于debug的形式, 根據(jù)服務(wù)端參數(shù)接收及邏輯執(zhí)行情況。
測試過程中可以發(fā)現(xiàn),對于員工狀態(tài)字段(status)服務(wù)端返回的是狀態(tài)碼(1或者0),但是頁面上顯示的則是“正?!被蛘摺耙呀谩?#xff0c;這是因為頁面中在展示數(shù)據(jù)時進行了處理。
4. 啟用/禁用員工賬號
4.1 需求分析
在員工管理列表頁面,可以對某個員工賬號進行啟用或者禁用操作。賬號禁用的員工不能登錄系統(tǒng),啟用后的員工可以正常登錄。如果某個員工賬號狀態(tài)為正常,則按鈕顯示為 "禁用",如果員工賬號狀態(tài)為已禁用,則按鈕顯示為"啟用"。
==需要注意,只有管理員(admin用戶)可以對其他普通用戶進行啟用、禁用操作,所以普通用戶登錄系統(tǒng)后啟用、禁用按鈕不顯示。==
A. admin 管理員登錄
B. 普通用戶登錄
4.2 程序執(zhí)行流程
4.2.1 頁面按鈕動態(tài)展示
在上述的需求中,我們提到需要實現(xiàn)的效果是 : 只有管理員(admin用戶)可以對其他普通用戶進行啟用、禁用操作,所以普通用戶登錄系統(tǒng)后啟用、禁用按鈕不顯示 , 頁面中是怎么做到只有管理員admin能夠看到啟用、禁用按鈕的?
1). 在列表頁面(list.html)加載時, 觸發(fā)鉤子函數(shù)created, 在鉤子函數(shù)中, 會從localStorage中獲取到用戶登錄信息, 然后獲取到用戶名
2). 在頁面中, 通過Vue指令v-if進行判斷,如果登錄用戶為admin將展示 啟用/禁用 按鈕, 否則不展示
4.2.2 執(zhí)行流程分析
1). 當(dāng)管理員admin點擊 "啟用" 或 "禁用" 按鈕時, 調(diào)用方法statusHandle
scope.row : 獲取到的是這一行的數(shù)據(jù)信息 ;
2). statusHandle方法中進行二次確認(rèn), 然后發(fā)起ajax請求, 傳遞id、status參數(shù)
最終發(fā)起異步請求, 請求服務(wù)端, 請求信息如下:
請求 | 說明 |
請求方式 | PUT |
請求路徑 | /employee |
請求參數(shù) | {"id":xxx,"status":xxx} |
{...params} : 三點是ES6中出現(xiàn)的擴展運算符。作用是遍歷當(dāng)前使用的對象能夠訪問到的所有屬性,并將屬性放入當(dāng)前對象中。
4.3 代碼實現(xiàn)
在開發(fā)代碼之前,需要梳理一下整個程序的執(zhí)行過程:
1). 頁面發(fā)送ajax請求,將參數(shù)(id、status)提交到服務(wù)端
2). 服務(wù)端Controller接收頁面提交的數(shù)據(jù)并調(diào)用Service更新數(shù)據(jù)
3). Service調(diào)用Mapper操作數(shù)據(jù)庫
啟用、禁用員工賬號,本質(zhì)上就是一個更新操作,也就是對status狀態(tài)字段進行操作。在Controller中創(chuàng)建update方法,此方法是一個通用的修改員工信息的方法。
4.4 功能測試
代碼編寫完畢之后,我們需要將工程重啟。 然后訪問前端頁面, 進行 "啟用" 或 "禁用" 的測試。
測試過程中沒有報錯,但是功能并沒有實現(xiàn),查看數(shù)據(jù)庫中的數(shù)據(jù)也沒有變化。但是從控制臺輸出的日志, 可以看出確實沒有更新成功。
而在我們的數(shù)據(jù)庫表結(jié)構(gòu)中, 并不存在該ID, 數(shù)據(jù)庫中 風(fēng)清揚 對應(yīng)的ID為 1420038345634918401
4.5 代碼修復(fù)
4.5.1 原因分析
通過觀察控制臺輸出的SQL發(fā)現(xiàn)頁面?zhèn)鬟f過來的員工id的值和數(shù)據(jù)庫中的id值不一致,這是怎么回事呢?
在分頁查詢時,服務(wù)端會將返回的R對象進行json序列化,轉(zhuǎn)換為json格式的數(shù)據(jù),而員工的ID是一個Long類型的數(shù)據(jù),而且是一個長度為 19 位的長整型數(shù)據(jù), 該數(shù)據(jù)返回給前端是沒有問題的。
那么具體的問題出現(xiàn)在哪兒呢?
問題實際上, 就出現(xiàn)在前端JS中, js在對長度較長的長整型數(shù)據(jù)進行處理時, 會損失精度, 從而導(dǎo)致提交的id和數(shù)據(jù)庫中的id不一致。 這里,我們也可以做一個簡單的測試,代碼如下:
4.5.2 解決方案
要想解決這個問題,也很簡單,我們只需要讓js處理的ID數(shù)據(jù)類型為字符串類型即可, 這樣就不會損失精度了。同樣, 大家也可以做一個測試:
那么在我們的業(yè)務(wù)中, 我們只需要讓分頁查詢返回的json格式數(shù)據(jù)庫中, long類型的屬性, 不直接轉(zhuǎn)換為數(shù)字類型, 轉(zhuǎn)換為字符串類型就可以解決這個問題了 , 最終返回的結(jié)果為 :
4.5.3 代碼修復(fù)
由于在SpringMVC中, 將Controller方法返回值轉(zhuǎn)換為json對象, 是通過jackson來實現(xiàn)的, 涉及到SpringMVC中的一個消息轉(zhuǎn)換器MappingJackson2HttpMessageConverter, 所以我們要解決這個問題, 就需要對該消息轉(zhuǎn)換器的功能進行拓展。
具體實現(xiàn)步驟:
1). 提供對象轉(zhuǎn)換器JacksonObjectMapper,基于Jackson進行Java對象到j(luò)son數(shù)據(jù)的轉(zhuǎn)換(資料中已經(jīng)提供,直接復(fù)制到項目中使用)
2). 在WebMvcConfig配置類中擴展Spring mvc的消息轉(zhuǎn)換器,在此消息轉(zhuǎn)換器中使用提供的對象轉(zhuǎn)換器進行Java對象到j(luò)son數(shù)據(jù)的轉(zhuǎn)換
1). 引入JacksonObjectMapper
2). 在WebMvcConfig中重寫方法extendMessageConverters
5. 編輯員工信息
5.1 需求分析
在員工管理列表頁面點擊 "編輯" 按鈕,跳轉(zhuǎn)到編輯頁面,在編輯頁面回顯員工信息并進行修改,最后點擊 "保存" 按鈕完成編輯操作。
那么從上述的分析中,我們可以看出當(dāng)前實現(xiàn)的編輯功能,我們需要實現(xiàn)兩個方法:
A. 根據(jù)ID查詢, 用于頁面數(shù)據(jù)回顯
B. 保存修改
5.2 程序執(zhí)行流程
在開發(fā)代碼之前需要梳理一下操作過程和對應(yīng)的程序的執(zhí)行流程:
1). 點擊編輯按鈕時,頁面跳轉(zhuǎn)到add.html,并在url中攜帶參數(shù)[員工id]
2). 在add.html頁面獲取url中的參數(shù)[員工id]
3). 發(fā)送ajax請求,請求服務(wù)端,同時提交員工id參數(shù)
4). 服務(wù)端接收請求,根據(jù)員工id查詢員工信息,將員工信息以json形式響應(yīng)給頁面
5). 頁面接收服務(wù)端響應(yīng)的json數(shù)據(jù),通過VUE的數(shù)據(jù)綁定進行員工信息回顯
6). 點擊保存按鈕,發(fā)送ajax請求,將頁面中的員工信息以json方式提交給服務(wù)端
7). 服務(wù)端接收員工信息,并進行處理,完成后給頁面響應(yīng)
8). 頁面接收到服務(wù)端響應(yīng)信息后進行相應(yīng)處理
注意:add.html頁面為公共頁面,新增員工和編輯員工都是在此頁面操作
5.3 代碼實現(xiàn)
5.3.1 根據(jù)ID查詢
經(jīng)過上述的分析,我們看到,在根據(jù)ID查詢員工信息時,請求信息如下:
請求 | 說明 |
請求方式 | GET |
請求路徑 | /employee/{id} |
代碼實現(xiàn):
在EmployeeController中增加方法, 根據(jù)ID查詢員工信息。
5.3.2 修改員工
經(jīng)過上述的分析,我們看到,在修改員工信息時,請求信息如下:
請求 | 說明 |
請求方式 | PUT |
請求路徑 | /employee |
請求參數(shù) | {.......} json格式數(shù)據(jù) |
代碼實現(xiàn):
在EmployeeController中增加方法, 根據(jù)ID更新員工信息。
5.4 功能測試
代碼編寫完畢之后,我們需要將工程重啟。 然后訪問前端頁面, 按照前面分析的操作流程進行測試,查看數(shù)據(jù)是否正常修改即可。