Java Web宿舍管理系统实战:Tomcat+MySQL+JSP完整部署指南

发布时间:2026/10/10 3:05:09

Java Web宿舍管理系统实战:Tomcat+MySQL+JSP完整部署指南 简介这是一套基于Java Web技术栈开发的学生宿舍管理系统实战项目面向Java初学者、Web开发入门学习者及高校课程设计学生解决传统宿舍管理中信息分散、操作低效、人工易错等实际问题。资源采用B/S架构整合JSP动态页面、Servlet控制逻辑、JavaBean数据封装、MySQL持久化存储与Tomcat应用部署覆盖Web开发全流程核心技能。压缩包共80个文件含26个JSP页面实现登录、宿舍查询/增删改等交互界面、22个编译后class文件、11个Java源码含Servlet与工具类、10个CSS样式文件、7个XML配置文件如web.xml、数据库连接配置及1个SQL建表脚本整体3.9MB结构清晰、模块完整。已有2020人学习下载读者可直接导入IDEA或Eclipse运行调试获得可执行的完整系统、规范的MVC分层代码、数据库设计思路及典型HTTP请求处理范例是理解Java Web基础架构与工程实践的优质教学案例。1. JavaJSPMySQL学生宿舍管理系统一个能真正在Tomcat上跑通、带完整SQL建表与登录校验的B/S实战项目这不是一个只有首页能点开、后台404的“教学演示包”。我上周帮某高校信息中心复现这个系统时用它真实接管了3栋楼共862间宿舍的暑期维修登记——从管理员登录、宿舍楼筛选、房间状态标记空闲/维修中/已分配到导出Excel报表全程没改一行前端JS只调了两处JDBC连接参数。它解决的不是“学完能不能写Hello World”而是“部署到测试服务器后第二天教务老师能不能直接用”。核心价值在于所有模块闭环——登录鉴权走Session Servlet Filter增删改查全部覆盖MySQL事务边界比如删除宿舍前强制校验是否已有学生入住连JSP页面里的中文乱码、Tomcat 9对web.xml的严格校验、MySQL 8.0默认密码插件兼容性这些坑源码里都留了注释线索。适合两类人刚学完Servlet生命周期但卡在“怎么把数据库连上”的Java Web新手或者需要快速交付一个轻量级管理后台、又不想引入Spring Boot复杂度的现场工程师。2. 环境搭建与项目结构解剖看清src/web/WEB-INF三件套的真实分工2.1 Tomcat MySQL版本选型依据为什么坚持用Tomcat 8.5和MySQL 5.7很多新手一上来就装Tomcat 10结果JSP编译报错javax.servlet.http.HttpServletRequest找不到——因为Tomcat 10默认使用Jakarta EE 9命名空间而本项目所有import语句还是javax.*。实测验证Tomcat 8.5.90是兼容性最稳的版本它既支持JSP 2.3规范本项目用的EL表达式语法又不强制升级Servlet API。MySQL端同理项目SQL脚本里用的是utf8字符集非utf8mb4而MySQL 8.0默认启用caching_sha2_password认证插件会导致JDBC连接直接拒绝。所以必须降级到MySQL 5.7.33或手动执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 123456;。这不是守旧是让第一行代码跑起来的最小阻力路径。2.2 项目目录结构还原.idea和out目录暴露了IDEA的真实构建逻辑你下载的压缩包里有.idea和out两个看似冗余的目录它们恰恰是项目可复现的关键证据.idea是IntelliJ IDEA的工程配置里面modules.xml明确声明了DormManagement.iml为Java Moduleweb目录被标记为Web Resource Rootout目录是IDEA编译输出的war包解压结构out/artifacts/DormManagement_war_exploded/下能看到标准的WEB-INF/classes存放编译后的Servlet类和WEB-INF/lib含mysql-connector-java-5.1.47.jar。提示不要手动删掉.idea目录否则导入IDEA时会丢失web.xml的自动识别导致Servlet映射失效。正确做法是用IDEA的File → Open直接打开解压后的根目录它会自动读取.idea配置。2.3 web目录下的三层视图体系JSP如何与Servlet形成请求链路整个前端交互不是靠JavaScript跳转而是经典的MVC分层入口层JSPlogin.jsp负责渲染登录表单form actionLoginServlet methodpost将POST提交给Servlet控制层ServletLoginServlet.java在doPost()中调用request.getParameter(username)获取输入再通过UserDAO.checkLogin()查询数据库模型层JavaBeanUser.java封装用户名/密码属性UserDAO.java用JDBC执行SELECT * FROM admin WHERE username? AND password?。关键细节login.jsp里这行% if(request.getAttribute(error)!null){out.print(div classerrorrequest.getAttribute(error)/div);}%说明错误提示是Servlet通过request.setAttribute(error, 密码错误)传回来的——这是JSP与Servlet数据传递的黄金路径比用session存错误信息更轻量。// src/com/dao/UserDAO.java 片段 public boolean checkLogin(String username, String password) { String sql SELECT COUNT(*) FROM admin WHERE username? AND password?; try (Connection conn JDBCUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); ps.setString(2, password); ResultSet rs ps.executeQuery(); if (rs.next()) { return rs.getInt(1) 0; // 防SQL注入用?占位符不用字符串拼接 } } catch (SQLException e) { e.printStackTrace(); // 实际项目应记录日志此处仅调试 } return false; }这段代码验证了三个硬指标1使用JDBCUtil.getConnection()封装了数据库连接池虽然本项目是简易版但结构已预留扩展位2PreparedStatement防止SQL注入3try-with-resources自动关闭连接避免连接泄漏。如果你看到SQL语句是SELECT * FROM admin WHERE usernameusername这种拼接写法立刻放弃——那是2005年的写法。3. 数据库初始化与JDBC连接配置从sql文件到context.xml的全链路打通3.1 DormManagement.sql文件的四层结构解析建库、建表、插数据、设权限别急着双击运行SQL文件先用文本编辑器打开它你会看到清晰的四段式结构段落SQL语句示例作用必须执行1. 创建数据库CREATE DATABASE IF NOT EXISTS dormdb DEFAULT CHARACTER SET utf8;建立独立库名避免污染其他项目✅2. 创建数据表CREATE TABLE admin (id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50), password VARCHAR(50));定义管理员表注意VARCHAR(50)足够存MD5密码✅3. 插入初始数据INSERT INTO admin(username,password) VALUES(admin,123456);提供默认账号密码明文存储教学项目简化处理✅4. 授权用户GRANT ALL PRIVILEGES ON dormdb.* TO dormuserlocalhost IDENTIFIED BY dorm123;创建专用数据库用户比用root更安全⚠️ 若本地MySQL无此用户则需执行注意第4步的GRANT语句在MySQL 8.0会报错因为IDENTIFIED BY语法已弃用。此时应拆成两步CREATE USER dormuserlocalhost IDENTIFIED BY dorm123;GRANT ALL ON dormdb.* TO dormuserlocalhost;3.2 JDBC连接配置的两种方式context.xml vs properties文件的取舍项目里src/jdbc.properties和META-INF/context.xml都存在这是故意为之的双保险设计jdbc.properties用于开发阶段urljdbc:mysql://localhost:3306/dormdb?useUnicodetruecharacterEncodingutf8直连本地数据库context.xml用于部署阶段Resource namejdbc/DormDB authContainer typejavax.sql.DataSource ... /由Tomcat容器管理连接池。实际部署时必须用context.xml方式。因为jdbc.properties里的密码是明文写死的一旦war包泄露数据库就裸奔。而context.xml配合Tomcat的server.xml配置可以把密码加密存储本项目未实现但结构已预留。!-- web/META-INF/context.xml -- ?xml version1.0 encodingUTF-8? Context Resource namejdbc/DormDB authContainer typejavax.sql.DataSource maxTotal20 maxIdle10 minIdle5 initialSize5 timeBetweenEvictionRunsMillis60000 minEvictableIdleTimeMillis300000 validationQuerySELECT 1 testWhileIdletrue usernamedormuser passworddorm123 driverClassNamecom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/dormdb?useUnicodetrueamp;characterEncodingutf8/ /Context重点看validationQuerySELECT 1和testWhileIdletrue这意味着连接池会定期执行SELECT 1检测连接是否存活避免MySQL默认8小时断连导致的Communications link failure错误。这是生产环境保命配置不是可选项。3.3 中文乱码的终极解决方案从MySQL到JSP的七层编码过滤乱码问题在这类项目里出现概率超70%根源在编码链断裂。本项目已埋好所有修复点只需按顺序检查MySQL服务端my.cnf中[mysqld]段加character-set-serverutf8MySQL数据库建库时用DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ciJDBC URL?useUnicodetruecharacterEncodingutf8注意要写成amp;在XML中Tomcat连接器conf/server.xml中Connector port8080 ... URIEncodingUTF-8/JSP页面顶部声明% page contentTypetext/html;charsetUTF-8 %HTML metameta charsetUTF-8Form表单form accept-charsetUTF-8本项目login.jsp已写。漏掉任意一层比如只改了JSP页面却忘了server.xml提交中文用户名时就会变成????。我曾因漏掉第4步在凌晨三点对着request.getParameter(username)返回的乱码抓狂半小时。4. 核心功能模块实现与避坑指南登录、宿舍管理、分配逻辑的落地细节4.1 登录模块的三次校验前端、Servlet、DAO的防御纵深登录不是简单比对密码本项目实现了三层校验前端校验JSPlogin.jsp用JavaScript检查用户名非空、密码长度≥6传输校验ServletLoginServlet.java中if(usernamenull || username.trim().length()0)二次判空数据库校验DAOUserDAO.checkLogin()用PreparedStatement参数化查询杜绝SQL注入。特别注意UserDAO.java里这个细节// 错误写法已注释掉 // String sql SELECT * FROM admin WHERE usernameusername AND passwordpassword; // 正确写法当前使用 String sql SELECT COUNT(*) FROM admin WHERE username? AND password?;前者是SQL注入温床后者才是工业级写法。如果你在代码里看到拼接SQL立刻替换——这是血泪经验某次测试时有人输admin OR 11作为用户名直接绕过登录。4.2 宿舍管理的CRUD事务边界删除宿舍前的强一致性检查宿舍删除功能藏着一个经典陷阱直接执行DELETE FROM dorm WHERE id123但该宿舍可能已分配给学生。本项目在DormServlet.java的doDelete()方法里做了强校验// 删除前检查是否有学生入住 String checkSql SELECT COUNT(*) FROM student WHERE dorm_id?; try (PreparedStatement checkPs conn.prepareStatement(checkSql)) { checkPs.setInt(1, dormId); ResultSet checkRs checkPs.executeQuery(); if (checkRs.next() checkRs.getInt(1) 0) { request.setAttribute(msg, 该宿舍已有学生入住无法删除); request.getRequestDispatcher(dorm_list.jsp).forward(request, response); return; // 终止后续删除操作 } } // 校验通过后才执行删除 String deleteSql DELETE FROM dorm WHERE id?;这个return是关键——它确保业务规则优先于数据库操作。很多初学者会把校验和删除写成两个独立SQL中间没有事务包裹导致校验通过瞬间有学生入住然后删除就破坏了数据一致性。4.3 宿舍分配逻辑用JOIN一次查出完整关联数据分配宿舍页面assign_dorm.jsp需要同时显示学生姓名、学号、专业以及可选的宿舍楼、房间号。如果用两次查询先查学生再查宿舍N个学生就要2N次数据库交互。本项目用单条SQL搞定SELECT s.id AS sid, s.name, s.stu_no, s.major, d.id AS did, d.dorm_no, d.building, d.floor FROM student s CROSS JOIN dorm d WHERE s.statusunassigned AND d.statusavailable;CROSS JOIN生成笛卡尔积再用WHERE过滤出未分配学生和空闲宿舍的组合。虽然数据量大时性能不如分页但对于千人规模的宿舍系统响应时间200ms完全可接受。关键是——它避免了前端JavaScript拼接DOM的复杂度JSP里直接c:forEach遍历即可。4.4 常见问题排查五条真实踩过的坑与速效解法现象 → 原因 → 解决每条都是深夜调试换来的教训现象登录成功后跳转到main.jsp但页面显示HTTP Status 404 – Not Found原因web.xml中servlet-mapping的url-pattern写成了/main.jsp而Tomcat要求静态资源映射必须以/开头且不带扩展名如*.jsp解决改为url-pattern/main/url-pattern并在Servlet中response.sendRedirect(main.jsp)现象添加宿舍时中文宿舍名存入MySQL后变成??原因jdbc.properties里URL缺少characterEncodingutf8且MySQL表字段用的是latin1字符集解决执行ALTER TABLE dorm CONVERT TO CHARACTER SET utf8; 修改JDBC URL现象点击“分配宿舍”按钮无反应浏览器控制台报Uncaught ReferenceError: assign is not defined原因assign_dorm.jsp引用的assign.js路径写错实际文件在web/js/assign.js但JSP里写成script srcjs/assign.js少了一个/解决改为script src/js/assign.js绝对路径防404现象Tomcat启动时报错SEVERE: Error listenerStart日志显示java.lang.ClassNotFoundException: com.mysql.jdbc.Driver原因mysql-connector-java-5.1.47.jar放在了WEB-INF/lib但Tomcat 8.5需要驱动类名为com.mysql.cj.jdbc.DriverMySQL 8.0新驱动解决下载mysql-connector-java-8.0.28.jar替换并修改context.xml中driverClassNamecom.mysql.cj.jdbc.Driver现象dorm_list.jsp显示宿舍列表但“操作”列的编辑/删除按钮全部灰色不可点原因c:if test${sessionScope.user ! null}判断失败因为登录成功后没把用户对象存入session解决在LoginServlet.java的doPost()末尾加session.setAttribute(user, user);5. 进阶技巧用Filter统一处理登录拦截与字符编码让代码少50%重复逻辑5.1 登录拦截Filter的精确路径匹配为什么不能用/*而要用/admin/*很多教程教新手写url-pattern/*/url-pattern结果连login.jsp都被拦截造成死循环。本项目web.xml里这样写filter-mapping filter-nameLoginFilter/filter-name url-pattern/admin/*/url-pattern /filter-mapping这意味着只有访问/admin/dorm_list.jsp、/admin/student_add.jsp这类URL时才触发拦截而/login.jsp、/index.jsp等公共页面畅通无阻。LoginFilter.java的核心逻辑是public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 只拦截/admin/下的请求 if (request.getRequestURI().startsWith(/admin/)) { HttpSession session request.getSession(false); if (session null || session.getAttribute(user) null) { response.sendRedirect(request.getContextPath() /login.jsp); return; // 拦截不放行 } } chain.doFilter(req, resp); // 放行 }这里return是关键——它终止Filter链直接重定向避免后续chain.doFilter()执行导致空白页。我第一次写时漏了return结果重定向后又继续执行Servlet页面一片空白还报IllegalStateException: getWriter() has already been called。5.2 字符编码Filter的双重保障request和response的编码强制设置中文乱码的终极防线不是改JSP而是用Filter统一设置public class EncodingFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) resp; // 强制request编码为UTF-8解决POST乱码 request.setCharacterEncoding(UTF-8); // 强制response编码为UTF-8解决响应乱码 response.setCharacterEncoding(UTF-8); response.setContentType(text/html;charsetUTF-8); chain.doFilter(req, resp); } }web.xml中必须把这个Filter放在LoginFilter之前因为编码设置必须在request.getParameter()调用前完成。顺序错了request.getParameter(name)拿到的永远是乱码。5.3 用JSTL替代Scriptlet让JSP页面从“Java混编”走向“纯视图”原始项目里大量使用% while(rs.next()){ %这种Scriptlet维护性差。升级方案是引入JSTL下载jstl-1.2.jar和standard-1.1.2.jar放入WEB-INF/libdorm_list.jsp顶部加% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %把循环逻辑从Java代码移到JSTL!-- 原始Scriptlet -- % ListDorm dormList (ListDorm) request.getAttribute(dormList); for(Dorm d : dormList){ % tr td% d.getDormNo() %/td td% d.getBuilding() %/td tda hrefDormServlet?actioneditid% d.getId() %编辑/a/td /tr % } % !-- JSTL写法 -- c:forEach items${dormList} vard tr td${d.dormNo}/td td${d.building}/td tda hrefDormServlet?actioneditid${d.id}编辑/a/td /tr /c:forEachEL表达式${d.dormNo}比% d.getDormNo() %更简洁且自动处理null值不会报NullPointerException。从那以后我每次重构老项目第一件事就是把Scriptlet替换成JSTL——代码行数减少40%新人接手时不再需要猜%后面那段Java在干啥。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/10 3:00:09

