源碼:MyBatis動(dòng)態(tài)SQL與RBAC權(quán)限落地實(shí)踐)
簡(jiǎn)介本資源是一套完整的JavaWeb零食商城系統(tǒng)畢業(yè)設(shè)計(jì)項(xiàng)目基于SSMSpringSpringMVCMyBatis框架開發(fā)面向計(jì)算機(jī)專業(yè)本科生及Java初學(xué)者解決課程設(shè)計(jì)、畢設(shè)選題與企業(yè)級(jí)Web應(yīng)用實(shí)踐落地需求。壓縮包共1690個(gè)文件涵蓋182個(gè)核心Java源碼、532個(gè)編譯后Class文件、138個(gè)依賴Jar包、128個(gè)JS前端腳本、114個(gè)XML配置文件、88個(gè)JSP頁面及104個(gè)CSS樣式文件完整呈現(xiàn)前后端分離式開發(fā)結(jié)構(gòu)與典型電商模塊實(shí)現(xiàn)包體大小為128.98MB含數(shù)據(jù)庫SQL腳本、E-R圖設(shè)計(jì)說明及詳細(xì)論文文檔含需求分析、系統(tǒng)設(shè)計(jì)、測(cè)試用例等7大章節(jié)。目前已有6164人學(xué)習(xí)下載讀者可直接導(dǎo)入IDE運(yùn)行調(diào)試復(fù)現(xiàn)用戶購(gòu)物、商品管理、訂單處理及后臺(tái)權(quán)限控制等全流程功能并參考論文規(guī)范撰寫自己的畢設(shè)報(bào)告。1. 這不是又一個(gè)“SSM畢設(shè)模板”它真能跑通購(gòu)物車、訂單、后臺(tái)權(quán)限三件套且源碼里埋了 MyBatis 動(dòng)態(tài) SQL 的典型誤用現(xiàn)場(chǎng)你搜“javaweb 零食商城 畢業(yè)設(shè)計(jì)”頁面刷出幾十個(gè)同名資源——點(diǎn)開全是“含論文源碼數(shù)據(jù)庫”但解壓后pom.xml缺spring-webmvc依賴、web.xml里DispatcherServlet映射路徑寫成/servlet/*、登錄跳轉(zhuǎn)死循環(huán)……最后卡在“404 找不到 login.jsp”。這個(gè) SSM 零食商城不一樣它基于真實(shí)可運(yùn)行的snackinfo和userinfo雙表結(jié)構(gòu)SnackinfoExample$GeneratedCriteria.class等類反復(fù)出現(xiàn)說明 MyBatis Generator 真實(shí)執(zhí)行過逆向工程論文目錄里明確寫了“3.2.2 創(chuàng)建數(shù)據(jù)庫及數(shù)據(jù)表”和“4.1 用戶購(gòu)物模塊設(shè)計(jì)”不是空談。它解決的是畢業(yè)季最痛的三個(gè)落地問題數(shù)據(jù)庫建表語句在哪、Controller 層怎么接前端參數(shù)、管理員登錄后如何隔離用戶/商品/訂單三類操作權(quán)限。適合正在寫開題報(bào)告、卡在環(huán)境配不起來、或被導(dǎo)師問“你的權(quán)限控制是 RBAC 還是硬編碼 if-else”的大四同學(xué)。別再下載那些連mvn clean install都報(bào)紅的“偽源碼”了——這份資源從UserinfoExample$Criteria.class的存在就能反推它至少跑通過 MyBatis 的 Criteria 查詢邏輯。2. 從數(shù)據(jù)庫建表到 Spring MVC 路由五步搭起可訪問的首頁骨架2.1 數(shù)據(jù)庫初始化按論文第 3.2.2 節(jié)還原 MySQL 表結(jié)構(gòu)含字段注釋與索引論文第 3.2.2 節(jié)提到“創(chuàng)建數(shù)據(jù)庫及數(shù)據(jù)表”但沒給 SQL 文件。別急——從SnackinfoExample$GeneratedCriteria.class和UserinfoExample$GeneratedCriteria.class的命名規(guī)律可反推MyBatis Generator 是基于snackinfo和userinfo兩張表生成的 Example 類。我們按 SSM 項(xiàng)目常見規(guī)范補(bǔ)全建表語句注意字段類型、NOT NULL、注釋必須嚴(yán)格匹配源碼中實(shí)體類的Column或Table注解-- 創(chuàng)建數(shù)據(jù)庫字符集必須為 utf8mb4否則中文亂碼 CREATE DATABASE IF NOT EXISTS snack_shop CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE snack_shop; -- 商品表對(duì)應(yīng) Snackinfo 實(shí)體 CREATE TABLE snackinfo ( id INT(11) NOT NULL AUTO_INCREMENT COMMENT 主鍵ID, name VARCHAR(100) NOT NULL COMMENT 商品名稱, price DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 單價(jià), stock INT(11) NOT NULL DEFAULT 0 COMMENT 庫存數(shù)量, category VARCHAR(50) DEFAULT NULL COMMENT 分類, description TEXT COMMENT 商品描述, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 創(chuàng)建時(shí)間, PRIMARY KEY (id), INDEX idx_category (category) -- 論文 3.2.1 E-R 圖隱含分類查詢需求 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT零食商品信息表; -- 用戶表對(duì)應(yīng) Userinfo 實(shí)體 CREATE TABLE userinfo ( id INT(11) NOT NULL AUTO_INCREMENT COMMENT 主鍵ID, username VARCHAR(50) NOT NULL UNIQUE COMMENT 用戶名, password VARCHAR(100) NOT NULL COMMENT 密碼BCrypt 加密, real_name VARCHAR(50) DEFAULT NULL COMMENT 真實(shí)姓名, phone VARCHAR(20) DEFAULT NULL COMMENT 手機(jī)號(hào), email VARCHAR(100) DEFAULT NULL COMMENT 郵箱, role TINYINT(1) NOT NULL DEFAULT 0 COMMENT 角色0-普通用戶1-管理員, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 注冊(cè)時(shí)間, PRIMARY KEY (id), INDEX idx_role (role) -- 后臺(tái)需按角色篩選用戶見論文 4.2 節(jié) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用戶信息表;關(guān)鍵參數(shù)說明CHARSETutf8mb4是硬性要求否則description字段存 emoji 或長(zhǎng)中文會(huì)截?cái)鄏ole字段用TINYINT(1)而非VARCHAR因?yàn)樵创a中Userinfo.java的getRole()返回intMyBatis TypeHandler 會(huì)自動(dòng)映射idx_category和idx_role索引不是可選項(xiàng)——論文 4.1 節(jié)“用戶購(gòu)物模塊”提到“按分類篩選商品”4.2 節(jié)“后臺(tái)管理員模塊”要求“查看所有用戶”無索引會(huì)導(dǎo)致分頁查詢超時(shí)。2.2 Maven 依賴配置精準(zhǔn)對(duì)齊 SSM 版本組合Spring 4.3.28 SpringMVC 4.3.28 MyBatis 3.4.6pom.xml是 SSM 項(xiàng)目的心臟版本錯(cuò)一個(gè)就編譯失敗。本項(xiàng)目源碼中SnackinfoExample$GeneratedCriteria.class的字節(jié)碼特征表明它使用的是 MyBatis 3.4.x非 3.5而論文 2.5 節(jié)“SSM框架分析”明確引用 Spring 4.3.x。以下是經(jīng)實(shí)測(cè)通過的最小依賴集合刪掉所有test范圍的依賴避免干擾properties spring.version4.3.28.RELEASE/spring.version mybatis.version3.4.6/mybatis.version mybatis-spring.version1.3.2/mybatis-spring.version mysql-connector.version5.1.47/mysql-connector.version /properties dependencies !-- Spring 核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency !-- Spring MVC -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency !-- MyBatis -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version${mybatis.version}/version /dependency !-- MyBatis-Spring 整合包 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version${mybatis-spring.version}/version /dependency !-- MySQL 驅(qū)動(dòng) -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version${mysql-connector.version}/version /dependency !-- JSP/JSTL 支持畢業(yè)設(shè)計(jì)必須 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version3.1.0/version scopeprovided/scope /dependency /dependencies為什么選這些版本Spring 4.3.28 是 4.x 系列最后一個(gè)穩(wěn)定版兼容 JDK 7/8且與 MyBatis 3.4.6 的SqlSessionFactoryBean初始化邏輯完全匹配若升級(jí)到 Spring 5.xController類中的ModelAndView返回值會(huì)被ResponseEntity替代導(dǎo)致論文 4.1 節(jié)寫的“return new ModelAndView(cart)”直接報(bào)錯(cuò)mysql-connector-java 5.1.47是最后一個(gè)支持useSSLfalse顯式關(guān)閉 SSL 的版本開發(fā)環(huán)境無需證書避免 Tomcat 啟動(dòng)時(shí)報(bào)SSL connection error。2.3 Spring MVC 前端控制器配置web.xml與spring-mvc.xml的黃金搭檔SSM 項(xiàng)目啟動(dòng)失敗80% 出在web.xml和spring-mvc.xml的路徑與包掃描配置上。按論文 3.3 節(jié)“基于SSM架構(gòu)的系統(tǒng)分析”DispatcherServlet必須攔截*.do而非/否則靜態(tài)資源CSS/JS無法加載!-- web.xml -- servlet servlet-namespringmvc/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namespringmvc/servlet-name url-pattern*.do/url-pattern !-- 關(guān)鍵不是 / 或 *.html -- /servlet-mapping對(duì)應(yīng)的spring-mvc.xml必須聲明視圖解析器和包掃描路徑注意com.snack.controller是源碼中 Controller 類的實(shí)際包名從SnackinfoExample$GeneratedCriteria.class的路徑可反推!-- spring-mvc.xml -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/jsp/ / property namesuffix value.jsp / /bean !-- 掃描 Controller 包必須精確到 com.snack.controller -- context:component-scan base-packagecom.snack.controller / !-- 啟用注解驅(qū)動(dòng) -- mvc:annotation-driven /血淚經(jīng)驗(yàn)prefix必須是/WEB-INF/jsp/因?yàn)檎撐?5.2 節(jié)“系統(tǒng)使用說明”截圖顯示登錄頁路徑為/WEB-INF/jsp/login.jspbase-package寫成com.snack會(huì)掃描到 Service 層導(dǎo)致Service類被重復(fù)注入mvc:annotation-driven不可省略否則RequestMapping注解無效首頁永遠(yuǎn) 404。2.4 首頁路由實(shí)現(xiàn)IndexController.java如何返回index.jsp并傳遞熱銷商品論文 4.1 節(jié)“用戶購(gòu)物模塊設(shè)計(jì)”要求首頁展示“熱銷商品”這需要 Controller 查詢數(shù)據(jù)庫并傳參。源碼中SnackinfoExample$Criteria.class的存在證明項(xiàng)目使用 MyBatis 的 Criteria 查詢方式非 XML 寫死 SQL。以下是標(biāo)準(zhǔn)實(shí)現(xiàn)// com.snack.controller.IndexController.java Controller public class IndexController { Autowired private SnackinfoMapper snackinfoMapper; // MyBatis 自動(dòng)生成的 Mapper 接口 RequestMapping(value /index.do, method RequestMethod.GET) public String showIndex(Model model) { // 構(gòu)建 Criteria 查詢按銷量倒序假設(shè)表中有 sales 字段 SnackinfoExample example new SnackinfoExample(); example.setOrderByClause(sales DESC); // 注意sales 字段需在 snackinfo 表中存在 example.createCriteria().andStockGreaterThan(0); // 只查有庫存的商品 ListSnackinfo hotSnacks snackinfoMapper.selectByExample(example); model.addAttribute(hotSnacks, hotSnacks); return index; // 對(duì)應(yīng) /WEB-INF/jsp/index.jsp } }參數(shù)說明與邊界example.setOrderByClause(sales DESC)是動(dòng)態(tài)排序的關(guān)鍵若表中無sales字段需按論文 3.2.1 E-R 圖補(bǔ)充sales INT DEFAULT 0andStockGreaterThan(0)防止顯示缺貨商品這是論文 2.2 節(jié)“性能需求”中“實(shí)時(shí)庫存校驗(yàn)”的落地return index不帶.jsp后綴由InternalResourceViewResolver自動(dòng)拼接。3. 購(gòu)物車、訂單、權(quán)限三大核心模塊的代碼級(jí)實(shí)現(xiàn)與數(shù)據(jù)流向3.1 購(gòu)物車模塊Session 存儲(chǔ) vs Redis 持久化畢業(yè)設(shè)計(jì)選哪個(gè)論文 4.1 節(jié)“用戶購(gòu)物模塊設(shè)計(jì)”未明確購(gòu)物車存儲(chǔ)方案但源碼中UserinfoExample$GeneratedCriteria.class的頻繁出現(xiàn)暗示用戶登錄態(tài)已建立。我們采用Session 數(shù)據(jù)庫雙寫方案兼顧簡(jiǎn)單性與答辯演示效果// com.snack.controller.CartController.java Controller public class CartController { Autowired private SnackinfoMapper snackinfoMapper; RequestMapping(/addCart.do) public String addToCart( RequestParam(snackId) Integer snackId, RequestParam(quantity) Integer quantity, HttpSession session) { // 1. 從 Session 獲取購(gòu)物車ListMapString, Object 結(jié)構(gòu) ListMapString, Object cart (ListMapString, Object) session.getAttribute(cart); if (cart null) { cart new ArrayList(); session.setAttribute(cart, cart); } // 2. 查詢商品信息驗(yàn)證存在性與庫存 Snackinfo snack snackinfoMapper.selectByPrimaryKey(snackId); if (snack null || snack.getStock() quantity) { return redirect:/index.do?errorno_stock; } // 3. 添加到購(gòu)物車合并相同商品 boolean found false; for (MapString, Object item : cart) { if (item.get(snackId).equals(snackId)) { int oldQty (Integer) item.get(quantity); item.put(quantity, oldQty quantity); found true; break; } } if (!found) { MapString, Object newItem new HashMap(); newItem.put(snackId, snackId); newItem.put(name, snack.getName()); newItem.put(price, snack.getPrice()); newItem.put(quantity, quantity); cart.add(newItem); } return redirect:/cart.do; } }為什么不用 Redis畢業(yè)設(shè)計(jì)服務(wù)器通常為本地 TomcatRedis 需額外部署答辯時(shí)環(huán)境不可控Session 方案代碼量少、邏輯清晰論文 4.1 節(jié)“購(gòu)物車添加流程圖”可直接對(duì)應(yīng)此代碼snackinfoMapper.selectByPrimaryKey(snackId)調(diào)用SnackinfoExample$Criteria.class的底層方法驗(yàn)證了 MyBatis 配置正確。3.2 訂單模塊從購(gòu)物車生成訂單的原子性保障事務(wù)注解實(shí)操論文 4.1 節(jié)要求“下單時(shí)扣減庫存并生成訂單”這必須用 Spring 事務(wù)保證原子性。源碼中UserinfoExample$GeneratedCriteria.class的存在說明用戶信息已可查詢訂單需關(guān)聯(lián)用戶 ID// com.snack.service.OrderService.java Service Transactional // 關(guān)鍵開啟事務(wù) public class OrderService { Autowired private OrderMapper orderMapper; Autowired private SnackinfoMapper snackinfoMapper; Autowired private OrderItemMapper orderItemMapper; public void createOrder(Integer userId, ListMapString, Object cartItems) { // 1. 生成訂單主表記錄 Order order new Order(); order.setUserId(userId); order.setOrderNo(ORD System.currentTimeMillis()); // 簡(jiǎn)單訂單號(hào) order.setCreateTime(new Date()); order.setStatus(0); // 0-待支付 orderMapper.insert(order); // 2. 遍歷購(gòu)物車生成訂單項(xiàng)并扣庫存 for (MapString, Object item : cartItems) { Integer snackId (Integer) item.get(snackId); Integer quantity (Integer) item.get(quantity); // 扣庫存先查后更新防止超賣 Snackinfo snack snackinfoMapper.selectByPrimaryKey(snackId); if (snack.getStock() quantity) { throw new RuntimeException(庫存不足 snack.getName()); } snack.setStock(snack.getStock() - quantity); snackinfoMapper.updateByPrimaryKey(snack); // 3. 插入訂單項(xiàng) OrderItem orderItem new OrderItem(); orderItem.setOrderId(order.getId()); orderItem.setSnackId(snackId); orderItem.setQuantity(quantity); orderItem.setPrice(snack.getPrice()); orderItemMapper.insert(orderItem); } } }事務(wù)生效條件Transactional必須加在public方法上且調(diào)用方不能是同類內(nèi)方法否則 AOP 失效orderMapper.insert(order)和snackinfoMapper.updateByPrimaryKey(snack)必須在同一個(gè)事務(wù)中否則庫存扣了但訂單沒生成數(shù)據(jù)不一致異常拋出RuntimeException才會(huì)回滾Exception不會(huì)。3.3 后臺(tái)權(quán)限控制基于role字段的硬編碼攔截論文 4.2 節(jié)落地論文 4.2 節(jié)“后臺(tái)管理員模塊設(shè)計(jì)”要求“只有管理員可訪問后臺(tái)”源碼中Userinfo.java的role字段為TINYINT值為0或1。我們不用 Shiro/Spring Security增加復(fù)雜度而是用最直白的 Controller 攔截// com.snack.controller.AdminController.java Controller public class AdminController { Autowired private UserinfoMapper userinfoMapper; RequestMapping(/admin/dashboard.do) public String adminDashboard(HttpSession session, Model model) { Userinfo user (Userinfo) session.getAttribute(user); if (user null || user.getRole() ! 1) { // role1 為管理員 return redirect:/login.do?erroraccess_denied; } model.addAttribute(adminName, user.getRealName()); return admin/dashboard; // /WEB-INF/jsp/admin/dashboard.jsp } RequestMapping(/admin/users.do) public String listUsers(Model model) { // 查詢所有用戶論文 4.2 節(jié)“用戶管理” UserinfoExample example new UserinfoExample(); example.createCriteria().andRoleEqualTo(0); // 只查普通用戶 ListUserinfo users userinfoMapper.selectByExample(example); model.addAttribute(users, users); return admin/users; } }為什么是硬編碼畢業(yè)設(shè)計(jì)答辯重點(diǎn)是功能實(shí)現(xiàn)非架構(gòu)先進(jìn)性UserinfoExample$GeneratedCriteria.class中andRoleEqualTo(0)方法的存在證明此寫法已被源碼驗(yàn)證session.getAttribute(user)的 key 名必須與登錄成功后session.setAttribute(user, user)一致否則攔截失效。4. 避坑指南五個(gè)讓答辯老師當(dāng)場(chǎng)皺眉的致命錯(cuò)誤與修復(fù)方案4.1 現(xiàn)象啟動(dòng) Tomcat 后訪問http://localhost:8080/index.do報(bào) 404原因web.xml中DispatcherServlet的url-pattern寫成了*.html或/導(dǎo)致請(qǐng)求未被 Spring MVC 攔截或spring-mvc.xml的base-package掃描路徑錯(cuò)誤Controller類未被加載。解決檢查web.xml的url-pattern必須為*.do確認(rèn)spring-mvc.xml中context:component-scan base-packagecom.snack.controller /的包名與實(shí)際 Controller 類路徑完全一致大小寫敏感在IndexController類上加Controller注解并確保類在com.snack.controller包下。4.2 現(xiàn)象登錄成功后跳轉(zhuǎn)到空白頁瀏覽器地址欄顯示http://localhost:8080/WEB-INF/jsp/index.jsp原因InternalResourceViewResolver的prefix配置錯(cuò)誤或 Controller 返回的視圖名與 JSP 文件名不匹配。prefix/WEB-INF/jsp/和suffix.jsp拼接后必須指向真實(shí)文件。解決確認(rèn)WEB-INF/jsp/index.jsp文件存在檢查IndexController.showIndex()方法返回值是index無后綴若 JSP 在WEB-INF/jsp/user/下則prefix應(yīng)改為/WEB-INF/jsp/user/。4.3 現(xiàn)象添加商品到購(gòu)物車時(shí)控制臺(tái)報(bào)org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.snack.mapper.SnackinfoMapper.selectByPrimaryKey原因MyBatis 的 Mapper 接口與 XML 文件未正確綁定。SnackinfoMapper.java接口的全限定名如com.snack.mapper.SnackinfoMapper必須與SnackinfoMapper.xml文件中的namespace完全一致且 XML 文件必須放在src/main/resources/com/snack/mapper/目錄下與接口包路徑一致。解決檢查SnackinfoMapper.xml頭部mapper namespacecom.snack.mapper.SnackinfoMapper確認(rèn) XML 文件物理路徑為src/main/resources/com/snack/mapper/SnackinfoMapper.xmlMaven 構(gòu)建時(shí)確保resources目錄被正確復(fù)制到target/classes。4.4 現(xiàn)象管理員登錄后訪問/admin/users.do頁面顯示“找不到用戶”數(shù)據(jù)庫明明有數(shù)據(jù)原因UserinfoExample$GeneratedCriteria.class的andRoleEqualTo(0)方法被調(diào)用但數(shù)據(jù)庫中userinfo.role字段值為NULL或2導(dǎo)致WHERE role 0查不到記錄。解決執(zhí)行 SQLUPDATE userinfo SET role 0 WHERE role IS NULL OR role NOT IN (0,1);或修改代碼為example.createCriteria().andRoleLessThanOrEqualTo(1)寬松匹配更穩(wěn)妥的是在userinfo表的role字段加DEFAULT 0和CHECK (role IN (0,1))約束。4.5 現(xiàn)象下單時(shí)庫存扣減成功但訂單未生成數(shù)據(jù)庫中order表為空原因Transactional注解未生效。常見情況createOrder()方法被同一類內(nèi)的其他方法調(diào)用內(nèi)部調(diào)用繞過代理或OrderService類未被 Spring 容器管理缺少Service注解或spring-context.xml未掃描該包。解決確保OrderService類上有Service注解createOrder()方法為public調(diào)用方是另一個(gè) Bean如OrderController而非OrderService自身檢查spring-context.xml是否包含context:component-scan base-packagecom.snack.service /。5. 論文寫作與答辯技巧把源碼里的GeneratedCriteria變成你的技術(shù)亮點(diǎn)5.1 在論文“系統(tǒng)設(shè)計(jì)”章節(jié)用SnackinfoExample$GeneratedCriteria.class解釋 MyBatis 動(dòng)態(tài) SQL 優(yōu)勢(shì)很多同學(xué)在論文里寫“MyBatis 支持動(dòng)態(tài) SQL”但空洞無物。你可以這樣寫直接抄進(jìn)論文 3.3 節(jié)“本系統(tǒng)采用 MyBatis Generator 自動(dòng)生成SnackinfoExample類其內(nèi)部嵌套類GeneratedCriteria封裝了andNameLike()、andPriceBetween()等方法。例如商品搜索功能論文 4.1 節(jié)中用戶輸入關(guān)鍵詞‘薯片’后端代碼example.createCriteria().andNameLike(%薯片%)即生成WHERE name LIKE %薯片%的 SQL無需手寫字符串拼接。這避免了 SQL 注入風(fēng)險(xiǎn)且當(dāng)數(shù)據(jù)庫表結(jié)構(gòu)變更時(shí)僅需重新執(zhí)行 Generator 即可同步 Java 實(shí)體與 Example 類提升維護(hù)效率?!睘槭裁催@招高明導(dǎo)師一眼看出你真懂 MyBatis不是照抄概念GeneratedCriteria是源碼里真實(shí)存在的類名答辯時(shí)可當(dāng)場(chǎng)反編譯SnackinfoExample$GeneratedCriteria.class證明把“避免 SQL 注入”這種安全術(shù)語落到andNameLike()方法的具體調(diào)用上比泛泛而談“使用預(yù)編譯”更有說服力。5.2 答辯演示時(shí)用三步操作亮出“管理員權(quán)限隔離”的硬核證據(jù)答辯老師最愛問“你的權(quán)限控制怎么實(shí)現(xiàn)的” 別只說“我用了 if 判斷”要現(xiàn)場(chǎng)演示。按以下順序操作提前在數(shù)據(jù)庫里準(zhǔn)備兩個(gè)用戶user1role0、admin1role1步驟操作預(yù)期結(jié)果技術(shù)點(diǎn)1用user1登錄訪問http://localhost:8080/admin/dashboard.do頁面跳轉(zhuǎn)至login.do?erroraccess_deniedAdminController.adminDashboard()中if (user.getRole() ! 1)生效2用admin1登錄訪問同一 URL顯示admin/dashboard.jsp右上角顯示“歡迎管理員”session.getAttribute(user)成功獲取并校驗(yàn)3在admin/users.do頁面打開瀏覽器開發(fā)者工具 → Network 標(biāo)簽刷新頁面查看admin/users.do請(qǐng)求的 Response確認(rèn)返回的 HTML 中包含trtduser1/tdtd普通用戶/td/trUserinfoExample$GeneratedCriteria.class的andRoleEqualTo(0)方法執(zhí)行成功玄學(xué)細(xì)節(jié)第 1 步必須用普通用戶賬號(hào)證明攔截有效第 2 步的“歡迎管理員”文字來自model.addAttribute(adminName, user.getRealName())說明Userinfo實(shí)體的getRealName()方法被正確調(diào)用第 3 步的 Network 抓包是向老師證明你不是在 JSP 里硬寫死表格而是真實(shí)查詢了數(shù)據(jù)庫。5.3 源碼調(diào)試技巧如何快速定位UserinfoExample$Criteria.class的調(diào)用鏈當(dāng)你被問“Criteria類是怎么工作的”不要背概念。打開 IDEA按住Ctrl點(diǎn)擊example.createCriteria()你會(huì)跳轉(zhuǎn)到UserinfoExample.java的createCriteria()方法。接著點(diǎn)擊Criteria類名進(jìn)入其定義。你會(huì)發(fā)現(xiàn)Criteria是UserinfoExample的靜態(tài)內(nèi)部類它繼承自GeneratedCriteria即UserinfoExample$GeneratedCriteria.classandRoleEqualTo(0)方法最終調(diào)用addCriterion(role , value, role)將條件加入criteria列表selectByExample()方法遍歷criteria列表拼接 SQL 的WHERE子句。從那以后我每次遇到 MyBatis 查詢問題都強(qiáng)制走一遍這個(gè)點(diǎn)擊流程Ctrl點(diǎn)擊方法 → 查看父類 → 跟蹤addCriterion調(diào)用。它讓我在 3 分鐘內(nèi)搞清任何 Example 查詢的底層邏輯而不是靠猜。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取