Java Web图书管理系统毕业设计:JSP+Servlet+Layui+MySQL完整实现与避坑指南
2026/9/24 19:32:28 网站建设 项目流程

简介:这是一套面向高校计算机专业学生与Java Web初学者整理的图书管理系统完整项目,可直接用于毕业设计、课程大作业或自学练手。系统基于JSP、Servlet、Layui与MySQL开发,运行环境为IDEA、JDK1.8、MySQL5.7与Tomcat9,界面美观且带公告功能。功能按角色划分:用户可查看公告、浏览图书与个人违章;图书管理员负责借还图书及借阅、还书报表;系统管理员则管理书籍、借阅规则,并进行图书信息查询与借阅统计。资源包共1046个文件,约40.91MB,包含212个Java源码、156个JSP页面、120个JS脚本、57个CSS样式及3个SQL数据库脚本,另附完整文档,源码、数据库与说明一应俱全。目前已有93人学习下载,适合需要快速搭建可运行项目、理解分层开发与数据库设计的读者参考借鉴。

1. 从一份能跑起来的 Java Web 图书管理系统说起

如果你正在为毕业设计选题发愁,或者需要一个能直接跑通、界面不寒碜的 Java Web 大作业,这套基于 JSP + Servlet 的图书管理系统值得花时间拆一遍。它不是那种只有增删改查的裸 Demo,而是把用户、图书管理员、系统管理员三个角色的权限边界划清楚了,公告、违章、借阅报表、还书报表这些毕业设计里常被要求的功能点都有对应实现。技术栈是经典的 JSP + Servlet + Layui + MySQL,IDE 用 IDEA,JDK 1.8,Tomcat 9,MySQL 5.7,这套组合在高校机房和答辩现场几乎不会出兼容性问题。源码、数据库脚本、配套文档都在包里,拿到手改改包名和数据库连接就能跑。适合谁?适合不想从零搭架子、但又需要理解 MVC 分层逻辑的计算机毕业设计选手,也适合想拿一个完整项目练手 Servlet 生命周期的 Java Web 初学者。

2. 环境搭建与数据库初始化:把项目从压缩包跑到浏览器

2.1 为什么选 JDK 1.8 + Tomcat 9 + MySQL 5.7 这套组合

这套环境不是随便写的,是血泪经验堆出来的稳定组合。JDK 1.8 对 Servlet 3.1 和 JSP 2.3 的支持最成熟,IDEA 2020 之后的版本对它的识别也最省心。Tomcat 9 实现了 Servlet 4.0,但向下兼容 3.1,项目里的web.xml如果是 3.1 版本,Tomcat 9 不会报错。MySQL 5.7 的驱动包mysql-connector-java-5.1.47.jar和 8.0 的驱动在 URL 参数上有区别,5.7 不需要加serverTimezone,少一个玄学报错点。如果你用 MySQL 8.0,连接 URL 要改成jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8,否则时区报错会让你怀疑人生。

常见做法是先在 IDEA 里新建一个 Java Enterprise 项目,勾选 Web Application,然后把源码里的src目录整个拷进去。但更省事的办法是直接打开项目根目录的.iml文件,让 IDEA 自动识别模块。注意,项目里的lib目录必须手动添加到 Artifacts 的WEB-INF/lib下,否则 Tomcat 启动时会报ClassNotFoundException

2.2 数据库建库建表与连接配置

数据库脚本一般在sqldb目录下,文件名可能是book.sqllibrary.sql。用 Navicat 或者命令行执行都行。命令行方式如下:

# 登录 MySQL,输入密码 mysql -u root -p # 创建数据库,字符集用 utf8mb4 兼容性更好 CREATE DATABASE library_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 切换到该数据库 USE library_db; # 执行脚本,假设脚本在当前目录 source /path/to/book.sql;

执行完检查表是否齐全,通常包含adminbookborrowborrow_listillegalnoticeuser等。borrowborrow_list容易混淆,前者记录当前借阅状态,后者是历史流水,还书报表就是从borrow_list里按时间范围查。

