ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JDBC+JSP+Servlet图书管理系统:环境配置、三层架构与避坑实战

JDBC+JSP+Servlet图书管理系统:环境配置、三层架构与避坑实战 简介这是一份基于 JDBC、JSP、Servlet 技术栈实现的图书管理系统完整工程定位为 Java Web 课程设计或毕业大作业适合计算机相关专业学生用于课程验收、答辩演示和二次开发。项目涵盖前端 JSP 页面、Servlet 控制层、JDBC 数据访问层以及配套数据库脚本按典型三层架构组织管理员登录、图书信息增删改查、借书还书等核心模块均已实现可直接运行展示完整业务闭环。压缩包共 141 个文件整体约 5.12MB文件类型以 Java 源文件、JSP 页面、class 字节码、XML 配置、JAR 依赖库、CSS 样式、SQL 脚本等为主同时包含项目说明文档目录结构清楚导入常见 IDE 后即可对照学习。当前已有 100 人浏览学习项目无需修改即可运行既适合作为高分必过型课程作业直接采用也便于在此基础上扩展功能或理解 JDBCJSPServlet 的典型协作方式。1. 拿到JDBCJSPServlet图书管理系统先看这三件事再动手每年课程设计答辩前后台都会收到一类私信压缩包下了、项目导进去了、Tomcat也点了结果页面起不来要么数据库裸奔要么404。基于JDBCJSPServlet的图书管理系统就是典型的课设项目它不算难但坑全藏在环境匹配和代码细节里。这套资源我拆过几遍可以负责任地说只要按顺序做对三件事——数据库脚本先导入、JDBC连接串改成你自己的密码、JDK/Tomcat版本对齐——从压缩包到能点着演示耗时不会超过半小时。它解决的是“工科生做图书管理大作业”最实际的诉求代码结构够讲、功能够全、演示不翻车。适合正在赶Java Web课程设计的同学也适合想重新捋一遍ServletJDBC三层架构的初级开发者。2. 项目骨架拆解三层架构、四个核心类与一条完整请求链路2.1 为什么是JSPServletJDBC这个选型在课设里意味着什么现在的Java Web课设主流路线其实有三条Spring Boot全家桶、SSM框架、以及这套JDBCJSPServlet原生态。前两条看起来很新但很多学校的评审老师对框架不熟反而问不出什么东西而这套老三层架构老师一看就懂你自己也讲得明白JSP负责页面展示Servlet负责接收请求和控制跳转JDBC负责跟MySQL打交道。整个项目的分层边界清楚回答“你讲讲项目架构”这种答辩必问题三句话就能讲完。从学习角度讲这个选型还有个隐性好处框架被封装掉的东西在这里全部露在外面。你看得到HttpServletRequest怎么拿参数、PreparedStatement怎么防注入、Connection怎么开怎么关。这些东西不是过时的知识Spring Boot的JdbcTemplate、MyBatis的SQL会话底层干的事和它一模一样。把这套项目跑通一次再去看框架源码很多概念是直接对得上的。2.2 拿到压缩包先认门目录结构和四个核心类解压之后不要急着往IDE里塞先花两分钟认清结构。一个标准的老三层课设项目源码目录下面一定有这么几组东西实体类包、DAO包、Service包、Servlet包再加WebContent里的JSP页面和WEB-INF下的配置文件。这个项目里最核心的类是这么四个它们在请求链路里的位置也完全对应BaseDao数据库连接与释放的基类所有DAO类的父类负责驱动加载、Connection获取、资源关闭。BookDaoImplBookDao接口的实现类里面是所有图书相关的SQL操作增删改查都在这。BookServiceImplBookService接口的实现类承载借阅天数计算、超期判断这类业务规则。Student学生实体类字段对应student表承载登录后的用户信息还书的时候要操作它。LoginServlet控制层入口接收登录请求、调Service做校验、决定页面跳转。2.3 一条请求走完全流程从登录表单到数据库再回到页面理解这套项目最好的办法是跟着一个登录请求走一遍。在login.jsp页面填好用户名密码、点提交浏览器发出POST请求到login这个URL。容器根据注解或web.xml里的映射把这个请求交给LoginServlet处理LoginServlet从request里取出参数调用Service层Service再调DAO层DAO里的BaseDao把SQL发到MySQL执行。等数据原路返回Servlet拿到结果后做两件事把用户信息塞进session然后调用response.sendRedirect做重定向。整个过程里Servlet不碰任何SQLJSP里也不写任何Java业务逻辑——如果源码里出现JSP页面大段scriptlet写JDBC的情况那你拿到的不是这个结构。识别这个分层答辩时按“请求→控制层→业务层→数据层→视图”这条线讲评委最买账。关键代码长这样注意看BaseDao里static块加载驱动的写法public class BaseDao { // 四个连接参数课设最常见的写法是直接写死在类里 private static final String DRIVER com.mysql.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/library?useUnicodetruecharacterEncodingutf-8; 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 SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }把驱动加载放在static块里是因为类加载只发生一次驱动也就注册一次连接串里的characterEncodingutf-8是中文不乱码的前提这个参数后面避坑章节还要提。USE和PASSWORD是这套资源里你唯一必须改的地方。再往下BookDaoImpl里查全部图书的方法是那种“课设必写、面试也爱问”的标准写法public ListBook findAll() { ListBook list new ArrayListBook(); String sql SELECT id, book_name, author, price, stock, publish_date FROM book; try { Connection conn BaseDao.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery(); while (rs.next()) { Book b new Book(); b.setId(rs.getInt(id)); b.setBookName(rs.getString(book_name)); b.setAuthor(rs.getString(author)); b.setPrice(rs.getDouble(price)); b.setStock(rs.getInt(stock)); b.setPublishDate(rs.getDate(publish_date)); list.add(b); } // 注意释放顺序先rs再ps最后conn BaseDao.close(rs, ps, conn); } catch (SQLException e) { e.printStackTrace(); } return list; }这个方法能看出三个课设评审会盯的细节是否用PreparedStatement而不是拼字符串的Statement、ResultSet有没有被完整遍历、连接有没有在finally里关闭。这套源码里close方法做的是反向关闭从ResultSet到Statement再到Connection顺序对了才不会在MySQL连接数上翻车。你可以看看自己下载的包里这段代码是不是这样写的——如果是直接交如果不是建议按这个改。2.4 实体类与数据库字段的映射关系实体类和表字段的对应是另一个答辩容易踩的深水区。拿Student举例源码里的student表一般有学生编号、姓名、学号、密码、专业、班级、借书数量这几个字段实体类的属性要和它们一一对应。很多同学改代码翻车就翻在实体类里用了studentNameSQL里写的是student_name结果rs.getXxx取不到值。这套资源里字段映射我在第3章放一张对照表你核对一遍再动手。总的原则很土但很实用实体类属性名、数据库字段名、getter/setter三个地方必须全部一致。3. 数据库与JDBC连接表设计、驱动版本和那几行连接串3.1 四张表搞定整个系统别把表设计复杂化课设项目的数据库贵在够用不在花哨。这套图书管理系统的标准表设计是四张表管理员表admin或者并入student表用type区分、学生表student、图书表book、借阅记录表borrow。为什么是这四张因为图书管理系统的核心业务就两类管书、管人。管书需要book表记录书名、作者、价格、库存管人需要student表存学生身份信息借阅关系要单独一张borrow表存“谁借了哪本书、什么时候借、什么时候还”。这套数据结构能覆盖老师最爱问的三个业务场景图书信息维护、学生借书、归还和超期。表设计到这一层就足够拿分了多余的关联表反而容易在答辩时被问住。数据库脚本一般放在压缩包的sql目录下文件名叫library.sql类似的东西。导入之前先看一眼脚本头部的CREATE DATABASE语句确认数据库名和连接串里的库名对得上这一步能省掉后面一堆幺蛾子。3.2 导入SQL脚本命令行和Navicat两种姿势Navicat导入比较简单连接上MySQL后新建一个同名数据库选中它再右键运行SQL文件。但命令行方式其实更稳因为很多同学电脑上装的是MySQL 8.xNavicat版本太老的话连接方式还有兼容问题。我一般喜欢直接用命令行导脚本比界面操作更容易排查出错位置mysql -uroot -p123456先登录进MySQL交互终端然后逐条执行CREATE DATABASE IF NOT EXISTS library DEFAULT CHARACTER SET utf8mb4; USE library; SOURCE /YourPath/library.sql;source后面跟SQL脚本的绝对路径Windows路径里的反斜杠记得换成左斜杠。字符集指定utf8mb4是为了兼容更多字符和连接串里的utf-8对应。执行完可以用SHOW TABLES;验证一下看到四张表全在就说明导入成功。3.3 MySQL驱动版本5.x和8.x是两套完全不同的写法JDBC连接MySQL最疼的坑是驱动类名和连接串格式跟着MySQL版本走。MySQL 5.x时代驱动类是com.mysql.jdbc.Driver连接串写成jdbc:mysql://localhost:3306/library。到了MySQL 8.x驱动类改成了com.mysql.cj.jdbc.Driver连接串后面还必须追加serverTimezone参数指定时区否则直接报The server time zone错误。这套资源的BaseDao里大概率写的是老版驱动因为大多数课设项目最初就是在MySQL 5.7环境下开发的。如果你的电脑装的是MySQL 8.x前面BaseDao那段代码要改两处private static final String DRIVER com.mysql.cj.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/library?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai;两行改完Class.forName才会认得驱动DriverManager才能建立连接。判断自己该用哪个版本很简单mysql-connector-java的jar包如果版本号是8开头就用cj那个5开头就用老的。这个对应关系课设文档里一般不写属于必须靠经验填的一类坑。3.4 数据库字段与实体类对照核查表导入完成后对照这张表检查一遍字段再继续往下走表名核心字段对应实体类属性备注studentid, student_no, name, passwordid, studentNo, name, password登录身份bookid, book_name, author, price, stockid, bookName, author, price, stock库存要建索引borrowid, student_id, book_id, borrow_date, return_dateid, studentId, bookId, borrowDate, returnDate记录借还adminid, username, passwordid, username, password管理员登录对照完你会发现列名和属性名大多是去掉下划线再驼峰化的关系Java常见命名规范就是这种。字段对不齐的话改实体类比改SQL安全因为SQL是已经验证过能跑的。4. 核心业务落地登录校验、图书CRUD与借阅归还的代码写法4.1 登录与Session拦截页面跳转的正确打开方式登录是每个Java Web课设都有的模块也是最容易写出漏洞的地方。这套项目的LoginServlet处理流程是标准的从request里拿参数调Service查询判断返回结果最后做session处理。下面这段是Servlet的骨架注意关键注释的位置WebServlet(/login) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(utf-8); String username request.getParameter(username); String password request.getParameter(password); // 调Service做校验返回null表示用户名或密码不对 Student student new StudentServiceImpl().login(username, password); if (student ! null) { HttpSession session request.getSession(); session.setAttribute(student, student); response.sendRedirect(main.jsp); // 登录成功进主界面 } else { response.sendRedirect(login.jsp?error1); // 失败回登录页 } } }setCharacterEncoding这行必须写在拿参数之前不然中文用户名直接乱码。重定向而不是在服务端转发到main.jsp是为了防止浏览器刷新时重复提交表单。这里有个细节登录失败带了一个error1参数login.jsp页面里用EL表达式判断这个参数显示“用户名或密码错误”这就是JSP配合Servlet传参的典型姿势。登录成功后把Student对象塞进session后续所有JSP页面里都能用session里的对象判断“当前是谁登录的”这比每次查询数据库高效得多。还书的时候程序要从session里拿studentId再和bookId拼成一条借阅记录这就是session的意义。别小看这一层很多同学的课设问题就出在“每个页面都重新登录一次”——那就是session没用好。4.2 图书增删改查PreparedStatement防注入与参数的实用写法图书管理是系统的重头戏Add/Delete/Update/Query四类SQL操作覆盖了“数据库增删改查”的核心要求。写这套DAO的时候有个原则必须坚持所有带参数的操作一律用PreparedStatement不要用Statement拼字符串。一方面是防SQL注入另一方面是参数类型不用手动转义代码更干净。添加图书的方法常见写法是这样public int addBook(Book book) { String sql INSERT INTO book(book_name, author, price, stock, publish_date) VALUES(?,?,?,?,?); try (Connection conn BaseDao.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, book.getBookName()); ps.setString(2, book.getAuthor()); ps.setDouble(3, book.getPrice()); ps.setInt(4, book.getStock()); ps.setDate(5, new java.sql.Date(book.getPublishDate().getTime())); return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); return 0; } }这里用的是try-with-resources写法Java 7之后的特性连接和PreparedStatement用完后自动关闭比手写finally干净得多。setDate这行尤其要注意java.util.Date不能直接塞给PreparedStatement得转成java.sql.Date这是初学者最容易卡的一行。executeUpdate的返回值表示影响行数大于0就说明插入成功这个返回值可以作为Servlet判断操作是否成功的依据。五个问号的顺序必须和SQL里的列顺序严格对应我刚才见过有同学把书名和作者的位置搞反结果整本书的作者信息全错了。删除和更新的写法套路完全一样只是SQL语句不同不再贴代码。你可以打开源码里的BookDaoImpl逐个方法对应着看。4.3 借书还书与超期判断用日期算出差值才叫业务逻辑借书操作的业务逻辑比单纯的CRUD多一点内容要检查库存够不够、要往borrow表插一条记录、还要把book表里的库存减1。这三个动作实际上是三个SQL按课设的简单方案它们按顺序执行就行。但严格来说这三步应该放在一个事务里——借书这个操作要么全部成功要么全部不执行不然会出现“库存减了但借阅记录没插上”这种数据不一致。JDBC里开启事务的标准姿势是关掉自动提交Connection conn null; try { conn BaseDao.getConnection(); conn.setAutoCommit(false); // 关闭自动提交开启事务 // 执行查库存 - 插borrow记录 - 扣减库存 conn.commit(); // 全部成功才提交 } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); }这是JSPServlet课设里少见的加分点。绝大多数同学的课设借书操作就是三条SQL裸奔没有事务保护。你要是能在答辩时说清楚“借书和扣库存必须是一个原子操作所以我用setAutoCommit(false)开启事务异常时回滚”这个回答能把项目档次从“能跑”提到“有点设计”。还书的逻辑里有一个值钱的判断——超期天数计算。归还日期减去应还日期差值转成天数正数就是超期public long calcOverdueDays(Date returnDate, Date dueDate) { long diff returnDate.getTime() - dueDate.getTime(); long days diff / (1000 * 60 * 60 * 24); return days 0 ? days : 0; }getTime()拿到的是毫秒时间戳差值除以一天的毫秒数得到天数。这个计算放在Service层而不是DAO层因为它是纯业务规则和数据存取无关 —— 这个分层决策也是答辩时能说出口的点。超期判断的另一个隐藏细节是还书时得先查borrow表里那条记录取出book_id才能知道还的是哪本书、对应扣掉谁的库存。这就是为什么borrow表必须存book_id和student_id两个外键字段。这套源码里的borrow查询一般写在BookDaoImpl里用student_id和book_id联合查你翻代码的时候留意一下逻辑不对的改成上面这种。4.4 JSP页面渲染列表页循环输出与个人信息展示图书列表页是JSP被问得最多的地方。标准课设写法是Servlet把查到的List 放进request用request.setAttribute(bookList, list)再转发给bookList.jsp。JSP里用JSTL的forEach标签循环渲染而不是用Java代码块写for循环c:forEach varbook items${bookList} tr td${book.id}/td td${book.bookName}/td td${book.author}/td td${book.price}/td td${book.stock}/td tda hrefborrow?bookId${book.id}借阅/a/td /tr /c:forEachEL表达式${book.bookName}会自动调getBookName()写错属性名会直接报EL解析错误。这里有个判断优先级的问题JSP页面上拿数据的时候如果没有写成${bookList}而是直接脚本片段说明代码没走MVC答辩要扣分。这套资源如果用了JSTL就能直接交如果页面里是大段Java代码建议改成这种写法页面的可维护性提升好几个档次。个人信息展示页面同理学生登录后在main.jsp头部显示“当前用户${sessionScope.student.name}”这个在答辩演示时一定要点出来。5. 避坑排查从404到中文乱码的五个常见翻车现场5.1 项目导入IDE后一堆红叉现象eclipse或IDEA里导入项目工程名旁边一个红叉或者无数个红叉编译都过不去。原因JDK版本不匹配。课设项目一般基于JDK 1.8编译你电脑上如果默认的是JDK 11或17编译级别不对所有类全是红叉另一种情况是Tomcat没有关联到项目上Servlet类找不到javax.servlet的jar包。解决在IDE里找到Build Path或Project Structure把Project SDK改成1.8然后在Facets或Dependencies里把运行环境改成Tomcat 8或9。改了这三处还红就看某个具体类的报错信息八成是某个类没找到依赖Weld按需处理。5.2 Tomcat启动正常但访问404现象Tomcat起来了控制台没有报错浏览器访问localhost:8080/projectName/index.jsp直接404。原因部署的应用名和访问路径不一致。Tomcat默认部署的应用名是war包名或项目名如果项目名是library你却访问8080图书管理系统那自然找不到。解决统一成一致的名字。在IDE里改Tomcat部署的application context或者在web.xml或注解里确认Servlet映射的URL。排查顺序是先确认8080能看到Tomcat欢迎页再确认项目名最后才查Servlet映射路径。很多同学把顺序搞反最后发现Tomcat压根没部署上项目。5.3 JDBC连接报Communications link failure现象点击登录或打开列表页控制台报“Communications link failure”后面跟着一串时区或者连接超时的英文。原因这个是MySQL版本与驱动不匹配的最典型症状。MySQL 8.x用了新的认证插件老驱动连不上或者驱动类名写错Class.forName异常导致连接失败。解决先看mysql-connector-java的jar包版本8.x就按第3章的方式改成cj驱动并加serverTimezone5.x就把URL里的serverTimezone去掉保持老写法。还有一种情况是MySQL服务根本没启动Windows下到服务管理器里看MySQL服务状态或者在任务管理器确认mysqld进程在跑。数据库地址如果不在本机还要确认3306端口能通。5.4 页面和数据库中文全是问号现象页面显示中文正常但往数据库一插存进去的变成了??或者反过来的数据库里中文正常页面上全是乱码。原因两头没对齐。存进去变问号是连接串里的characterEncoding没写或写错页面取出来乱码是JSP页面本身的编码和request的编码不一致。解决三处统一成UTF-8。第一处BaseDao连接串加上useUnicodetruecharacterEncodingutf-8第二处JSP页面顶部声明pageEncodingUTF-8第三处从request取参数之前调用request.setCharacterEncoding(utf-8)。三处全改中文乱码这个坑基本绝迹。数据库表如果建的时候忘了指定字符集ALTER TABLE语句也能补救但不如建表时直接写明utf8mb4靠谱。5.5 借书成功但库存没减或者记录没插上现象页面上提示借阅成功borrow表里也有一条记录但book表里的库存数字没变化或者反过来库存减了但borrow表是空的。原因这就是第4章提到的“非事务”问题三条SQL各自独立执行中间任何一条报错或没执行数据就对不上。课设环境里数据量小这种问题偶尔才暴露一次但答辩时老师会盯着数据一致性问。解决把借书的三个动作放进同一个事务setAutoCommit(false)最后统一commit。这个改动量不大但代码质量立刻上了一个台阶。改完再验证一遍借一本库存为2的书看库存变1、borrow记录新增一条两个动作同时成功才是正常的。6. 部署与验证从压缩包到可演示项目的完整流程与加分改造6.1 五步通电流程每一个环节都要有可验证的输出拿到压缩包按下面的顺序操作每步都先确认输出了预期结果再走下一步步骤操作验证方法1装JDK 1.8并配JAVA_HOMEjava -version指令输出1.82装Tomcat 8.5启动后访问8080看到猫3MySQL执行library.sqlSHOW TABLES看到四张表4改BaseDao连接串为你的密码看日志无ClassNotFound5发布项目并启动用项目说明里的测试账号登录这套顺序是我拆了十几个类似项目总结出来的核心在于每个环节的验证成本都很低出了问题能立刻定位在哪个环节而不是把问题攒到最后一起爆炸。常见的反面教材是一上来就启动Tomcat数据库根本没配然后被一长串异常日志淹没。6.2 一份启动自测清单答辩前必测的六个动作配好环境后按照下面这条用户路径完整走一遍没问题再去答辩现场学生账号登录确认能进主页面且右上角显示当前用户名点击“图书列表”确认表格渲染正常且无乱码执行一次“添加图书”确认成功后列表里能查到新书执行一次“借阅”确认库存数字减一、借阅记录里多一条执行一次“还书”确认借阅记录状态更新、库存加一退出登录再访问main.jsp确认被拦截回login.jsp第6条很多同学会漏掉未登录直接访问受保护页面在Servlet里靠session取null做拦截。答辩演示时老师最常干的事就是“我不登录直接访问看看”提前把拦截逻辑跑通这个分数就稳了。6.3 两个白送的加分改造分页和密码加密如果项目已经跑通还有余力优先做这两个改动改动量小但答辩效果极好。图书列表加分页SQL里加LIMIT子句JSP侧加一个页码参数传入代码量不大讲出来却是“我考虑了大数据量下的查询性能”。密码存库前用MD5加一次密讲出来是“我考虑了用户信息安全”。这两个点评委一听就记得住而且不会问出你答不上的深坑。改完记得多跑两遍完整流程每次改动都是风险。从那以后我每次拿到课设压缩包都强制自己先走一遍“看SQL版本→改连接串→起Tomcat→测试账号登录”的流程五分钟确认能不能跑再碰业务代码。环境问题永远比业务问题先解决这个顺序救过我很多次希望帮到你。提示如果你下载的包内项目说明里写了默认账号密码先用默认的没写的话去student表里直接查一条记录前缀密码一翻就出来了。本文还有配套的精品资源点击获取
返回列表