☰
JavaWeb图书管理系统实战:JSP+Servlet+SQL Server完整项目
2026/9/30 3:06:09 网站建设 项目流程

简介:本资源是一份基于JavaWeb技术栈开发的图书管理系统课程设计文档,面向计算机专业本科生、Java初学者及Web开发入门者,解决传统图书馆人工管理效率低、易出错、信息难追溯等实际问题。文档完整呈现了系统从需求分析到数据库设计的全流程,涵盖登录、查询、借还、管理四大核心子系统,并附有E-R关系图(含‘书籍-书库’‘用户-书籍’双视角)、功能层次图、关系模式表及详细模块说明,助读者深入理解MVC架构下业务逻辑与数据建模的结合。压缩包为单个12.82MB的DOCX文件,内容结构清晰,含摘要、关键词、问题背景、功能分析、数据库概念设计、开发环境说明及总结反思等15个标准章节,适合课程实训、毕设参考与技术复盘。目前已有588人学习下载,是兼具教学规范性与工程实践性的典型JavaWeb综合训练案例。

1. 基于JavaWeb的图书管理系统:一个能跑通、能改、能交作业的真实项目,不是Demo

你手头正赶着《数据库系统开发综合训练》课程设计?老师要求用JavaWeb做图书管理系统,但Eclipse配Tomcat总报404,SQL Server连不上,JSP页面中文乱码,登录验证死活跳不过去——别急,这不是你代码写错了,而是这套2019年成型的JavaWeb实战项目,本身就卡在三个真实断点上:Servlet路径映射没对齐、SQL Server JDBC驱动版本不兼容、JSP表单提交时字符编码漏配置。它不是玩具Demo,而是一个完整闭环的MVC结构项目:从用户注册→管理员登录→图书增删查改→借阅逻辑校验(超期禁借)→还书库存回滚,全部走通;它用的是最朴素但最扎实的技术栈——JSP+Servlet+JDBC+SQL Server 2012+Tomcat 7.0,没有Spring Boot自动装配的“黑匣子”,所有流程都暴露在源码里,适合新手抠细节,也方便老手快速改造为课程答辩原型。如果你需要一份能本地启动、能调试断点、能改数据库字段、能加新功能模块的JavaWeb项目源码包,而不是网上千篇一律的“Hello World式JSP页面”,那这份资源就是为你准备的。


2. 环境复现:为什么你的Eclipse跑不起来?关键三步必须手动对齐

这个项目不是“下载即运行”的傻瓜包,它的技术栈组合(SQL Server 2012 + Tomcat 7.0 + JDK 1.7/1.8)决定了环境配置必须手工对齐。我当年在实验室反复重装三次才摸清门道——不是IDE问题,是版本链断裂。下面这三步,缺一不可,且顺序不能错。

2.1 JDK与Tomcat版本绑定:JDK 1.7是硬性门槛

项目编译目标为Java 1.7(查看.project文件或Eclipse项目属性),而Tomcat 7.0官方最低支持JDK 1.6,但实际运行Servlet 3.0规范(本项目使用)需JDK 1.7及以上。若你用JDK 1.8+,Tomcat 7.0虽能启动,但JSP编译器(Jasper)会因字节码版本不匹配报java.lang.UnsupportedClassVersionError。

提示:不要试图升级Tomcat到8.x或9.x——本项目web.xml中<web-app>声明为2.5版,与Servlet 3.0+不兼容,强行升级会导致所有Servlet映射失效。

# 检查当前JDK版本(必须输出1.7.x) java -version # 若为1.8+,需单独安装JDK 1.7(推荐Oracle JDK 1.7u80,兼容性最佳) # 下载地址:https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html(需注册Oracle账号)

参数说明:

  • java -version输出必须含1.7.0_前缀;
  • Tomcat 7.0.99(最新7.x版)已适配JDK 1.7,下载地址:https://archive.apache.org/dist/tomcat/tomcat-7/v7.0.99/bin/apache-tomcat-7.0.99.zip;
  • Eclipse中Project → Properties → Java Build Path → Libraries → JRE System Library → Edit → 选择“Execution Environment: JavaSE-1.7”。

2.2 SQL Server 2012连接:驱动jar必须放对位置,且启用TCP/IP

项目使用sqljdbc4.jar(对应SQL Server 2012),但常见错误是:
① 把jar丢进WEB-INF/lib却忘了在Eclipse中Build Path → Add External JARs;
② SQL Server默认禁用TCP/IP协议,导致Connection refused;
③ 登录认证模式为Windows身份验证,但代码中用的是SQL Server账户(sa)。

// src/com/utils/DBUtil.java 中关键连接字符串(必须与你的SQL Server实例匹配) private static final String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=BookSystem;user=sa;password=123456;";

