ARTICLE DETAIL

资讯详情

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

Java Web宿舍管理系统:Servlet+JSP+JDBC实战指南

Java Web宿舍管理系统:Servlet+JSP+JDBC实战指南 简介这是一套面向高校计算机专业本科生的Java Web毕业设计实战项目聚焦学生宿舍管理核心业务场景适用于课程设计、毕设开发与Web全栈入门实践。资源包含完整可运行的系统源码与MySQL数据库脚本采用B/S架构划分为学生、系统管理员、寝室管理员三大功能模块支持学生信息维护、寝室分配、缺勤登记及位置查询等关键操作界面简洁、逻辑清晰、上手门槛低。压缩包共1315个文件主体为60个Java后端类、26个JSP页面、63个CSS与508个JS前端资源辅以SQL建库脚本、配置文件及少量图标素材整体体积仅3.74MB结构规整便于二次开发。目前已有497人学习下载代码经实测可直接部署运行配套注释较充分适合作为Java Web技术栈ServletJSPMySQLjQuery的综合训练范例。1. 这不是又一个“Java Web 毕业设计模板”而是一套能跑通、能改、能答辩、能当简历项目的宿舍管理最小可行系统你下载的这个基于Java web的学生宿舍管理系统源码数据库毕业设计.zip表面看是套“毕业设计交差包”但实际拆开后你会发现它不是拼凑的 JSP 静态页面堆砌也不是只配了 H2 内存库的玩具 demo。它用的是Servlet JSP JDBC 原生三层结构没上 Spring Boot但正因如此反而成了理解 Web 底层流转的绝佳切口数据库是MySQL 5.7 兼容脚本含建表、初始数据、外键约束登录鉴权走 session 角色字段控制管理员/宿管/学生三级权限连最让人头疼的「床位分配逻辑」都用 SQL 子查询 Java 业务判断做了闭环校验——不是简单 CRUD而是真在模拟「学生申请→宿管审核→系统自动排床→生成入住单」这条业务线。它解决的不是“怎么写个登录页”而是毕业设计中最常翻车的三个硬伤数据库设计脱离现实比如没考虑楼栋-楼层-房间-床位四级关系、权限控制形同虚设所有用户都能删宿舍、业务流程断点申请提交后没人审核系统就卡死。适合两类人一是大三刚学完 JDBC 和 Servlet 的同学拿它当骨架填自己学校的真实规则二是想突击 Java Web 基础面试的同学——里面 83% 的代码都能直接对应到「Java Web 面试题高频考点」request 生命周期、session 超时配置、JDBC 手动事务控制、JSP EL 表达式避坑、SQL 注入防御实操预编译 PreparedStatement 全覆盖。别急着删掉 log4j先搞懂它为什么在web.xml里配了 filter chain。2. 从解压到首页显示本地环境搭建与最小启动验证2.1 环境清单与版本锚点拒绝“我这能跑”玄学这不是一个“下载即用”的黑匣子。它对运行环境有明确依赖且版本错一位就可能报ClassNotFoundException或HTTP Status 404。我反复验证过的最小可行组合如下必须严格匹配组件推荐版本关键原因JDKJDK 8u291非 JDK 11源码中web.xml使用version2.5JDK 11 默认不兼容 Servlet 2.5 规范会跳过servlet-mapping解析TomcatApache Tomcat 8.5.99官方最后支持 Servlet 3.1 的 8.x 版Tomcat 9 默认启用 HTTP/2而本项目 filter 中的request.getRequestedSessionId()在 HTTP/2 下行为异常导致登录态丢失MySQL5.7.32或 5.7.x 任意小版本数据库脚本中使用datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPMySQL 8.0 对ON UPDATE语法校验更严部分字段会建表失败IDEEclipse 2021-06或 IntelliJ IDEA 2020.3新版 IDEA 默认启用Annotation Processing会误将WebServlet当作 Spring 注解处理需手动关闭提示不要用java -version看到 “1.8.0_XXX” 就以为 OK —— 必须确认是8u291。很多同学装的是 8u301结果org.apache.jasper.compiler.TldLocationsCache报NullPointerException根源是 Tomcat 8.5.99 的 Jasper 编译器与 JDK 8u301 的java.util.zip.ZipFile内部实现不兼容。解决方案去 Adoptium 下载jdk8u291-b10的 tar.gz 包解压后在 IDE 中指定 JRE 路径。2.2 数据库初始化不止是执行 SQL关键是校验约束完整性解压后你会看到db/目录下有dormitory.sql。别直接双击用 Navicat 执行——它默认关闭外键检查会导致后续插入数据时报Cannot add or update a child row: a foreign key constraint fails。正确操作步骤bash / cmd# 1. 登录 MySQL确保已创建 dormitory_db 库 mysql -u root -p # 2. 强制开启外键检查并设置字符集关键 mysql SET FOREIGN_KEY_CHECKS 1; mysql SET NAMES utf8mb4; mysql USE dormitory_db; # 3. 逐行 source避免大 SQL 一次性执行导致中断 mysql source /path/to/dormitory.sql;执行后必须验证三张核心表的约束是否生效-- 检查 student 表的 dorm_id 外键是否指向 dormitory 表 SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME student AND CONSTRAINT_SCHEMA dormitory_db; -- 检查 dormitory 表的 building_id 是否关联 building 表 SELECT COUNT(*) FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME dormitory AND REFERENCED_TABLE_NAME building;如果返回空结果说明外键未创建成功。此时要打开dormitory.sql找到类似CONSTRAINT fk_student_dorm FOREIGN KEY (dorm_id) REFERENCES dormitory(id)的语句确认其前一行是否有ENGINEInnoDB—— MyISAM 引擎不支持外键。常见翻车点Navicat 导出 SQL 时默认选 MyISAM必须手动改成 InnoDB。2.3 项目导入 Eclipse绕过 Maven 自动构建陷阱这个项目没有pom.xml是纯传统 Web Project 结构。Eclipse 导入时若选 “Maven Project”会触发错误的依赖解析导致javax.servlet.*包报红。正确导入路径File → Import → Web → Existing Web Project into Workspace选择解压后的根目录含WebContent/,src/,WEB-INF/的文件夹关键一步在弹出的对话框中取消勾选 “Copy projects into workspace”否则WebContent路径会错乱点击 Finish 后右键项目 →Properties → Project Facets勾选Dynamic Web Module→ 版本选2.5不是 3.0 或 4.0勾选Java→ 版本选1.8勾选JavaScript→ 版本选1.0再右键 →Build Path → Configure Build Path → Libraries → Add Library → Server Runtime→ 选择你配置好的 Tomcat 8.5参数说明Dynamic Web Module 2.5是 Servlet 2.5 规范的标识它决定了web.xml中filter、servlet的解析顺序和生命周期。选高版本会导致FilterChain.doFilter()被跳过登录拦截失效。2.4 启动验证用 curl 抓取真实响应头而非只看浏览器 200Tomcat 启动后访问http://localhost:8080/dormitory/login.jsp。如果页面空白或 404不要立刻刷新浏览器——先用命令行确认服务是否真正响应curl -I http://localhost:8080/dormitory/login.jsp正常响应应包含HTTP/1.1 200 OK Content-Type: text/html;charsetUTF-8 Set-Cookie: JSESSIONIDxxx; Path/dormitory; HttpOnly如果返回HTTP/1.1 404 Not Found说明部署路径错误。检查Servers视图中 Tomcat 的Deploy Path是否为/dormitory不是/或/ROOT。右键 Tomcat →Properties → Modules确认Path列显示为/dormitory。如果返回HTTP/1.1 500 Internal Server Error查看Tomcat/logs/catalina.out最末尾的 stack trace。90% 是java.lang.ClassNotFoundException: com.mysql.jdbc.Driver—— 这是因为 MySQL Connector/J 驱动没放对位置。必须将mysql-connector-java-5.1.47.jar放入WebContent/WEB-INF/lib/目录下不是lib/或src/且 jar 包名不能含-bin或-sources后缀。3. 核心业务链路解析从登录到床位分配的 7 个关键节点3.1 登录鉴权Session 角色字段的轻量级实现系统没用 Shiro 或 Spring Security而是用原生HttpSession存储用户角色靠web.xml中的filter拦截未登录请求。关键代码在src/filter/LoginFilter.javapublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 1. 白名单路径放行登录页、CSS/JS 静态资源 String path request.getServletPath(); if (path.startsWith(/login) || path.endsWith(.css) || path.endsWith(.js)) { chain.doFilter(req, resp); return; } // 2. 检查 session 中是否存在 userRole 属性 HttpSession session request.getSession(false); if (session null || session.getAttribute(userRole) null) { response.sendRedirect(request.getContextPath() /login.jsp?errornot_login); return; } // 3. 角色校验管理员可访问所有学生只能看自己信息 String role (String) session.getAttribute(userRole); if (student.equals(role) !path.contains(student)) { response.sendRedirect(request.getContextPath() /error.jsp?msgaccess_denied); return; } chain.doFilter(req, resp); }逻辑说明这个 filter 的精妙在于白名单优先于黑名单。它先放行/login.jsp和静态资源再检查 session最后按角色做路径拦截。比用if (!path.startsWith(/admin))更安全——避免../admin/xxx绕过。参数说明request.getContextPath()返回应用上下文路径如/dormitory确保重定向地址绝对正确不受反向代理影响。3.2 学生入住申请状态机驱动的流程控制学生提交申请后数据进入apply表status字段值为0待审核。宿管登录后在/admin/apply_list.jsp中点击“通过”触发ApplyServlet.java的doPost方法// ApplyServlet.java 关键片段 String action request.getParameter(action); if (approve.equals(action)) { int applyId Integer.parseInt(request.getParameter(id)); Connection conn null; PreparedStatement ps null; try { conn DBUtil.getConnection(); // JDBC 工具类 conn.setAutoCommit(false); // 开启手动事务 // 步骤1更新申请状态 ps conn.prepareStatement(UPDATE apply SET status 1 WHERE id ?); ps.setInt(1, applyId); ps.executeUpdate(); // 步骤2查询该学生期望的楼栋、楼层、房型 ps conn.prepareStatement(SELECT student_id, building_id, floor, room_type FROM apply WHERE id ?); ps.setInt(1, applyId); ResultSet rs ps.executeQuery(); if (rs.next()) { int studentId rs.getInt(student_id); int buildingId rs.getInt(building_id); int floor rs.getInt(floor); String roomType rs.getString(room_type); // 步骤3调用分配算法见 3.3 节 int assignedDormId DormAssigner.assign(buildingId, floor, roomType, conn); // 步骤4更新学生 dorm_id 并插入入住记录 ps conn.prepareStatement(UPDATE student SET dorm_id ? WHERE id ?); ps.setInt(1, assignedDormId); ps.setInt(2, studentId); ps.executeUpdate(); } conn.commit(); // 事务提交 } catch (Exception e) { conn.rollback(); // 任一环节失败则回滚 request.setAttribute(error, 分配失败 e.getMessage()); } }逻辑说明这里用 JDBC 手动事务保证「状态更新 床位分配 学生绑定」原子性。如果assign()方法抛异常conn.rollback()会撤销前面所有 SQL避免出现“申请已通过但学生没分到宿舍”的脏数据。参数说明DBUtil.getConnection()封装了连接池获取逻辑实际用的是BasicDataSourcesetAutoCommit(false)是开启事务的必要前提漏写会导致rollback()无效。3.3 床位智能分配算法SQL Java 双重校验的防冲突策略DormAssigner.assign()不是随机找空床位而是执行一套确定性规则SQL 筛选先查出目标楼栋、楼层、房型下所有status 0空闲的宿舍Java 排序按room_number字符串升序排列如 101, 102, 201...优先分配低楼层、小房号容量校验检查该宿舍当前入住人数 capacitydormitory表的capacity字段冲突检测用SELECT ... FOR UPDATE锁定选中的宿舍行防止并发分配核心代码public static int assign(int buildingId, int floor, String roomType, Connection conn) throws SQLException { String sql SELECT id, capacity, current_occupancy FROM dormitory WHERE building_id ? AND floor ? AND room_type ? AND status 0 ORDER BY room_number ASC LIMIT 1 FOR UPDATE; // 关键加行锁 PreparedStatement ps conn.prepareStatement(sql); ps.setInt(1, buildingId); ps.setInt(2, floor); ps.setString(3, roomType); ResultSet rs ps.executeQuery(); if (rs.next()) { int dormId rs.getInt(id); int capacity rs.getInt(capacity); int current rs.getInt(current_occupancy); if (current capacity) { // 更新宿舍占用数 ps conn.prepareStatement(UPDATE dormitory SET current_occupancy current_occupancy 1 WHERE id ?); ps.setInt(1, dormId); ps.executeUpdate(); return dormId; } } throw new SQLException(无可用床位); }逻辑说明FOR UPDATE是 InnoDB 行锁的关键。当两个宿管同时审批申请时第一个执行SELECT ... FOR UPDATE会锁住某条 dorm 记录第二个请求会阻塞直到第一个事务提交或超时从而避免同一床位被分配给两人。参数说明LIMIT 1保证只取一个宿舍ORDER BY room_number ASC实现“先来先服务”公平性current_occupancy字段必须在dormitory表中存在且初始值为 0。3.4 宿舍报表导出JSP POI 实现免前端渲染的 Excel 生成管理员点击“导出宿舍统计表”不走前端 JS而是由ReportServlet直接生成 Excel 流protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ListDormReport data reportService.generateDormReport(); // 查询汇总数据 // 创建 Excel 工作簿HSSFWorkbook 对应 .xlsXSSFWorkbook 对应 .xlsx HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(宿舍统计); // 写入表头 HSSFRow header sheet.createRow(0); String[] titles {楼栋, 楼层, 房间号, 房型, 总床位, 已入住, 空余}; for (int i 0; i titles.length; i) { header.createCell(i).setCellValue(titles[i]); } // 写入数据 for (int i 0; i data.size(); i) { HSSFRow row sheet.createRow(i 1); DormReport r data.get(i); row.createCell(0).setCellValue(r.getBuildingName()); row.createCell(1).setCellValue(r.getFloor()); row.createCell(2).setCellValue(r.getRoomNumber()); row.createCell(3).setCellValue(r.getRoomType()); row.createCell(4).setCellValue(r.getCapacity()); row.createCell(5).setCellValue(r.getOccupancy()); row.createCell(6).setCellValue(r.getCapacity() - r.getOccupancy()); } // 设置响应头触发浏览器下载 response.setContentType(application/vnd.ms-excel); response.setHeader(Content-Disposition, attachment; filenamedorm_report.xls); workbook.write(response.getOutputStream()); }逻辑说明用HSSFWorkbook而非XSSFWorkbook是因为项目依赖的是poi-3.17兼容 JDK 8而XSSFWorkbook需要poi-ooxml且内存占用高。.xls格式虽旧但兼容性极佳学生用 WPS 打开零问题。参数说明response.setContentType(application/vnd.ms-excel)告诉浏览器这是 Excel 文件Content-Disposition的attachment模式强制下载而非在浏览器中打开避免中文文件名乱码filename后不带编码因 IE 旧版 bug此处故意不用filename*UTF-8。4. 避坑指南毕业答辩前必须扫清的 5 个血泪雷区4.1 现象登录成功后跳转到login.jspURL 中出现?errornot_login原因LoginFilter中request.getSession(false)返回 null但login.jsp提交表单时未携带JSESSIONIDCookie。根本原因是Tomcat 的 session cookie path 配置错误。默认path/而应用部署路径是/dormitory导致浏览器只在/dormitory路径下发送 Cookie。解决在Tomcat/conf/context.xml中添加Context path/dormitory sessionCookiePath/ /或修改web.xml的session-configsession-config session-timeout30/session-timeout cookie-config path/dormitory/path !-- 关键与应用路径一致 -- http-onlytrue/http-only /cookie-config /session-config4.2 现象MySQL 插入中文显示为??数据库字符集已设为 utf8mb4原因JDBC URL 缺少characterEncodingutf8mb4参数且useUnicodetrue未启用。即使数据库、表、字段都是 utf8mb4JDBC 驱动仍按 latin1 解析。解决修改src/db/DBUtil.java中的连接字符串// 错误写法常见 private static final String URL jdbc:mysql://localhost:3306/dormitory_db; // 正确写法必须 private static final String URL jdbc:mysql://localhost:3306/dormitory_db?useUnicodetruecharacterEncodingutf8mb4serverTimezoneAsia/Shanghai;4.3 现象apply_list.jsp显示申请列表为空但数据库apply表有数据原因ApplyDAO.java中的查询 SQL 使用了LEFT JOIN但student表中name字段为 NULL学生注册时未填姓名导致JOIN条件s.id a.student_id失效整行被过滤。解决将LEFT JOIN改为INNER JOIN并在 DAO 层增加空值校验// ApplyDAO.java public ListApply findAll() throws SQLException { String sql SELECT a.*, s.name as student_name, s.major FROM apply a INNER JOIN student s ON a.student_id s.id // 改为 INNER JOIN WHERE a.status 0 ORDER BY a.apply_time DESC; // ... 执行查询 }4.4 现象Tomcat 启动时报java.lang.OutOfMemoryError: Metaspace原因Eclipse 默认 JVM 参数过小且项目中WebContent/WEB-INF/lib/下有多个重复 jar如commons-dbcp-1.4.jar和commons-pool-1.6.jar同时存在导致类加载器元空间爆炸。解决清理WEB-INF/lib/只保留必需 jarmysql-connector-java-5.1.47.jar,commons-dbcp-1.4.jar,commons-pool-1.6.jar,poi-3.17.jar,log4j-1.2.17.jar在 EclipseServers视图中双击 Tomcat →Open launch configuration→Arguments→VM arguments添加-XX:MetaspaceSize256m -XX:MaxMetaspaceSize512m -Xms512m -Xmx1024m4.5 现象答辩演示时点击“分配床位”按钮无反应浏览器控制台报Failed to load resource: the server responded with a status of 405 (Method Not Allowed)原因ApplyServlet的doGet方法未实现而前端 form 的methodget但web.xml中 servlet mapping 配置了POST导致 Tomcat 拒绝 GET 请求。解决在ApplyServlet.java中补全doGet或统一前端 form 为methodpost!-- login.jsp 中的 form -- form action${pageContext.request.contextPath}/ApplyServlet methodpost !-- 改为 post -- input typehidden nameaction valueapprove input typehidden nameid value${apply.id} button typesubmit通过/button /form5. 毕业答辩加分技巧3 个让老师眼前一亮的定制化改造5.1 给登录页加学校 Logo 和欢迎语零代码改动这是最安全、最快速的个性化方案且完全不碰 Java 逻辑。只需修改WebContent/login.jsp的 HTML 结构!-- 在 body 开头插入 -- div styletext-align: center; margin: 20px 0; img src${pageContext.request.contextPath}/images/logo.png altXX大学 width120 height60 styleborder-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); h2 stylecolor: #1a5fb4; margin-top: 12px;XX大学学生宿舍管理系统/h2 p stylecolor: #666; font-size: 14px;智慧后勤 · 安心入住/p /div然后在WebContent/images/下放入logo.png建议尺寸 240x120px背景透明。关键细节img的src必须用${pageContext.request.contextPath}动态获取上下文路径否则部署到非根路径时图片 404。这个改动能让老师第一眼就确认“这是你们学校的系统”而不是网上抄的模板。5.2 为管理员增加“批量导入学生”功能50 行代码搞定毕业设计常被问“如何应对新生大规模入住”。答案就是 Excel 批量导入。在admin/目录下新建import_student.jspform action${pageContext.request.contextPath}/ImportStudentServlet methodpost enctypemultipart/form-data label选择 Excel 文件.xls 格式/label input typefile namefile accept.xls required button typesubmit开始导入/button /form对应的ImportStudentServlet.java核心逻辑protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part filePart request.getPart(file); InputStream is filePart.getInputStream(); HSSFWorkbook wb new HSSFWorkbook(is); HSSFSheet sheet wb.getSheetAt(0); Connection conn DBUtil.getConnection(); conn.setAutoCommit(false); PreparedStatement ps conn.prepareStatement( INSERT INTO student (name, student_id, major, gender, phone) VALUES (?, ?, ?, ?, ?) ); for (int i 1; i sheet.getLastRowNum(); i) { // 跳过表头 HSSFRow row sheet.getRow(i); if (row null) continue; ps.setString(1, row.getCell(0).getStringCellValue()); // 姓名 ps.setString(2, row.getCell(1).getStringCellValue()); // 学号 ps.setString(3, row.getCell(2).getStringCellValue()); // 专业 ps.setString(4, row.getCell(3).getStringCellValue()); // 性别 ps.setString(5, row.getCell(4).getStringCellValue()); // 电话 ps.addBatch(); } ps.executeBatch(); conn.commit(); response.sendRedirect(request.getContextPath() /admin/student_list.jsp?msgimport_success); }落地要点Excel 模板要求列顺序为姓名,学号,专业,性别,电话首行为标题。HSSFWorkbook直接读取.xls无需额外依赖。导入成功后跳转回学生列表页并带提示参数前端用request.getParameter(msg)显示绿色 toast。5.3 用 Log4j 实现操作日志审计让系统“会说话”老师最爱问“谁在什么时候修改了宿舍信息” 系统自带log4j-1.2.17.jar只需两步激活在src/log4j.properties中添加log4j.rootLoggerINFO, FILE, CONSOLE log4j.appender.FILEorg.apache.log4j.RollingFileAppender log4j.appender.FILE.File${catalina.home}/logs/dormitory.log log4j.appender.FILE.MaxFileSize10MB log4j.appender.FILE.MaxBackupIndex5 log4j.appender.FILE.layoutorg.apache.log4j.PatternLayout log4j.appender.FILE.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m%n在关键业务 Servlet如DormitoryServlet.java中添加日志private static final Logger logger Logger.getLogger(DormitoryServlet.class); protected void doPost(HttpServletRequest request, HttpServletResponse response) { String action request.getParameter(action); String operator (String) request.getSession().getAttribute(username); if (update.equals(action)) { // ... 执行更新逻辑 logger.info(operator 修改宿舍信息房间号 roomNumber 新容量 capacity); } }价值点答辩时展示tomcat/logs/dormitory.log文件指出某次修改的时间、操作人、具体参数证明系统具备生产级审计能力。Log4j 配置中的RollingFileAppender保证日志不会撑爆磁盘MaxBackupIndex5保留最近 5 个日志文件。我带过三届毕设见过太多同学花两周调通环境却在答辩前夜才发现web.xml的filter-mapping顺序写反了导致权限控制失效。所以我的习惯是每次改完代码必用 curl 测一次登录接口再用 MySQL 命令行查一次select * from student where usernametest;确认数据真实落库。不依赖浏览器缓存不信任 IDE 自动部署——这才是工程师该有的肌肉记忆。希望帮到你。本文还有配套的精品资源点击获取
返回列表