简介:这是一套基于 Java 与 JSP 实现的图书馆管理系统代码包,面向高校 Java 课程设计、期末大作业及初阶 Web 开发学习者,也可作为毕业设计前的练手项目。系统涵盖读者管理、图书管理、借还书处理、登录鉴权、逾期提醒等核心业务,代码按控制层、业务层、数据访问层分层组织,能够清晰展示前端页面、后台逻辑与数据库之间的调用关系,对理解 Java Web 请求处理流程很有帮助。压缩包内共 178 个文件,主要包括 50 个 Java 业务类、25 个 JSP 页面、59 个 XML 配置、2 个 SQL 数据库脚本,以及 JS、CSS、图片等前端资源,整体大小约 11MB;源码已经本地编译验证可运行,评审成绩达到 98 分,并经助教老师审定,难度适中,目录中区分源码与数据库文件,便于按模块检索学习。读者拿到后可以导入开发工具,配合 SQL 脚本快速初始化数据库并复现运行环境,再结合分层代码梳理图书借还、管理员权限、读者查询等业务链路,为期末答辩或课程设计演示形成完整可展示的方案。该资源目前已有 149 人学习下载,适合需要可运行参考项目、对照源码理解业务逻辑,或需要快速搭建课程设计演示系统的学习者。
1. 先看这套 JSP 图书馆管理系统到底卡在哪
很多同学拿到这份“java期末大作业基于Java+JSP实现的图书馆管理系统源码+数据库文件”之后,第一反应是打开源码从头读起,结果读了两个小时还在和项目结构搏斗。以我的经验,期末大作业这套东西真正卡人的地方从来不是代码本身,而是“能不能在你自己的电脑上五分钟跑起来”。下载是一分钟,跑通是一晚上,这句话在这个项目上几乎每天都在验证。这篇笔记就顺着一个目标走:让这份源码和数据库文件在你本地变成一个能打开登录页、能点两下的真实系统,顺带把这些年常见的部署翻车点都拎出来讲透。
这套系统适合的是三类人:期末要交 Java Web 作业的人、第一次正经接触 JSP+Servlet+MySQL 老技术栈的人、想快速拿一套可用代码做二次修改的初级开发者。看完你至少能说清楚每个类在干什么、数据库表为什么这么建、报错去哪查。
2. JDK、Tomcat、MySQL 版本搭配:让 JSP 老项目活过来的第一步
2.1 为什么版本不对,项目直接给你颜色看
JSP 项目对运行环境极其敏感,比 Spring Boot 那套敏感得多。原因在于 JSP 本质上是 Servlet 的模板引擎,它依赖 Tomcat 提供的 Servlet API 规范。你要是装了 Tomcat 10,会发现源码里所有javax.servlet包的 import 全部报红,项目根本编译不过,因为 Tomcat 10 把命名空间从javax改成了jakarta。这不是你代码的问题,是规范迁移的历史遗留问题。我见过不少同学把环境从 JDK 8 一路装到 JDK 17,然后一脸懵地问我为什么代码跑不了,其实就是版本兼容性没对上。
这套图书馆管理系统属于典型的“老项目”,正常写法都是基于 JDK 8 和旧版 Tomcat 写的。我的建议是:不要追求环境新,追求环境“稳”。你期末答辩的时间是有限的,环境越稳,你留给改功能和准备答辩的时间越多。
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8(Oracle 或 OpenJDK 都行) | JSP 老项目的黄金版本 |
| Tomcat | 8.5.x 或 9.0.x | 兼容javax.servlet,部署简单 |
| MySQL | 5.7 或 8.0 | 5.7 最省心,8.0 需要处理时区和公钥问题 |
| MySQL 驱动 | mysql-connector-java-5.1.49 | 兼容 JDK 8,老项目的常见驱动选择 |
版本搭配的逻辑就一句话:JDK 8 + Tomcat 8.5 是老项目最低成本组合,能避开后续所有命名空间和加密连接带来的坑。这就像开一台老车,别乱换零件才跑得稳。
2.2 安装 JDK 8 并确认环境变量的两条命令
安装 JDK 本身没有太多花样,但环境变量配置完之后,一定要在命令行里确认版本。这一步看起来简单,实际上三个变量一个都不能少,少了任何一个 Tomcat 都起不来。
# 查看 Java 版本,确认 java 命令可用 java -version # 查看 JAVA_HOME 环境变量是否生效 echo $JAVA_HOME # 查看 PATH 中是否包含 JDK 的 bin 目录 echo $PATH三条命令的输出要能对上:java -version显示 1.8 或 8 开头,JAVA_HOME指向实际的 JDK 安装目录而不是bin文件夹,PATH里有%JAVA_HOME%\bin或$JAVA_HOME/bin。我第一次给某个同学排查时,他 cmd 里java -version输出的是 JDK 11,但 IDEA 里的项目结构配的是 JDK 8,两边不一致导致编译出来的 class 一直报错。所以这里参数说明就一条:务必保证命令行和 IDE 用的是同一个 JDK,否则后面全是玄学问题。
Windows 用户装完 JDK 之后记得重启 cmd ,否则环境变量不刷新。这不算坑,但每天都有人在这上面浪费十分钟。
2.3 Tomcat 端口和连接串:两个容易忽视的参数
Tomcat 安装包解压之后,conf/server.xml里的默认端口是 8080。如果你本机装了别的东西占用了这个端口,改端口的方法很多,但我推荐只改 HTTP 连接端口,不要动关闭端口和 AJP 端口。改法如下。
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />把8080改成8081或者其他没被占用的端口。注意一件事:改完端口之后,你访问系统的 URL 里也必须带这个新端口,不然怎么刷新都是 404。很多同学改了端口然后忘了访问路径,翻车翻得毫无悬念。
MySQL 连接串这边,源码里的DBUtil.java或者jdbc.properties里通常长这样:
Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/library_db?useUnicode=true&characterEncoding=utf8"; String user = "root"; String password = "123456";useUnicode=true&characterEncoding=utf8这两个参数是中文不乱码的前提。如果你用的 MySQL 8.0,系统会额外要求你在 url 后面加useSSL=false&allowPublicKeyRetrieval=true,否则启动时可能会报错。
3. 看目录、导数据库、把项目丢进 Tomcat:一气呵成的三步
3.1 拿到源码后的第一件事:认清目录结构
解压源码包之后,先别急着用 IDEA 打开,先在文件管理器里看一眼目录。常见的目录布局是这样的:
LibrarySystem/ ├── src/ │ ├── com/library/bean/ │ ├── com/library/dao/ │ ├── com/library/servlet/ │ └── com/library/util/ ├── WebContent/ (或 webapp/) │ ├── WEB-INF/ │ │ ├── lib/ │ │ └── web.xml │ ├── login.jsp │ ├── index.jsp │ └── css/ └── library.sql看清楚三层:src放 Java 源码,WebContent或webapp放 JSP 页面和资源,WEB-INF/lib放依赖的 JAR 包,library.sql就是数据库文件。这套结构本身不复杂,复杂的是很多人刚拿到项目就把 JSP 文件当成 HTML 去打开,看不见效果就断定项目有问题,这是最大的误解。
3.2 导入数据库:命令行与客户端两种方式选一个
数据库文件是整套系统的大脑,导不进去后面代码全废。你在 MySQL 里先建库,再导入 sql 文件即可。
# 先登录本机 MySQL 服务器,root 用户 mysql -u root -p # 在 MySQL 命令行内创建一个库,注意默认字符集 CREATE DATABASE IF NOT EXISTS library_db DEFAULT CHARACTER SET utf8mb4; # 切换到目标库 USE library_db; # 第二种:直接在系统命令行导入 mysql -u root -p library_db < library.sql这段逻辑说明一下:库名必须和源码里 url 写的库名一致,如果源码里写的是library_db而你建的是test,那 JDBC 连不上是必然的。使用utf8mb4而不是utf8的好处是可以存表情符号,但这套系统用不上,真正的价值在于避免排序规则不一致导致的查询报错。
有一个易错点是:你看到的library.sql文件本身可能包含CREATE DATABASE语句。这种情况下直接执行mysql -u root -p < library.sql就行,不需要手动建库。如果里面有CREATE TABLE而没有建库语句,就手动建库再导入。多留一个心眼,一次成功。
3.3 从 Tomcat 解压到登录页:每一步都看得见的启动方式
很多人习惯在 IDEA 里点绿色按钮启动 Tomcat,但期末环境里我更推荐直接用命令行的方式,因为你自己能看见完整日志。先把项目文件夹整个丢到 Tomcat 的webapps目录下。
# 在 Tomcat 根目录下执行启动命令 cd /path/to/tomcat/bin # 启动并保持前台输出日志 ./catalina.sh runWindows 下换成catalina.bat run。这个run参数是个好习惯,它让 Tomcat 在前台运行,日志输出直接打在控制台上。一旦项目启动报错,你能立刻看到异常栈,而不是跑到logs/catalina.out里翻半天。我看到很多人用startup.sh启动之后窗口一闪而过,连报错都看不见,然后来回找原因,非常低效。
启动成功之后不要急着关,等日志里出现 “Server startup in xxx ms”,打开浏览器访问:
http://localhost:8080/LibrarySystem/login.jsp路径大小写要对齐,Linux 环境下大小写敏感,Windows 不敏感。这是最常见的 404 来源。
4. 源码主线拆解:登录、图书管理、借阅归还三条主流程这样读不慌
4.1 数据库连接类:所有模块的地基,先看它
源码里第一个该打开文件是数据库连接工具类,通常叫DBUtil.java或BaseDao.java。这是整个系统的地基,也是期末答辩时导师最爱问“谈谈你的项目架构”时你会首先想到的类。它一般长这样:
package com.library.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class DBUtil { private static final String DRIVER = "com.mysql.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/library_db?useUnicode=true&characterEncoding=utf8"; private static final String USER = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws Exception { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { // 判断非空再关闭,顺序注意:rs → stmt → conn } }这段代码里最要留意的参数是URL里的characterEncoding=utf8和useUnicode=true,它们直接决定了中文会不会变成问号。然后是PASSWORD,默认密码经常是123456或root,你要改成自己本机 MySQL 的实际密码。最后是Class.forName(DRIVER)这一行,静态代码块里只执行一次,如果这一行抛异常,你启动时就会看到ClassNotFoundException: com.mysql.jdbc.Driver。
4.2 登录逻辑:Servlet 里到底做了什么
登录功能是大多数 JSP 项目的“脸面”,导师打开系统第一个点的就是它。它的逻辑链路是:JSP 表单提交 → Servlet 接收参数 → DAO 查库 → 判断结果 → 跳转。核心代码一般在LoginServlet.java里,常见的写法如下:
package com.library.servlet; import com.library.bean.User; import com.library.dao.UserDao; import javax.servlet.ServletException; import javax.servlet.http.*; import java.io.IOException; public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); UserDao dao = new UserDao(); User user = dao.findUserByUsernameAndPassword(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("user", user); response.sendRedirect("index.jsp"); } else { request.setAttribute("error", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); } } }request.setCharacterEncoding("utf-8")这一行不写,表单里输入中文用户名就会乱码。session.setAttribute("user", user)是把登录状态存进 Session,后续所有页面判断是否登录都是看这个属性在不在。sendRedirect和forward是有区别的,前者是浏览器重新请求一个新的 URL,地址栏会变化;后者是服务端内部转发,地址栏不变。期末答辩时能说出这两行的区别,是很加分的点。
4.3 图书的增删改查:最常见的 JSP+Servlet 循环
图书管理模块通常有BookServlet.java,里面一个doPost方法通过method参数区分 add、delete、update。这是 JSP 老项目最典型的处理方式。
String method = request.getParameter("method"); if ("add".equals(method)) { Book book = new Book(); book.setName(request.getParameter("name")); book.setAuthor(request.getParameter("author")); book.setPublisher(request.getParameter("publisher")); book.setPrice(Double.parseDouble(request.getParameter("price"))); bookDao.add(book); response.sendRedirect("book_list.jsp"); } else if ("delete".equals(method)) { int id = Integer.parseInt(request.getParameter("id")); bookDao.deleteById(id); response.sendRedirect("book_list.jsp"); }这一段的参数解析值得说明:Double.parseDouble是一个隐藏坑,如果前端表单的 price 输入框里传了非数字内容,这一行会直接抛NumberFormatException,页面报 500。建议在解析前做一次判断,或者用try...catch包住,提示用户输入合法数字而不是把整个页面崩掉。bookDao.deleteById(id)删除图书时要注意外键约束,如果这张表和其他表有关联,可能会因为约束而删不掉,此时需要去数据库里手动解除关联或者批量删除相关借阅记录。
4.4 借阅和归还:状态字段控制流程,而不是疯狂写新表
借阅功能是图馆管理系统的业务核心,它的表结构通常是borrow表,里面有id、book_id、user_id、borrow_time、return_time、status等字段。状态字段的值一般为 0 表示在借、1 表示已还。新增借阅记录和改状态是两回事,不能混在一起。
// 借阅时插入一条记录,状态默认0表示未归还 String sql = "INSERT INTO borrow (book_id, user_id, borrow_time, status) VALUES (?, ?, NOW(), 0)"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, bookId); ps.setInt(2, userId); ps.executeUpdate();使用PreparedStatement而不是直接拼接 SQL,是为了防止 SQL 注入。期末答辩时你要能接住这个问题:“为什么用问号而不是直接用字符串拼接?”答案是预编译会先让数据库识别 SQL 骨架,参数作为纯数据传入,不会破坏原 SQL 结构。NOW()是数据库时间函数,不需要在 Java 代码里用new Date(),这样能保证时间和数据库服务器一致,这个细节导师问了不亏。
5. 部署排查清单:五个 JSP 图书馆系统最容易翻车的地方
5.1 现象:启动后访问登录页 404
拿到源码,把项目丢进 Tomcat,打开浏览器访问localhost:8080/login.jsp,结果 404。原因通常有两点。第一点是项目没有真正在webapps下形成目录结构,比如你把压缩包直接丢进去了,Tomcat 不会自动解压 war 包之外的格式。第二点是访问路径里缺少项目文件夹名。解决方式:先确认webapps目录下能看到你的项目文件夹并放对了位置,再访问http://localhost:8080/项目文件夹名/login.jsp。
我在帮某个同学排查时发现他用的 INTJ 里的 Tomcat 配置和本地解压的 Tomcat 是两份,他把项目部署到 IDEA 内置 Tomcat 的临时目录里,自然在浏览器里访问不到。这类问题不是环境坏了,而是 Tomcat 实例搞混了。
5.2 现象:ClassNotFoundException: com.mysql.jdbc.Driver
当你看到这个异常,说明 JVM 在运行时没有找到 MySQL 驱动类。原因只有一个:mysql-connector-java-xxx.jar没有打到 WEB-INF/lib 目录下。很多人在 IDEA 里导入项目时,lib 目录是空的。解决方式:找一个 5.1.49 版本的驱动 jar 放进去,然后重新启动 Tomcat 或 Redeploy。
注意放对位置,放在src下没有用,放在Java Resources/lib下面也不一定有用,必须出现在WEB-INF/lib目录里。部署时这个目录会被原样拷贝到 Tomcat 的应用目录里,驱动才会进入运行时 classpath。
5.3 现象:登录时输入中文乱码
界面能打开,但是输入中文用户名登录后显示乱码,或者数据库里存进去的中文变成问号。原因跨度比较大,常见的有三处不一致:JSP 页面本身编码不为 UTF-8、Servlet 里没有设置request.setCharacterEncoding("utf-8")、MySQL 连接串里没带characterEncoding=utf8。解决方式:从上到下逐一排查,在 JSP 文件顶部加<%@ page contentType="text/html;charset=UTF-8" language="java" %>,Servlet 里加入 request 编码设置,最后检查 url 参数。这三个地方任何一个不对都会乱码。
5.4 现象:MySQL 8 连接时报错 Public Key Retrieval is not allowed
用 MySQL 8.0 跑老项目时,这个错很典型,原因在于 MySQL 8 默认使用 caching_sha2_password 认证插件,如果连接走的是非 SSL 通道,第一次需要从服务端拿公钥。解决方式是在 JDBC url 后面追加allowPublicKeyRetrieval=true&useSSL=false。
String url = "jdbc:mysql://localhost:3306/library_db?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true";这两个参数只用于本地开发和测试场景,你需要知道它是做什么的:useSSL=false关闭 SSL 加密,allowPublicKeyRetrieval=true允许客户端从服务端获取公钥。答辩时如果导师问到,你可以说这是为了兼容本地开发环境,生产环境中应启用 SSL 并配置证书。
5.5 现象:登录成功后跳转 500,日志里有 NullPointerException
登录成功了,但页面跳过去是 500,控制台报NullPointerException且定位到index.jsp。原因是登录成功后代码里session.setAttribute("user", user)这一行执行了,但 index.jsp 里获取用户信息时,那个字段名 和你 set 的 key 不一致。比如 set 的是"user",页面上用${sessionScope.userInfo.username}或request.getSession().getAttribute("userInfo")去取,取出来是 null。解决方式:找到 JSP 里取 Session 的字段名,把 Java 代码里 set 的 key 改成一致,或者把 JSP 里的字段名改成一致。这个问题的难点不在修,而在定位。先看异常栈中提示哪个 JSP 文件哪一行,再看它取的是哪个属性,往上倒推就清晰了。
6. 答辩与进阶:把期末作业从“能跑”变成“能讲”
6.1 一条主线讲清楚整个系统
答辩时不要一上来就说“我用了 JSP、Servlet、MySQL”,而是要讲一条主线:用户打开登录页输入账号密码,提交到 LoginServlet,经过 DAO 查询数据库验证身份,验证通过后把用户对象放进 Session;进入主界面后,图书模块通过 BookServlet 接收 method 参数区分增删改查;借阅模块在 borrow 表里插入状态为 0 的记录,归还时更新状态。这条主线讲完,项目架构已经听得很清楚了,比你背半天技术名词有效得多。
6.2 三个低成本的加分改动
第一个是加一个简单的借阅历史记录页面,查 borrow 表里的所有记录,按用户分组显示。这个改动不需要建新表,只用一条带 JOIN 的 SQL 就能搞定。第二个是给图书列表页加搜索框,用模糊查询 LIKE 来过滤书名或作者。这会让导师觉得你有业务意识,而不是只会 CRUD。第三个是做一个简单的状态统计,比如目前借出多少本、还有多少本在馆,用一条 SQL 的 COUNT 加 GROUP BY 就能完成。这三个改动合计一天内可以做完,但效果远超十几个小时的反复重构。
6.3 我的一次翻车经历
记得有一次我带一个学弟做类似的系统,他把图书删除功能设置成直接 DELETE,然后告诉我“删不了”。我过去一看,数据库里 borrow 表的外键约束阻止了删除。我当时跟他说的原话是:“期末大作业级别的系统,能不物理删除就不物理删除,加一个 is_delete 状态字段比删行安全得多。”后来他把删除改成软删除,不仅避开了约束问题,答辩时还能说“我做了数据保留设计”。至此之后我拿到任何系统源码都会先问一句:删除是物理的还是逻辑的。这个习惯救了我很多次。
图书馆管理系统这套架构虽然老,但它能让你在一周之内把 Java Web 的核心链路走通一遍,从数据库到后端再到页面,每一层都有实物可看。把环境搭顺、把每段代码的主线讲清楚,你已经超过所在组里大多数人。希望帮到你。
本文还有配套的精品资源,点击获取