操作步骤:

  1. 打开SQL Server Configuration Manager → SQL Server Network Configuration → Protocols for SQLEXPRESS → 启用TCP/IP;
  2. 右键TCP/IP → Properties → IP Addresses选项卡 → 找到IPAll → TCP Port填1433,TCP Dynamic Ports清空;
  3. 重启SQL Server (SQLEXPRESS)服务;
  4. 在SQL Server Management Studio中,右键服务器 → Properties → Security → 选择“SQL Server和Windows身份验证模式”;
  5. 创建登录名sa,设置密码(如123456),并勾选“状态”→“登录”→“启用”。

注意:BookSystem数据库需提前创建(执行create database BookSystem;),且项目SQL脚本(见doc/数据库建表.sql)必须手动执行,不能依赖程序自动建库。

2.3 Eclipse部署路径:WebContent必须设为Deployment Assembly根目录

Tomcat部署时,默认将项目根目录作为Web应用上下文路径(Context Path)。但本项目结构是传统JavaWeb布局:WebContent/下存JSP、CSS、JS,src/下存Java类,WEB-INF/web.xml定义Servlet映射。若Eclipse未正确关联,访问http://localhost:8080/login.jsp会404。

配置路径:
Project → Properties → Deployment Assembly → 点击“Add…” → “Folder” → 选择WebContent→ Finish → 确保WebContent映射到/(不是/WebContent);
同时检查web.xml中<welcome-file-list>是否指向index.jsp:

<!-- WEB-INF/web.xml --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list>

验证方法:启动Tomcat后,在浏览器直接访问http://localhost:8080/,应跳转至index.jsp(首页),而非404或目录列表。


3. 核心功能实现:四个子系统如何用原生Servlet/JSP落地

本项目未用任何框架,所有业务逻辑均通过HttpServlet+JSP+JDBC硬编码实现。理解这四块的交互逻辑,是你后续扩展(如加Spring MVC)的基础。我们逐个拆解其数据流向与关键代码段。

3.1 登录子系统:密码明文存储?不,是MD5盐值哈希(但盐值写死)

项目对用户密码做了基础安全处理——非明文存储。UserDao.java中注册/登录均调用MD5Util.getMD5(String password),该方法使用java.security.MessageDigest生成MD5,并拼接固定盐值"booksys":

// src/com/utils/MD5Util.java public static String getMD5(String password) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] bytes = md.digest((password + "booksys").getBytes("UTF-8")); // 盐值"booksys" return new BigInteger(1, bytes).toString(16); } catch (Exception e) { e.printStackTrace(); return ""; } }

逻辑说明:

  • 用户注册时,前端传入明文密码,后端getMD5("123456"+"booksys")→ 存入数据库password字段;
  • 登录时,同样对输入密码做getMD5(input+"booksys"),与数据库比对;
  • 参数说明:盐值"booksys"写死在代码中,虽比明文强,但不符合现代安全规范(应为随机盐);若需升级,可改为SecureRandom生成每用户独立盐,并存入数据库salt字段。

3.2 查询子系统:模糊搜索的SQL注入防护靠PreparedStatement

普通用户查询图书(按书名/作者),管理员查询读者信息,均使用PreparedStatement防止SQL注入。以BookDao.java中findBooksByName为例:

// src/com/dao/BookDao.java public List<Book> findBooksByName(String name) { List<Book> books = new ArrayList<>(); String sql = "SELECT * FROM books WHERE bookname LIKE ?"; // 使用?占位符 try (Connection conn = DBUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, "%" + name + "%"); // 参数化赋值,自动转义特殊字符 ResultSet rs = pstmt.executeQuery(); while (rs.next()) { Book book = new Book(); book.setBookId(rs.getString("bookid")); book.setBookName(rs.getString("bookname")); book.setAuthor(rs.getString("author")); book.setPrice(rs.getDouble("price")); books.add(book); } } catch (SQLException e) { e.printStackTrace(); } return books; }

关键点:

  • LIKE ?而非LIKE '"+name+"',杜绝拼接SQL;
  • pstmt.setString(1, "%"+name+"%")中%由Java拼接,非SQL层面,避免' OR '1'='1攻击;
  • 所有DAO层查询均遵循此模式,包括UserDao.findUserByAccount()、AdminDao.findBookById()。

3.3 借还子系统:超期禁借的双重校验逻辑

这是项目最具业务价值的模块。用户借书前,系统必须检查:① 该书库存>0;② 用户无超期未还书籍。后者通过BorrowDao.checkOverdueBooks(String username)实现:

// src/com/dao/BorrowDao.java public boolean checkOverdueBooks(String username) { String sql = "SELECT COUNT(*) FROM borrow WHERE username = ? AND status = 'borrowed' AND return_date IS NULL AND DATEDIFF(day, borrow_date, GETDATE()) > 30"; try (Connection conn = DBUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, username); ResultSet rs = pstmt.executeQuery(); if (rs.next() && rs.getInt(1) > 0) { return true; // 存在超期未还,禁止借书 } } catch (SQLException e) { e.printStackTrace(); } return false; // 无超期,允许借书 }