连接配置在src下的db.propertiesc3p0-config.xml里。如果是db.properties,内容大概长这样:

jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/library_db?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=你的密码

参数说明:useUnicode=truecharacterEncoding=utf8必须同时出现,否则中文公告和书名会变成问号。jdbc.driver在 MySQL 5.7 下用com.mysql.jdbc.Driver,8.0 用com.mysql.cj.jdbc.Driver。改完配置后,在 IDEA 的 Database 面板里测试连接,能连上再启动 Tomcat。

2.3 Tomcat 部署与上下文路径调整

在 IDEA 里配置 Tomcat 时,Deployment 选项卡下添加 Artifact,Application context 建议设为/library,不要用默认的/,否则静态资源路径容易冲突。启动后浏览器访问http://localhost:8080/library/,如果看到登录页而不是 404,说明部署成功。

如果启动时报Port 8080 already in use,要么改 Tomcat 端口,要么在命令行用netstat -ano | findstr :8080找到占用进程并结束。另一个高频问题是 JSP 页面中文乱码,检查<%@ page contentType="text/html;charset=UTF-8" language="java" %>是否在每个 JSP 顶部都有,以及 Tomcat 的conf/server.xml里 Connector 标签是否加了URIEncoding="UTF-8"

3. 三层架构拆解:Servlet 接请求、Service 做逻辑、DAO 碰数据库

3.1 包结构与请求流转路径

项目源码的包名一般是com.xxx.controllercom.xxx.servicecom.xxx.daocom.xxx.entity这种分层。Servlet 作为控制器,负责接收前端 Layui 表格的 AJAX 请求,解析参数,调用 Service,再把结果以 JSON 格式写回。比如借书操作,前端发POST /borrow?action=borrowBookBorrowServletdoPost方法里根据action参数分发到不同逻辑。

一个典型的 Servlet 分发结构如下:

// BorrowServlet.java 片段 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); if ("borrowBook".equals(action)) { // 获取当前登录用户和图书 ID int userId = Integer.parseInt(request.getParameter("userId")); int bookId = Integer.parseInt(request.getParameter("bookId")); // 调用 Service 层 BorrowService borrowService = new BorrowServiceImpl(); boolean success = borrowService.borrowBook(userId, bookId); // 返回 JSON 结果 response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); out.write("{\"success\":" + success + "}"); out.flush(); } }

逻辑说明:action参数是前后端约定的分发键,避免为每个操作单独写一个 Servlet。response.setContentType必须设成application/json;charset=UTF-8,否则 Layui 的table.render解析不了返回数据。参数说明:userId从 session 里取更安全,这里为了演示直接从前端传,实际项目里应该用request.getSession().getAttribute("user")获取。

3.2 借阅规则与违章逻辑的实现细节

借阅规则管理是系统管理员模块的一部分,通常存在borrow_rule表里,字段包括max_borrow_count(最大借阅数)、borrow_days(借阅天数)、fine_per_day(每日罚款)。借书时 Service 层要先查当前用户已借数量是否超过max_borrow_count,再查图书库存是否大于零。还书时计算逾期天数,如果超过borrow_days,就往illegal表插一条违章记录,罚款金额 = 逾期天数 ×fine_per_day

// BorrowServiceImpl.java 借书核心逻辑 public boolean borrowBook(int userId, int bookId) { // 1. 查用户当前借阅数 int currentCount = borrowDao.countByUserId(userId); // 2. 查借阅规则 BorrowRule rule = ruleDao.getRule(); if (currentCount >= rule.getMaxBorrowCount()) { return false; // 超过最大借阅数 } // 3. 查图书库存 Book book = bookDao.getById(bookId); if (book.getStock() <= 0) { return false; // 库存不足 } // 4. 库存减一,插入借阅记录 bookDao.reduceStock(bookId); borrowDao.insert(userId, bookId, new Date()); return true; }

参数说明:maxBorrowCount默认可能是 5,borrowDays默认 30,这些值在系统管理员界面可以改。注意,库存减一和插入借阅记录应该放在同一个事务里,否则减了库存但插入失败会导致数据不一致。项目里如果没用 Spring 事务,就在 DAO 层用Connection.setAutoCommit(false)手动控制。

