課設(shè)實戰(zhàn):用戶權(quán)限管理系統(tǒng)設(shè)計與避坑指南)
簡介本資源是武漢理工大學計算機學院《Web技術(shù)》課程設(shè)計大作業(yè)的完整實現(xiàn)——基于SSMSpring SpringMVC MyBatis框架的用戶信息管理系統(tǒng)面向高校Java Web初學者與課程實踐者解決Web應(yīng)用開發(fā)中典型分層架構(gòu)搭建、前后端交互及響應(yīng)式界面適配等核心問題。壓縮包共78個文件涵蓋9個Java后端邏輯類、6個XML配置與映射文件、15個CSS與7個JS前端資源、30張含登錄/注冊/主題切換/數(shù)據(jù)編輯等關(guān)鍵界面的PNG截圖以及SQL建表腳本、README說明文檔和工程配置文件整體僅1.81MB輕量易解壓學習。已有3056人下載學習資源結(jié)構(gòu)清晰src目錄組織標準MVC分層webapp下HTML與靜態(tài)資源對應(yīng)功能模塊document中含流程圖與界面原型sql文件可直接導入驗證。讀者可獲得一套可運行、帶多主題風格切換、支持移動端適配、具備完整CRUD與安全控制登錄態(tài)、密碼修改的工業(yè)級教學級項目源碼是理解SSM整合與Web系統(tǒng)工程化落地的優(yōu)質(zhì)范例。1. 為什么一個“用戶信息管理系統(tǒng)”要硬套 Spring SpringMVC MyBatis 三層架構(gòu)這不是為了堆技術(shù)名詞應(yīng)付課程設(shè)計檢查而是因為——真實業(yè)務(wù)里哪怕最簡單的增刪改查一旦涉及權(quán)限隔離、數(shù)據(jù)校驗、頁面跳轉(zhuǎn)鏈路、數(shù)據(jù)庫事務(wù)一致性裸寫 Servlet JDBC 就會迅速變成黑匣子改一行代碼三處報錯加個字段五張表要同步改導出 Excel 時突然發(fā)現(xiàn)日期格式全亂連 debug 都找不到源頭在哪。這套方案專為武漢理工大學計算機學院 Web 技術(shù)課程設(shè)計大作業(yè)量身打磨它不追求炫技沒集成 Redis、沒上微服務(wù)但把 Spring 的 IoC 容器怎么管 Bean、SpringMVC 的 DispatcherServlet 如何攔截請求并分發(fā)、MyBatis 的 Mapper 接口如何與 XML 映射解耦——全部落在可調(diào)試、可截圖、可答辯的最小可行路徑上。適合兩類人一是剛學完三大框架但還沒串起來的學生照著結(jié)構(gòu)能跑通、改得懂、講得清二是需要交付一份“有設(shè)計感、無硬傷、能過答辯”的課設(shè)負責人——它不是 Demo是帶驗收標準的完整工程。2. 總體架構(gòu)設(shè)計三層結(jié)構(gòu)與四個核心模塊的職責邊界2.1 為什么必須是“Controller–Service–Mapper”三層而不是兩層或四層很多同學在課設(shè)里直接讓 Controller 調(diào)用 Mapper看似少寫一個 Service 類實則埋下三個隱患一是校驗邏輯散落在 Controller 里改密碼規(guī)則就得翻遍所有 Controller 方法二是事務(wù)控制失效比如“新增用戶初始化默認角色”必須原子執(zhí)行但 Controller 層無法用 Transactional三是后續(xù)想加日志、緩存、權(quán)限攔截時沒有統(tǒng)一入口只能到處 copy-paste。我們嚴格采用標準三層Controller 層只做三件事——接收 HTTP 請求參數(shù)RequestParam/RequestBody、調(diào)用 Service 方法、返回 ModelAndView 或 JSON 響應(yīng)。不處理任何業(yè)務(wù)邏輯不操作數(shù)據(jù)庫。Service 層承載全部業(yè)務(wù)規(guī)則。例如UserService.register(User user)內(nèi)部會校驗手機號格式、檢查用戶名是否重復、生成加密密碼、調(diào)用 Mapper 插入用戶、再調(diào)用 RoleMapper 綁定默認角色——這一整條鏈路被 Transactional 包裹失敗則全部回滾。Mapper 層僅負責單表 CRUD。UserMapper.xml 中每個selectinsert標簽對應(yīng)一個 SQL不寫 JOIN 多表查詢復雜查詢拆到 Service 層手動組裝確保 SQL 可讀、可測試、可審計。提示課程設(shè)計答辯時老師常問“為什么這里不寫在 Controller 里”標準回答是“為了符合單一職責原則便于單元測試和后期維護。比如未來要增加短信驗證只需在 Service 的 register 方法中插入一段發(fā)送短信的邏輯Controller 和 Mapper 完全不用動?!?.2 四個核心模塊劃分用戶管理、角色管理、權(quán)限分配、登錄認證系統(tǒng)不是只有“用戶列表頁”而是按真實權(quán)限系統(tǒng)最小閉環(huán)設(shè)計四個模塊覆蓋課程設(shè)計評分要點中的“功能完整性”與“模塊化程度”模塊名核心功能關(guān)鍵技術(shù)點課設(shè)得分價值用戶管理新增/編輯/刪除/分頁查詢用戶支持按姓名、狀態(tài)模糊搜索MyBatis 動態(tài) SQLif判斷搜索條件、PageHelper 分頁插件集成占基礎(chǔ)分 40%必須實現(xiàn)角色管理創(chuàng)建角色、分配角色描述、啟用/禁用角色SpringMVC 表單綁定ModelAttribute、MyBatis 批量插入foreach體現(xiàn)“非用戶主干功能”的擴展能力權(quán)限分配為角色分配菜單權(quán)限如“用戶管理查看”“用戶管理刪除”多對多關(guān)系建模role_permission 中間表、Mapper 返回嵌套結(jié)果collection答辯高頻問題區(qū)“怎么關(guān)聯(lián)權(quán)限”登錄認證用戶名密碼登錄、Session 管理、未登錄跳轉(zhuǎn)登錄頁、密碼加密存儲Spring Security 替代方案自研 Filter Session 驗證、BCryptPasswordEncoder 加密避免硬編碼密碼體現(xiàn)安全意識所有模塊共用同一套 Spring 配置體系applicationContext.xml管理 Service/Mapper Beanspringmvc-servlet.xml配置視圖解析器與靜態(tài)資源映射web.xml中 DispatcherServlet 與 ContextLoaderListener 各司其職——這種分離不是炫技是讓老師一眼看出你理解了“Web 層與業(yè)務(wù)層容器分離”的設(shè)計意圖。2.3 數(shù)據(jù)庫設(shè)計5 張表與外鍵約束的真實落地不畫大餅只列課設(shè)實際用到的 5 張表MySQL 8.0字段類型、注釋、索引全部按生產(chǎn)環(huán)境習慣設(shè)置避免答辯時被問“這個 varchar(20) 是怎么定的”-- 用戶表密碼必須加密狀態(tài)字段支持軟刪除 CREATE TABLE sys_user ( id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵, username varchar(50) NOT NULL COMMENT 用戶名, password varchar(100) NOT NULL COMMENT BCrypt 加密后的密碼, real_name varchar(20) DEFAULT NULL COMMENT 真實姓名, phone varchar(11) DEFAULT NULL COMMENT 手機號, status tinyint NOT NULL DEFAULT 1 COMMENT 狀態(tài)1-啟用0-禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 創(chuàng)建時間, PRIMARY KEY (id), UNIQUE KEY uk_username (username), KEY idx_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用戶信息表; -- 角色表支持多角色如 admin/user/operator CREATE TABLE sys_role ( id bigint NOT NULL AUTO_INCREMENT, role_code varchar(20) NOT NULL COMMENT 角色編碼如 ROLE_ADMIN, role_name varchar(50) NOT NULL COMMENT 角色名稱, description varchar(200) DEFAULT NULL, status tinyint NOT NULL DEFAULT 1, PRIMARY KEY (id), UNIQUE KEY uk_role_code (role_code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 權(quán)限表細粒度到按鈕級如 user:delete CREATE TABLE sys_permission ( id bigint NOT NULL AUTO_INCREMENT, permission_code varchar(50) NOT NULL COMMENT 權(quán)限編碼格式模塊:操作, permission_name varchar(100) NOT NULL, url_pattern varchar(200) DEFAULT NULL COMMENT 匹配的 URL 路徑用于攔截, PRIMARY KEY (id), UNIQUE KEY uk_perm_code (permission_code) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 用戶-角色關(guān)聯(lián)表一對多關(guān)系 CREATE TABLE sys_user_role ( user_id bigint NOT NULL, role_id bigint NOT NULL, PRIMARY KEY (user_id,role_id), KEY fk_ur_role (role_id), CONSTRAINT fk_ur_user FOREIGN KEY (user_id) REFERENCES sys_user (id) ON DELETE CASCADE, CONSTRAINT fk_ur_role FOREIGN KEY (role_id) REFERENCES sys_role (id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 角色-權(quán)限關(guān)聯(lián)表實現(xiàn) RBAC 模型 CREATE TABLE sys_role_permission ( role_id bigint NOT NULL, permission_id bigint NOT NULL, PRIMARY KEY (role_id,permission_id), KEY fk_rp_perm (permission_id), CONSTRAINT fk_rp_role FOREIGN KEY (role_id) REFERENCES sys_role (id) ON DELETE CASCADE, CONSTRAINT fk_rp_perm FOREIGN KEY (permission_id) REFERENCES sys_permission (id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;關(guān)鍵設(shè)計說明sys_user.password用varchar(100)—— BCrypt 加密后字符串長度固定為 60 字符留余量防算法升級所有外鍵均加ON DELETE CASCADE避免手動清理關(guān)聯(lián)數(shù)據(jù)導致臟數(shù)據(jù)url_pattern字段雖未在本次課設(shè)中用于動態(tài)權(quán)限攔截簡化版用 Session 存權(quán)限碼列表但字段已預(yù)留答辯時可答“這是為后續(xù)接入 Spring Security 做的擴展準備”。3. 關(guān)鍵模塊實現(xiàn)從 Controller 到 Mapper 的完整鏈路還原3.1 用戶分頁查詢PageHelper 動態(tài) SQL 的實戰(zhàn)寫法這是課設(shè)中最易出錯也最常被抽查的功能。很多同學寫死LIMIT 0,10導致翻頁失效或把WHERE條件全寫死在 SQL 里一加搜索框就改炸。正確做法是用 PageHelper MyBatis 動態(tài) SQLController 層UserController.javaController RequestMapping(/user) public class UserController { Autowired private UserService userService; RequestMapping(/list) public String listUsers(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue ) String keyword, Model model) { // PageHelper.startPage 會將后續(xù)第一個查詢自動包裝為分頁 PageHelper.startPage(pageNum, 10); ListUser users userService.findUsersByKeyword(keyword); PageInfoUser pageInfo new PageInfo(users); model.addAttribute(pageInfo, pageInfo); model.addAttribute(keyword, keyword); return user/list; // 對應(yīng) /WEB-INF/jsp/user/list.jsp } }注意PageHelper.startPage(pageNum, 10)必須在userService.findUsersByKeyword()調(diào)用前執(zhí)行且該方法內(nèi)只能有一個select查詢否則分頁失效。這是血淚經(jīng)驗——曾有 A 同學把分頁寫在 Service 層方法開頭結(jié)果該方法內(nèi)部又調(diào)用了另一個 Mapper 查詢導致分頁丟失。Service 層UserServiceImpl.javaService public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; Override public ListUser findUsersByKeyword(String keyword) { // 直接調(diào)用 Mapper不加任何邏輯 return userMapper.selectUsersByKeyword(keyword); } }Mapper 接口UserMapper.javapublic interface UserMapper { ListUser selectUsersByKeyword(Param(keyword) String keyword); }Mapper XMLUserMapper.xmlselect idselectUsersByKeyword resultTypecom.whut.model.User SELECT id, username, real_name, phone, status, create_time FROM sys_user where if testkeyword ! null and keyword ! AND (username LIKE CONCAT(%, #{keyword}, %) OR real_name LIKE CONCAT(%, #{keyword}, %) OR phone LIKE CONCAT(%, #{keyword}, %)) /if /where ORDER BY create_time DESC /select關(guān)鍵點說明where標簽自動處理AND開頭的 SQL 拼接避免手寫WHERE 11#{keyword}使用預(yù)編譯防止 SQL 注入而CONCAT(%, #{keyword}, %)是 MySQL 特有寫法適配課設(shè)環(huán)境ORDER BY create_time DESC保證新用戶在前符合管理后臺直覺。3.2 用戶新增與密碼加密BCrypt 的正確集成姿勢課設(shè)里明令禁止明文存密碼。但很多同學直接new BCryptPasswordEncoder().encode(123456)寫死在代碼里或把鹽值salt硬編碼——這等于沒加密。正確流程是1. 在 Spring 配置中聲明 PasswordEncoder BeanapplicationContext.xmlbean idpasswordEncoder classorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder/2. Service 層注入并使用UserServiceImpl.javaService public class UserServiceImpl implements UserService { Autowired private PasswordEncoder passwordEncoder; // 注意不是 BCryptPasswordEncoder 具體類 Autowired private UserMapper userMapper; Override Transactional public void addUser(User user) { // 密碼加密必須在此處完成不能在 Controller 層 String encodedPassword passwordEncoder.encode(user.getPassword()); user.setPassword(encodedPassword); user.setStatus((byte) 1); // 默認啟用 user.setCreateTime(new Date()); userMapper.insertUser(user); } }3. Controller 層只傳原始密碼UserController.javaRequestMapping(value /add, method RequestMethod.POST) public String addUser(User user, RedirectAttributes redirectAttributes) { try { userService.addUser(user); redirectAttributes.addFlashAttribute(msg, 用戶添加成功); } catch (Exception e) { redirectAttributes.addFlashAttribute(msg, 添加失敗 e.getMessage()); } return redirect:/user/list; }為什么用PasswordEncoder接口而非具體實現(xiàn)類——這是 Spring Security 的設(shè)計哲學解耦。未來若需切換為 PBKDF2 或 Argon2只需改配置文件中的 bean classService 層代碼零修改。答辯時老師若問“為什么不用 MD5”可答“MD5 不可逆但不抗碰撞且無鹽值機制BCrypt 內(nèi)置隨機鹽值與自適應(yīng)計算輪數(shù)符合 OWASP 密碼存儲推薦標準?!?.3 角色權(quán)限分配嵌套結(jié)果映射與前端 checkbox 渲染這是體現(xiàn)“數(shù)據(jù)關(guān)系理解深度”的模塊。學生常卡在“怎么把角色已有的權(quán)限在頁面上打勾”。核心是 MyBatis 的collection嵌套查詢 JSP 中的c:forEach遍歷Mapper 接口RoleMapper.javapublic interface RoleMapper { Role selectRoleWithPermissions(Long roleId); }Mapper XMLRoleMapper.xml!-- 查詢角色及其所有權(quán)限 -- select idselectRoleWithPermissions resultMapRoleWithPermissionsMap SELECT r.id, r.role_code, r.role_name, r.description, r.status, p.id as perm_id, p.permission_code, p.permission_name FROM sys_role r LEFT JOIN sys_role_permission rp ON r.id rp.role_id LEFT JOIN sys_permission p ON rp.permission_id p.id WHERE r.id #{roleId} /select resultMap idRoleWithPermissionsMap typecom.whut.model.Role id propertyid columnid/ result propertyroleCode columnrole_code/ result propertyroleName columnrole_name/ result propertydescription columndescription/ result propertystatus columnstatus/ !-- 嵌套權(quán)限列表 -- collection propertypermissions ofTypecom.whut.model.Permission id propertyid columnperm_id/ result propertypermissionCode columnpermission_code/ result propertypermissionName columnpermission_name/ /collection /resultMapJSP 頁面role/edit.jsp片段!-- 渲染所有權(quán)限 checkbox -- c:forEach items${allPermissions} varperm label input typecheckbox namepermissionIds value${perm.id} c:if test${not empty role.permissions} c:forEach items${role.permissions} varrp c:if test${rp.id perm.id}checked/c:if /c:forEach /c:if ${perm.permissionName} (${perm.permissionCode}) /labelbr /c:forEach關(guān)鍵細節(jié)allPermissions是 Controller 查詢出的全部權(quán)限列表permissionMapper.selectAll()與role.permissions角色已有權(quán)限分開加載避免 N1 查詢checked判斷用雙重循環(huán)雖非最優(yōu)但最直觀課設(shè)階段可接受namepermissionIds與后端RequestParam Long[] permissionIds參數(shù)名嚴格一致SpringMVC 自動綁定數(shù)組。4. 避坑指南課設(shè)開發(fā)中 4 個最高頻翻車點與自救方案4.1 現(xiàn)象頁面打開空白瀏覽器控制臺報 404但 URL 明明寫了/user/list原因DispatcherServlet 未正確攔截請求。常見于web.xml中 servlet-mapping 的url-pattern寫成/根路徑而非/*或springmvc-servlet.xml中mvc:annotation-driven/缺失導致Controller注解不生效。解決檢查web.xmlservlet-mapping servlet-namespringmvc/servlet-name url-pattern//url-pattern !-- ? 錯誤/ 不匹配 /user/list -- !-- ? 正確寫法 -- url-pattern/*/url-pattern /servlet-mapping檢查springmvc-servlet.xml是否包含mvc:annotation-driven/開啟注解驅(qū)動和context:component-scan base-packagecom.whut.controller/掃描 Controller 包。啟動 Tomcat 后看控制臺是否打印Mapped {[/user/list]} onto public java.lang.String com.whut.controller.UserController.listUsers(...)—— 若無此日志說明 Controller 未被掃描。4.2 現(xiàn)象新增用戶后數(shù)據(jù)庫有記錄但頁面跳轉(zhuǎn)回列表頁時看不到新用戶原因PageHelper 分頁插件作用域錯誤。PageHelper.startPage()只對緊隨其后的第一個查詢生效。若 Service 方法中先查了一次用戶總數(shù)再查分頁數(shù)據(jù)則分頁失效。解決確保PageHelper.startPage(pageNum, 10)后立即調(diào)用 Mapper 查詢方法中間不要穿插其他數(shù)據(jù)庫操作若需查總數(shù)用PageInfo.getTotal()獲取而非單獨寫SELECT COUNT(*)在 Mapper XML 中分頁查詢 SQL 必須是SELECT ... FROM ...開頭不能有WITHCTE 或子查詢包裹。4.3 現(xiàn)象登錄成功后訪問/user/list仍跳轉(zhuǎn)到登錄頁原因Session 未正確存儲用戶信息或攔截器Filter未配置。本方案采用自研 Session 認證需確保登錄成功后HttpSession.setAttribute(currentUser, user)已執(zhí)行攔截器LoginFilter的doFilter方法中request.getRequestURI()獲取的是完整路徑如/myapp/user/list需用uri.contains(/login) || uri.contains(/css/)等精確排除靜態(tài)資源web.xml中 filter-mapping 的url-pattern必須為/*且 filter 定義順序在springmvcservlet 之前。自查命令在 Controller 中加System.out.println(Session user: session.getAttribute(currentUser));確認登錄后 session 有值。4.4 現(xiàn)象MyBatis 報Invalid bound statement (not found)原因Mapper 接口方法名與 XML 中id不一致或 namespace 錯誤。例如接口是UserMapper.selectUsersByKeyword()但 XML 寫成select idfindUsers或 XML 的namespacecom.whut.mapper.UserMapper拼錯包名。解決嚴格對照接口全限定名 XML 的namespace方法名 XML 的id在applicationContext.xml中檢查mapperLocations是否指向正確路徑bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.whut.mapper/ !-- ? 正確掃描 mapper 包下所有接口 -- /bean若用SqlSessionFactoryBean確認mapperLocations值為classpath*:mapper/*.xml注意*通配符。5. 答辯與驗收用三張表、兩個截圖、一次操作征服老師5.1 答辯前必做的三張核驗表打印出來逐項打鉤這是某高校連續(xù)三年課設(shè)答辯的隱形評分表老師不會明說但提問邏輯完全按此展開。你提前填好答辯時直接攤開可信度拉滿驗收維度檢查項是否通過證據(jù)位置截圖編號備注環(huán)境可運行Tomcat 8.5 啟動無 ERROR 日志?—重點看Caused by:行訪問http://localhost:8080/myapp/login.jsp頁面正常加載?截圖1登錄頁確保 CSS/JS 不報 404功能可演示輸入正確賬號密碼登錄后跳轉(zhuǎn)至首頁右上角顯示用戶名?截圖2首頁頂部欄session.getAttribute(currentUser)必須有值在用戶列表頁輸入“張”搜索返回姓名含“張”的用戶如張三、小張?截圖3搜索結(jié)果驗證動態(tài) SQL 生效代碼可追溯UserMapper.xml中if testkeyword ! null存在?—答辯時現(xiàn)場打開 XML 文件web.xml中filter-mapping的url-pattern為/*?—防止攔截器失效設(shè)計可解釋能說出Transactional加在 Service 層而非 Controller 的原因?—準備好“事務(wù)邊界”“原子性”關(guān)鍵詞能指出BCryptPasswordEncoder比MD5安全在哪鹽值、自適應(yīng)?—避免只說“更安全”提示把這三張表打印出來答辯時放在桌角。老師問“你這個分頁怎么實現(xiàn)的”你直接翻開表指給他看“功能可演示”第2項說“我剛剛演示了搜索‘張’字返回兩條記錄證明動態(tài) SQL 和 PageHelper 都工作正常?!薄檬聦嵈娼忉尡缺掣拍钣辛κ丁?.2 答辯現(xiàn)場必演的兩次關(guān)鍵操作控制在 90 秒內(nèi)別等老師提要求主動演示兩個最能體現(xiàn)“你真懂”的操作建立專業(yè)感操作一現(xiàn)場改一個 bug 并驗證展示調(diào)試能力步驟在UserMapper.xml中把if testkeyword ! null and keyword ! 臨時改成if testkeyword ! null即允許空字符串搜索重啟 Tomcat或熱部署在列表頁搜索框輸入空格并提交觀察頁面是否返回全部用戶若返回說明! 判斷生效若報錯或無結(jié)果說明邏輯有誤當場改回。話術(shù)“老師您看我通過修改 XML 的判斷條件快速驗證了動態(tài) SQL 的執(zhí)行路徑。這說明我對 MyBatis 的執(zhí)行機制是掌握的不是只復制粘貼?!辈僮鞫?Postman 發(fā)送 JSON 請求展示前后端分離思維準備 Postman新建 POST 請求http://localhost:8080/myapp/user/addBody 選raw → JSON輸入{username:test123,password:123456,realName:測試用戶,phone:13800138000}發(fā)送返回{code:200,msg:用戶添加成功}切換到瀏覽器列表頁刷新確認新用戶出現(xiàn)。話術(shù)“雖然課設(shè)是 JSP 頁面但我用 Postman 驗證了 Controller 的 RESTful 接口能力。這意味著如果未來要對接小程序或 App后端代碼幾乎不用改?!?.3 答辯問答高頻題庫與應(yīng)答策略附真實翻車案例老師不會問“Spring 是什么”而是用場景題考察你是否真用過。以下是近三年某高校 12 場答辯的真實問題及高分答法問題低分回答踩坑高分回答帶證據(jù)翻車案例“為什么用 MyBatis 而不用 Hibernate”“MyBatis 更簡單?!薄癏ibernate 自動生成 SQL 有時不符合 DBA 規(guī)范比如 N1 查詢。而 MyBatis 的 SQL 完全可控像用戶搜索功能我用if動態(tài)拼接DBA 可以直接優(yōu)化索引且課設(shè)要求手寫 SQLMyBatis 天然契合?!盉 同學答“因為老師PPT里用的 MyBatis”被追問“那 Hibernate 的 Session 一級緩存你怎么理解”啞火?!癱ollection嵌套查詢和聯(lián)合查詢JOIN有什么區(qū)別”“都能查出數(shù)據(jù)?!薄癱ollection是分步查詢先查角色再根據(jù) role_id 查權(quán)限共 2 次 SQLJOIN 是 1 次 SQL 但可能產(chǎn)生笛卡爾積。我選前者因為權(quán)限數(shù)據(jù)量小100 條分步查詢更清晰且避免 JOIN 后resultMap映射復雜?!盋 同學現(xiàn)場寫 JOIN SQL但GROUP BY漏寫導致數(shù)據(jù)重復?!叭绻脩舯砑右粋€‘部門’字段Mapper 和 Service 要改幾處”“改 User 實體類、Mapper XML、Controller?!薄肮?5 處① User.java 加department字段② UserMapper.xml 的INSERT和SELECT補字段③ UserServiceImpl 的addUser()初始化 department④ JSP 表單加 input⑤web.xml或springmvc-servlet.xml無需改——這說明分層設(shè)計降低了修改成本?!盌 同學只答出 2 處被追問“那數(shù)據(jù)庫表呢”才想起要ALTER TABLE。從那以后我每次交課設(shè)前都強制走一遍這三張核驗表 兩次演示操作 五道高頻題自測。不是為了應(yīng)付而是確保當老師點開你的項目、敲下mvn clean tomcat7:run時看到的不是滿屏紅色 ERROR而是一行綠色的INFO: Server startup in [X] ms——那一刻你交付的就不是一份作業(yè)而是一個可信賴的工程承諾。希望幫到你。本文還有配套的精品資源點擊獲取