简介JavaWeb学生宿舍管理系统设计与实现资源包面向JavaWeb初学者、课程设计与毕业设计人群提供一套基于JSP/SSMMySQL的完整项目方案覆盖学生信息管理、房间分配、来访登记、物品报修等核心业务模块。资源共1070个文件压缩包73.72MB以Java源码、Vue前端组件、SQL数据库脚本、XML配置文件、Jar依赖包及Word版论文为主要文件类型同时含有构建脚本和部署配置方便直接本地运行。论文按标准毕业设计格式撰写涵盖绪论、相关技术介绍、系统分析、总体设计、数据库设计、功能实现与测试等章节前后台代码与数据库设计同步配套。目前已有23431人学习内容完整度高可作为毕业设计题目参考、项目实训或二次开发基础帮助读者快速掌握宿舍管理系统的完整开发流程与排错思路。1. javaweb学生宿舍管理系统为什么说真正的难点不在写代码“javaweb学生宿舍管理系统”这个题目每年有大量应届生在搜索框里敲下它。真正动手之后的体感往往和预想的不一样以我带学生做毕设的经验看最大的时间黑洞根本不是业务代码而是环境配置、数据库连接和中文乱码这三件事。论文里写的设计与代码对不上也是答辩现场被追问的高发区。这篇文章按我实际落地的一套做法讲完整路径先梳理业务和表结构设计再给一套能直接改的分层代码骨架然后是 IDEA 里从零跑通的配置过程最后是部署与答辩阶段我提前避开的四个坑。适合正在准备毕业设计的学生也适合想拿 ServletJSPMySQL 这套技术栈练手完整案例的开发者。目标是让你照着走一遍真的能把系统跑起来并且能讲清楚每一步为什么这么做。2. 先拆业务再建表宿舍管理系统的功能清单与数据库设计为什么先做表而不是先写代码因为这类业务系统的核心是数据关系。表结构定下来之后Servlet 和 JSP 本质上只是数据的搬运工。我接到这类需求时先拿一张 A4 纸把“谁、在什么角色下、能做什么、数据落在哪张表”画一遍画通了再进 IDE 写代码效率会高很多。2.1 三种角色和功能边界这个系统最少需要三类角色学生、宿管员、系统管理员。学生的操作面查看自己的宿舍和床位、在线提交报修、查看卫生检查结果、退宿时发起申请。宿管员的操作面办理入住和退宿登记、分配床位、登记来访人员、录入卫生检查评分、处理报修工单。系统管理员的操作面维护楼栋和房间信息、创建宿管账号、重置密码、查看整体入住率统计。每一个功能都应该对应到一张表或一个字段。比如“来访登记”如果当初只设计了学生和宿舍两张表后面要给宿管补功能就得改表。为了避免返工我一般至少设计六张表账号表 t_user、楼栋表 t_building、宿舍表 t_dorm、学生表 t_student、报修表 t_repair、来访表 t_visit。卫生检查结果可以并入宿舍表里用评分字段存储这样能控制论文里的 ER 图规模不至于画满一整页。2.2 数据库设计字段类型、床位冗余与唯一索引下面是核心建表 SQL我拆成两部分来说。CREATE TABLE t_building ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT 楼栋ID, building_name VARCHAR(50) NOT NULL COMMENT 楼栋名称如梅苑1号楼, floor_count INT DEFAULT 6 COMMENT 楼层总数, dorm_count INT DEFAULT 60 COMMENT 宿舍总间数, status TINYINT DEFAULT 1 COMMENT 1在用 0停用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT宿舍楼栋表; CREATE TABLE t_dorm ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT 房间ID, building_id INT NOT NULL COMMENT 所属楼栋ID外键指向 t_building.id, dorm_no VARCHAR(10) NOT NULL COMMENT 宿舍编号如A-302, bed_count INT DEFAULT 4 COMMENT 床位总数, live_count INT DEFAULT 0 COMMENT 当前已住人数冗余字段, room_status TINYINT DEFAULT 1 COMMENT 1可住 2满员 3维修中, UNIQUE KEY uk_building_dorm (building_id, dorm_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT宿舍房间表;两个选型说明dorm_no 用 VARCHAR 而不是 INT。宿舍编号经常是“A-302”这种带横杠的格式INT 存不了即便编号全是数字用字符串也能避免“0302”被自动去掉前导零。live_count 是冗余字段允许它和学生表实际统计值在极端情况下不一致换来的是列表页查询不用每次 COUNT 扫描。对课程设计这点数据量来说意义不大但论文评审喜欢看到这种有取舍的设计我会在论文里写“用冗余字段换取读性能”。uk_building_dorm 唯一索引防止同一栋楼出现两个“A-302”这是数据完整性的第一道防线。CREATE TABLE t_student ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT 学生ID, student_no VARCHAR(20) NOT NULL COMMENT 学号如202301010101, student_name VARCHAR(50) NOT NULL, gender TINYINT DEFAULT 1 COMMENT 1男 0女, phone VARCHAR(20) COMMENT 联系电话, dorm_id INT COMMENT 宿舍ID外键指向 t_dorm.id, bed_no VARCHAR(10) COMMENT 床位编号如1号床, status TINYINT DEFAULT 1 COMMENT 1在住 0退宿, UNIQUE KEY uk_student_no (student_no), KEY idx_dorm (dorm_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT学生信息表; CREATE TABLE t_repair ( id INT AUTO_INCREMENT PRIMARY KEY COMMENT 报修单ID, student_id INT COMMENT 报修学生ID外键指向 t_student.id, dorm_id INT NOT NULL COMMENT 宿舍ID, content VARCHAR(200) NOT NULL COMMENT 报修内容水龙头漏水、灯管不亮, status TINYINT DEFAULT 0 COMMENT 0待处理 1处理中 2已完成, handler VARCHAR(50) COMMENT 处理人姓名, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 提交时间, finish_time DATETIME DEFAULT NULL COMMENT 完成时间, KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT报修工单表;student_no 加唯一索引但主键单独用自增 id。这样学号在录入错误时可以直接 UPDATE不用牵连外键关系也符合数据表设计的基本习惯。t_repair 里给 status 建普通索引因为宿管查列表时几乎都是按“待处理”“已完成”来过滤的。外键我要专门说一句建表时我习惯不写物理 FOREIGN KEY只在字段注释里标明逻辑关系。设计文档的 ER 图里必须画出关系线但数据库层面用外键约束删除楼栋时就会遇到“有子表数据存在删不掉”的报错。具体踩坑记录放在第 5 章这里先记住逻辑外键 代码校验比物理外键在中小型管理系统里更实用。3. 三层架构与核心代码实现从 DAO 到过滤器的可抄作业模板3.1 数据怎么流动从 JSP 点击到 MySQL 返回先看一次“登录”请求走完的完整链路login.jsp 把学号密码 POST 给 LoginServletLoginServlet 调用 StudentService 的登录方法Service 调用 StudentDao 的 findByNoDAO 通过 DBUtil 拿到数据库连接执行 SELECT查到则返回 Student 对象Servlet 把对象存进 session 并跳转首页查不到则在 request 里放一条错误提示转发回 login.jsp。这个走查能解释一个常见的代码坏味道不要把数据库连接写在 Servlet 里。我见过不少项目把 JDBC 代码直接堆在 Servlet 的 doPost 里表面看功能能跑但每加一个页面就要复制一遍连接代码后面替换连接池时更是全局搜索替换到手软。分层之后换数据库或者换连接池只需要动 util 包里的一个类。3.2 DBUtil 连接工具与 BaseDao 增删改查模板先从数据库连接工具开始。这一步跑通后面所有 DAO 都依赖它。package com.dorm.util; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class DBUtil { private static String url; private static String username; private static String password; static { try (InputStream in DBUtil.class.getClassLoader() .getResourceAsStream(db.properties)) { Properties prop new Properties(); prop.load(in); url prop.getProperty(jdbc.url); username prop.getProperty(jdbc.username); password prop.getProperty(jdbc.password); Class.forName(prop.getProperty(jdbc.driver)); } catch (Exception e) { throw new ExceptionInInitializerError(数据库配置加载失败 e.getMessage()); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, username, password); } }对应的 db.properties 放在 src/main/resources 下jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/dorm?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.password123456说明两点MySQL 8 必须带 serverTimezoneAsia/Shanghai否则连接一建立就报时区错误用户名密码换成你自己的本地配置。Class.forName 这行在 Tomcat 8.5 之后其实可以不写驱动通过 SPI 机制自动注册但写上更稳妥兼容老版本 Tomcat 和部分奇葩部署环境。然后是 DAO 层的通用模板。几乎所有业务表的增删改查都能复用这两个方法。package com.dorm.dao; import com.dorm.util.DBUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class BaseDao { public static int executeUpdate(String sql, Object... params) { try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { for (int i 0; i params.length; i) { ps.setObject(i 1, params[i]); } return ps.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(数据库增删改操作失败, e); } } public static ListMapString, Object queryForList(String sql, Object... params) { ListMapString, Object rows new ArrayList(); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { for (int i 0; i params.length; i) { ps.setObject(i 1, params[i]); } ResultSet rs ps.executeQuery(); ResultSetMetaData md rs.getMetaData(); while (rs.next()) { MapString, Object row new HashMap(); for (int i 1; i md.getColumnCount(); i) { row.put(md.getColumnLabel(i), rs.getObject(i)); } rows.add(row); } return rows; } catch (SQLException e) { throw new RuntimeException(数据库查询失败, e); } } }代码说明全部使用 PreparedStatement 的占位符传参而不是把参数拼进 SQL 字符串。这是防 SQL 注入的第一道门也是答辩时老师最爱问的点。queryForList 返回 List用列名做 key适合列表页直接交给 JSTL 渲染。所有连接都放在 try-with-resources 里finally 不用手动关连接。连接泄漏这种问题在本地开发时不一定立刻爆但系统跑一天后会出现“Connection is not available, request timed out”到时候排查代价更高。3.3 用 Filter 锁住后台页面几行代码挡住未登录访问如果不加拦截浏览器直接访问 studentList.jsp 这种内部页面没登录也能看到全部数据。这是安全管理上的明显漏洞但很多课程设计项目都漏了。下面的过滤器是整个系统的访问入口闸门。package com.dorm.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; WebFilter(/*) public class LoginFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); // 放行登录页、登录接口和静态资源 if (uri.endsWith(/login.jsp) || uri.endsWith(/LoginServlet) || uri.contains(/css/) || uri.contains(/js/) || uri.contains(/images/)) { chain.doFilter(request, response); return; } HttpSession session req.getSession(false); if (session null || session.getAttribute(loginUser) null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } chain.doFilter(request, response); } }这段代码的效果是除登录页和静态资源外一切请求都要求 session 里存在 loginUser。如果用户没登录直接重定向回 login.jsp。注意 getSession(false) 不会主动创建新会话避免每个未登录请求都生成一个无意义的 session 对象。如果项目用的是 web.xml 配置方式而不是注解把 Filter 类去掉 WebFilter在 web.xml 里加 filter 和 filter-mapping 是一样的效果映射的 url-pattern 写成 /* 即可。4. 在 IDEA 里跑通 javaweb 项目配置过程、数据库初始化与连接池参数4.1 IDEA 运行 javaweb 项目配置的六个步骤这一步是新手翻车最严重的环节。我按顺序列一遍实际操作的配置路径。第一步从 IDEA 菜单 File → New → Project from Existing Sources 选中项目根目录。如果目录里没有 pom.xmlIDEA 会提示检测不到项目类型先选普通 Java 项目后面再补 Web 模块。第二步打开 File → Project Structure在 Project 里把 SDK 选到 1.8 或 11。在 Modules 里把 src/main/java 标记为 Sources如果项目带 web 目录右键勾选 Web 并指定 web.xml 路径。第三步配置 Tomcat。Run → Edit Configurations → 左上角加号 → Tomcat Server → Local。Tomcat Home 选择本地的解压目录URL 一栏会默认生成 http://localhost:8080/。第四步部署 Artifact。在 Tomcat 配置的 Deployment 页签点加号选 Artifact类型选 war explodedApplication context 填 /dorm。用 exploded 模式比 war 包方便修改 JSP 后不用重新打包刷新浏览器就能看到效果。第五步先初始化数据库再启动。很多人直接启动 Tomcat等登录页一输入账号后台立刻报数据库连接失败。数据库初始化方式见 4.2 小节。第六步点右上角启动按钮浏览器访问 http://localhost:8080/dorm/login.jsp。第一次跑通先别急着写新功能把控制台日志从上到下过一遍确认没有异常再继续。4.2 数据库初始化SQL 脚本的三种执行方式拿到 dorm.sql 脚本后有三种常见执行方式。第一种是 MySQL 命令行。登录后执行 use dorm; 再执行 source /绝对路径/dorm.sql。注意路径不要带中文和空格否则报“无法打开文件”时很难反应过来是路径问题。第二种是 Navicat 或 DBeaver。新建数据库 dorm字符集选 utf8mb4右键数据库 → 运行 SQL 文件选择脚本执行。执行完在表列表里能看到 t_user、t_building、t_dorm、t_student、t_repair 这些表。第三种是直接用 IDEA 的 Database 面板。右侧 Database → 加号 → Data Source → MySQL填好主机、端口和账号后选定 dorm 数据库右键 SQL 文件执行。一个很实际的提醒脚本里如果没写 DROP TABLE IF EXISTS第二次执行同一份脚本时建表语句会报“Table already exists”。所有建表语句前都保留 DROP TABLE IF EXISTS后面重复执行脚本回归测试时会省很多事。另外脚本里的 INSERT 语句自带管理员账号初始化完成后去 t_user 表确认一下密码字段是否和登录代码里的校验逻辑一致这属于“运行前检查清单”不查的话经常出现界面报“用户名或密码错误”其实只是密码加密方式对不上。4.3 数据库连接池Druid 最小配置与参数表纯 JDBC 的 DBUtil 在课程设计阶段够用但论文里写“系统使用数据库连接池”是一个常见加分点。连接池选型我一般推荐 Druid自带监控页面能演示 SQL 执行次数答辩时打开 /druid/index.html 给老师看一眼比嘴上说性能要好用得多。package com.dorm.util; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; public class DruidUtil { private static DruidDataSource dataSource; static { try (InputStream in DruidUtil.class.getClassLoader() .getResourceAsStream(druid.properties)) { Properties p new Properties(); p.load(in); dataSource (DruidDataSource) DruidDataSourceFactory.createDataSource(p); } catch (Exception e) { throw new ExceptionInInitializerError(连接池初始化失败 e.getMessage()); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }druid.properties 最小配置driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/dorm?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai usernameroot password123456 initialSize5 maxActive20 maxWait60000 minEvictableIdleTimeMillis1800000 testWhileIdletrue连接池参数说明参数默认值建议值作用initialSize05启动时预建立的连接数减少首次请求的等待maxActive820最大活跃连接数超出后新请求排队等待maxWait不设60000等待连接的最大毫秒数超时抛异常minEvictableIdleTimeMillis30分钟1800000空闲连接最小存活时间防止空闲连接被 MySQL 端主动断开testWhileIdletruetrue空闲时发送验证查询剔除失效连接换连接池时只需要把 DAO 里调用 DBUtil.getConnection() 的静态引用改成 DruidUtil.getConnection()其余业务代码一行不用动。这就是分层设计节省返工时间的实际体现。提示连接串里的 serverTimezone 必须写成 Asia/Shanghai。写 UTC 虽然能连上但数据库里存的时间会比北京时间少 8 小时查出来的数据在页面上会对不上。5. 从部署到答辩的避坑实录环境、编码与数据关系5.1 启动即报 Communications link failure先从驱动和时区查起现象Tomcat 启动正常登录页能打开一点“登录”按钮就抛异常核心信息是 Communications link failure 或 Cannot create PoolableConnectionFactory。但本机命令行用 mysql -u root -p 又能正常登录。原因最常见的是 MySQL 8.0 默认认证插件是 caching_sha2_password项目里放的是 mysql-connector-java 5.1.x 老驱动5.x 驱动不认这个认证方式握手直接被拒。另一种情况是连接串里没加 serverTimezone8.x 驱动强制要求显式指定时区否则报“The server time zone value is unrecognized”。解决把依赖里的 mysql-connector-java 升级到 8.0.33连接串加上 serverTimezoneAsia/Shanghai 和 useSSLfalse。如果项目 lib 里同时有两个版本的驱动 jar必须把 5.x 的删干净。两个驱动共存时Class.forName 加载哪个版本取决于类路径顺序这种问题靠看代码很难定位只能一个个排除。这条经验只在 MySQL 5.7 上不受影响所以网上很多老教程里的配置放到 MySQL 8 上就成了玄学问题。拿到项目先看连接驱动和版本比看半天代码配置更有效率。5.2 中文全部变成问号请求、页面、数据库三层编码逐个排查现象页面上写死的中文正常但表单新增一条记录后列表里显示的中文变成“??”或“ä½ å¥½”这种乱码。不同项目乱码形态还不一样有的只在提交后出现有的从数据库里查出来就是乱码。原因Tomcat 8 之后默认对 POST 请求不按 UTF-8 解码表单提交的中文到了 Servlet 里已经变成乱码后面再存进数据库自然就是坏的JSP 文件本身的编码和 pageEncoding 声明不一致也会导致页面显示乱码数据库连接串没带 characterEncodingutf8 时MySQL 端按 latin1 存储存进去的字符再查出来就是乱码。解决从三层统一缺一不可。JSP 头部写 pageEncodingUTF-8 和 contentTypetext/html;charsetUTF-8写一个 CharacterEncodingFilter在请求进入 Servlet 前调用 request.setCharacterEncoding(UTF-8)响应统一 setContentType(text/html;charsetUTF-8)这个 Filter 要注册在 LoginFilter 之前连接串带上 characterEncodingutf8建库语句确认是 DEFAULT CHARSETutf8mb4。排查顺序也有讲究先用 Navicat 打开表看原始值。如果数据库里存的已经是乱码问题出在写入前重点查请求编码如果数据库里正常、页面乱码问题出在读取和响应编码。从数据源头一层层往前找比同时改五个地方瞎试要快。5.3 删除楼栋被外键拦下物理删不掉停用才是正解现象在管理后台点“删除楼栋”页面直接抛 SQLException错误信息是 Cannot delete or update a parent row: a foreign key constraint fails。数据库工具里手动删 t_building 也一样删不掉。原因t_dorm 的 building_id 外键指向 t_building 的 id。删除楼栋时数据库要保证子表里没有引用它的记录但一栋楼下面通常已经分配了多个宿舍、入住了一批学生外键约束直接拒绝删除操作。解决优先采用逻辑删除。后台的“删除”按钮改成“停用”代码执行 UPDATE t_building SET status 0 WHERE id ?查询时默认过滤 status1。这样历史报修记录和入住记录都能保留论文里还能写“系统支持数据的可追溯性”。如果坚持物理删除就要按子表到父表的顺序清理数据先删 t_student、t_repair再删 t_dorm最后删 t_building。但宿舍楼里有历史报修数据时物理删除会把这些记录一起销毁从管理角度看这其实是个业务错误。所以这个项目里“能不能删楼栋”和“该不该删楼栋”是两件事坑在把业务判断交给了数据库错误信息。5.4 Tomcat 端口被占用8080 和 1099 的排查顺序现象IDEA 里点启动按钮控制台很快出现 Port 8080 was already in use 或 Address already in use: JVM_Bind。有时候还要再加一个 1099 端口冲突提示 JMX connector 端口被占用Tomcat 根本没机会启动。原因上一次在 IDEA 里非正常停止的 Tomcat 进程还残留在系统里或者本机装了 nginx、占了 8080 的开发服务1099 端口一般是 IDEA 里启动 Tomcat 时 JMX 监控用的进程残留会把它一起锁住。解决先确认端口被谁占用。Windows 用 netstat -ano | findstr 8080 找到 PID再用 tasklist | findstr PID 看进程名确定是残留的 Tomcat 就 taskkill /PID /F。macOS 和 Linux 用 lsof -i:8080 看占用进程。如果 8080 被不想关闭的服务占用就改 Tomcat conf/server.xml 里的 Connector port 为 8081顺手把 8009 和 8005 也改掉。IDEA 的 HTTP port 会自动读取 server.xml不用额外配置。1099 冲突多半是上次 IDEA 异常退出留下的镜像彻底退出 IDEA 再重新打开问题通常会消失。端口冲突看着像玄学本质上都是资源没释放。5.5 登录密码校验失败不一定是 SQL 写错可能是加密方式不一致现象数据库初始化之后用脚本里预设的管理员账号登录页面提示“用户名或密码错误”。但用 SQL 直接在数据库里查账号是存在的密码字段也非空。原因项目代码里登录时对密码做了 MD5 加密但 dorm.sql 里 INSERT 进去的管理员密码是明文。两边比较时一个是加密后的密码一个是明文永远对不上。解决翻一下 LoginServlet 或 UserDao 里的密码校验代码确认加密方式然后把 SQL 里的预设密码改成对应密文。或者临时把代码里的加密逻辑注释掉登录成功后重新保存一次用户数据让系统自己生成密文。这里没有标准答案因为不同模板项目的加密方案不一样关键是“先确认再改”。如果两项都不动这个 bug 会浪费掉一晚上的排查时间。6. 论文怎么写才不拖后腿ER 图、数据字典和答辩追问6.1 论文第三章的系统设计怎么让图表和代码对得上论文里的系统设计章节最容易被挑毛病的就是图表和代码实现不一致。我吃过这个亏画 ER 图时把宿舍和学生画成 1 对 1代码里实际是一间宿舍住四个人答辩时被老师指着图问“这间宿舍的床位在哪”当场答不上来。ER 图严格按照表结构来画。楼栋到宿舍是 1N宿舍到学生是 1N学生到报修单是 1N。关系线上标清楚外键字段名图下方加一段文字说明冗余字段 live_count 的存在理由。数据字典直接对照建表 SQL 抄字段名、类型、长度、是否主外键、说明五项列全注意和数据库里完全一致别出现文档里是 varchar(20)、数据库里是 varchar(50) 这种低级偏差。测试用例表要能跑得通。至少写三条登录成功、登录密码错误、未登录直接访问后台页面被重定向到 login.jsp。每条写模块、操作步骤、输入数据、预期结果、实际结果。预期结果要和系统实际行为一致“跳转首页”“提示用户名或密码错误”都可以但别写“系统运行正常”这种没信息量的话。老师翻到这个表就知道你真的跑过系统。6.2 答辩现场的高频追问两个问题提前准备第一个高频问题“你怎么防 SQL 注入”回答路径是 PreparedStatement 预编译加参数占位再补一句后端对输入做长度和格式校验。前提是你的 DAO 代码真的用了 PreparedStatement没用的话这个回答就是给自己挖坑。第二个高频问题“如果 1000 人同时查房系统扛得住吗”不要吹。如实说项目是单体架构按当前数据量设计遇到高并发需要引入连接池、缓存和优化索引然后指出 Druid 连接池已经落地、宿舍表 live_count 冗余字段就是为读性能做的准备。这回答比“绝对没问题”可信得多。我自己的教训是答辩演示环境一定要提前完整跑一遍包括重新启动 Tomcat 和 MySQL。曾经有一次现场演示浏览器一打开就是 404原因是上次调试时改了 Application context 没同步到部署配置。从那次以后我答辩前会做一张自查表数据库脚本重新初始化一遍新增、修改、删除三条主路径各走一遍浏览器清一次缓存。这套流程花不了十分钟但能避免九成的演示翻车。答辩前把这三条路径跑通比背十页答辩稿都管用。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?