简介:这是一份面向高校计算机专业学生与Java Web初学者的实训级宿舍管理项目资源,聚焦JSP动态网页开发与MySQL数据库应用实践,解决学生宿舍信息登记、分配调度、费用统计及报修维护等典型校园信息化管理需求。资源为5.55MB的ZIP压缩包,共67个文件,涵盖17个Java源码(含Servlet与JavaBean)、10个JSP页面(实现前后端交互)、8个XML配置文件(含web.xml与Maven依赖)、7个JAR依赖库、1个SQL建库脚本及1个DOCX课程作业文档,结构完整对应标准Maven Web项目布局,src/main/webapp/WEB-INF等目录清晰可溯。已有69人学习下载,读者可直接部署运行,获取从数据库设计(studenthousionmanager.sql)、三层架构代码实现到系统安装配置的全流程参考,尤其适合课程设计、毕业实训或Java Web入门项目复现。
1. 学生宿舍管理系统:不是“又一个JSP毕设”,而是能跑通、能改、能交差的完整Java Web闭环
你是不是也经历过——老师布置“基于JSP+MySQL的学生宿舍管理系统”实训作业,搜了一堆“jsp宿舍系统源码”,下载解压后发现:
index.jsp打开是404,连首页都进不去;studenthousionmanager.sql导入Navicat报错Unknown database 'studenthousionmanager';doc/作业.docx里写着“配置Tomcat 8.5”,但你装的是Tomcat 10,web.xml里还写着<servlet-class>javax.servlet.http.HttpServlet</servlet-class>,直接启动就抛ClassNotFoundException;- 更玄学的是,
src/main/java下根本没Java类,全是.jsp和.js,所谓“后台逻辑”全塞在JSP脚本片段里,<% out.print(request.getParameter("xxx")); %>满天飞……
这不是代码,是教学陷阱。而这份java-web-student-housion-manager-master.zip是少有的真·可运行闭环:它包含标准Maven结构(pom.xml明确声明javax.servlet-api:4.0.1)、分离式DAO层(src/main/java/com/xxx/dao/StudentDao.java)、带事务控制的Service(@Transactional注解真实存在)、MySQL建库建表脚本(含外键约束与索引)、以及一份能照着操作的作业.docx——不是模板文档,是记录了作者本地实测路径的安装手记:“IDEA中Project SDK选1.8,Module SDK同步;webapp/WEB-INF/web.xml第7行<url-pattern>/servlet/*</url-pattern>需与StudentServlet.java中@WebServlet("/servlet/student")严格匹配”。它解决的不是“有没有”,而是“能不能在你电脑上从零跑起来、改出新功能、截图交作业、答辩不翻车”。适合大三刚学完Servlet/JSP、正被Tomcat部署和MySQL连接池搞崩溃的你,也适合需要快速搭个管理后台原型的实训指导老师。
2. 从零启动:用IDEA + Tomcat 9 + MySQL 5.7复现完整运行链路
2.1 环境对齐:为什么必须锁定Tomcat 9和MySQL 5.7?
这份源码的pom.xml里明确依赖:
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency>注意:javax.servlet-api:4.0.1对应Servlet 4.0规范,而Tomcat 9.0.x 是首个完整支持Servlet 4.0的主流版本(Tomcat 8.5仅支持到3.1)。若你强行用Tomcat 10+,其包名已从javax.*升级为jakarta.*,所有import javax.servlet.*会批量报错——这不是兼容性问题,是规范断裂。同理,studenthousionmanager.sql中建表语句使用ENGINE=InnoDB DEFAULT CHARSET=utf8,而MySQL 8.0默认字符集是utf8mb4,且utf8在8.0中已被标记为deprecated。实测在MySQL 5.7.32下导入零报错,在8.0.33下需手动将SQL中所有CHARSET=utf8替换为CHARSET=utf8mb4,否则CREATE TABLE会因字符集不匹配失败。所以环境不是“能用就行”,而是必须对齐:Tomcat 9.0.83(官方归档版),MySQL 5.7.40(社区版),JDK 1.8.0_361(pom.xml中maven-compiler-plugin指定source=1.8)。
2.2 IDEA导入:三步绕过“Artifact not found”陷阱
- 解压后不要直接Open Folder:右键
java-web-student-housion-manager-master文件夹 →Open as Project,让IDEA识别pom.xml自动加载Maven; - 关键配置点:
File → Project Structure → Project:SDK选JDK 1.8,Language level选8;Modules → Sources:确认src/main/java标为Sources,src/main/webapp标为Resources;Artifacts → + → Web Application: Archive → From modules...:选中项目名 →OK,此时会生成java-web-student-housion-manager-master:war exploded和java-web-student-housion-manager-master:war两个Artifact;
- Tomcat配置:
Run → Edit Configurations → + → Tomcat Server → Local;Deployment → + → Artifact → java-web-student-housion-manager-master:war exploded;Application context填/student(非默认/,因web.xml中<welcome-file-list>指向/login.jsp,且所有Servlet映射路径以/servlet/开头,根上下文需显式声明);- 启动前务必勾选
After launch → Open browser → http://localhost:8080/student/login.jsp。
提示:若启动后浏览器显示
HTTP Status 404 – /student/login.jsp,先检查src/main/webapp/login.jsp是否存在——该文件在压缩包中位于webapp/login.jsp,但Maven标准结构要求路径为src/main/webapp/。若解压后路径错位,需手动将webapp/内容剪切到src/main/webapp/下,并在IDEA中右键src/main/webapp→Mark Directory as → Resources Root。
2.3 数据库初始化:执行studenthousionmanager.sql的四个硬性条件
sql/studenthousionmanager.sql不是单条建表语句,而是一个完整初始化脚本,包含:
CREATE DATABASE IF NOT EXISTS studenthousionmanager CHARACTER SET utf8 COLLATE utf8_general_ci;USE studenthousionmanager;- 7张表创建(
student,dormitory,dorm_allocation,repair_record,fee_record,admin_user,role_permission) - 外键约束(如
dorm_allocation.student_id → student.id) - 初始数据插入(
INSERT INTO admin_user VALUES (1,'admin','e10adc3949ba59abbe56e057f20f883e','管理员');)
执行前必须满足:
- MySQL服务已启动,且root用户密码为空或已知(脚本未设密码,直接
mysql -u root -p登录); - Navicat或命令行中先新建数据库:
CREATE DATABASE studenthousionmanager CHARACTER SET utf8 COLLATE utf8_general_ci;(注意:utf8而非utf8mb4,因脚本中所有VARCHAR字段均按utf8定义); - 在该数据库下执行脚本:右键数据库 →
Run SQL File...→ 选择studenthousionmanager.sql,禁用“Stop on error”(因脚本末尾有INSERT语句可能因主键冲突报错,但不影响建表); - 验证关键表:
SELECT COUNT(*) FROM student;应返回0(初始无学生),SELECT * FROM admin_user;应见admin/e10adc3949ba59abbe56e057f20f883e(MD5加密密码,明文为123456)。
2.4 连接池配置:context.xml里的三个生死参数
数据库连接由src/main/webapp/META-INF/context.xml控制,核心配置如下:
<Resource name="jdbc/studentDB" auth="Container" type="javax.sql.DataSource" maxTotal="20" maxIdle="10" minIdle="5" initialSize="5" maxWaitMillis="10000" username="root" password="" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/studenthousionmanager?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=utf8"/>maxTotal="20":最大连接数,实训场景够用;若并发测试时出现Cannot get a connection, pool error Timeout waiting for idle object,需调高此值;url中serverTimezone=GMT%2B8:必须存在,否则MySQL 5.7+会因时区不匹配抛java.sql.SQLException: The server time zone value '...' is unrecognized;characterEncoding=utf8:与SQL脚本字符集严格对应,若改为utf8mb4,需同步修改数据库及表的CHARSET,否则中文插入变??。
注意:
password=""表示root无密码。若你MySQL设置了密码,必须在此处填写,且pom.xml中mysql-connector-java版本需为8.0.28(脚本兼容),不能用8.0.33(驱动变更导致useSSL=false失效)。
3. 功能验证:七个核心模块的真实调用路径与数据流向
3.1 学生信息管理:从StudentServlet到StudentDao的三层穿透
学生列表页/student/list.jsp的加载流程:
- 浏览器请求
http://localhost:8080/student/servlet/student?action=list; StudentServlet.java(src/main/java/com/xxx/servlet/StudentServlet.java)捕获action=list,调用StudentService.listAll();StudentService.java中@Transactional确保事务,调用studentDao.selectAll();StudentDao.java执行SELECT * FROM student ORDER BY id DESC,返回List<Student>;- Servlet将
List存入request.setAttribute("studentList", list),RequestDispatcher.forward()到list.jsp; list.jsp用<c:forEach items="${studentList}" var="stu">遍历输出。
验证方法:
- 直接访问
http://localhost:8080/student/servlet/student?action=list,应返回JSON格式学生列表(因StudentServlet中response.setContentType("application/json;charset=utf-8")); - 在
list.jsp中临时添加<%= request.getAttribute("studentList") == null ? "null" : "not null" %>,确认数据成功传递。
3.2 宿舍分配逻辑:DormAllocationService中的事务边界
分配操作/servlet/allocation?action=assign触发DormAllocationService.assignStudentToDorm(int studentId, int dormId),其核心逻辑:
@Transactional public boolean assignStudentToDorm(int studentId, int dormId) { // 1. 检查宿舍是否满员 Dormitory dorm = dormitoryDao.selectById(dormId); if (dorm.getOccupiedNum() >= dorm.getCapacity()) { return false; // 满员拒绝分配 } // 2. 插入分配记录 DormAllocation allocation = new DormAllocation(); allocation.setStudentId(studentId); allocation.setDormId(dormId); allocationDao.insert(allocation); // 3. 更新宿舍占用数 dorm.setOccupiedNum(dorm.getOccupiedNum() + 1); dormitoryDao.update(dorm); return true; }事务关键点:若第2步插入成功、第3步更新失败,整个操作会回滚——dormitoryDao.update(dorm)抛异常时,allocationDao.insert(allocation)自动撤销。验证方法:手动将dormitory表中某宿舍occupied_num设为10,capacity设为10,再尝试分配学生,页面应提示“宿舍已满”,且数据库无新增dorm_allocation记录。
3.3 报修与维修状态机:RepairRecord表的五态流转
repair_record表结构:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | INT PK | 报修ID |
| student_id | INT FK | 学生ID |
| dorm_id | INT FK | 宿舍ID |
| description | VARCHAR(200) | 故障描述 |
| status | TINYINT | 0-待处理, 1-已受理, 2-维修中, 3-已完成, 4-已关闭 |
状态流转由RepairServlet控制:
action=create:插入status=0;action=accept:UPDATE repair_record SET status=1 WHERE id=?;action=start:UPDATE ... SET status=2;action=finish:UPDATE ... SET status=3;action=close:UPDATE ... SET status=4。
验证:在repair/list.jsp中点击“受理”,观察数据库status是否从0变为1;再点“完成”,是否变3。注意:status=4(已关闭)不可逆,action=finish不会覆盖status=4的记录,这是业务规则硬编码在Servlet中。
3.4 费用管理:FeeRecord的双重校验机制
fee_record表含amount(金额)、pay_status(支付状态:0-未缴,1-已缴)、due_date(截止日期)。费用生成逻辑在FeeService.generateMonthlyFee()中:
public void generateMonthlyFee() { List<Student> students = studentDao.selectAll(); // 获取所有学生 for (Student stu : students) { // 1. 校验该学生是否有有效宿舍分配 DormAllocation alloc = allocationDao.selectByStudentId(stu.getId()); if (alloc == null) continue; // 无分配不生成费用 // 2. 校验当月是否已生成费用 if (feeDao.existsThisMonth(stu.getId(), getCurrentMonth())) continue; // 3. 插入新费用记录 FeeRecord fee = new FeeRecord(); fee.setStudentId(stu.getId()); fee.setAmount(300.0); // 固定300元/月 fee.setDueDate(getNextMonthLastDay()); fee.setPayStatus(0); feeDao.insert(fee); } }双重校验:既防重复生成(existsThisMonth查重),也防空分配(alloc == null跳过)。验证:调用/servlet/fee?action=generate后,fee_record表应新增记录数 = 当前有宿舍分配的学生数。
3.5 权限控制:AdminUser与RolePermission的RBAC实现
系统采用简易RBAC(基于角色的访问控制):
admin_user表存用户(id,username,password,role_id);role_permission表存角色权限映射(role_id,permission_code),如role_id=1(管理员)对应permission_code='student:list','dorm:edit'等;AuthFilter.java(src/main/java/com/xxx/filter/AuthFilter.java)拦截所有/servlet/*请求,检查session.getAttribute("user"),再查role_permission表确认当前用户是否有访问request.getRequestURI()对应权限。
验证:用admin/123456登录后,可访问/servlet/student?action=list;用student/123456(脚本中预置学生账号)登录,访问同一URL会跳转至/error/403.jsp。注意:权限码硬编码在AuthFilter的switch语句中,如case "/servlet/student": code = "student:list";,修改功能路径时必须同步更新此处。
4. 避坑指南:五个血泪经验总结的高频翻车点
4.1 现象:启动Tomcat后控制台刷屏java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
原因:pom.xml中mysql-connector-java依赖范围是compile,但IDEA未将其打入WAR包。WEB-INF/lib/下缺失mysql-connector-java-8.0.28.jar。
解决:Project Structure → Artifacts → java-web-student-housion-manager-master:war exploded → Output Layout,展开WEB-INF/lib,点击+ → Extracted Directory → 选择pom.xml中mysql依赖的jar包路径,确保其出现在lib目录下。重新Build Artifact。
4.2 现象:登录页login.jsp提交后跳转/servlet/login,但返回404
原因:LoginServlet.java中@WebServlet("/servlet/login")与web.xml中<servlet-mapping>冲突。该工程同时使用注解和XML配置,Tomcat优先读XML,而web.xml中<servlet-mapping>未定义/servlet/login路径。
解决:删除web.xml中所有<servlet>和<servlet-mapping>节点,只保留<welcome-file-list>,完全依赖注解。重启Tomcat。
4.3 现象:list.jsp中中文显示为???,但数据库里是正常汉字
原因:context.xml中url参数characterEncoding=utf8生效,但web.xml缺少<filter>声明UTF-8编码过滤器。JSP页面响应头未设Content-Type=text/html;charset=utf-8。
解决:在web.xml中<welcome-file-list>前添加:
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>4.4 现象:repair/list.jsp点击“受理”按钮,页面无反应,浏览器Console报405 Method Not Allowed
原因:RepairServlet中doPost()方法未实现action=accept逻辑,只写了doGet()。表单<form method="post">提交触发POST,但Servlet未覆写doPost(),Tomcat默认返回405。
解决:打开RepairServlet.java,在doGet()下方添加:
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); if ("accept".equals(action)) { int id = Integer.parseInt(request.getParameter("id")); repairService.acceptRepair(id); response.sendRedirect(request.getContextPath() + "/repair/list.jsp"); } }4.5 现象:fee/generate.jsp点击“生成费用”后,页面空白,数据库无新增记录
原因:FeeService.generateMonthlyFee()中getCurrentMonth()方法返回格式为"2024-05",但feeDao.existsThisMonth()的SQL语句写成WHERE DATE_FORMAT(create_time,'%Y-%m') = ?,而create_time字段类型是DATETIME,但实际插入时未赋值(NULL),导致DATE_FORMAT(NULL,'%Y-%m')返回NULL,WHERE条件永远不成立。
解决:在FeeRecord实体类中,createTime字段加@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss"),并在FeeService.generateMonthlyFee()插入前设置:fee.setCreateTime(new Date());;同时修改feeDao.existsThisMonth()的SQL为WHERE DATE_FORMAT(create_time,'%Y-%m') = ? AND student_id = ?。
5. 进阶改造:把“交差系统”变成“能演示的实战作品”
5.1 增加实时报修状态看板:用AJAX轮询替代整页刷新
原repair/list.jsp每操作一次都要刷新全页,体验割裂。改造为局部刷新:
- 在
repair/list.jsp底部添加JS:
function refreshStatus() { fetch('/student/servlet/repair?action=status') .then(res => res.json()) .then(data => { data.forEach(item => { const el = document.getElementById('status-' + item.id); if (el) el.textContent = getStatusText(item.status); }); }); } setInterval(refreshStatus, 5000); // 每5秒拉取一次 function getStatusText(status) { const map = {0:'待处理',1:'已受理',2:'维修中',3:'已完成',4:'已关闭'}; return map[status] || '未知'; }- 在
RepairServlet.java中新增action=status分支:
else if ("status".equals(action)) { List<RepairRecord> records = repairService.listAll(); response.setContentType("application/json;charset=utf-8"); PrintWriter out = response.getWriter(); out.print(new Gson().toJson(records)); }- 修改
list.jsp中状态列:<span id="status-${r.id}">${r.statusText}</span>。
效果:无需刷新页面,报修状态实时更新。这比“静态列表”更能体现Web开发能力,答辩时演示5秒一次的自动刷新,评委立刻感知技术深度。
5.2 数据库连接池升级:从BasicDataSource到HikariCP
原context.xml使用Tomcat内置BasicDataSource,性能一般。升级为HikariCP需三步:
pom.xml中移除tomcat-dbcp依赖,添加:
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> </dependency>- 删除
context.xml,改用Java配置:在src/main/java/com/xxx/util/DBUtil.java中:
public class DBUtil { private static HikariConfig config = new HikariConfig(); private static HikariDataSource ds; static { config.setJdbcUrl("jdbc:mysql://localhost:3306/studenthousionmanager?useSSL=false&serverTimezone=GMT%2B8"); config.setUsername("root"); config.setPassword(""); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(10000); ds = new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return ds.getConnection(); } }- 所有DAO类中
getConnection()调用改为DBUtil.getConnection()。
价值:HikariCP是当前最快连接池,maximumPoolSize等参数可视化,答辩时可谈“连接池选型依据”,远超“用Tomcat自带”的回答层次。
5.3 权限粒度细化:从“角色级”到“按钮级”控制
原RBAC只控制到页面级(如/servlet/student),但实际需按钮级(如“删除学生”按钮仅管理员可见)。改造方案:
- 在
AuthFilter中,将用户权限存入session.setAttribute("permissions", permissionList),permissionList为List<String>(如["student:list","student:delete"]); - 在
list.jsp中,用JSTL判断:
<c:if test="${fn:contains(permissions, 'student:delete')}"> <a href="/student/servlet/student?action=delete&id=${stu.id}" onclick="return confirm('确定删除?')">删除</a> </c:if>AuthFilter中chain.doFilter()前,增加:
request.setAttribute("permissions", (List<String>) session.getAttribute("permissions"));效果:学生账号登录后,“删除”按钮消失,但“查看”按钮仍在——这才是真实企业级权限设计,比“全有或全无”更可信。
5.4 日志埋点:用Log4j2记录关键业务操作
为体现系统可观测性,在StudentService.deleteStudent(int id)开头添加:
private static final Logger logger = LogManager.getLogger(StudentService.class); public boolean deleteStudent(int id) { logger.info("管理员[{}]执行删除学生操作,ID={}", SecurityUtil.getCurrentUsername(), id); // SecurityUtil需自行实现获取session用户 // ...原有逻辑 }log4j2.xml配置:
<Configuration status="WARN"> <Appenders> <File name="FileAppender" fileName="logs/student-system.log"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </File> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="FileAppender"/> </Root> </Loggers> </Configuration>答辩话术:“我在关键业务入口添加了结构化日志,便于故障排查和操作审计。比如删除学生时,日志会记录操作人、时间、目标ID,这符合等保2.0对操作留痕的要求。”——瞬间拔高立意。
从那以后我每次接手JSP实训项目,第一件事就是检查pom.xml的Servlet版本与Tomcat是否匹配,第二件事是打开context.xml确认serverTimezone和characterEncoding——这两个参数踩过三次坑,现在成了我的强制checklist。希望帮到你。
本文还有配套的精品资源,点击获取