ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Java Web课程设计:Servlet图书管理信息系统开发实战

Java Web课程设计:Servlet图书管理信息系统开发实战 1. 项目概述与需求拆解1.1 一个高校图书管理系统到底要解决什么问题在大学里做过图书管理或教务相关系统的人都知道小到班级图书角、大到图书馆借阅管理最核心的需求永远是那么几件事书在哪、谁借了、什么时候还、逾期了多少天。这套用 Servlet 实现的高校图书管理信息系统本质就是为了把这四件事从“手工登记 Excel 表格”里解放出来做成一个可登录、可查询、可统计的线上流程化系统。从标题里的“servlet”和“图书管理信息系统”就能看出它是一门典型的 Java Web 课程设计或毕业设计题目。这类项目的特点是技术栈不花哨、功能逻辑清晰、足够覆盖 Servlet、JSP、JDBC、MySQL 这些 Java Web 核心知识点同时又有完整的业务流程登录、增删改查、借还书、权限控制非常适合拿来练手、答辩、或者改成自己的课程设计。源码编号 26779 对应的完整工程里一般会包含数据库脚本、项目源码、部署说明和报告文档拿来即用。1.2 为什么选 Servlet 而不是一上来就上 Spring有些读者会疑惑现在企业里都用 Spring Boot 了为什么课程设计还要写 Servlet这个问题我每年都会被问一次。其实答案很简单Servlet 是 Java Web 的根。Spring MVC 也好Spring Boot 也好底层本质还是 Servlet Filter Listener。Servlet 让你亲手写一次请求从 url 映射到 doGet / doPost再到操作数据库、跳转页面这个完整链条你对 HTTP 协议、请求响应模型、Session 原理的理解会扎实得多。这套项目正是用最朴素的方式把这一整个链路串起来浏览器发请求 → Tomcat 把请求交给对应 Servlet → Servlet 用 JDBC 查 MySQL → 把结果封装成 JavaBean → 转发给 JSP 渲染成 HTML。没有 AOP、没有依赖注入、没有魔法注解所有流程全部透明可见。另外从答辩角度讲Servlet 项目的代码量适中逻辑直观老师问你“这个查询怎么写、这个事务怎么处理”你能清清楚楚讲出每一步不像 Spring 框架经常被追问到源码层面就卡壳。2. 技术栈与系统整体架构2.1 核心技术栈梳理整套系统的技术选型非常贴近 Java Web 课程的经典组合层级技术作用Web 容器Tomcat 8/9运行 Servlet 和 JSP 的服务器后端Servlet 4.x / JSP 2.x处理请求、控制流程、渲染页面数据库MySQL 5.7/8.0持久化图书、用户、借阅记录数据数据库访问JDBC / DBUtils连接数据库、执行 SQL、封装结果集前端HTML CSS JavaScript Bootstrap页面布局与交互效果构建Maven / IDEA 内置构建管理依赖和打包部署数据访问层很多课程设计会直接使用 JDBC 原生代码也就是 Connection、PreparedStatement、ResultSet 三板斧。有的版本会封装一个 DBUtil 工具类负责加载驱动、获取连接、关闭资源也可能用到 Apache Commons DBUtils 的 QueryRunner减少手写结果集映射的重复代码。这两种写法在这个项目里都很常见源码里无论哪一种都不奇怪。2.2 三层架构与请求流转路径在拿到任何源码之前我建议你先在脑子里建立一个三层架构的模型这样读代码不会迷路表示层JSP 页面 前端资源css/js/images负责展示数据和收集用户输入。控制层Servlet负责接收请求、参数解析、调用业务对象、决定跳转哪个页面。数据层DAOData Access Object负责所有 SQL 操作把结果转换成 JavaBean。一次典型“查询图书列表”的请求是这样流转的用户在浏览器地址栏输入 http://localhost:8080/library/bookListServlet 回车后Tomcat 根据 web.xml 或 WebServlet 注解找到 BookListServlet 的 doGet 方法Servlet 调用 BookDao 的 findAll() 方法BookDao 用 JDBC 执行 SELECT 语句把每行记录封装成 Book 对象放进 List Servlet 把列表放到 request 域中再通过 RequestDispatcher 转发到 bookList.jspJSP 在服务端被解析成 HTML 返回浏览器浏览器最终渲染成表格。整个过程是“请求 → 控制 → 数据 → 模型 → 视图”的经典闭环。这套思路和你以后用的 Spring MVC 其实是一脉相承的DispatcherServlet 做的就是把请求分发到 ControllerController 再调 Service、Mapper最后返回视图。理解了这个唯一的 Servlet 直连模式再学任何 Web 框架都会轻松很多。3. 数据库设计与核心表结构3.1 核心数据表图书管理系统的数据库设计通常围绕五个核心实体管理员、学生读者、图书分类、图书、借阅记录。我在本地跑源码的时候发现经典设计方案一般包含以下表表名关键字段说明adminid, username, password管理员登录信息注意密码要做 md5 处理studentid, stu_no, name, phone, major学生读者信息book_typeid, type_name图书分类表比如文学、计算机、数理book_infoid, book_no, book_name, author, publisher, price, type_id, stock图书基本信息与馆藏册数borrow_infoid, stu_id, book_id, borrow_time, return_time, status借阅记录status 区分未还/已还这类系统的数据量不大表之间用外键逻辑关联即可。需要特别注意借阅记录表里的状态字段很多实现里面用 status 区分“未归还”和“已归还”有的是用 return_time 是否为 NULL 来判断。我个人更推荐加一个 status 字段因为以后做续借、超期罚款、预借排队时仅靠时间字段判断会非常痛苦。3.2 库存设计与关键字段的坑库存设计这里先浇一盆冷水很多课程设计的库存字段只是简单存一个 number借书时 number - 1还书时 number 1这样做逻辑最简单但有两个很容易被答辩老师追问的问题一是在同一时刻两个学生同时借同一本库存只剩 1 本的书程序怎么控制二是如果库存减到 0 但系统里还有未还记录此时还能不能再借对应的解决思路一是在借书 SQL 里加条件 UPDATE book_info SET stock stock - 1 WHERE id ? AND stock 0利用数据库行锁保证原子性二是借书前不仅要查 stock 0还要去 borrow_info 表查这个学生是否已有未还的同一本书。我建议源码里哪怕只是课程设计级别也要把这层考虑写进代码注释里答辩时主动提“并发场景下我会用条件更新来控制超卖”老师对你的印象分瞬间就不一样了。3.3 初始化数据库源码里一般会附带 library.sql 或 book.sql 文件。我喜欢直接把它放进项目根目录下而不是放在子文件夹里被忽略。打开 MySQL 命令行或者 Navicat先执行 CREATE DATABASE library DEFAULT CHARACTER SET utf8mb4;再 use library; 然后把 SQL 文件导入。这一步看着简单但有两个地方要留意一是确保数据库字符集是 utf8mb4否则中文书名和作者名很容易乱码二是导入前检查 SQL 文件里的表名是否和你源码里 DBUtil 的 SQL 语句一致我之前就遇到过源码里写的表名是 t_bookSQL 文件里却是 book_info直接把整个项目搞挂掉的奇葩情况。4. 核心功能模块与 Servlet 实现要点4.1 登录认证与会话管理系统分管理员和学生两种角色。管理员登录的流程大概是LoginServlet 接收用户名和密码 → 调 AdminDao 根据用户名查询记录 → 比对密码一般密码是 MD5 加密存储比对时把用户输入的密码先加密再比较→ 成功则把 admin 对象放入 session 并跳到主框架页面 index.jsp失败则回到 login.jsp 并携带错误信息。这里有几个实打实的提示session 里建议只放用户 id 或轻量对象不要放整张对象否则很耗 session 内存。登录成功后所有需要权限的 Servlet 都要做一道拦截检查从 session 中取用户信息取不到就直接重定向到 login.jsp并且附带提示“请先登录”。Filter 虽然是更专业的做法但在纯 Servlet 的项目里很多同学偷懒没加那至少在每个 Servlet 的 doGet/doPost 第一行写上这个检查。另一个不太起眼但很常见的错误是登录成功后跳转用了重定向但接着在 res.sendRedirect 后面又继续执行代码容易出问题必须立即 return。4.2 图书管理模块图书管理涵盖新增、编辑、删除、列表分页、按书名/作者模糊搜索等典型操作。新增图书的核心代码思路大致是// 从请求中获取表单参数 String bookNo request.getParameter(bookNo); String bookName request.getParameter(bookName); String author request.getParameter(author); ... Book book new Book(); book.setBookNo(bookNo); book.setBookName(bookName); book.setAuthor(author); // 库存默认值 book.setStock(Integer.parseInt(request.getParameter(stock))); BookDao dao new BookDao(); int result dao.insert(book); if (result 0) { // 成功则重定向到列表页防表单重复提交 response.sendRedirect(bookListServlet); } else { // 失败则回填错误信息转发到新增页 request.setAttribute(errorMsg, 新增失败请检查数据是否合法); request.getRequestDispatcher(bookAdd.jsp).forward(request, response); }这里要重点强调一个设计选择新增成功之后为什么用 sendRedirect 而不是 forward因为如果 forward 到列表页浏览器地址栏还停留在 bookAddServlet用户只要一刷新就会再次提交表单产生一条重复数据。而 sendRedirect 会让浏览器重新请求 bookListServlet地址栏变成列表页地址刷新只能刷新列表不会重复入库。这是 Web 开发里非常有名的“Post/Redirect/Get”模式也是答辩考核点。模糊查询用 LIKE 参数把查到的列表放 request 域再 forward 到列表页即可。列表分页则相对复杂一点一般是通过参数 pageNo、pageSize 实现SQL 用 LIMIT offset, pageSize同时再查询一条 count 语句算总页数。这种手写分页看着笨但能帮你彻底搞懂 MySQL 分页的原理之后接触 PageHelper 或 MyBatis-Plus 分页插件时理解会快得多。4.3 借阅与归还流程借书流程是整个系统中业务逻辑最重的部分正常思路是校验学生是否存在。校验图书是否存在且库存 0。校验该学生是否有未归还的同本书防止重复借阅。插入一条 borrow_info 记录borrow_time 取当前日期。更新 book_info 的 stock使库存减 1。归还流程相对简单根据借阅记录 id 找到对应记录。判断 return_time 是否为空/status 是否为未还如果已经还过就提示“该记录已归还”。更新 borrow_info将 return_time 设为当前时间、status 改为已还。更新 book_info 的 stock 加 1。从工程角度讲这两个操作最好放在一个事务里借阅记录插入成功但库存更新失败或者库存更新成功但记录插入失败数据都会不一致。JDBC 事务代码大概是Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 执行 insert borrow_info // 执行 update book_info set stock stock - 1 conn.commit(); } catch (Exception e) { if (conn ! null) conn.rollback(); e.printStackTrace(); } finally { // 恢复自动提交并归还连接 }我在给学生看源码时常常发现借阅模块是最容易出现“逻辑看着对但数据对不上”的地方基本都是一条 SQL 搞定、没做事务或者 try-catch 里忘记回滚。如果你能把这个事务写明白整个项目的评优概率会高出一大截。5. 项目部署与运行环境配置5.1 准备开发环境在跑这个源码之前先把环境准备好我推荐完全一致的组合可以减少很多不必要的兼容性折腾JDK 1.8绝大多数 Servlet 课程设计源码都基于 JDK8 编写个别老源码甚至用 JDK7但 JDK8 基本通吃。Tomcat 8.5 或 9这个版本跟 Servlet 3.1/4.0 是匹配的网上资料最多报错也最好查。MySQL 5.7 或 8.0两个版本都行但注意 MySQL 8 的驱动类名依旧是 com.mysql.cj.jdbc.Driver连接 URL 里必须带上 useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingUTF-8 这些参数。IDEA 或 EclipseIDEA 导入项目更省事直接选 Maven Project 或普通 Java Web 项目都行。Maven 3.6如果源码带 pom.xml就用 Maven 管理依赖。这里我发现一个高频坑很多下载下来的源码里数据库连接配置写在 db.properties 或 DBUtil.java 里用的驱动类名还是老旧的 com.mysql.jdbc.Driver。如果你用的是 MySQL 8 驱动必须改成 com.mysql.cj.jdbc.Driver而且驱动 jar 包也要换成 mysql-connector-java 8.x否则一启动准报 ClassNotFoundException 或 SQLException。这不是源码烂而是版本代差问题。5.2 数据库初始化与账号配置拿到源码后的第一步永远是看数据库脚本。我一般习惯这样做在源码包里搜索 db.properties、jdbc.properties 或 DBUtil.java。打开文件确认数据库连接url、用户名、密码、驱动类名。把连接改成你自己的本地账号比如 USER rootPASSWORD root123456。找到 sql 文件用 Navicat 或命令行导入。导入时尽量使用 SQL 文件自带的建库语句如果 SQL 文件里没有 CREATE DATABASE就需要先手工建一个库再执行 use 语句或直接导入进对应库。一个常见错误是SQL 文件开头是 DROP TABLE IF EXISTS而且没有 CREATE DATABASE但你在导入时却选错了数据库导致所有表建到了别的库运行半天找不到表名。5.3 Tomcat 部署与启动把项目导入 IDEA 后配置 Tomcat 的方式各版本 UI 不同但逻辑都一样Run/Debug Configurations 中新增 Tomcat Server - Local。在 Server 标签页选择已安装的 Tomcat 目录。在 Deployment 标签页添加 Artifact / Exploded俗称 war exploded。Application context 尽量设为 /library 或直接 / 。建议设一个明确路径如 /library这样访问 URL 是 http://localhost:8080/library/login.jsp 或直接访问首页。注意项目里所有相对路径是否写死成上下文路径比如很多老项目里写 /bookListServlet 这种绝对路径如果你的上下文是 /library那就要改成 /library/bookListServlet否则会 404。有一个小经验启动 Tomcat 前先访问一下 http://localhost:8080 确认 Tomcat 本身没问题如果 8080 端口被占用去 Tomcat 的 conf/server.xml 里改端口但文件里的项目内跳转路径一般是相对路径改端口不需要动代码。6. 常见问题与排错实录6.1 中文乱码问题图书管理系统全是中文数据乱码是出现频率最高的一个入门问题。乱码三件套排查思路数据库显示正常但页面乱码 → 检查 JSP 页面编码确保 % page contentTypetext/html;charsetUTF-8 % 存在浏览器也最好 UTF-8。页面显示正常但写入数据库后乱码 → 检查 MySQL 连接 URL 是否带 characterEncodingUTF-8同时确认数据库表本身是 utf8mb4。表单提交中文乱码 → 在 Servlet 里做 req.setCharacterEncoding(UTF-8)且放在获取任何参数之前。有些老源码只在 doPost 里做了编码处理doGet 没处理Tomcat 8 默认 GET 请求是 UTF-8 还可以但 Tomcat 7 及以前 GET 参数是 ISO-8859-1就得在 server.xml 里配置 URIEncodingUTF-8。这些细节排查时要注意环境差异。6.2 404 与 500 错误排查404 无非两类请求的 Servlet 路径没匹配上或 JSP 文件路径不对。排查步骤很机械不要慌查看浏览器控制台 / 地址栏请求的 URL。对照 web.xml 或 WebServlet 注解中的 urlPatterns确认路径是否一致。查看项目的部署结构确认 target / webapp 目录中的 JSP 文件是否存在于对应位置。如果是重定向后的 404特别留意上下文路径。500 则是代码 stack trace 问题一般出现在 Tomcat 的 catalina.out 日志或 IDEA 控制台。最常见的 500 原因SQL 表名或字段名写错、字段类型转换异常String 转 int 失败、空指针没有查到的对象直接调方法。还有一种隐藏原因是 jar 包冲突比如 lib 下同时放了两个不同版本的 mysql-connector-java也会莫名报错。6.3 数据库连接失败报错 Communications link failure 或 Access denied for user基本就是三类问题MySQL 服务没启动去服务面板看 mysql 服务状态。用户名或密码不对对照 DBUtil / db.properties 慢慢改。连接 URL 写错比如主机地址、端口、数据库名。注意 MySQL 8 的时区参数 serverTimezone 和 useSSL如果漏了 serverTimezone 会报 CST 错误或连接超时。还有一个容易忽略的点MySQL 驱动 jar 包没放进 Tomcat 的 lib 目录或项目 lib。IDEA 构建里虽然有依赖但不代表部署到 Tomcat 时自动带上需要检查 Artifact 的 Output Layout 是否把依赖 jar 打进去了。在部署位置确认 mysql-connector-java 在目标 artifact 的 lib 下是关键一步。7. 源码结构与扩展思路7.1 源码目录结构我用 IDEA 打开项目或者看源码压缩包内的结构一般长这样src ├── main │ ├── java │ │ └── com/xxx/library │ │ ├── dao // 数据访问对象BookDao、StudentDao、BorrowDao │ │ ├── entity // 实体类Book、Student、Borrow、Admin │ │ ├── servlet // 所有 Servlet │ │ ├── filter // 如果有过滤器在这里 │ │ └── util // DBUtil 等工具类 │ ├── resources │ │ └── db.properties // 数据库连接配置 │ └── webapp │ ├── WEB-INF │ │ ├── web.xml │ │ └── lib // 依赖 jar 包 │ ├── css / js / images │ ├── login.jsp │ ├── bookList.jsp │ ├── bookAdd.jsp │ └── ... └── sql └── library.sql记住这个结构你大概就知道源码里每个文件是干吗的。实体类只存数据DAO 只写 SQLServlet 只做转发和跳转。如果哪个地方职责混乱多半是学生写的代码也能理解。课程设计项目最重要的追寻是业务逻辑都清楚即可不需要过度设计。7.2 核心类职责与读码顺序拿到源码后如果你想快速把它改成自己的课程设计推荐按以下顺序读代码先读 web.xml 和 DBUtil.java搞清楚入口和数据库连接。再读实体类搞清楚数据模型。再读一个简单的 Servlet 和它的 DAO搞清楚一个完整的请求链路。最后读借阅/归还相关 Servlet 和 JSP把最有业务深度的流程吃透。读代码时用调试器打断点是效率最高的方式在 doGet/doPost 入口打上断点用浏览器发一个请求看变量一步步怎么走。比看十遍博客都有用。7.3 后续可以怎么扩展如果你打算拿这个项目当课程设计提交或者想把它完善成更像个真系统我推荐几个经典扩展方向将 DAO 层升级为 MyBatis 或 MyBatis-Plus保留 Servlet 做控制层这个组合对课设来说性价比极高。给图书列表加上前端分页和数据导出 Excel 功能网上开源实现很多。把借阅期限改成可配置并增加过期自动检测任务用 ScheduledExecutorService 即可在 Java Web 容器内也能跑。密码存储从简单的 MD5 改成 MD5 加盐或 BCrypt既体现安全意识又是很好的加分项。加一个 Redis Session 共享虽然是分布式时代的基础认知但作为扩展写在报告里很加分。不过最后我想提醒一句扩展的前提是先把现有 Servlet 代码彻底跑通、看懂而不是一上来就换框架。课程设计的核心考核点是“你是不是真的理解了这套技术”你亲手把 Servlet 整个链路走通了比堆任何花哨框架都值钱。跑过一次这个项目之后我自己最大的感受是Servlet 这种“原始但完整”的技术栈反而比框架更能训练 Web 开发的底层直觉。当年我也是一个啥都不会、只会复制粘贴的课设小白后来把 Servlet 的生命周期、请求流程、DAO 封装一个个啃透切换到 Spring 的时候几乎没遇到什么概念障碍。如果你正在为这套源码的部署或者答辩发愁按这几章的思路一步步自查配置对不对、路径对不对、SQL 表名对不对、jar 包在不在九成问题都能解决。剩下的那一成往往就是版本代差或环境差异把报错信息贴到搜索引擎里基本都有答案。
返回列表