3.3 公告模块与 Layui 表格的数据对接

公告模块相对简单,notice表存标题、内容、发布时间。用户登录后首页会查最新几条公告展示。Layui 的表格组件通过url属性请求 Servlet,返回格式必须是{"code":0,"msg":"","count":总数,"data":[...]}。很多新手在这里翻车,返回的 JSON 里code不是 0,表格就一直显示“数据接口请求异常”。

// notice.jsp 里的 Layui 表格初始化 layui.use(['table'], function(){ var table = layui.table; table.render({ elem: '#noticeTable', url: 'NoticeServlet?action=list', page: true, cols: [[ {field: 'id', title: 'ID', width: 80}, {field: 'title', title: '公告标题', minWidth: 200}, {field: 'createTime', title: '发布时间', width: 180} ]] }); });

逻辑说明:url指向的 Servlet 必须返回 Layui 规定的 JSON 结构。page: true开启分页,Servlet 里要接收pagelimit两个参数,分别表示当前页码和每页条数。参数说明:cols里的field必须和返回 JSON 里的键名完全一致,大小写敏感。如果公告内容太长,可以在表格里只显示标题,点击标题弹层显示详情。

4. 避坑与排查:从 404 到乱码的五个高频翻车现场

4.1 启动后访问 404,但 Tomcat 日志没报错

现象:浏览器打开http://localhost:8080/library/显示 404,IDEA 控制台没有异常堆栈。

原因:Artifact 里没有把 JSP 和web.xml打进去,或者 Application context 设成了/library但访问时漏了。另一个可能是web.xmlwelcome-file-list配置的首页文件名和实际 JSP 文件名不一致。

解决:打开 IDEA 的 Project Structure → Artifacts,确认 Output Layout 里WEB-INF下有classeslibweb.xml,根目录下有 JSP 文件。然后检查web.xml<welcome-file>login.jsp</welcome-file>是否和实际文件名匹配。改完重新 Build Artifact 再启动。

4.2 数据库连接报 Access denied 或 Unknown database

现象:Tomcat 启动时抛java.sql.SQLException: Access denied for user 'root'@'localhost'

原因:db.properties里的密码和本机 MySQL 密码不一致,或者数据库名拼写错误。MySQL 8.0 还会因为驱动类名不对报ClassNotFoundException

解决:先在命令行用mysql -u root -p确认密码能登录,再SHOW DATABASES;确认库名存在。如果密码对但还报错,检查db.properties里有没有多余空格。MySQL 8.0 用户把驱动类改成com.mysql.cj.jdbc.Driver,URL 加上serverTimezone=Asia/Shanghai

4.3 中文乱码:公告变问号、书名变方块

现象:页面显示的中文全是???或者乱码方块。

原因:三个地方可能出问题——JSP 页面编码、Servlet 响应编码、数据库连接编码。任何一个环节不是 UTF-8 都会导致乱码。

解决:JSP 顶部加<%@ page contentType="text/html;charset=UTF-8" %>;Servlet 里response.setContentType("text/html;charset=UTF-8")request.setCharacterEncoding("UTF-8")都要写;数据库 URL 加useUnicode=true&characterEncoding=utf8。如果还不行,检查 MySQL 的my.inicharacter-set-server=utf8mb4是否生效,改完重启 MySQL 服务。

4.4 借书成功但库存没减,或者减了没记录

现象:点击借书提示成功,但图书库存还是原数,或者库存减了但借阅记录里查不到。

原因:DAO 层两个操作没有放在同一个事务里,第一个执行成功第二个失败,或者反过来。也可能是borrow表的book_id外键约束导致插入失败但没抛异常。

解决:在 Service 层手动控制事务,Connection conn = DBUtil.getConnection(); conn.setAutoCommit(false);然后依次执行reduceStockinsertBorrow,都成功再conn.commit(),捕获异常时conn.rollback()。检查borrow表的外键是否引用了book表的id,如果引用了,插入的book_id必须存在。

