據(jù)庫系統(tǒng)應(yīng)用開發(fā)實例:JSP/Servlet+JDBC+MySQL源碼視頻解析)
簡介Java Web數(shù)據(jù)庫系統(tǒng)應(yīng)用開發(fā)與實例是一份面向Web開發(fā)者的源碼與視頻學習包內(nèi)容圍繞Java Web和數(shù)據(jù)庫系統(tǒng)開發(fā)展開覆蓋Servlet、JSP、JDBC、Spring MVC/Struts以及SQL、事務(wù)、存儲過程和Hibernate/MyBatis等ORM映射技術(shù)。整個包共884個文件約222.5MB核心包括163個Java源碼、140個JSP頁面、181個編譯后Class文件、17個SQL腳本和48個AVI操作演示視頻另有JAR包、XML配置、JS/CSS等輔助資源便于對照學習與二次調(diào)試。已有470人學習下載適合希望從基礎(chǔ)到進階掌握Java Web與數(shù)據(jù)庫整合開發(fā)的初學者也適合有一定經(jīng)驗的開發(fā)者查漏補缺。通過源碼閱讀和視頻演示可直觀理解系統(tǒng)演示、共通Servlet封裝、第一個JSP應(yīng)用、報表打印等關(guān)鍵場景快速搭建數(shù)據(jù)庫驅(qū)動的Web應(yīng)用并優(yōu)化連接、認證與并發(fā)處理。1. Java Web數(shù)據(jù)庫系統(tǒng)應(yīng)用開發(fā)與實例源碼、視頻和課設(shè)的完整閉環(huán)如果你正在準備Java Web數(shù)據(jù)庫方向的課設(shè)最讓人心態(tài)失衡的事往往不是寫代碼本身而是找不到一個“能跑起來”的參考項目。網(wǎng)上的Demo不少可要么頁面是靜態(tài)的要么SQL腳本導入就報錯。這套《Java Web數(shù)據(jù)庫系統(tǒng)應(yīng)用開發(fā)與實例》的源碼與視頻資源解決的就是這個痛點它以一個賬戶信息管理Demo為載體把數(shù)據(jù)庫建表、JDBC連接、用戶登錄、增刪改查完整走了一遍。配套視頻按模塊拆開講每一步都有對應(yīng)的代碼位置。適合兩類人一是新手想照著視頻從零搭環(huán)境二是已經(jīng)寫過一些Java Web代碼的開發(fā)者想直接扒一套規(guī)范的分層代碼來改。2. 技術(shù)選型與工程結(jié)構(gòu)JSP/Servlet、JDBC、MySQL 怎么湊成一套不翻車的課設(shè)2.1 為什么還在用 JSP/Servlet課設(shè)場景下的務(wù)實選擇這套資源沒有追新技術(shù)棧相當克制前端用JSP后端用Servlet數(shù)據(jù)庫訪問用JDBC數(shù)據(jù)庫用MySQL容器用Tomcat。第一反應(yīng)當然是現(xiàn)在不都用Spring Boot嗎但如果你打開課程大綱會發(fā)現(xiàn)很多數(shù)據(jù)庫系統(tǒng)課程的核心要求仍然是“掌握Servlet生命周期”“使用JDBC完成數(shù)據(jù)庫增刪改查”。用Spring Boot超綱不說演示時被問到“Servlet里為什么不是service()方法”反而容易翻車。從這個角度看JSP/Servlet恰恰是最穩(wěn)妥的課設(shè)選擇。另一個維度是學習路徑足夠短。JSP負責頁面展示Servlet負責接收請求JDBC負責和MySQL交互整條鏈路可以在配套視頻里一步步看到。項目內(nèi)部并不是把所有邏輯堆在JSP里而是拆成了bean、dao、service、servlet、util幾個包。視頻的順序也按這個依賴關(guān)系排先裝環(huán)境再寫SQL腳本接著封裝DBUtil最后做Servlet和JSP。跟著視頻走實際就是按技術(shù)棧的依賴順序重新搭一遍。如果你之前只寫過單文件Servlet這套結(jié)構(gòu)正好幫你理解“類多了以后怎么分工”。2.2 WebRoot、src、sql 目錄先分清三塊再動手項目的目錄結(jié)構(gòu)如下ProjectName/ ├─ src/ │ ├─ com/xxx/ │ │ ├─ bean/User.java │ │ ├─ dao/UserDao.java │ │ ├─ service/UserService.java │ │ ├─ servlet/LoginServlet.java │ │ └─ util/DBUtil.java ├─ WebRoot/ │ ├─ css/ │ ├─ WEB-INF/ │ │ └─ web.xml │ ├─ login.jsp │ ├─ list.jsp │ └─ index.jsp ├─ sql/ │ └─ init.sql └─ README.txtsrc下主要看五個包bean里的User對應(yīng)數(shù)據(jù)庫表字段名盡量和表列名保持一致否則ResultSet取值時容易踩坑dao就是數(shù)據(jù)訪問層只負責拼SQL、執(zhí)行SQL、把結(jié)果封裝成對象service是業(yè)務(wù)層比如登錄時候的密碼校驗、刪除前的關(guān)聯(lián)檢查都放這里servlet負責接收瀏覽器參數(shù)調(diào)用service最后跳轉(zhuǎn)或轉(zhuǎn)發(fā)util里放DBUtil這類公共工具。WebRoot是Web應(yīng)用的根目錄部署到Tomcat后訪問路徑就是WebRoot下的文件路徑web.xml用來配置Servlet映射和歡迎頁。sql/init.sql是全項目最關(guān)鍵的文件。很多課設(shè)翻車的第一個原因不是代碼寫錯而是沒先執(zhí)行init.sql。你直接啟動項目DBUtil能連上MySQL但登錄查詢會報“Table doesnt exist”。所以拿到資源包以后先看sql目錄把腳本導入數(shù)據(jù)庫再用工具確認表和代碼里的字段對得上。README.txt一般會寫清楚MySQL用戶名密碼和初始化步驟我第一次跑的時候沒看它直接改代碼里的密碼折騰了半小時才發(fā)現(xiàn)只是數(shù)據(jù)庫密碼寫錯了。這套結(jié)構(gòu)是典型的“傳統(tǒng)Web項目”不是Maven項目。構(gòu)建時要把src編譯輸出到WEB-INF/classes把mysql-connector-java的jar包放到WEB-INF/lib。如果你看到的是Maven結(jié)構(gòu)那就在pom.xml里寫依賴。判斷方式很簡單看工程目錄下有沒有pom.xml有就是Maven沒有就是傳統(tǒng)Web項目。2.3 JDBC 工具類把 DriverManager 封裝成單例省掉一半重復代碼每個DAO都要拿連接、關(guān)連接如果不封裝寫出來的代碼會有大量重復。所以項目里通常會有這么個DBUtil核心代碼大致如下package com.xxx.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/account_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai; private static final String USER root; private static final String PASSWORD root; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { if (rs ! null) { try { rs.close(); } catch (SQLException ignored) {} } if (stmt ! null) { try { stmt.close(); } catch (SQLException ignored) {} } if (conn ! null) { try { conn.close(); } catch (SQLException ignored) {} } } }URL里的參數(shù)值得逐個記一下。useUnicodetrue和characterEncodingutf8是為了讓中文能以UTF-8寫入useSSLfalse是因為本地開發(fā)不加密不加的話MySQL 8.0會一直報警告serverTimezoneAsia/Shanghai是MySQL 8.0之后才需要的時區(qū)參數(shù)少了它會在獲取連接時報時間差錯誤。驅(qū)動類名也有版本講究mysql-connector 8.x對應(yīng)com.mysql.cj.jdbc.Driver8.0之前是com.mysql.jdbc.Driver。視頻里如果第一次用5.x后來換8.0不少人就是在這里栽跟頭。close方法先關(guān)ResultSet再關(guān)Statement最后關(guān)Connection。這個順序不能亂因為ResultSet依賴StatementStatement又依賴Connection。我見過有人先關(guān)Connection再讀ResultSet的時候直接空指針還以為是自己SQL寫錯了。這套DBUtil是教學項目里最常見的寫法。如果以后要上生產(chǎn)建議把URL、用戶名、密碼抽到db.properties里再用ResourceBundle讀取改配置不用改代碼。課設(shè)沒這個要求但作為二次開發(fā)習慣提前做沒壞處。3. 核心模塊拆解一個登錄請求從表單到 Session 再到數(shù)據(jù)庫的完整鏈路3.1 登錄模塊表單提交后 Servlet 里發(fā)生了什么登錄邏輯看起來簡單卻是很多問題的集中地。先看LoginServlet的doPostWebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String password request.getParameter(password); UserService userService new UserService(); User user userService.login(username, password); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); response.sendRedirect(request.getContextPath() /list); } else { request.setAttribute(errorMsg, 用戶名或密碼錯誤); request.getRequestDispatcher(/login.jsp).forward(request, response); } } }request.setCharacterEncoding(UTF-8)這一行必須在getParameter之前執(zhí)行。如果放在之后POST請求里的中文參數(shù)會按容器默認編碼解析常見表現(xiàn)是用戶名里的中文變成亂碼。登錄成功以后把User對象放進Session后續(xù)JSP頁面才能通過session里的loginUser判斷“是否已登錄”。這里用的是sendRedirect而不是forward好處是瀏覽器地址欄變成/list用戶按F5刷新時不會重復提交登錄表單。登錄失敗則用forward把錯誤提示帶回login.jsprequest里的errorMsg能在頁面上顯示。很多人會問為什么Servlet里不直接寫SQL因為代碼一旦寫成Servlet里new一個UserDao再查庫后續(xù)要加“連續(xù)輸錯三次鎖定賬號”這類規(guī)則時就得改Servlet。項目里用UserService包了一層登錄這種業(yè)務(wù)邏輯放在service里。UserService內(nèi)部再調(diào)用UserDao這樣Servlet只負責參數(shù)解析和頁面跳轉(zhuǎn)職責很干凈。密碼字段在視頻里是明文存儲這是教學項目為了方便演示。如果你要做成作品展示至少要改成MD5加鹽或者直接用BCrypt。我一般會在service里加一層“從庫里查出用戶對比密碼”的邏輯而不是讓SQL直接寫where username? and password?因為后者沒法在代碼里做加密和登錄次數(shù)限制。3.2 用戶列表與分頁LIMIT 的參數(shù)不能靠字符串拼接列表頁是CRUD里最常改的部分。分頁查詢的UserDao實現(xiàn)大致是這個樣子public ListUser findPage(int pageNum, int pageSize) { ListUser list new ArrayList(); String sql SELECT id, username, nickname, email FROM user ORDER BY id LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, (pageNum - 1) * pageSize); ps.setInt(2, pageSize); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { User user new User(); user.setId(rs.getInt(id)); user.setUsername(rs.getString(username)); list.add(user); } } } catch (SQLException e) { e.printStackTrace(); } return list; }LIMIT ? ?是MySQL分頁的標準寫法第一個參數(shù)是偏移量第二個參數(shù)是每頁條數(shù)。pageNum從1開始所以偏移量等于(pageNum - 1) * pageSize。比如第3頁每頁10條就是從第21條開始取10條。用PreparedStatement的setInt傳參而不是拼SQL是因為這些參數(shù)來自頁面請求一旦拼SQL就存在注入風險。你在瀏覽器把pageSize改成“10 or 11”如果代碼是字符串拼接后面的查詢條件就會被改掉。這段代碼沒有寫COUNT查詢但列表頁一般要顯示“共幾頁”所以還需要一個配套方法public int count() { String sql SELECT COUNT(*) FROM user; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { if (rs.next()) { return rs.getInt(1); } } catch (SQLException e) { e.printStackTrace(); } return 0; }總頁數(shù)的計算方式是(total pageSize - 1) / pageSize。比如總數(shù)是21每頁10這樣算出的是3頁而不是2頁。視頻里通常會單獨講這個細節(jié)因為它最容易在列表頁翻頁時出現(xiàn)最后一頁少一條的“玄學”問題。3.3 刪除用戶事務(wù)邊界和子表刪除順序刪除功能的典型場景是用戶主表一條記錄用戶角色關(guān)聯(lián)表里還有多條記錄。如果只刪主表外鍵約束會報錯如果只刪關(guān)聯(lián)表主表留下孤兒數(shù)據(jù)。項目里的刪除邏輯通常會這樣寫public boolean deleteUser(int userId) { Connection conn null; PreparedStatement ps null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); String deleteRole DELETE FROM user_role WHERE user_id ?; ps conn.prepareStatement(deleteRole); ps.setInt(1, userId); ps.executeUpdate(); String deleteUser DELETE FROM user WHERE id ?; ps conn.prepareStatement(deleteUser); ps.setInt(1, userId); ps.executeUpdate(); conn.commit(); return true; } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { e.printStackTrace(); } } e.printStackTrace(); return false; } finally { if (conn ! null) { try { conn.setAutoCommit(true); } catch (SQLException ignored) {} } DBUtil.close(conn, ps, null); } }核心點是setAutoCommit(false)。一旦關(guān)閉自動提交后面兩條DELETE要么一起成功要么一起回滾。如果第一條成功第二條失敗commit不會執(zhí)行rollback會把第一次刪除也撤銷避免出現(xiàn)“關(guān)聯(lián)表刪了主表還在”的臟數(shù)據(jù)。事務(wù)只包寫操作查詢不需要包因為查詢不存在一致性問題。另一個細節(jié)是刪除順序。如果user_role表有外鍵指向user表必須先刪user_role再刪user否則MySQL會報外鍵約束失敗。有些項目為了省事把外鍵去掉這樣先刪誰都能跑但數(shù)據(jù)完整性就丟了。我建議保留外鍵讓數(shù)據(jù)庫幫你兜底演示時還可以順勢講一句“外鍵約束保證了引用的有效性”這對課設(shè)評分是加分項。更新操作和刪除類似但要注意executeUpdate的返回值。返回0表示影響行數(shù)為0常見原因是數(shù)據(jù)已經(jīng)被別人刪了或者你提交的id根本不存在。前端提示“更新失敗”總比悄無聲息成功要好。4. 從導入到跑通Tomcat和MySQL下的部署步驟與配置檢查4.1 環(huán)境準備JDK、Tomcat、MySQL 版本怎么選視頻里從頭講環(huán)境搭建但你不需要完全復刻版本。JDK 1.8、Tomcat 8/9、MySQL 5.7或8.0這是教學項目最保險的組合。如果你的機器已經(jīng)裝了JDK 11甚至17傳統(tǒng)JSP項目在Tomcat 9上也能跑但要注意Tomcat 10及以上把包名換成了jakarta.*老項目的javax.*代碼直接編譯不過。為了少折騰我建議直接用JDK 8和Tomcat 8.5。版本對照可以看這張表組件推薦版本注意點JDK1.8Servlet編譯兼容性最好Tomcat8.5 / 9.0WebServlet注解可用MySQL5.7 / 8.08.0需要serverTimezone參數(shù)mysql-connector-java5.1.x / 8.0.x驅(qū)動類名不一樣MySQL 5.7的好處是省心驅(qū)動類名用com.mysql.jdbc.Driver不需要時區(qū)參數(shù)。MySQL 8.0性能更好但sql_mode和排序規(guī)則更容易出幺蛾子。視頻里演示用的具體版本我不重復原則是跟著視頻版本走別自己混搭最新版。尤其是mysql-connector 8.0.x對MySQL 5.7也能連反過來5.1.x連8.0會報SSL握手失敗這里面坑很多。4.2 把工程導入 IDE傳統(tǒng)Web項目與 WEB-INF 檢查拿到源碼后先看是不是Maven工程。傳統(tǒng)Web項目用Eclipse導入File Import Existing Projects into WorkspaceIDEA則直接Open目錄然后在Project Structure里設(shè)置SDK和Web Facet。導入后最重要的一步是檢查WEB-INF/lib下有沒有mysql-connector的jar包。沒有的話啟動后跑一次登錄就會報ClassNotFoundException。IDEA里傳統(tǒng)Web項目啟動前還要設(shè)置Artifacts。常見翻車現(xiàn)場是Tomcat啟動成功瀏覽器訪問login.jsp能打開但一點登錄就404控制臺提示Servlet沒找到。原因通常是.class文件沒有編譯輸出到WEB-INF/classes或者WebServlet注解沒有被掃描。解決方法是重新Build Artifacts并在Run Configuration的Deployment里確認war exploded已經(jīng)加進去了。如果是Maven工程導入后會自動下載依賴。等待進度條走完再啟動否則JSP頁面里用了JSTL標簽時會報“Cannot find the tag library descriptor for core”。JSTL需要jstl和standard兩個jar缺一不可。部署前建議按這個順序過一遍項目編譯無紅叉、WEB-INF/lib能看到驅(qū)動、Tomcat啟動無異常、訪問http://localhost:8080/項目名/login.jsp能正常顯示。4.3 執(zhí)行 init.sql初始化數(shù)據(jù)庫的三步檢查初始化數(shù)據(jù)庫不是“雙擊執(zhí)行”就完事。第一步確認腳本里是否已經(jīng)包含CREATE DATABASE。如果包含你直接執(zhí)行就行如果不包含需要手動創(chuàng)建數(shù)據(jù)庫再use進入。第二步檢查腳本里的表名和UserDao里的表名是否一致。我見過一個項目代碼里寫的表名是user腳本里建的表名是users啟動不報錯但查詢永遠返回空。第三步在DBUtil或db.properties里核對用戶名、密碼特別是密碼里有特殊字符時URL里偶爾還需要做URL編碼。還有一條實戰(zhàn)經(jīng)驗數(shù)據(jù)庫連不上時先別懷疑代碼。在終端用mysql -uroot -p試一下能不能登錄能登錄說明MySQL服務(wù)正常。如果終端能連而項目連不上就檢查URL里的端口是否被改過。MySQL默認3306有些機器裝了多版本MySQL端口改成了3307URL沒同步就會一直報Connection refused。這些都不算代碼邏輯問題但占了我?guī)腿伺挪閱栴}的七成時間。初始化完成后用一條最簡單查詢驗證SELECT * FROM user; 如果能查出數(shù)據(jù)再啟動項目。直接跑項目容易把“SQL腳本沒執(zhí)行”和“代碼有bug”混在一起到最后你根本不知道是哪里出了問題。5. 常見問題與避坑404、500、中文亂碼的排查筆記這套源碼視頻在本地跑起來的過程里下面幾個問題是出現(xiàn)頻率最高的。我按“現(xiàn)象、原因、解決”三條寫方便你直接對號入座。5.1 訪問 JSP 一直 404頁面像沒部署現(xiàn)象Tomcat能啟動瀏覽器打開login.jsp卻顯示404或者訪問一個Servlet地址下載了JSP源碼。原因項目沒有真正部署到Tomcat或者部署路徑和訪問路徑不一致。解決先確認IDE里Run Configuration的Deployment中已經(jīng)添加了項目的war或war exploded。Application context建議設(shè)為/項目名訪問時用帶上下文路徑的地址。Eclipse用戶右鍵項目Run As Run on Server不要直接雙擊jsp文件。Tomcat的webapps目錄下也應(yīng)該看到對應(yīng)的項目文件夾如果沒有說明部署沒生效。這類問題我遇到最多的是IDEA多模塊工程module沒被加到Artifacts里導致頁面前端資源能找到但Servlet的class文件不在WEB-INF/classes下。檢查方法是看Tomcat日志里有沒有打印“Deploying web application directory”有的話再確認WEB-INF/classes里有沒有LoginServlet.class。5.2 ClassNotFoundException驅(qū)動類名按版本選現(xiàn)象訪問數(shù)據(jù)庫相關(guān)頁面控制臺報ClassNotFoundException后面跟著com.mysql.jdbc.Driver或com.mysql.cj.jdbc.Driver。原因一是驅(qū)動jar沒有放到WEB-INF/lib二是驅(qū)動類名和驅(qū)動版本不匹配。解決先確認mysql-connector-java的版本。8.0.x必須用com.mysql.cj.jdbc.Driver5.1.x用com.mysql.jdbc.Driver。然后把jar放到WEB-INF/lib下重新部署不要放在IDE的external libraries里因為Tomcat運行時不會去讀IDE的類路徑。Maven項目則要檢查pom.xml里的驅(qū)動依賴scope如果寫成了provided或者testTomcat運行時會找不到類。順便說一句驅(qū)動jar包版本不要亂用最新的8.4、8.5項目里視頻用的是8.0.x系列就保持一致。打包部署的環(huán)境最怕“我更新了一下依賴然后突然壞了”。5.3 中文亂碼從頁面到數(shù)據(jù)庫要統(tǒng)一三處編碼現(xiàn)象表單輸入中文插入MySQL后變成問號或者頁面顯示“用戶名”變成“?”開頭的一串亂碼。原因JSP頁面編碼、Servlet請求編碼、JDBC連接編碼三處不一致。解決JSP第一行寫pageEncodingUTF-8Servlet在doPost開頭第一行寫request.setCharacterEncoding(UTF-8)JDBC URL加characterEncodingutf8MySQL建表時指定DEFAULT CHARACTER SET utf8mb4。三個地方缺一個都會出問題但最常見的是漏了Servlet里的setCharacterEncoding因為頁面和數(shù)據(jù)庫都改好了反而這個不起眼的一行被忽略。Tomcat 8.5之后對GET請求的參數(shù)默認按UTF-8解碼所以很多人在GET請求里不寫setCharacterEncoding也沒事。但POST請求還是建議顯式設(shè)置因為換成其他容器或Tomcat版本后行為可能不同。課設(shè)演示時最好三種請求都試一遍避免現(xiàn)場翻車。5.4 數(shù)據(jù)庫連接耗盡操作幾次后卡死現(xiàn)象項目剛啟動能正常增刪改查翻幾頁之后越來越卡最后請求一直轉(zhuǎn)圈控制臺報Too many connections或者Connection refused。原因代碼里getConnection后沒有close連接泄漏MySQL連接數(shù)被占滿。解決在DAO每個方法里用try-with-resources或者finally里調(diào)用DBUtil.close。關(guān)閉順序按ResultSet、Statement、Connection來。如果用了連接池還要檢查池的最大連接數(shù)和空閑超時。排查時在MySQL執(zhí)行SHOW PROCESSLIST能看到大量Sleep的連接基本就能實錘。這里有個容易誤傷的點JDBC的Connection.close不是直接把進程殺死而是把連接放回連接池或標記為關(guān)閉。如果你在finally里關(guān)閉后后續(xù)又去操作ResultSet會報ResultSet closed。所以取值范圍只在try塊內(nèi)取完再關(guān)不要把rs拿到方法外面去用。5.5 視頻里能跑我這兒就是不行版本和緩存現(xiàn)象每一步都跟著視頻做軟件版本也一樣但啟動后報錯信息五花八門。原因多半是驅(qū)動jar版本不一致、數(shù)據(jù)庫端口不對或者瀏覽器緩存了舊的JSP。解決先暫停視頻逐行對照自己的配置文件和代碼不要憑記憶寫URL。再確認MySQL服務(wù)真的啟動了Windows下服務(wù)列表可能顯示“已停止”。瀏覽器按CtrlF5強制刷新排除舊頁面緩存。最后還不行就刪除項目重新導入一次IDEA緩存導致的資源沒刷新問題重導往往能解決。這一條看著像玄學其實背后是“環(huán)境狀態(tài)不確定”。我處理這類問題時會寫一個環(huán)境檢查清單JDK版本、Tomcat版本、MySQL版本、驅(qū)動版本、端口、字符集。逐個打勾不猜。很多時候你盯著代碼看半天最后發(fā)現(xiàn)Tomcat的CATALINA_BASE指到了另一個安裝目錄項目根本沒部署到你正在修改的那個Tomcat上。6. 二次開發(fā)指南把單用戶登錄改造成多角色權(quán)限控制6.1 改造思路登錄后把角色信息放進 Session這套Demo的Session里只存了User對象所有登錄用戶看到的功能都一樣。要做多角色權(quán)限第一步是擴展表結(jié)構(gòu)user表加一個role_id字段再建role表保存角色名比如admin和user。登錄時除了查User還要通過role_id查出角色名稱。// 登錄成功后額外查詢角色并放入 Session Role role roleService.findByUserId(user.getId()); session.setAttribute(currentRole, role.getName());第二步在JSP頁面判斷角色決定是否顯示某個入口比如管理員才能看到“用戶管理”鏈接。但頁面判斷只能算展示層控制真正的控制要在Servlet入口做。6.2 驗證方法用普通賬號試一次管理員頁面最簡單可演示的權(quán)限控制是在管理員相關(guān)Servlet的doGet或doPost開頭加幾行HttpSession session request.getSession(); if (!admin.equals(session.getAttribute(currentRole))) { response.sendRedirect(request.getContextPath() /login.jsp); return; }這樣輸入普通賬號登錄后直接訪問管理員的Servlet地址會被彈回登錄頁瀏覽器地址欄也能看到變化。演示時先截一張普通賬號被攔截的圖再換成管理員賬號訪問成功就是這個功能最好的說明。如果需要更完整的攔截再考慮寫一個Filter統(tǒng)一檢查除login之外的路徑。我在第一次給類似項目加權(quán)限時把角色判斷直接塞進了JSP頁面里結(jié)果別人改個頁面就能繞過。后來我強制要求所有權(quán)限校驗都放在Servlet入口完成JSP只負責展示。從那以后我每次做Java Web數(shù)據(jù)庫項目的二次開發(fā)都會先畫一遍“請求從哪里進、角色在哪里校驗、失敗回哪里”的路徑圖再動手。希望幫到你。本文還有配套的精品資源點擊獲取