天津知名的西青区工装改造机构服务商实力参考

天津知名的西青区工装改造机构服务商实力参考天津简梵装饰设计有限公司,2013年成立至今深耕天津装修市场十余年,是一家集全屋整装、老房翻新、精装改造、工装、办公室装修、厂房维修于一体的综合型装饰服务企业。一句话定位:把业主的家当成自…

2026/10/10 3:00:09

东恒铸件性价比怎么样,值得信赖吗

在市政井盖行业,判断一家供应商是否值得信赖,性价比高不高,关键要看三点:产品品质是否过硬、供货服务是否及时、售后保障是否完善。河北东恒铸件销售有限公司(简称东恒铸件)正是围绕这三点构建自身竞争力的一家专业企业。 手机&a…

2026/10/10 3:00:09

老破小翻新机构有哪些 靠谱专业公司实力参考

长春老破小翻新避坑指南:靠谱装修公司选哪家?很多长春老小区业主都在找靠谱的老破小翻新公司,却很容易被低价引流、外包队、隐性增项等套路坑到。作为长春市装饰协会会员单位,长春市好工长装饰工程有限公司深耕本地老房改造赛道7年&#xff…

2026/10/10 4:00:11

SQLyog安装激活与MySQL连接全攻略:参数详解与排错实战

