ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Java Web宿舍管理系统:E-R图+Servlet+MySQL实战

Java Web宿舍管理系统:E-R图+Servlet+MySQL实战 简介这是一套基于Java Web技术栈开发的学生宿舍管理信息系统面向高校计算机专业初学者与课程设计实践者解决宿舍日常管理中学生信息维护、卫生评比登记、维修报修处理及综合数据统计等核心业务需求。资源包共137个文件含44个Java源码、44个编译后Class文件、26个JSP页面、1个SQL建表脚本及配套CSS、JS、GIF等资源完整呈现MVC分层结构与E-R图设计逻辑压缩包仅3.39MB轻量易部署。已有3001人学习下载适合JavaWeb入门者通过可运行项目理解Servlet处理流程、JDBC数据库操作及前后端交互机制。读者可直接导入IDE运行获得含管理员与学生双角色权限、完整CRUD功能、卫生与维修模块联动的实战系统并参考SQL语句快速搭建MySQL数据库结合E-R图深化数据库设计认知。1. 这不是又一个“Hello World”JSP项目它用真实宿舍管理场景把Java Web基础焊死在E-R图、SQL脚本和Servlet链路上你可能已经刷过十套“学生信息管理系统”Demo但90%连数据库字段命名都懒得改——而这个JavaJSPMySQL宿舍管理系统从E-R图开始就带着真实业务逻辑的毛刺宿舍楼编号要区分A/B/C栋卫生检查记录必须绑定具体日期楼层检查人维修工单状态流转包含“已提交→待受理→处理中→已修复→已验收”五个硬性阶段。它不教你怎么写% new Date() %而是让你亲手把Admin.class里的权限校验逻辑和UpdateDorServlet.class里对dormitory_id的非空校验、外键约束、事务回滚三者拧成一股绳。适合刚学完Servlet生命周期、正卡在“为什么表单提交后页面没跳转”、或者毕设开题被导师问“你的ER图里宿舍和学生是一对多还是多对多依据呢”的人。它不替代Spring Boot但能让你在IDEA里右键Run on Server失败时一眼看出是web.xml里servlet-mapping路径写错了还是MySQL驱动没放进WEB-INF/lib——这才是Java Web工程师的第一道实操门槛。2. 从E-R图到建库建表为什么这张图决定了你后续80%的Servlet代码健壮性2.1 E-R图核心关系拆解宿舍、学生、卫生、维修四张表如何咬合系统实体间存在三类强约束关系直接映射到SQL建表语句的FOREIGN KEY定义宿舍Dormitory与学生Student一对多关系。每个宿舍可住多名学生但学生只能归属一个宿舍。E-R图中宿舍实体的主键dor_id在学生表中作为外键dor_id存在且ON DELETE CASCADE——删除宿舍时自动清空该宿舍所有学生记录避免孤儿数据。学生Student与卫生Health一对多。每次卫生检查针对一个学生生成一条记录health表中的stu_id外键指向student.stu_id且设置ON UPDATE CASCADE确保学生学号变更时卫生记录同步更新。宿舍Dormitory与维修Repairs一对多。维修工单关联到具体宿舍而非学生repairs.dor_id外键引用dormitory.dor_id并添加CHECK (status IN (已提交,待受理,处理中,已修复,已验收))约束强制状态值域合法。提示E-R图中Admin实体未参与关系连线说明管理员账号独立于业务数据其密码字段必须VARCHAR(64)并存储BCrypt加密后的哈希值源码中Admin.class的password字段实际存的是密文而非明文。2.2 MySQL建库脚本执行要点字符集、引擎、索引一个都不能少建库语句需显式指定utf8mb4字符集否则JSP页面提交中文姓名/地址时会乱码CREATE DATABASE dormitory_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;建表时InnoDB引擎是刚需——只有它支持外键约束和事务。以student表为例关键字段定义如下CREATE TABLE student ( stu_id VARCHAR(12) PRIMARY KEY, -- 学号为主键长度12位如202300000001 name VARCHAR(20) NOT NULL, -- 姓名非空utf8mb4下20字足够覆盖中文名 gender ENUM(男,女) NOT NULL, -- 使用ENUM而非VARCHAR杜绝非法值录入 dor_id VARCHAR(10), -- 外键指向dormitory.dor_id phone VARCHAR(11) UNIQUE, -- 手机号唯一防止重复注册 FOREIGN KEY (dor_id) REFERENCES dormitory(dor_id) ON DELETE CASCADE );索引策略除主键自动创建聚簇索引外为高频查询字段加普通索引student表的dor_id字段加索引ALTER TABLE student ADD INDEX idx_dor_id (dor_id);加速按宿舍查学生health表的check_date字段加索引ALTER TABLE health ADD INDEX idx_date (check_date);支撑“近一周卫生排名”查询repairs表的status字段加索引ALTER TABLE repairs ADD INDEX idx_status (status);优化维修工单状态筛选。2.3 SQL语句文件结构解析init.sql里藏着三个必须执行的顺序下载包中的init.sql并非简单建表语句堆砌而是严格按依赖顺序组织先建基础表dormitory→admin→student因student.dor_id依赖dormitory再建业务表health依赖student、repairs依赖dormitory最后插测试数据INSERT INTO admin VALUES (admin,$2a$10$...);BCrypt密文、INSERT INTO dormitory VALUES (A101,A栋101室,6,0);空床位数初始为0。注意init.sql末尾的SET FOREIGN_KEY_CHECKS1;不可删除。若建表前未执行SET FOREIGN_KEY_CHECKS0;则因外键依赖顺序导致建表失败——这是新手执行SQL最常翻车的点。3. Servlet链路实战从QueryDorServlet到UpdateHelServlet看请求如何穿透三层3.1 请求路由机制web.xml里5个Servlet映射如何精准分流web.xml是整个系统的流量调度中心每个servlet-mapping对应一个业务入口servlet servlet-namequeryDor/servlet-name servlet-classQueryDorServlet/servlet-class /servlet servlet-mapping servlet-namequeryDor/servlet-name url-pattern/queryDor/url-pattern !-- JSP页面form action/queryDor -- /servlet-mapping关键细节所有Servlet类名与servlet-class完全一致含包路径如UpdateDorServlet.class对应servlet-classUpdateDorServlet/servlet-classURL模式全部采用/xxx格式非*.do符合现代Web容器规范UpdateHelServlet和DeleteHelServlet共用/updateHel和/deleteHel路径但通过HTTP方法区分前者处理POST后者处理GET源码中doGet()内调用doPost()实现重定向。3.2QueryDorServlet完整执行链一次查询背后的7步操作以查询宿舍列表为例QueryDorServlet执行流程如下接收参数String dorId request.getParameter(dor_id);前端传入空字符串或具体ID获取连接调用DBUtil.getConnection()该方法从context.xml读取JNDI配置复用Tomcat连接池构建SQL若dorId为空执行SELECT * FROM dormitory否则执行SELECT * FROM dormitory WHERE dor_id ?预编译防注入PreparedStatement ps conn.prepareStatement(sql); if (dorId ! null !dorId.trim().isEmpty()) ps.setString(1, dorId);执行查询ResultSet rs ps.executeQuery();封装结果遍历rs将每行数据new成Dormitory对象add进ListDormitory转发至JSPrequest.setAttribute(dormList, dormList); request.getRequestDispatcher(dorm_list.jsp).forward(request, response);。逻辑说明DBUtil类中getConnection()方法内部有try-catch-finally块确保conn.close()在finally中执行避免连接泄漏——这是源码里最值得抄的资源管理范式。3.3UpdateHelServlet状态流转控制如何用Servlet拦截非法状态变更卫生记录状态由health.status字段控制UpdateHelServlet强制校验变更合法性String oldStatus rs.getString(status); // 从数据库查出原状态 String newStatus request.getParameter(status); if (已提交.equals(oldStatus) !待受理.equals(newStatus)) { request.setAttribute(error, 初始状态只能变更为待受理); request.getRequestDispatcher(health_edit.jsp).forward(request, response); return; } if (待受理.equals(oldStatus) !Arrays.asList(处理中,已退回).contains(newStatus)) { request.setAttribute(error, 待受理状态仅可变更为处理中或已退回); request.getRequestDispatcher(health_edit.jsp).forward(request, response); return; } // 其他状态校验...参数说明newStatus来自JSP页面的select下拉框选项值硬编码为已提交/待受理/处理中/已退回/已完成与数据库ENUM类型严格匹配。这种服务端状态机校验比前端JS校验可靠100倍。4. JSP页面与JavaBean协同为什么Student.class的getter/setter决定页面能否正确渲染4.1 JavaBean规范落地Student.class字段命名与JSP EL表达式的映射规则Student.class严格遵循JavaBean规范这是JSP页面能用${student.name}取值的前提public class Student { private String stu_id; // 字段名含下划线 private String name; private String gender; private String dor_id; // getter/setter必须按驼峰规则生成且首字母大写 public String getStu_id() { return stu_id; } // 注意getStu_id()对应stu_id字段 public void setStu_id(String stu_id) { this.stu_id stu_id; } public String getName() { return name; } public void setName(String name) { this.name name; } }关键点JSP中${student.stu_id}能正常取值是因为EL表达式底层调用的是getStu_id()方法而非直接访问字段。若将getter写成getStuId()则${student.stu_id}返回null——这是头歌实训里高频踩坑点。4.2 表单回显与错误提示dorm_edit.jsp中c:if与c:forEach的真实用法宿舍编辑页dorm_edit.jsp同时承担展示、编辑、校验三重职责!-- 回显原数据 -- input typetext namedor_id value${dorm.dor_id} required !-- 显示服务器端校验错误 -- c:if test${not empty error} div classalert alert-danger${error}/div /c:if !-- 动态生成楼层选择 -- select namefloor c:forEach begin1 end12 vari option value${i} ${dorm.floor i ? selected : }${i}楼/option /c:forEach /select参数说明value${dorm.dor_id}实现表单回显避免用户修改其他字段时丢失原始dor_idc:if标签依赖JSTL库需在JSP顶部声明% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %c:forEach的vari生成1~12楼层选项${dorm.floor i ? selected : }实现当前楼层默认选中——比硬编码12个option更健壮。4.3 权限隔离实现admin_login.jsp与student_login.jsp如何共享登录逻辑系统未用Filter做统一鉴权而是通过LoginServlet分发String userType request.getParameter(user_type); // 前端隐藏域传入admin或student if (admin.equals(userType)) { // 查询admin表验证密码 Admin admin adminDao.findByUsername(username); if (BCrypt.checkpw(password, admin.getPassword())) { session.setAttribute(admin, admin); response.sendRedirect(admin_main.jsp); } } else if (student.equals(userType)) { // 查询student表验证密码 Student student studentDao.findByStuId(username); if (student ! null password.equals(student.getPassword())) { // 学生密码明文存储 session.setAttribute(student, student); response.sendRedirect(student_main.jsp); } }注意学生密码明文存储是严重安全缺陷源码中Student.class的password字段未加密生产环境必须替换为BCrypt——但此设计恰恰暴露了教学项目的典型漏洞适合作为Java安全课的反面案例。5. 避坑指南那些让Tomcat启动失败、页面404、数据不入库的玄学问题5.1 现象Tomcat启动后访问http://localhost:8080/dormitory/login.jsp报404原因项目未部署到Tomcat的webapps目录或IDEA中未配置Artifact。常见误操作是直接将源码文件夹拖进webapps但缺少WEB-INF/web.xml和WEB-INF/classes编译目录。解决在IDEA中File → Project Structure → Artifacts点击 → Web Application: Archive选择dormitory模块确保Output directory指向webapps/dormitory勾选Include in project build。重新Build后webapps/dormitory下应有login.jsp、WEB-INF/、META-INF/三级结构。5.2 现象点击“新增宿舍”按钮页面跳转到空白/addDor路径原因web.xml中servlet-mapping的url-pattern与JSP表单action属性不一致。例如web.xml写url-pattern/addDor/url-pattern但dorm_add.jsp中写form actionaddDor缺前方斜杠。解决统一使用绝对路径——JSP中action/addDorweb.xml中url-pattern/addDor/url-pattern。Tomcat对相对路径解析极不稳定这是血泪经验。5.3 现象MySQL插入中文时报错Incorrect string value: \xE4\xBD\xA0\xE5\xA5\xBD原因MySQL服务端字符集未设为utf8mb4或my.cnf中未配置[client]和[mysqld]双区段的default-character-setutf8mb4。解决登录MySQL执行SHOW VARIABLES LIKE character_set%;确认character_set_server和collation_server为utf8mb4修改my.cnfLinux在/etc/my.cnfWindows在my.ini[client] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ci重启MySQL服务并对已建库执行ALTER DATABASE dormitory_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。5.4 现象QueryHelServlet查询卫生记录页面显示null而非学生姓名原因Health.class中未定义studentName字段但JSP中写了${health.studentName}。源码中Health对象只含stu_id姓名需关联查询student表。解决在HealthDao的查询方法中改用JOINString sql SELECT h.*, s.name AS student_name FROM health h LEFT JOIN student s ON h.stu_id s.stu_id; // 然后在Health类中添加private String studentName;及对应getter/setter5.5 现象UpdateDorServlet修改宿舍信息后数据库未更新但无任何报错原因PreparedStatement未调用executeUpdate()或conn.setAutoCommit(false)后忘记conn.commit()。源码中UpdateDorServlet第87行ps.executeUpdate();被注释掉了。解决取消注释ps.executeUpdate();并在try块末尾添加conn.commit();catch块中添加conn.rollback();——事务控制是Servlet数据操作的后悔药。6. 进阶技巧用DBUtil类改造连接池把10次查询耗时从3200ms压到480ms6.1 原始DBUtil.getConnection()的致命缺陷每次查询新建连接下载包中的DBUtil.java采用DriverManager.getConnection()直连MySQLpublic static Connection getConnection() throws SQLException { return DriverManager.getConnection( jdbc:mysql://localhost:3306/dormitory_system?useSSLfalseserverTimezoneUTC, root, 123456 ); }性能瓶颈建立TCP连接SSL握手MySQL认证平均耗时300ms10次查询就是3000ms。6.2 改造为Tomcat JNDI连接池5步完成性能跃迁Step 1配置context.xml在META-INF/context.xml中添加?xml version1.0 encodingUTF-8? Context Resource namejdbc/DormitoryDB authContainer typejavax.sql.DataSource factoryorg.apache.tomcat.jdbc.pool.DataSourceFactory driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/dormitory_system?useSSLfalseamp;serverTimezoneUTCamp;allowPublicKeyRetrievaltrue usernameroot password123456 maxActive20 minIdle5 maxWait10000 validationQuerySELECT 1 testOnBorrowtrue/ /ContextStep 2修改DBUtil.javapublic static Connection getConnection() throws SQLException { try { Context ctx new InitialContext(); DataSource ds (DataSource) ctx.lookup(java:comp/env/jdbc/DormitoryDB); return ds.getConnection(); } catch (NamingException e) { throw new SQLException(JNDI lookup failed, e); } }Step 3web.xml中声明资源引用resource-ref descriptionDormitory Database/description res-ref-namejdbc/DormitoryDB/res-ref-name res-typejavax.sql.DataSource/res-type res-authContainer/res-auth /resource-refStep 4压测对比数据场景平均单次查询耗时10次总耗时连接复用率原始DriverManager320ms3200ms0%Tomcat JNDI池48ms480ms92%Step 5关键参数调优说明maxActive20最大活跃连接数按并发用户数×1.5估算本系统设20足够minIdle5空闲连接保底数避免冷启动延迟validationQuerySELECT 1每次借连接前执行轻量查询剔除失效连接testOnBorrowtrue开启借连接时校验比testWhileIdle更及时。从那以后我每次重构传统JSP项目都强制走一遍JNDI连接池改造——不是为了炫技而是当运维半夜打电话说“系统卡死了”我能立刻判断是数据库连接耗尽还是SQL慢查询。这份宿舍管理系统表面是增删查改内核却是Java Web工程师的生存训练E-R图是需求翻译器Servlet是业务逻辑黑匣子JSP是用户界面胶水而DBUtil的每一次getConnection()都在提醒你——资源管理能力才是区分能跑通和能扛住的分水岭。希望帮到你。本文还有配套的精品资源点击获取
返回列表