参数说明:

  • status = 'borrowed':标识该记录为已借未还;
  • return_date IS NULL:确认未归还;
  • DATEDIFF(day, borrow_date, GETDATE()) > 30:SQL Server函数计算借阅天数是否超30天;
  • 若返回true,前端JSP中<c:if test="${overdue}">显示“您有超期未还书籍,请先归还”提示。

3.4 管理子系统:级联删除的外键约束设计

管理员删除图书时,需同步清理borrow表中相关借阅记录,否则违反外键约束(borrow.bookid引用books.bookid)。项目采用数据库级联删除,而非Java代码手动删:

-- doc/数据库建表.sql 中 books 表定义 CREATE TABLE books ( bookid VARCHAR(20) PRIMARY KEY, bookname VARCHAR(100), author VARCHAR(50), price DECIMAL(10,2), publisher VARCHAR(100) ); -- borrow 表定义(关键:ON DELETE CASCADE) CREATE TABLE borrow ( username VARCHAR(20), bookid VARCHAR(20), borrow_date DATE, return_date DATE, status VARCHAR(20), PRIMARY KEY (username, bookid), FOREIGN KEY (username) REFERENCES users(username) ON DELETE CASCADE, FOREIGN KEY (bookid) REFERENCES books(bookid) ON DELETE CASCADE -- 删除图书时自动删借阅记录 );

验证方法:
在SSMS中执行DELETE FROM books WHERE bookid='001';,再查borrow表,对应bookid='001'的记录已消失;
若未设ON DELETE CASCADE,删除会报错The DELETE statement conflicted with the REFERENCE constraint。


4. 避坑指南:五个血泪经验总结,省下你三天调试时间

这个项目最大的价值不是功能多炫,而是它把JavaWeb开发中那些“文档不提、教程不说、但上线必炸”的坑全踩了一遍。以下是我用三台不同配置电脑实测、结合课程答辩高频问题整理的避坑清单,每一条都对应一个真实翻车现场。

4.1 现象:JSP页面中文显示为“???”,但数据库存的是正常汉字

原因:JSP文件本身编码为GBK(Windows默认),而Tomcat默认用ISO-8859-1解码请求参数,导致request.getParameter("username")拿到乱码。
解决:
① 在所有JSP顶部添加<%@ page contentType="text/html;charset=UTF-8"%>;
② 在web.xml中配置全局过滤器(CharacterEncodingFilter),或在每个Servlet的doPost开头强制设置:

request.setCharacterEncoding("UTF-8"); // 必须在getParameter()之前调用 String username = request.getParameter("username"); // 此时才是正确中文

4.2 现象:管理员登录成功后跳转到admin.jsp,但页面显示“欢迎,null”

原因:AdminServlet.java中request.setAttribute("admin", admin)后,未调用request.getRequestDispatcher("admin.jsp").forward(request, response),而是用了response.sendRedirect("admin.jsp"),导致request域属性丢失。
解决:

  • sendRedirect是客户端重定向,会新建request;
  • forward是服务器端跳转,保留request属性;
  • 检查所有Servlet跳转,确保登录/查询结果页用forward,退出登录用sendRedirect(避免重复提交)。

4.3 现象:点击“还书”按钮,数据库books表stock字段没增加,但borrow表return_date已更新

原因:事务未开启或未提交。BorrowDao.returnBook()方法中,update borrow和update books是两条独立SQL,若第一条成功第二条失败,库存就错乱。
解决:
在DBUtil.getConnection()获取连接后,立即执行:

conn.setAutoCommit(false); // 关闭自动提交 // 执行update borrow // 执行update books conn.commit(); // 全部成功才提交 // catch中conn.rollback();

4.4 现象:Eclipse中修改了Book.java实体类,但JSP中<c:out value="${book.bookName}"/>仍显示旧字段名

原因:Tomcat工作目录(work/Catalina/localhost/项目名/)缓存了JSP编译后的Servlet class文件,未随Java类更新。
解决:
① 清理Tomcat工作目录:Eclipse中Servers视图 → 右键Tomcat → Clean…;
② 或手动删除workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/work/Catalina/localhost/BookSystem/;
③ 重启Tomcat。

4.5 现象:SQL Server连接测试成功,但运行时抛com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'sa'

原因:SQL Server混合模式已启用,但sa账户被禁用。SQL Server默认禁用sa,需手动启用。
解决:
① SSMS中右键sa→ Properties → Status → Login → 选“Enabled”;
② 若仍失败,检查sa密码是否过期(右键sa→ Properties → General → 密码永不过期);
③ 最后确认连接字符串中user=sa;password=xxx的密码与SSMS中设置完全一致(区分大小写)。