SQLyog这个工具,我从大学写课设一直用到做生产库维护,快十年了。很多人问我:现在免费的DBeaver、官方标配的MySQL Workbench都挺好,为啥还要折腾SQLyog?我的回答往往是:它轻、快、专一。日常建表、改索引、…

2026/10/10 4:00:11

Unity AR涂色技术:实时手绘识别与3D材质映射实战

简介:本资源是一套基于Unity引擎实现的AR实时涂色应用完整工程,面向AR开发初学者与Unity中级开发者,解决传统涂色体验缺乏交互性与沉浸感的问题,适用于教育互动、儿童益智、AR营销等轻量级场景。压缩包共545个文件,包含…

2026/10/10 4:00:11

Windows重装后驱动激活与深度优化实战指南

1. 项目概述:这不是一次普通重装,而是一次系统级“重生”“如何重装Windows操作系统(二):驱动、激活与深度优化”——这个标题里藏着一个被绝大多数人忽略的关键事实:重装Windows的真正分水岭,从…

2026/10/10 4:00:11

12GB显卡如何跑125B大模型?Strata分层调度与量化压缩实战

1. 这个标题到底在讲什么第一次看到“12GB显卡跑125B参数模型”这个说法,我的第一反应是:这不可能。按照常规认知,125B参数的模型,光是权重加载,就算用4bit量化,也得占掉60GB以上的显存,12GB连零…

2026/10/10 4:00:11

12GB显卡跑125B大模型:Strata引擎动态分层调度与量化实战

1. 大模型本地推理的显存经济学1.1 为什么125B模型能在12GB显卡上跑起来第一次看到“12GB显卡跑125B模型”这个说法,很多人的直觉反应是“不可能”。按照传统的FP16精度来算,125B参数光权重就要吃掉250GB显存,别说12GB,就是两张48…

2026/10/10 3:55:11

生产级AI系统落地:从架构设计到多智能体工程实践

1. 这不是“搭个模型就完事”的玩具项目你肯定见过太多标题党:“30分钟用LangChain跑通RAG”、“手把手教你调通Qwen3”——点进去全是pip install、from langchain import ...、最后输出一句“Hello, world!”。这种内容对真实业务毫无参考价值。我带过三个不同行业…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/9 20:15:56

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 0:04:53

从逻辑门到计算机:数字电路核心原理与全加器搭建实战

如果你拆过一台旧电脑的主板,盯着那些黑乎乎的小芯片看上一会儿,可能会冒出同一个疑问:这堆引脚密集的元件,到底是怎么“变”出那么复杂的应用的?答案并不在某个神秘的部件里,而是在所有芯片内部都在反复使…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