
简介本资源是一套完整的Java Web课程设计项目——基于JSPServletJDBC实现的学生请假信息管理系统面向计算机专业本科生及Java初学者解决高校学生日常请假流程数字化管理需求适用于课设开发、Web基础技术综合实践与MVC模式入门训练。压缩包共117个文件含78个JSP页面负责展示层逻辑、5个Java类核心Servlet控制器与工具类、2个SQL脚本建表与初始化数据、2个CSS样式文件经典蓝色UI主题、5个JAR依赖包含数据库驱动与工具库整体体积仅2.25MB结构清晰、部署轻量。已有2402人学习下载资源附带完整可运行代码、分角色权限控制学生/辅导员/宿管员、典型业务流程闭环请假提交→审核→记录查询→导出并包含PageBean分页工具、Excel导出功能及验证码校验等实用模块便于理解Web三层架构与数据库交互细节。1. 为什么这个“老掉牙”的技术栈依然是 Java Web 课程设计的硬通货你打开学校教务系统查课表点开学院通知看放假安排甚至用校园卡刷门禁——背后很可能跑着和这门课一模一样的技术逻辑JSP 渲染页面、Servlet 处理请求、JDBC 连数据库。这不是过时是稳得让人安心。学生请假信息管理系统表面是个 CRUD 小项目实则是把 Java Web 三层架构表现层 JSP、控制层 Servlet、数据层 JDBC拧成一股绳的最小闭环。它不追求高并发、不卷微服务但必须能跑通学生填请假单 → 辅导员审批 → 状态实时更新 → 历史记录可查。课程设计要的不是炫技而是让你亲手把“Java 能连数据库”“HTTP 请求怎么流转”“页面怎么动态变”这些抽象概念焊死在 Tomcat 的 war 包里。用 JSPServletJDBC没有 Spring Boot 的自动装配遮掩每个 request.getParameter()、每个 Connection.prepareStatement()、每个 out.println() 都是你对 Web 底层的一次确认。它适合刚学完 Java 基础、还没碰过框架的大二学生——因为翻车点清晰、报错信息直白、调试路径短。别被“老技术”吓退这恰恰是少有的、你能从 URL 输入框一路 trace 到 MySQL 表字段的完整链路。2. 搭建最小可运行环境绕过 IDE 陷阱用最朴素的方式验证三件套2.1 选 Tomcat 而不是 Jetty 或 Undertow课程设计的兼容性底线课程设计交付物通常是 WAR 包或整个项目文件夹评审老师大概率用 Tomcat 8.5 或 9.0 打开。Jetty 启动快但 JSP 编译器Jasper默认配置和 Tomcat 不同常出现org.apache.jasper.JasperException: Unable to compile class for JSPUndertow 根本不原生支持 JSP需额外集成 jsp-api。Tomcat 是唯一一个把 JSP 引擎、Servlet 容器、JNDI 数据源全打包进 bin/ 目录的“全家桶”。下载地址认准 Apache 官网tomcat.apache.org/download.cgi务必选 zip 包非 installer 版——installer 会偷偷改注册表、装 Windows 服务导致你后续在 IDEA 里 debug 时端口冲突、热部署失效。解压后进入conf/server.xml把Connector port8080改成8081避开公司开发机常用端口保存即生效。启动bin/startup.batWindows或./startup.shLinux/Mac浏览器访问http://localhost:8081出现 Apache Tomcat 页面说明容器就绪。2.2 在 IDEA 中新建纯 JSP 项目拒绝向导式陷阱手动配 classpathIDEA 的 “New Project → Jakarta EE → Web Application” 向导会默认勾选 Servlet 4.0 和 JSP 2.3但课程设计要求 JDK 1.8学校机房普遍版本而 Servlet 4.0 需 JDK 1.8 但实际依赖 Java EE 8 API极易和 Tomcat 8.5 的 Servlet 3.1 冲突。正确做法是File → New → Project → Empty Project → Next → Finish然后手动添加模块。右键项目 → Add Framework Support → 勾选 “Web Application” → Version 3.1对应 Tomcat 8.5→ OK。此时 IDEA 会生成web/WEB-INF/web.xml但注意不要删掉它。虽然 Servlet 3.0 支持注解但课程设计验收时老师可能用老版 Tomcat 7 测试而 web.xml 是兼容性保险栓。接着右键web文件夹 → New → Directory → 命名为jsp在里面放index.jsp右键src→ New → Package →servlet放LeaveApplyServlet.java右键src→ New → Package →dao放LeaveDao.java。最后Project Structure → Modules → Dependencies → → JARs or directories → 选中你解压的 Tomcat 目录下的lib/servlet-api.jar和lib/jsp-api.jar——这是让 IDEA 知道“Servlet 和 JSP 类在哪”否则写HttpServlet会爆红。2.3 JDBC 驱动加载mysql-connector-java 8.0.26 是当前课程设计的黄金版本用最新版 mysql-connector-java 8.0.33小心java.sql.SQLException: The server time zone value XXX is unrecognized这类时区报错——它默认开启serverTimezoneUTC校验而学校 MySQL 服务器多为本地时区且未配置。用 5.1.47又会和 JDK 1.8 的java.time类冲突。实测 mysql-connector-java 8.0.26 是平衡点兼容 JDK 1.8、Tomcat 8.5且默认关闭严格时区校验。下载地址dev.mysql.com/downloads/connector/j/选 Platform Independent → ZIP Archive。解压后将mysql-connector-java-8.0.26.jar复制到项目web/WEB-INF/lib/目录下不是src下。然后在LeaveDao.java中写public class LeaveDao { private static final String URL jdbc:mysql://localhost:3306/leave_system?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue; private static final String USER root; private static final String PASSWORD 123456; public Connection getConnection() throws SQLException { // 关键显式加载驱动类避免 DriverManager.getConnection() 自动发现失败 try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new RuntimeException(MySQL Driver not found, e); } return DriverManager.getConnection(URL, USER, PASSWORD); } }提示useSSLfalse是课程设计环境的务实选择。生产环境必须开 SSL但学校机房 MySQL 默认未配证书开useSSLtrue会报Could not create SSL context。allowPublicKeyRetrievaltrue是 8.0 驱动连接老 MySQL 5.7 的必需参数否则报Public Key Retrieval is not allowed。3. 三层代码落地从 JSP 表单到数据库插入每行代码都带执行上下文3.1 JSP 页面用 EL 表达式替代 scriptlet但保留 request.setAttribute() 的原始感课程设计不鼓励用 JSTL需额外引入 taglib但也不能满屏% %脚本。核心原则JSP 只负责展示不处理业务逻辑。apply.jsp学生提交请假页这样写% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % !DOCTYPE html html head title学生请假申请/title meta charsetUTF-8 /head body h2填写请假信息/h2 !-- action 指向 Servlet 的 URL 映射不是 .java 文件名 -- form actionLeaveApplyServlet methodpost label学号input typetext namestudentId required/labelbr label姓名input typetext namestudentName required/labelbr label请假类型 select nameleaveType option value病假病假/option option value事假事假/option option value公假公假/option /select /labelbr label开始时间input typedate namestartTime required/labelbr label结束时间input typedate nameendTime required/labelbr label事由textarea namereason rows3 cols50 required/textarea/labelbr input typesubmit value提交申请 /form !-- 显示上一步操作结果用 EL 表达式不写 % out.print(request.getAttribute(msg)); % -- c:if test${not empty msg} p stylecolor:red${msg}/p /c:if /body /html逻辑说明form actionLeaveApplyServlet中的LeaveApplyServlet是web.xml里servlet-mapping定义的url-pattern不是类名。c:if用 JSTL 比 scriptlet 更安全但需在web/WEB-INF/lib/加jstl-1.2.jarTomcat 8.5 自带无需额外下载。c:if里的${msg}对应 Servlet 中request.setAttribute(msg, 提交成功)这是 JSP 和 Servlet 通信的原始方式——比 session 或 cookie 更轻量且一次请求生命周期内有效。3.2 Servlet 控制层doPost() 里做三件事——取参、调 DAO、转发LeaveApplyServlet.java必须继承HttpServlet且只重写doPost()表单 methodpost。关键点参数校验必须在 Servlet 层做不能全丢给 DAO。WebServlet(/LeaveApplyServlet) public class LeaveApplyServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取表单参数注意中文需 setCharacterEncoding request.setCharacterEncoding(UTF-8); String studentId request.getParameter(studentId); String studentName request.getParameter(studentName); String leaveType request.getParameter(leaveType); String startTime request.getParameter(startTime); String endTime request.getParameter(endTime); String reason request.getParameter(reason); // 2. 简单校验课程设计够用 if (studentId null || studentId.trim().isEmpty() || startTime null || endTime null) { request.setAttribute(msg, 学号、起止时间不能为空); request.getRequestDispatcher(/jsp/apply.jsp).forward(request, response); return; } // 3. 调用 DAO 插入数据 LeaveDao dao new LeaveDao(); try { int result dao.insertLeave(studentId, studentName, leaveType, startTime, endTime, reason); if (result 0) { request.setAttribute(msg, 请假申请已提交请等待辅导员审批); } else { request.setAttribute(msg, 提交失败请重试。); } } catch (SQLException e) { e.printStackTrace(); // 课程设计允许打印堆栈 request.setAttribute(msg, 系统异常 e.getMessage()); } // 4. 转发回原页面不是重定向保持 request.setAttribute 有效 request.getRequestDispatcher(/jsp/apply.jsp).forward(request, response); } }参数说明request.setCharacterEncoding(UTF-8)必须在getParameter()之前调用否则中文变乱码。forward()是服务器内部跳转URL 不变request对象全程传递sendRedirect()是客户端重定向URL 变request属性丢失——这里必须用forward才能显示${msg}。3.3 JDBC 数据层用 PreparedStatement 防 SQL 注入但不用连接池课程设计不考核性能手写连接池反而增加复杂度。LeaveDao.java的insertLeave()方法public int insertLeave(String studentId, String studentName, String leaveType, String startTime, String endTime, String reason) throws SQLException { String sql INSERT INTO t_leave (student_id, student_name, leave_type, start_time, end_time, reason, status, apply_time) VALUES (?, ?, ?, ?, ?, ?, 待审批, NOW()); try (Connection conn getConnection(); PreparedStatement pstmt conn.prepareStatement(sql)) { pstmt.setString(1, studentId); pstmt.setString(2, studentName); pstmt.setString(3, leaveType); pstmt.setString(4, startTime); pstmt.setString(5, endTime); pstmt.setString(6, reason); return pstmt.executeUpdate(); // 返回影响行数0 表示成功 } }逻辑说明try-with-resources自动关闭Connection和PreparedStatement避免连接泄漏。NOW()是 MySQL 函数直接写进 SQL 字符串比 Javanew Date()更精准时区一致。status字段固定为待审批体现业务规则——学生只能提交不能自审批。4. 避坑指南课程设计高频翻车点与血泪解决方案4.1 现象JSP 页面中文显示为 ????但数据库里存的是正常汉字原因Tomcat 默认用 ISO-8859-1 解码 POST 请求而页面meta charsetUTF-8只影响浏览器渲染不影响请求体编码。解决在每个 Servlet 的doPost()开头加request.setCharacterEncoding(UTF-8)且必须在getParameter()之前。同时在web.xml的filter中全局配置课程设计可省略但知道原理filter filter-nameCharacterEncodingFilter/filter-name filter-classorg.apache.catalina.filters.SetCharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameCharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping4.2 现象点击提交后页面空白控制台无报错network 查看响应状态码 404原因form actionLeaveApplyServlet的路径错误。常见误写为actionservlet/LeaveApplyServlet或action/LeaveApplyServlet。解决action值必须和web.xml中url-pattern完全一致不含/前缀。例如web.xml里写url-pattern/LeaveApplyServlet/url-pattern则 form action 就是LeaveApplyServlet如果写url-pattern/servlet/LeaveApplyServlet/url-patternaction 就是servlet/LeaveApplyServlet。最稳妥法用request.getContextPath()动态生成form action${pageContext.request.contextPath}/LeaveApplyServlet methodpost。4.3 现象MySQL 报错java.sql.SQLException: Access denied for user rootlocalhost原因MySQL 8.0 默认认证插件改为caching_sha2_password而 mysql-connector-java 8.0.26 默认用mysql_native_password协议连接。解决登录 MySQL 命令行执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456; FLUSH PRIVILEGES;或者在 JDBC URL 后追加serverRSAPublicKeyFile/path/to/public_key.pem课程设计不推荐太重。4.4 现象IDEA 里能 run但导出 WAR 包扔进 Tomcat webapps 后 404原因IDEA 的 Artifact 配置错误。默认Exploded模式只生成目录没打 WAR或WAR archive模式没勾选Include in project build。解决File → Project Structure → Artifacts → → Web Application: Archive → 选你的模块 → Output Layout 标签页确认Available Elements里有WEB-INF/lib/mysql-connector-java-8.0.26.jar和WEB-INF/classes/含编译后的.class文件。Build → Build Artifacts → Build。4.5 现象c:if标签不解析页面原样输出c:if test...原因JSTL jar 包缺失或版本不匹配。Tomcat 8.5 自带jstl-1.2.jar但若你手动删了web/WEB-INF/lib/下的它或用了jstl-1.1.jar不兼容 EL 表达式。解决确认web/WEB-INF/lib/下有jstl-1.2.jar和standard-1.1.2.jarJSTL 1.2 依赖。若无从 Maven Repository 下载jstl:jstl:1.2的 jar 包放入。5. 审批流程闭环用状态机思维实现辅导员操作不写新 Servlet5.1 数据库表结构升级增加 status 字段与审批人字段课程设计验收常要求“辅导员能审批”但很多同学傻傻新增ApproveServlet。其实只需复用原有 Servlet靠request.getParameter(action)区分操作类型。先扩表ALTER TABLE t_leave ADD COLUMN status ENUM(待审批,已批准,已驳回) DEFAULT 待审批, ADD COLUMN approver VARCHAR(20), ADD COLUMN approve_time DATETIME;注意ENUM类型比VARCHAR更安全防止 status 存入非法值如 已通过。approver存辅导员工号非姓名——姓名可能重名工号唯一。5.2 JSP 页面改造同一张表两种按钮逻辑list.jsp请假列表页用c:forEach遍历数据根据status动态渲染按钮c:forEach items${leaveList} varleave tr td${leave.studentId}/td td${leave.studentName}/td td${leave.leaveType}/td td${leave.startTime} 至 ${leave.endTime}/td td${leave.reason}/td td${leave.status}/td td !-- 只有 status待审批 时才显示审批按钮 -- c:if test${leave.status 待审批} form actionLeaveApplyServlet methodpost styledisplay:inline; input typehidden nameid value${leave.id} input typehidden nameaction valueapprove input typesubmit value批准 /form form actionLeaveApplyServlet methodpost styledisplay:inline; input typehidden nameid value${leave.id} input typehidden nameaction valuereject input typesubmit value驳回 /form /c:if /td /tr /c:forEach逻辑说明两个 form 共享actionLeaveApplyServlet但通过nameaction区分意图。styledisplay:inline;让按钮并排显示不换行。5.3 Servlet 统一入口用 if-else 分支处理不同 action在LeaveApplyServlet.doPost()末尾加一段审批逻辑// ... 原有提交逻辑 ... // 新增处理审批动作 String action request.getParameter(action); if (approve.equals(action) || reject.equals(action)) { String id request.getParameter(id); String approver admin; // 实际可从 session 获取登录辅导员工号 try { int result dao.updateStatus(id, action, approver); request.setAttribute(msg, 操作成功); } catch (SQLException e) { request.setAttribute(msg, 操作失败 e.getMessage()); } // 审批后重定向到列表页避免刷新重复提交 response.sendRedirect(request.getContextPath() /jsp/list.jsp); return; // 提前返回不再执行后面的 forward } // ... 原有 forward 逻辑 ...对应的LeaveDao.updateStatus()public int updateStatus(String id, String action, String approver) throws SQLException { String sql UPDATE t_leave SET status ?, approver ?, approve_time NOW() WHERE id ?; try (Connection conn getConnection(); PreparedStatement pstmt conn.prepareStatement(sql)) { if (approve.equals(action)) { pstmt.setString(1, 已批准); } else { pstmt.setString(1, 已驳回); } pstmt.setString(2, approver); pstmt.setString(3, id); return pstmt.executeUpdate(); } }关键技巧审批操作用response.sendRedirect()而非forward()。因为审批是幂等操作点两次批准结果一样但用户刷新页面会重复提交。重定向后浏览器 URL 变成/jsp/list.jsp再刷新只是重新 GET 列表不会二次审批。这是 HTTP 协议层面的防重放比前端加 disabled 按钮更可靠。5.4 最小化登录验证用 session 实现辅导员身份识别课程设计不强制做完整登录系统但需体现“谁审批的”。在list.jsp顶部加% String role (String) session.getAttribute(role); if (!admin.equals(role)) { response.sendRedirect(request.getContextPath() /jsp/login.jsp); return; } %login.jsp就一个表单LoginServlet只做最简校验// LoginServlet.java String username request.getParameter(username); String password request.getParameter(password); if (admin.equals(username) 123456.equals(password)) { request.getSession().setAttribute(role, admin); response.sendRedirect(request.getContextPath() /jsp/list.jsp); } else { request.setAttribute(msg, 用户名或密码错误); request.getRequestDispatcher(/jsp/login.jsp).forward(request, response); }我的习惯课程设计验收时老师大概率用 admin/123456 登录。我把这个账号写在README.txt里和 WAR 包一起交。不搞密码加密、不接真实 LDAP但逻辑闭环——session 有值才放行没值就跳登录页。这就是工程思维用最小成本满足需求边界。希望帮到你。本文还有配套的精品资源点击获取