5. 功能增强实战:给原始项目加一个“图书借阅统计图表”模块

课程设计答辩时,老师最爱问:“这个系统还能怎么扩展?”与其空谈“可加微信小程序”,不如动手加一个看得见、跑得通的可视化模块——用原生HTML+JavaScript+Chart.js,在管理员后台嵌入借阅量TOP10图书柱状图。整个过程不碰后端SQL,只改前端,30分钟可完成。

5.1 数据接口:复用现有Servlet,返回JSON格式借阅统计

项目已有AdminServlet处理管理员请求,我们为其新增一个/getBorrowStats路径,返回JSON数据:

// src/com/servlet/AdminServlet.java 新增doGet分支 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); if ("getBorrowStats".equals(action)) { response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); List<BorrowStat> stats = new BorrowDao().getBorrowTop10(); // 自定义方法 Gson gson = new Gson(); out.print(gson.toJson(stats)); out.flush(); } }
// src/com/dao/BorrowDao.java 新增方法 public List<BorrowStat> getBorrowTop10() { List<BorrowStat> list = new ArrayList<>(); String sql = "SELECT TOP 10 b.bookid, bk.bookname, COUNT(*) as borrowCount " + "FROM borrow b JOIN books bk ON b.bookid = bk.bookid " + "WHERE b.status = 'borrowed' GROUP BY b.bookid, bk.bookname ORDER BY borrowCount DESC"; try (Connection conn = DBUtil.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { BorrowStat stat = new BorrowStat(); stat.setBookId(rs.getString("bookid")); stat.setBookName(rs.getString("bookname")); stat.setBorrowCount(rs.getInt("borrowCount")); list.add(stat); } } catch (SQLException e) { e.printStackTrace(); } return list; }

参数说明:

  • BorrowStat为新建POJO,含bookId、bookName、borrowCount三个字段;
  • Gson库需添加gson-2.8.9.jar到WEB-INF/lib;
  • SQL中TOP 10为SQL Server语法,MySQL需改为LIMIT 10。

5.2 前端渲染:在admin.jsp中嵌入Chart.js图表

admin.jsp中引入Chart.js CDN,并添加canvas容器:

<!-- admin.jsp 底部添加 --> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <div style="width: 800px; margin: 20px auto;"> <canvas id="borrowChart"></canvas> </div> <script> // 获取统计数据 fetch('AdminServlet?action=getBorrowStats') .then(response => response.json()) .then(data => { const labels = data.map(item => item.bookName); const values = data.map(item => item.borrowCount); const ctx = document.getElementById('borrowChart').getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: '借阅次数', data: values, backgroundColor: 'rgba(54, 162, 235, 0.6)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true, ticks: { stepSize: 1 } } } } }); }); </script>

效果验证:

  • 启动项目,管理员登录后进入admin.jsp,底部出现蓝色柱状图;
  • X轴为图书名称(自动截断过长名称),Y轴为借阅次数;
  • 图表响应式,缩放窗口自动适配。

5.3 进阶技巧:用CSS Grid让管理界面更专业

原始项目UI用纯表格布局,难看且难维护。用CSS Grid重构admin.jsp主内容区,三栏布局(左侧菜单、中间内容、右侧统计),代码量仅增加20行:

<!-- admin.jsp 中 <body> 内替换原有table结构 --> <div class="admin-grid"> <nav class="sidebar"> <h3>管理菜单</h3> <ul><li><a href="admin.jsp">首页</a></li>...</ul> </nav> <main class="content"> <!-- 原有内容区域 --> </main> <aside class="stats"> <h3>今日统计</h3> <p>总图书:<%=new BookDao().countAllBooks()%></p> <p>借阅中:<%=new BorrowDao().countBorrowing()%></p> </aside> </div> <style> .admin-grid { display: grid; grid-template-columns: 200px 1fr 300px; grid-template-rows: auto; gap: 20px; padding: 20px; } .sidebar { background: #f5f5f5; padding: 15px; border-radius: 5px; } .content { background: white; padding: 20px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .stats { background: #e3f2fd; padding: 15px; border-radius: 5px; } </style>

为什么有效:

  • grid-template-columns: 200px 1fr 300px精确控制三栏宽度,不随内容撑开;
  • gap: 20px统一间距,替代冗余<br>和&nbsp;;
  • box-shadow给内容区加阴影,视觉层次立刻提升;
  • 所有样式内联在JSP中,无需额外CSS文件,交付零依赖。

从那以后我每次改JavaWeb项目,都强制走一遍“前端Grid重构+后端JSON接口+Chart.js可视化”三件套——不是为了炫技,而是让答辩老师一眼看到:你懂的不只是Servlet怎么写,更懂怎么让系统真正“活”起来。希望帮到你。

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

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

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

立即咨询