
简介这份PDF文档面向计算机专业学生与Java Web初学者围绕基于JSP的图书管理系统展开完整的设计与实现讲解可作为课程设计、毕业设计或自学练手的参考方案。文档共1个PDF文件压缩包约2.14MB内容涵盖绪论、系统分析、可行性分析及功能模块设计等章节结构完整、便于通读。系统以JSP为核心技术结合MVC设计模式与Struts开源框架通过JDBC驱动连接MySQL数据库实现了日常工作、查询、读者资料维护、图书资料维护、系统管理和更改口令六大功能模块覆盖借阅、归还、续借、检索等图书馆日常运营场景。读者可从中了解动态网页开发中页面呈现与业务逻辑分离的思路掌握控制器协调模型与视图的交互方式并借鉴数据库无缝连接与信息统计的实现方法。目前已有336人学习下载适合需要一份可参考、可复用的Web项目案例来梳理开发流程与架构设计的读者。1. 从一份“基于JSP的图书管理系统设计与实现.pdf”说起这套老技术栈为什么还值得动手做如果你正在搜“基于JSP的图书管理系统设计与实现.pdf”大概率是三种人之一要交毕设的学生、被安排带课程设计的助教或者接手了一个还在跑 JSP 的老系统、想把它摸清楚的运维。这套技术栈听起来确实不新Struts、JSP、MySQL 这套组合在招聘网站上几乎绝迹但它依然是国内高校 JavaWeb 课程设计里出现频率最高的题目之一。原因很现实它把 MVC 三层架构、请求转发、会话管理、数据库连接池这些 Web 开发的核心概念全串了一遍而且用 Tomcat 一跑就能看到效果反馈足够快。我前后帮人调过不下十个版本的图书管理系统从纯 JSP 脚本到 Struts 2 标签库坑基本集中在几个地方中文乱码、连接池泄漏、事务没提交、war 包部署路径不对。这篇笔记不打算复述一份不存在的“官方文档”而是按我实际搭这套系统的顺序把选型理由、目录结构、关键代码、参数配置和排错经验讲清楚。你照着走能在本地跑出一个能登录、能增删改查图书、能借还的完整系统熟手可以直接跳到参数和避坑章节看边界在哪。2. 技术选型与工程骨架JSP、Struts 与 MySQL 怎么搭才不散2.1 为什么是 JSP Servlet Struts而不是直接上 Spring MVC先把一个常见误解说清楚JSP 本身只是视图模板技术它不负责业务逻辑。一个“基于 JSP 的图书管理系统”通常有两种写法一种是 JSP Servlet JavaBean 的手写 MVC另一种是 JSP Struts 2 的框架 MVC。热搜词里同时出现了 MVC、Struts、Spring MVC说明很多人在这几个词之间摇摆。我的建议是如果只是完成课程设计或快速验证手写 Servlet 版足够依赖少、调试直观如果要求体现“框架分层”再引入 Struts 2。选 Struts 2 的理由是它把 Action、拦截器、结果视图这几层分得很干净配合 JSP 标签库能少写不少 Java 代码。但要注意Struts 2.3.37 这类老版本存在已知的安全问题仅限本地教学环境使用不要部署到公网。选 MySQL 的理由更简单免费、资料多、和 JDBC 驱动配合成熟热搜里那一堆“mysql安装教程”“mysql安装配置教程”也说明它是大多数人的第一选择。工程骨架我一般这样分层次目录/包职责视图层/webapp/*.jsp页面展示、表单提交控制层com.library.action接收请求、调用 Service业务层com.library.service借还书规则、事务边界持久层com.library.daoJDBC 或连接池操作实体层com.library.entityBook、User、Borrow 等 POJO配置struts.xml、web.xml、db.properties路由、过滤器、数据库参数这个分层不是摆设。我见过太多把 SQL 直接写在 JSP 里的版本改一个字段要翻十几个页面最后没人敢动。分层之后换数据库、加缓存、改页面互不影响。2.2 用 IDEA 新建 JSP 项目并跑通第一个页面热搜里“idea新建jsp项目”出现频率很高说明卡在第一步的人不少。下面是我常用的最小可运行步骤用 Maven 管理依赖避免手动拷 jar 包。# 1. 用 Maven 原型创建 webapp 项目 mvn archetype:generate -DgroupIdcom.library \ -DartifactIdlibrary-system \ -DarchetypeArtifactIdmaven-archetype-webapp \ -DinteractiveModefalse # 2. 进入目录补全 src/main/java 结构 cd library-system mkdir -p src/main/java/com/library/{action,service,dao,entity} mkdir -p src/main/resources创建完成后在pom.xml里加入 Servlet、JSP、MySQL 驱动和连接池依赖。注意版本不要盲目追新Servlet API 用 4.0 对应 Tomcat 9JSTL 用 1.2。dependencies !-- Servlet 与 JSPscope 必须是 provided否则和 Tomcat 冲突 -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency dependency groupIdjavax.servlet.jsp/groupId artifactIdjavax.servlet.jsp-api/artifactId version2.3.3/version scopeprovided/scope /dependency !-- JSTL 标签库JSP 页面循环输出用 -- dependency groupIdjavax.servlet/groupId artifactIdjstl/artifactId version1.2/version /dependency !-- MySQL 8 驱动注意驱动类名带 cj -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- Druid 连接池替代手写 DriverManager -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.20/version /dependency /dependencies逻辑说明provided作用域表示这些类由 Tomcat 容器提供打包成 war 时不会带进去否则会出现类加载冲突典型现象是启动报ClassCastException或NoSuchMethodError。MySQL 8 的驱动类是com.mysql.cj.jdbc.Driver不再是老的com.mysql.jdbc.Driver这一点在热搜“mysql ssl连接错误”里也常被提到——8.0 默认要求 SSL本地连接可以在 URL 里加useSSLfalseserverTimezoneAsia/Shanghai关掉。2.3 数据库表结构与连接池参数怎么定图书管理系统的表不多核心四张用户表、图书表、借阅记录表、分类表。建表时字符集统一用utf8mb4否则书名里的生僻字或 emoji 会插入失败。CREATE DATABASE library DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, isbn VARCHAR(20) NOT NULL UNIQUE, title VARCHAR(100) NOT NULL, author VARCHAR(50), stock INT NOT NULL DEFAULT 0, -- 库存热搜里“mysql设置默认值为0”就是这个场景 category_id INT, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE borrow ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, book_id INT NOT NULL, borrow_date DATE NOT NULL, return_date DATE, status TINYINT DEFAULT 0 -- 0 借出 1 已还 );连接池参数是这套系统最容易翻车的地方。我一般用 Druid配置写在druid.propertiesdriverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/library?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 usernameroot password你的密码 initialSize5 minIdle5 maxActive20 maxWait3000 validationQuerySELECT 1 testWhileIdletrue参数说明maxActive20是最大连接数课程设计并发低20 足够maxWait3000表示拿不到连接最多等 3 秒就抛异常避免请求无限挂起validationQuery配合testWhileIdle能在连接空闲时探活防止 MySQL 8 小时断连后第一次查询报Communications link failure。这个“8 小时断连”是血泪经验很多人第二天打开系统就报错就是连接池里全是失效连接。3. 从登录到借还把 MVC 三层真正串起来3.1 用 Servlet 或 Struts Action 处理登录与中文乱码登录是整个系统的入口也是乱码问题的高发区。POST 请求的中文参数如果不设编码用户名会变成问号。手写 Servlet 时我一般在过滤器里统一处理而不是每个 Servlet 里写一遍。// CharacterEncodingFilter.java public class CharacterEncodingFilter implements Filter { Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // 请求体编码解决 POST 中文乱码 req.setCharacterEncoding(UTF-8); resp.setContentType(text/html;charsetUTF-8); chain.doFilter(req, resp); } }在web.xml里注册这个过滤器url-pattern用/*覆盖所有请求。逻辑说明setCharacterEncoding只对请求体有效GET 请求的参数编码由 Tomcat 的server.xml里Connector的URIEncoding决定Tomcat 8 以后默认就是 UTF-8所以老教程里改URIEncoding的步骤现在可以省了。参数上过滤器要放在所有 Servlet 之前执行web.xml里 filter 的声明顺序就是执行顺序。如果用 Struts 2编码由struts.i18n.encoding常量控制在struts.xml里加一行constant namestruts.i18n.encoding valueUTF-8/即可。Action 类里字段名要和 JSP 表单的name属性一致Struts 会自动封装这是它比手写 Servlet 省事的地方。3.2 图书增删改查的 DAO 写法与事务边界DAO 层我只做一件事把 SQL 和 Java 对象互转。下面是一个带连接池的查询示例注意资源关闭顺序。public class BookDao { private DataSource dataSource; // 由 Druid 提供 public ListBook findAll() throws SQLException { String sql SELECT id, isbn, title, author, stock FROM book ORDER BY id DESC; ListBook list new ArrayList(); // try-with-resources 自动关闭顺序是 ResultSet - Statement - Connection try (Connection conn dataSource.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { Book b new Book(); b.setId(rs.getInt(id)); b.setIsbn(rs.getString(isbn)); b.setTitle(rs.getString(title)); b.setAuthor(rs.getString(author)); b.setStock(rs.getInt(stock)); list.add(b); } } return list; } }逻辑说明用PreparedStatement而不是Statement一是防 SQL 注入二是预编译对重复查询更快。try-with-resources保证异常时也能关闭连接这一点比手动finally里 close 更可靠——我见过连接池耗尽追查半天发现是某个分支 return 前忘了关连接。借书操作涉及两张表borrow插一条记录book的stock减一。这两步必须在同一个事务里否则会出现“记录有了但库存没减”的脏数据。事务边界放在 Service 层不要放在 DAOpublic boolean borrow(int userId, int bookId) throws SQLException { Connection conn null; try { conn dataSource.getConnection(); conn.setAutoCommit(false); // 关闭自动提交开启事务 borrowDao.insert(conn, userId, bookId); bookDao.decreaseStock(conn, bookId); conn.commit(); // 两步都成功才提交 return true; } catch (SQLException e) { if (conn ! null) conn.rollback(); // 任一步失败整体回滚 throw e; } finally { if (conn ! null) { conn.setAutoCommit(true); conn.close(); } } }参数说明setAutoCommit(false)是事务的开关忘记写这句两条 SQL 各自提交回滚就失效了。DAO 方法接收外部传入的Connection而不是自己从池里取这样多个 DAO 才能共享同一个事务。归还连接前把autoCommit恢复成 true否则这个连接被下一个请求拿到时会带着未提交状态产生难以复现的玄学问题。3.3 JSP 页面用 JSTL 输出列表别写 Java 脚本片段视图层最常见的坏味道是 JSP 里塞满% ... %脚本。正确做法是用 JSTL 和 EL 表达式页面只负责展示。% taglib prefixc urihttp://java.sun.com/jsp/jstl/core % table trthISBN/thth书名/thth作者/thth库存/th/tr c:forEach items${bookList} varb tr td${b.isbn}/td td${b.title}/td td${b.author}/td td${b.stock}/td /tr /c:forEach /table逻辑说明${bookList}是 request 或 session 域里的属性由 Servlet/Action 转发前setAttribute放入。c:forEach替代 Java 循环页面里看不到 import 和类型转换。注意 EL 表达式在 Servlet 2.4 以后才默认开启老项目如果页面直接输出${...}原文检查web.xml的版本声明是不是太老。参数上varb是循环变量名items必须是集合或数组传 null 时forEach不报错、直接不渲染这点比脚本片段安全。4. 打包部署与排错war 包、Tomcat 和那些反复出现的报错4.1 传统 JSP 项目打包 war 并部署到 Tomcat热搜里“传统jsp项目打包war”说明很多人卡在部署环节。Maven 项目执行mvn clean package就会在target下生成 war 包把它丢进 Tomcat 的webapps目录启动后访问http://localhost:8080/项目名/即可。# 打包跳过测试加快速度 mvn clean package -DskipTests # 查看产物 ls target/*.war # 部署拷贝到 Tomcat webapps路径按自己环境改 cp target/library-system.war $CATALINA_HOME/webapps/ # 启动 Tomcat $CATALINA_HOME/bin/startup.sh # Linux/Mac # 或 Windows 下双击 startup.bat逻辑说明war 包名决定访问路径library-system.war对应/library-system。如果想让项目直接跑在根路径把 war 改名为ROOT.war。参数上-DskipTests跳过单元测试课程设计阶段可以省时间但正式交付前建议跑一遍。部署后如果 404先看 Tomcat 日志logs/catalina.out八成是web.xml配置错误或类没编译进去。4.2 避坑与排查五个我踩过的真实问题现象一页面中文全是乱码。原因通常是三处编码不一致JSP 文件本身的pageEncoding、响应头Content-Type、数据库连接 URL 的characterEncoding。解决是把 JSP 顶部写成% page contentTypetext/html;charsetUTF-8 pageEncodingUTF-8 %过滤器设 UTF-8JDBC URL 加characterEncodingutf8三处对齐。现象二启动报ClassNotFoundException: com.mysql.cj.jdbc.Driver。原因是驱动 jar 没进WEB-INF/lib。Maven 项目检查依赖 scope 是不是误写成providedMySQL 驱动必须是默认的compile。手动导 jar 的项目确认 jar 放在WEB-INF/lib而不是项目根目录。现象三运行一段时间后报Communications link failure。原因是 MySQL 默认 8 小时空闲断连连接池里全是死连接。解决是配置validationQuerySELECT 1和testWhileIdletrue让池子定期探活或者把maxIdle调小减少长期空闲连接。现象四借书后库存没变但借阅记录有了。原因是事务没生效两条 SQL 各自自动提交。检查 Service 里有没有setAutoCommit(false)以及 DAO 是不是各自从池里取了不同的 Connection。事务必须共享同一个连接。现象五war 部署后访问 404日志报NoClassDefFoundError。原因是 Servlet API 或 JSP API 被打进了 war和 Tomcat 自带的冲突。解决是把这两个依赖的 scope 设为provided重新打包。提示排错时优先看 Tomcat 的catalina.out和浏览器 Network 面板的响应码比盲目改代码快得多。5. 进阶技巧把借阅规则做成可配置并用日志验证事务系统能跑通之后真正拉开差距的是可维护性。我一般会把借阅规则抽出来比如“每人最多借 5 本”“借期 30 天”“超期不能续借”这些不要硬编码在 Java 里而是放进配置文件或数据库改规则不用重新编译。# borrow-rule.properties borrow.max.count5 borrow.max.days30 borrow.renew.allowedtrueService 里读取这些值做校验超限时返回明确提示而不是抛异常。这样测试时改个数字就能验证边界不用改代码。验证事务是否真的生效我有个笨但有效的办法在borrow方法里故意让第二步抛异常看第一步的插入有没有回滚。如果borrow表里留下了脏记录说明事务没配好。这个“后悔药”式的自测比事后查数据快得多。另外日志不要只用System.out.println。引入 Log4j 或 SLF4J把 SQL 执行、事务提交回滚、连接获取都打出来出问题时能直接定位到是哪一步。我习惯在 DAO 的每个方法入口打一条 debug 日志参数值一并输出这样复现问题时不用加断点。最后说个习惯每次改完代码先本地mvn clean package重新打包再部署不要指望热部署能救你。老项目的热部署经常只更新了 class 没更新 JSP页面和逻辑对不上排查起来非常费劲。这套 JSP 图书管理系统虽然技术栈老但把 MVC 分层、事务、连接池、编码这几件事走一遍对理解 Web 开发的基本盘很有帮助。希望帮到你。本文还有配套的精品资源点击获取