部署教程:數(shù)據(jù)庫設(shè)計與借還書流程避坑指南)
簡介一份關(guān)于圖書館借閱系統(tǒng)的Java Web課程設(shè)計與畢業(yè)設(shè)計資源基于JSP與Servlet技術(shù)開發(fā)面向計算機專業(yè)學生、Java Web初學者以及需要快速完成課題的開發(fā)者可用于實現(xiàn)圖書查詢、借閱、歸還、讀者管理和館藏統(tǒng)計等核心業(yè)務。壓縮包內(nèi)共114個文件約1.64MB包含57個JSP動態(tài)頁面、4個依賴庫文件、SQL數(shù)據(jù)庫腳本及數(shù)據(jù)庫備份文件還有用于界面展示的圖片素材和論文文檔可兼顧運行使用與文檔撰寫。資源提供了完整源代碼和配套論文代碼采用模型-視圖-控制器的分層思想將頁面展示與業(yè)務邏輯分離便于逐段學習數(shù)據(jù)庫設(shè)計、數(shù)據(jù)訪問、會話跟蹤、權(quán)限驗證和異常處理等Web開發(fā)要點這些內(nèi)容對完成課程設(shè)計、準備畢業(yè)設(shè)計答辯或進行項目實踐均有直接幫助。已有128人學習適合有一定Java基礎(chǔ)、希望在較短時間內(nèi)獨立完成Web項目開發(fā)的讀者。1. 這個zip里裝的是什么東西JSP圖書館借閱系統(tǒng)的真實面貌圖書館借閱系統(tǒng)是 JSP Web 開發(fā)里被做爛了、但永遠不過時的課設(shè)題目。這個 zip 包通常包含一份可運行的 Web 工程源碼、數(shù)據(jù)庫腳本和配套論文文檔適合需要交課程設(shè)計或畢業(yè)設(shè)計的同學直接拿來跑通、改造成自己的項目。它的核心價值不是讓你學會 JSP 語法而是讓你在最短時間內(nèi)看到一個完整 Web 項目從數(shù)據(jù)庫到頁面、從登錄到借還書的全鏈路是怎么串起來的。本文會從拿到壓縮包后的第一步開始講清楚怎么把它跑起來、數(shù)據(jù)庫怎么建、借書還書流程怎么實現(xiàn)的以及最容易踩的五個坑。如果你手里正好有這么一個包或者準備做類似的 JSP 圖書館項目這篇文章可以幫你少走兩周彎路。2. 本地把項目跑通JDK、Tomcat、MySQL 與導入部署全流程2.1 環(huán)境版本怎么選JDK 8 Tomcat 8.5 是最穩(wěn)的組合這類 JSP 老項目大多是在 2015 到 2019 年之間寫的用的技術(shù)?;臼?JSP Servlet JDBC MySQL框架最多帶個 jQuery。給它配環(huán)境的第一原則是“越老越穩(wěn)”JDK 用 8Tomcat 用 8.5MySQL 用 5.7。JDK 11 以上不是跑不了但很多代碼里用了 javax.servlet 和 JDK 8 時期的寫法在高版本容器下容易報模塊訪問錯誤屬于自己給自己找麻煩。Tomcat 8.5 和 JDK 8 的搭配為什么穩(wěn)因為 Tomcat 8.5 本身就是在 JDK 8 年代發(fā)布的對 JSP 2.3 和 Servlet 3.1 的支持最成熟。MySQL 5.7 則是那個年代課設(shè)項目的默認配置數(shù)據(jù)庫腳本和驅(qū)動類名基本都是按 5.x 寫的。如果你機器上已經(jīng)裝了 MySQL 8.x 也不用慌第 5 章會專門講驅(qū)動和時區(qū)那個坑怎么處理。2.2 導入 IDEA/Eclipse 與修改數(shù)據(jù)庫連接配置拿到壓縮包先解壓常見目錄結(jié)構(gòu)是 src 代碼目錄、web 或 WebRoot 頁面目錄、sql 或 db 數(shù)據(jù)庫腳本目錄外加一份論文文件夾。先把 sql 目錄里的 .sql 文件找出來這個文件之后要用。打開 IDEA 或 Eclipse用導入 Maven 項目或?qū)?Dynamic Web Project 的方式把工程加載進來。需要注意如果原項目用的是 Eclipse 導入 IDEA路徑和 Facet 配置會丟失需要手動補上。數(shù)據(jù)庫連接配置一般在 src 目錄下的db.properties或者jdbc.properties文件里少數(shù)項目直接寫在 ConnectionUtil.java 類中。找到后檢查這幾項jdbc.urljdbc:mysql://localhost:3306/librarydb?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456 jdbc.drivercom.mysql.jdbc.Driver如果用的是 MySQL 5.7驅(qū)動類名com.mysql.jdbc.Driver沒問題如果是 MySQL 8.x需要改成com.mysql.cj.jdbc.Driver。URL 里的characterEncodingutf8是防中文亂碼的serverTimezoneAsia/Shanghai是 MySQL 8 必須加的否則會報時區(qū)錯誤。數(shù)據(jù)庫名librarydb要和 sql 里建庫語句的庫名對應密碼改成你自己 MySQL 的密碼。提示項目里的數(shù)據(jù)庫連接信息是最高頻的報錯源。改完配置后先連一下 MySQL 客戶端確認賬號密碼、庫名都對再啟動 Tomcat。2.3 執(zhí)行數(shù)據(jù)庫腳本與啟動 web 服務器打開 MySQL 命令行或 Navicat執(zhí)行 sql 目錄里的腳本。常見做法是用 source 命令mysql -u root -p123456 d:/library.sql或者進入 MySQL 后執(zhí)行source d:/library.sql;執(zhí)行完可以看到提示然后輸入show databases;確認 librarydb 存在。接著配置 Tomcat。如果是 IDEA在 Run/Debug Configurations 里添加 Tomcat Server LocalDeployment 里把項目 artifact 加進去如果是直接拿 Tomcat 跑把項目下的 target 目錄里打好的 war 包或 Exploded 目錄復制到 tomcat/webapps 下然后啟動cd /path/to/tomcat/bin startup.batWindows 下用 startup.batLinux 下用 startup.sh。啟動后看控制臺日志出現(xiàn) “Server startup in xxx ms” 才算成功。訪問 http://localhost:8080/項目名/ 一般默認賬號是 admin密碼 admin 或 123456登錄后能看到后臺管理界面。3. 數(shù)據(jù)庫設(shè)計與表結(jié)構(gòu)邏輯借閱系統(tǒng)的數(shù)據(jù)模型3.1 核心表拆解用戶、圖書、借閱記錄三張表撐起整個系統(tǒng)一套標準的 JSP 圖書館借閱系統(tǒng)后端數(shù)據(jù)庫一般至少包含三張核心表用戶表、圖書信息表、借閱記錄表。用戶表存管理員和讀者的賬號密碼圖書表存書的名稱、作者、ISBN、庫存等元數(shù)據(jù)借閱記錄表負責把用戶和書關(guān)聯(lián)起來并記錄借出時間、應還時間、實際歸還時間。這三張表之間的關(guān)系很直觀一個用戶對應多條借閱記錄一本書對應多條借閱記錄。說得更直白一點借閱記錄表就是連接用戶表和圖書表的中間表是這套系統(tǒng)里業(yè)務邏輯最密集的地方。下面是一個常見的建表設(shè)計字段命名經(jīng)過簡化你可以直接復制到你的數(shù)據(jù)庫腳本里。3.2 建庫建表 SQL可以抄作業(yè)的完整腳本CREATE DATABASE IF NOT EXISTS librarydb DEFAULT CHARACTER SET utf8; USE librarydb; CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(50) NOT NULL, realname VARCHAR(50), role TINYINT DEFAULT 1 COMMENT 0管理員 1讀者, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE t_book ( id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20) NOT NULL, book_name VARCHAR(200) NOT NULL, author VARCHAR(100), category VARCHAR(50), press VARCHAR(100), stock INT DEFAULT 1 COMMENT 可借庫存, total INT DEFAULT 1 COMMENT 總庫存, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE t_borrow ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, book_id INT NOT NULL, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP, due_time DATETIME COMMENT 應還時間, return_time DATETIME COMMENT 實際歸還時間, status TINYINT DEFAULT 1 COMMENT 1借出中 2已歸還 3逾期未還, KEY idx_user (user_id), KEY idx_book (book_id), CONSTRAINT fk_borrow_user FOREIGN KEY (user_id) REFERENCES t_user(id), CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES t_book(id) ); CREATE TABLE t_category ( id INT PRIMARY KEY AUTO_INCREMENT, category_name VARCHAR(50) NOT NULL UNIQUE );代碼說明庫名用librarydb字符集強制為 utf8避免建表后中文亂碼。t_user表把管理員和讀者放在同一張表用role字段區(qū)分這是課設(shè)里的常見做法比拆成兩張表更容易維護。t_book里stock表示當前可借數(shù)量total表示總庫存數(shù)兩個字段分開存是因為借出去的書記錄在借閱表里每次還書都需要把stock加回來。t_borrow表里的外鍵約束在真實項目中常常會被省略但課設(shè)建議保留答辯時可以說“我用外鍵保證了數(shù)據(jù)完整性”。參數(shù)說明due_time應還時間 borrow_time 借期天數(shù)默認 30 天逾期罰金一般按天計算不在表里存金額而在查詢時動態(tài)算。另外t_category分類表是可選表很多簡單系統(tǒng)直接用 t_book 里的 category 字符串字段不需要單獨建。如果你接手的是簡化版本沒有分類表也正常。3.3 借閱記錄狀態(tài)流轉(zhuǎn)為什么 status 用數(shù)字而不是字符串設(shè)計借閱記錄表時最容易翻車的地方是 status 字段。有的人圖省事直接存“借出中”“已歸還”這種中文后來想統(tǒng)計未歸還數(shù)量時發(fā)現(xiàn)大小寫不一致或編碼亂掉。更穩(wěn)的做法是用數(shù)字枚舉1 表示借出中2 表示已歸還3 表示逾期。這個數(shù)字狀態(tài)的好處是頂層代碼不需要解析字符串直接WHERE status 3就能查出所有逾期未還的人。逾期狀態(tài)怎么產(chǎn)生一種做法是還書時判斷當前時間大于 due_time 則更新為 3另一種是靠定時任務掃描。課設(shè)項目里最常見的是前者還書那一刻判斷是否超期順便把罰金算出來。查詢頁面上也可以用 JSTLc:if test${record.status 1}來渲染不同標簽邏輯干凈。4. 核心借還流程的實現(xiàn)Servlet JSP 怎么把業(yè)務串起來4.1 借書用例從頁面按鈕到數(shù)據(jù)庫記錄的兩條鏈路把這個流程拆開借一本書要經(jīng)過圖書列表頁 → 點擊“借書” → 發(fā)請求到 BorrowServlet → BorrowDao 查庫存和是否重復借 → 插入借閱記錄 → 減少庫存 → 跳轉(zhuǎn)結(jié)果頁。這個鏈路里 Servlet 是唯一入口JSP 只做展示和表單提交完整項目的代碼分層多數(shù)都是這樣組織的。// BorrowDao.java 中借書方法的核心片段 public boolean borrowBook(int userId, int bookId) { Connection conn null; PreparedStatement ps null; ResultSet rs null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 開啟事務 // 1. 查這本書當前庫存 String sqlStock SELECT stock FROM t_book WHERE id ? FOR UPDATE; ps conn.prepareStatement(sqlStock); ps.setInt(1, bookId); rs ps.executeQuery(); if (!rs.next()) return false; if (rs.getInt(stock) 1) return false; // 庫存不足直接失敗 // 2. 檢查用戶是否已經(jīng)借過同一本書且未歸還 String sqlCheck SELECT COUNT(*) FROM t_borrow WHERE user_id ? AND book_id ? AND status 1; ps conn.prepareStatement(sqlCheck); ps.setInt(1, userId); ps.setInt(2, bookId); rs ps.executeQuery(); if (rs.next() rs.getInt(1) 0) return false; // 3. 插入借閱記錄 String sqlInsert INSERT INTO t_borrow (user_id, book_id, due_time) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 30 DAY)); ps conn.prepareStatement(sqlInsert); ps.setInt(1, userId); ps.setInt(2, bookId); ps.executeUpdate(); // 4. 扣減庫存 String sqlUpdate UPDATE t_book SET stock stock - 1 WHERE id ? AND stock 0; ps conn.prepareStatement(sqlUpdate); ps.setInt(1, bookId); ps.executeUpdate(); conn.commit(); // 全部成功才提交 return true; } catch (SQLException e) { if (conn ! null) try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } return false; } finally { DBUtil.close(rs, ps, conn); } }這段代碼我故意加了三個平時項目里很容易忽略的細節(jié)。第一個是conn.setAutoCommit(false)把四條 SQL 包成一個事務任何一步失敗都整體回滾避免出現(xiàn)“借閱記錄插進去了但庫存沒減”這種數(shù)據(jù)不一致。第二個是庫存查詢用了FOR UPDATE這是行鎖兩個讀者同時借同一本書的最后一本時后一個請求會等待前一個提交不會出現(xiàn)兩個人都借走但系統(tǒng)庫存只剩 1 的問題。第三個是在扣庫存時不只執(zhí)行stock stock - 1而是帶上AND stock 0條件等于在更新語句再兜一次底防止并發(fā)把庫存扣成負數(shù)。參數(shù)說明DATE_ADD(NOW(), INTERVAL 30 DAY)設(shè)置應還時間為當前時間加 30 天。你如果想改成 14 天或 60 天改這個數(shù)字就行。需要說明的是很多網(wǎng)上流傳的代碼沒有FOR UPDATE那是為了演示簡單答辯時這段代碼會是你的加分項。4.2 還書流程與逾期罰金日期計算的三個小坑還書和借書在代碼上是對稱的先更新借閱記錄狀態(tài)和歸還時間再把圖書庫存加回去。但逾期判斷這里有個經(jīng)典坑就是拿 Java 的System.currentTimeMillis()直接減due_time.getTime()再除以 86400000得到不準確的天數(shù)。原因很簡單毫秒除法按 24 小時算但數(shù)據(jù)庫里存的due_time是帶時分秒的用戶下午 3 點借的書應還時間也是下午 3 點凌晨 1 點還書時毫秒除法會得出“逾期 0 天”實際已經(jīng)超了。正確處理是先把兩個日期都轉(zhuǎn)成LocalDate只比較年月日或者直接寫在 SQL 里UPDATE t_borrow SET return_time NOW(), status CASE WHEN NOW() due_time THEN 3 ELSE 2 END WHERE id ?;這段 SQL 把狀態(tài)更新交給數(shù)據(jù)庫判斷比 Java 端比較Date對象少踩很多坑。罰金計算再把 status 3 的記錄查出來用DATEDIFF(return_time, due_time) * 0.1算出金額不用在 Java 里做日期算術(shù)。4.3 讀者個人中心與個人信息展示頁面讀者登錄后看到的 jsp 個人信息展示頁面是這類項目里被大量復用的模塊。它通常分成三塊當前借閱列表、歷史借閱記錄、個人資料修改。前兩塊走的是同一個查詢接口只是加了status篩選條件。當前借閱列表一般會顯示借出時間、應還時間逾期的時候用紅色高亮標注。這個頁面的實現(xiàn)重點在分頁和狀態(tài)渲染。很多模板項目直接SELECT * FROM t_borrow WHERE user_id ?然后全量輸出在一個 jsp 頁面里記錄一多頁面就卡。如果你想把項目質(zhì)量做高在這里加一個分頁SQL 用LIMIT offset, pageSize配合 JSP 頁面底部上一頁下一頁按鈕。不用上復雜框架純 JSP 腳本和 JDBC 就能實現(xiàn)但做出來后明顯比原來高一個檔次。5. 避坑指南跑這類 JSP 項目最容易翻車的五個位置5.1 啟動報 ClassNotFoundException: com.mysql.jdbc.Driver這個錯幾乎人手一份?,F(xiàn)象是 Tomcat 啟動或訪問數(shù)據(jù)庫時報找不到驅(qū)動類但項目 lib 目錄里明明有 mysql-connector-java 的 jar 包。原因是 jar 包和數(shù)據(jù)庫版本對不上或者 jar 沒有被打進 WEB-INF/lib。解決方法是確認 jar 在WEB-INF/lib目錄下而不是只在 IDE 的 External Libraries 里如果換成了 MySQL 8.0 以上版本驅(qū)動類名改成com.mysql.cj.jdbc.Driver。在 IDEA 里右鍵項目選擇 Open Module Settings在 Artifacts 里把 mysql 驅(qū)動加進 WEB-INF/lib再重新構(gòu)建一下。5.2 數(shù)據(jù)庫中文亂碼頁面顯示一串問號現(xiàn)象是頁面上文字正常但插入到數(shù)據(jù)庫里的中文變成????或者反過來頁面亂碼數(shù)據(jù)庫正常。原因是建庫字符集和連接 URL 字符集沒有統(tǒng)一。最徹底的做法是建庫時指定DEFAULT CHARACTER SET utf8連接 URL 里加characterEncodingutf8JSP 頁面頂部寫contentTypetext/html; charsetUTF-8。三個地方全部統(tǒng)一基本不會再出現(xiàn)問號問題。如果還不行在 MySQL 命令行執(zhí)行SET NAMES utf8;臨時驗證一下是不是終端字符集的問題。5.3 端口 8080 被占用Tomcat 起不來Tomcat 啟動時直接報Port 8080 required by Tomcat v8.5 Server at localhost is already in use說明已有進程占用了 8080 端口。常見原因是之前啟動的 Tomcat 沒關(guān)干凈或者本機裝了別的 web 服務器。在命令行執(zhí)行netstat -ano | findstr 8080 taskkill /PID 進程號 /F把占用進程結(jié)束后重新啟動 Tomcat。如果 8080 對你很重要換不了就改 Tomcat 的server.xml里的 Connector port。需要注意改了端口之后訪問地址要同步改成http://localhost:新端口/項目名/代碼里如果有寫死的8080跳轉(zhuǎn)鏈接也要一并改掉。5.4 項目導入后大量紅叉或編譯版本不匹配Eclipse 導入項目常見的問題是工 程的 Java Compiler 版本和 Facet 版本不對齊?,F(xiàn)象是項目能打開但src目錄下代碼全報紅或者編譯時提示不支持 diamond 運算符。原因是項目當初用 JDK 8 寫的導入時默認 JDK 級別變成 1.5。解決方案在項目右鍵 Properties 里把 Java Compiler 的 Compiler compliance level 改成 1.8Java Build Path 的 JRE System Library 改成你本機的 JDK 8。IDEA 里則在 Project Structure 的 Modules 里確認 Language level 是 8。5.5 頁面 404 或 500Servlet 映射和項目上下文路徑出錯啟動成功之后點擊借書按鈕報 404大概率是web.xml里 Servlet 映射路徑和 jsp 表單提交的 action 不一致。檢查表單里的actionborrowServlet和 web.xml 里的url-pattern/borrowServlet/url-pattern是否完全匹配注意有沒有漏掉斜杠。報 500 則要看 Tomcat 的 logs 目錄下catalina.out或localhost.log異常堆棧指向哪一行就從哪里查起。這類項目的血淚經(jīng)驗是改完 Java 代碼后一定要 Project Clean 再重啟 Tomcat否則 Tomcat 還在跑舊 class 文件。6. 從能跑到能答辯把模板項目變成你自己的課程設(shè)計跑通代碼只是第一步你最終要交的是“自己的”項目。改造成自己的畢設(shè)其實不用把代碼重寫一遍而是做四件事改標識、加功能、寫測試、對應論文。改標識是最快的項目里所有l(wèi)ibrarydb、圖書管理系統(tǒng)字樣替換成你起的系統(tǒng)名包名從com.example換成com.你的學號。IDEA 里按Shift F6批量重命名包名別手動一個個改。加功能能明顯拉開和同學項目的差距。常見低成本高展示度的功能有三個首頁抄書排行榜、Excel 導出借閱記錄、讀者自助修改密碼。Excel 導出可以用 POI 庫本質(zhì)是查表后寫工作簿代碼量不大但答辯時操作演示效果很好。如果你會前端還可以把登錄頁和圖書列表頁的樣式換成 Bootstrap 或 Layui不用改后端邏輯只改 jsp 頁面引用的 CSS 和 HTML 結(jié)構(gòu)。論文和代碼的對應關(guān)系直接決定你答辯能不能站住腳。論文里的需求分析章節(jié)畫用例圖對應的是系統(tǒng)的管理員借書、讀者還書、圖書管理這些模塊概要設(shè)計章節(jié)畫三個層次結(jié)構(gòu)圖對應 jsp 展示層、Servlet 控制層、DAO 數(shù)據(jù)訪問層詳細設(shè)計章節(jié)的時序圖把第 4 章里借書那幾條 SQL 畫成一個完整序列測試章節(jié)把借書成功、庫存不足、重復借書、逾期還書四條用例在功能測試表里列出來每個用例寫清楚輸入數(shù)據(jù)和預期結(jié)果。這部分寫實了導師一看就知道你真跑過。最后給你一條我的教學式經(jīng)驗我當年拿到這類 zip 時第一步是原樣跑通第二步是備份 SQL 和源碼第三步才動手改。改的時候每完成一個小功能就重啟一次 Tomcat 驗證不要積攢一堆問題最后一起查。這個習慣幫我省了至少一周時間希望幫到你。本文還有配套的精品資源點擊獲取