4.5 Layui 表格一直显示“数据接口请求异常”

现象:公告列表或借阅报表页面表格加载不出来,弹窗提示数据接口请求异常。

原因:Servlet 返回的 JSON 格式不符合 Layui 要求,最常见的是code不是 0,或者count字段缺失,或者返回了 HTML 而不是 JSON。

解决:在浏览器 F12 的 Network 面板看该请求的 Response,确认是纯 JSON 且包含codemsgcountdata四个字段。如果返回的是 HTML,说明 Servlet 的action参数没匹配上,走了默认的doGet转发到了 JSP。检查web.xml@WebServlet注解里的 URL 映射是否正确。

5. 二次开发与答辩加分:从能跑到能讲清楚

5.1 把借阅报表导出成 Excel

答辩时老师经常问“数据能不能导出”,项目里如果没带这个功能,自己加一个不难。用 Apache POI 或者更轻量的 EasyExcel。在pom.xmllib里引入poi-ooxml依赖,然后在 Servlet 里写:

// ExportServlet.java 导出借阅报表 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Content-Disposition", "attachment;filename=borrow_report.xlsx"); List<BorrowList> list = borrowService.getAllBorrowList(); XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("借阅报表"); // 表头 XSSFRow header = sheet.createRow(0); header.createCell(0).setCellValue("用户名"); header.createCell(1).setCellValue("书名"); header.createCell(2).setCellValue("借阅日期"); // 数据行 for (int i = 0; i < list.size(); i++) { XSSFRow row = sheet.createRow(i + 1); row.createCell(0).setCellValue(list.get(i).getUserName()); row.createCell(1).setCellValue(list.get(i).getBookName()); row.createCell(2).setCellValue(list.get(i).getBorrowDate().toString()); } workbook.write(response.getOutputStream()); workbook.close(); }

参数说明:Content-Dispositionfilename如果包含中文,要用URLEncoder.encode("借阅报表.xlsx", "UTF-8")编码,否则浏览器下载文件名会乱码。XSSFWorkbook对应.xlsx格式,HSSFWorkbook对应.xls,前者支持更大数据量。

5.2 用过滤器统一处理编码和登录校验

项目里如果每个 Servlet 都写一遍request.setCharacterEncoding("UTF-8"),代码会很冗余。加一个CharacterEncodingFilterLoginFilter,在web.xml里配置拦截路径。LoginFilter拦截/admin/*/user/*,检查 session 里有没有用户对象,没有就重定向到登录页。这样答辩时你可以说“系统做了统一的权限拦截”,比逐个 Servlet 判断显得更有架构意识。

// LoginFilter.java 核心代码 public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String uri = request.getRequestURI(); // 放行登录页和静态资源 if (uri.contains("login.jsp") || uri.contains("LoginServlet") || uri.contains(".css") || uri.contains(".js")) { chain.doFilter(req, resp); return; } // 检查 session Object user = request.getSession().getAttribute("user"); if (user == null) { response.sendRedirect(request.getContextPath() + "/login.jsp"); } else { chain.doFilter(req, resp); } }

逻辑说明:chain.doFilter是放行到下一个过滤器或目标 Servlet。request.getContextPath()获取项目上下文路径,避免硬编码/library。注意,过滤器的url-pattern如果配成/*,登录页和登录请求必须放行,否则会死循环重定向。

5.3 答辩时怎么讲清楚 MVC 和分层

老师问“你这个系统架构是什么”,别只说“JSP + Servlet”。按这个顺序讲:浏览器发请求 → Filter 做编码和权限校验 → Servlet 接收参数并分发 → Service 处理业务逻辑(借阅规则、违章计算)→ DAO 通过 JDBC 操作 MySQL → 结果封装成 JSON 返回给 Layui 表格渲染。每一层只做一件事,Controller 不碰 SQL,Service 不碰HttpServletRequest。这样讲既体现了你对 MVC 的理解,也解释了为什么代码要分这么多包。从那以后我每次带学生做毕设,都要求他们先画一张请求流转图再动手写代码,图画清楚了,代码就不会乱。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询