简介:基于JSP与MySQL的学生宿舍管理系统实训项目,面向高校JavaWeb课程设计或毕业设计场景,覆盖学生信息、宿舍分配、费用管理、报修跟踪等核心功能,可作为完整课设方案直接参考或二次开发。压缩包共67个文件,大小约5.55MB,其中17个Java源文件与17个class文件构成后台业务逻辑,10个JSP页面负责动态界面展示,7个JAR包与8个XML配置支撑项目运行,另有1个SQL数据库脚本和1份docx作业文档,方便初始化环境与理解设计思路。已有69人浏览学习。这套资料可快速搭建基于MVC思想的学生宿舍管理系统,SQL脚本预置多张数据表,docx文档详细说明系统架构、数据库设计及部署步骤,能够有效节省编写代码和整理文档的时间,尤其适合需要提交源码、数据库和说明书的实训作业场景。
1. 实训作业系统拆解:JSP+MySQL宿舍管理项目要交付的三件套
学期末实训课上老师丢过来的这个标题,本质是一套典型的 Java Web 课程设计:前端用 JSP 展示页面,后端用 Servlet 处理请求,数据落在 MySQL 里,交付物是源代码、数据库脚本和文档三件套。学生宿舍管理系统解决的目标很具体——宿舍分配、学生信息登记、水电费记录、来访登记、报修处理这些宿舍管理员日常工作,每一项都对应一张表和一个可点击的网页。这个项目适合正在做实训作业的 Java Web 入门者,也适合想在毕业设计里快速搭一个管理系统骨架的人。难点不在功能多少,而在于把一个完整的增删改查系统从代码到数据库再到运行环境整条链路跑通,这恰恰是课堂上学不到的部分,也是这篇笔记要带你走完的路。
2. 拿到源代码先做三件事:读文档、看表结构、导入数据库
2.1 先读文档再开 IDE:从需求说明里找出系统的功能边界
常见做法是先把项目里的文档按文件名排序,找出需求分析、数据库设计、操作说明这几类。实训作业标题里的「文档」两个字不是凑数的,它通常包含三块内容:功能需求列表、E-R 图、页面清单。功能需求列表决定你要在代码里找哪些模块;E-R 图决定你要到数据库里看哪几张表;页面清单决定 JSP 文件应该有哪些名字。
我一般会先画一张最简单的脑图:管理员登录、学生管理、宿舍管理、水电费管理、报修管理、来访登记。这张脑图不需要很细,它的作用是让你在打开 IDE 之前已经知道这个系统的边界在哪里。很多同学一拿到源代码就点开 Tomcat 启动,结果登录页都出不来,就是因为没先确认数据库连接配置,也没确认项目里到底有哪些表。先读文档,能省掉后面至少一个小时的瞎猜时间。
2.2 表结构是系统的地基:读懂学生表、宿舍表与核心表的关系
打开数据库设计文档,典型的学生宿舍管理系统至少有五张表:管理员表、学生表、宿舍表、水电费表、报修表。这些表之间的关联关系决定了代码里怎么写 SQL,也是你答辩时被老师问得最多的地方。
以学生表和宿舍表为例,常见设计是学生表里放一个宿舍编号字段,或者用一张独立的宿舍分配表来维护学生和宿舍的多对一关系。直接放宿舍编号简单,但无法记录入住时间、退宿时间这些历史信息;用独立分配表更加规范,但查询时要用 JOIN。实训作业一般会用独立分配表来显得工作量更足,我建议你优先采用这种设计。
CREATE TABLE dormitory ( dorm_id INT PRIMARY KEY AUTO_INCREMENT, building VARCHAR(20) NOT NULL COMMENT '楼栋', room_no VARCHAR(10) NOT NULL COMMENT '房间号', bed_count INT NOT NULL DEFAULT 4 COMMENT '床位数', used_bed INT NOT NULL DEFAULT 0 COMMENT '已住人数', UNIQUE KEY uk_building_room (building, room_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE student ( student_id VARCHAR(20) PRIMARY KEY COMMENT '学号', name VARCHAR(50) NOT NULL, gender ENUM('男','女') NOT NULL, major VARCHAR(50), phone VARCHAR(20), dorm_id INT, FOREIGN KEY (dorm_id) REFERENCES dormitory(dorm_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;参数说明集中在表结构和字符集上。bed_count 和 used_bed 两个字段是我特别想提醒你注意的:评分标准里如果包含「宿舍分配不能超员」这一条,光靠这两个字段还不够,必须在代码里用事务保证「查询空床位 → 更新已住人数」两步是原子的,否则并发点击时会出现超员。字符集用 utf8mb4 而不是 utf8,是因为 utf8 在 MySQL 5.7 里存不了部分生僻字和 emoji,学生姓名里万一有生僻字,utf8 表结构在导入数据时就会报 Incorrect string value 错误。
2.3 把 sql 脚本变成可查询的数据库:命令行导入与 Navicat 导入两条路
数据库脚本文件一般是 .sql 格式,里面是建库、建表、插入初始数据的语句。导入方式有两条路,命令行适合交作业时展示「我懂底层」,图形化工具适合赶时间。
命令行导入的完整流程是:先登录 MySQL,再创建数据库,最后指定字符集导入。
mysql -u root -pCREATE DATABASE IF NOT EXISTS dormitory_system DEFAULT CHARACTER SET utf8mb4; USE dormitory_system; SOURCE D:/path/to/dormitory_system.sql;逻辑说明:SOURCE 命令是 MySQL 客户端自带的,它会把 sql 文件里的每一条语句顺序执行。如果文件路径包含中文或空格,Windows 下容易报错,常见解决方法是把 sql 文件拷到 C 盘根目录再用相对路径。
参数说明:登录时 -u 指定用户名,-p 表示接下来输入密码;SOURCE 后面的路径在 Windows 下用正斜杠或反斜杠都可以,但文件编码必须是 UTF-8,否则脚本里的中文注释会乱掉。
用 Navicat 导入的同学,注意导入前先在连接里右键「新建数据库」,字符集选 utf8mb4,排序规则选 utf8mb4_general_ci,然后再右键该数据库选择「运行 SQL 文件」。这个顺序不能反过来,直接对连接运行 SQL 文件,文件里的 USE 语句有时会把数据导错库。
导入完成后,用一个查询验证数据是否完整:查看管理员表里有没有初始账号,查看宿舍表里有没有已经录入的房间。这两项数据直接决定你能不能登录系统,所以把它设为第一步自检项。
3. 把系统跑通的最小路径:环境版本、配置文件与 Tomcat 部署
3.1 版本选型:JDK 8、Tomcat 8.5 与 MySQL 5.7 是实训作业最稳的组合
打开源代码之前,先确认环境版本。这是实训项目最容易翻车的地方:JDK 9 以上的模块化机制会让旧项目报错,Tomcat 10 用了 Jakarta 命名空间,老代码里 import javax.servlet 全部失效,MySQL 8.0 的驱动名和连接参数与 5.7 不同。最稳妥的组合是 JDK 8 + Tomcat 8.5 + MySQL 5.7,这个组合在几乎所有老项目中都能直接跑。
如果你的电脑已经装了 MySQL 8.0 也不用着急卸载,后面第 5 章会专门讲怎么改参数。选 JDK 8 的原因不是它新,而是 Java Web 老项目的 Servlet API 和 EL 表达式在 8 这个版本上行为最可预期;Tomcat 8.5 支持 Servlet 3.1,对应 JDK 8 编译的代码,不会出现类版本 52.0 之类的报错。版本检查命令如下。
java -version mysqld --version逻辑说明:java -version 输出里的版本号如果是 1.8.0_xx,说明是 JDK 8,可以继续;如果是 17 或 21,要考虑项目代码是否使用了高版本语法。mysqld --version 查看 MySQL 服务端版本,注意不是 mysql --version,后者只能看到客户端工具版本。
3.2 改对配置文件:JDBC 连接串、数据库密码与 web.xml 缺一不可
大多数实训项目把数据库连接信息放在 src 目录下的 jdbc.properties 或 db.properties 文件里,也有少数老项目直接写在 DAO 类的静态代码块里。先在整个项目里搜索「driver」这个关键词,很快就能定位。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/dormitory_system?characterEncoding=utf8&useSSL=false jdbc.username=root jdbc.password=123456参数说明:jdbc.driver 这一行在 MySQL 5.7 下用 com.mysql.jdbc.Driver,在 MySQL 8.0 下要改成 com.mysql.cj.jdbc.Driver,很多 500 错误就是这一行引起的。jdbc.url 里的 characterEncoding=utf8 保证中文传输不乱码;useSSL=false 是因为本地开发不需要 SSL 加密,省略时 MySQL 8.0 会报 SSL 连接警告。username 和 password 务必改成你自己 MySQL 的登录名和密码,这一步不改,后面所有 SQL 操作都会报 Access denied。
除了数据库配置,还要检查 web.xml 里的编码过滤器。这个配置决定表单提交的中文和数据查询的中文能否正常显示,通常长这样:
<filter> <filter-name>encodingFilter</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>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>逻辑说明:这个过滤器的作用是把请求和响应的字符集统一成 UTF-8。如果项目里没有这个配置,你需要在每个 Servlet 里手动写 request.setCharacterEncoding("UTF-8"),否则表单提交的中文到数据库里就是乱码。url-pattern 写 /* 表示拦截所有请求,注意不要写成 / 或漏掉这个过滤器。
3.3 部署与验证:把项目挂到 Tomcat 并看到登录页
环境配好后,把项目部署到 Tomcat。用 IDEA 或 Eclipse 的同学,在 Run Configuration 里选择 Tomcat Server,然后在 Deployment 标签里把项目 artifact 添加进去,Context Path 写成 /dormitory 或者直接留成 /。用命令行验证的同学,可以先把项目打成 war 包,复制到 Tomcat 的 webapps 目录下。
dormitory_system.war部署完成后启动 Tomcat,打开浏览器访问 http://localhost:8080/dormitory/login.jsp。看到登录页,说明环境基本通了;如果看到 404,先检查 context path 是不是写成了带版本号的路径,再看 webapps 下有没有正确解压出目录。
验证登录页只是第一步,真正能说明系统跑通的是「用初始账号密码登录成功」。初始账号通常写在文档或 SQL 脚本里,一般是 admin/admin 或 admin/123456。如果登录后跳转到了主页,说明 Session 写入和页面跳转正常,这一整套实训系统从源码到运行环境的链路才算真正打通。
4. 看懂核心代码的三个着力点:登录、宿舍分配与信息展示页面
4.1 登录入口:Servlet 转发、Session 会话与权限拦截
登录模块是几乎所有管理系统的门面,也是评分的固定考点。看懂了登录模块,也就看懂了这个项目里 JSP、Servlet、DAO 三层是怎么配合的。
典型流程是:login.jsp 提交表单 → LoginServlet 接收请求 → UserDao 查询管理员表 → 查询成功则把用户写入 Session → 重定向到 main.jsp;失败则返回登录页并附带提示信息。
@WebServlet("/login") public class LoginServlet extends HttpServlet { private AdminDao adminDao = new AdminDao(); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); Admin admin = adminDao.findByUsernameAndPassword(username, password); if (admin != null) { request.getSession().setAttribute("admin", admin); response.sendRedirect(request.getContextPath() + "/main.jsp"); } else { request.setAttribute("error", "用户名或密码错误"); request.getRequestDispatcher("/login.jsp").forward(request, response); } } }逻辑说明:request.getParameter 拿到表单字段,adminDao.findByUsernameAndPassword 执行 SELECT 查询;查询成功用 sendRedirect 跳转,失败用 forward 带回错误提示。这里有个容易被问到的问题——为什么失败用 forward 而不是 sendRedirect?因为 forward 能携带 request 作用域里的 error 属性,而 sendRedirect 是浏览器重新发起请求,request 里的数据会丢。
参数说明:Session 的 key 名「admin」要和后续 JSP 页面里的 ${sessionScope.admin.name} 保持一致,如果这里叫 admin,页面里写 ${sessionScope.user},就会拿到空值。main.jsp 里通常用 EL 表达式判断是否登录,可以在 main.jsp 开头看到这样的代码:如果 sessionScope.admin 为空就跳回登录页。这是最简单的权限控制,虽然没有拦截器那么专业,但足以应付实训答辩。
4.2 宿舍分配的核心逻辑:多表更新要用事务,分页查询要算 limit
宿舍分配是这个系统的业务核心,也是最容易在答辩时被追问「线程安全」的模块。先看需求:管理员把学生分配到某间宿舍,系统要检查该宿舍床位数是否已满,学生是否已分配过宿舍,然后更新宿舍表的已住人数和学生表的宿舍编号。
这个场景至少涉及两次更新操作,必须放在同一个事务里。常见做法是在 DAO 方法里手动控制事务边界。
public boolean assignDormitory(String studentId, int dormId) { Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交,开启事务 conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); String checkSql = "SELECT bed_count, used_bed FROM dormitory WHERE dorm_id = ? FOR UPDATE"; // 执行查询,判断 used_bed < bed_count String updateDorm = "UPDATE dormitory SET used_bed = used_bed + 1 WHERE dorm_id = ?"; String updateStudent = "UPDATE student SET dorm_id = ? WHERE student_id = ?"; // 依次执行两个 update conn.commit(); // 全部成功,提交事务 return true; } catch (Exception e) { if (conn != null) { conn.rollback(); // 任一步失败,回滚 } e.printStackTrace(); return false; } finally { DBUtil.close(conn, null, null); } }逻辑说明:setAutoCommit(false) 是事务的关键,它让后面的多条语句在 conn.commit() 之前不会真正写入数据库;FOR UPDATE 是行级锁,防止两个管理员同时分配同一间宿舍的最后一个床位;finally 里必须把连接归还连接池或关闭,否则实训项目跑久了会出现连接耗尽。
参数说明:TRANSACTION_READ_COMMITTED 是事务隔离级别,它能避免脏读;如果你对事务隔离级别不熟悉,可以不写 setTransactionIsolation 这一行,用数据库默认的 REPEATABLE_READ 也不会出大问题。注意租客管理系统常常把「宿舍编号变更」也做成单独功能,但在代码里直接 UPDATE student SET dorm_id 会留下历史空白,需要记录分配历史的系统应改为插入一条分配记录再更新当前状态,这个区别可以写进文档的「改进方向」一节。
分页查询也是宿舍管理系统里的常客,学生列表和报修列表都需要。常见写法是计算 limit 偏移量:
int pageNum = Integer.parseInt(request.getParameter("pageNum")); int pageSize = 10; int offset = (pageNum - 1) * pageSize; String sql = "SELECT * FROM student LIMIT ?, ?";参数说明:pageSize 是每页条数,offset 是跳过的条数;如果 pageNum 从 1 开始,offset 就是 (pageNum - 1) * pageSize。老项目里有人把 limit 写成 LIMIT 10, 20,意思是跳过 10 条取 20 条,语义和 LIMIT offset, count 一致,但容易和 pageSize 混淆,代码里建议用命名参数来避免答辩时解释不清。
4.3 个人信息展示页与表单提交:EL 表达式、JSTL 和页面刷新时机
JSP 页面里最常看到的是 jsp 个人信息展示页面,学生详情页就是一个典型。老实训项目会直接在 JSP 里写 Java 代码块,例如 <% Student s = (Student) request.getAttribute("student"); %>,这种写法现在不推荐,但不妨碍你读懂它。新一点的写法用 EL 表达式和 JSTL 标签。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <table> <tr><td>学号</td><td>${student.studentId}</td></tr> <tr><td>姓名</td><td>${student.name}</td></tr> <tr><td>宿舍</td><td>${student.dormitory.building}-${student.dormitory.roomNo}</td></tr> </table>逻辑说明:${student.studentId} 会调用 Student 类的 getStudentId() 方法,这就是后面要说的 JSP 属性访问规则。student 对象由 Servlet 通过 request.setAttribute("student", student) 传入,如果名字对不上,页面上会直接显示空字符串。
参数说明:JSTL 标签需要在 web.xml 所在项目的 WEB-INF/lib 下放 jstl.jar 和 standard.jar,如果项目报 TLD 相关错误,八成是这两个 jar 缺失或版本不匹配。
还有一个容易被忽略的小需求:JSP 页面在提交表单后需要在加载完成后自动刷新一次。常见做法有两种,一种是在页面 head 里加 meta refresh,另一种是用 JavaScript 的 window.onload。如果你在改完宿舍分配后想看最新床位数据而不想手动按 F5,可以这样写:
<meta http-equiv="refresh" content="0;url=listDormitory.jsp">window.onload = function() { location.reload(); };两种方式的区别在于:meta refresh 是页面加载完立即跳转到指定 URL,适合保存后自动跳回列表页;location.reload() 是原地刷新。实战里不要在列表页的 body 上直接挂 onload 刷新,否则每次进入页面都会反复刷新,产生闪烁。
5. 实训项目高频踩坑与排查:数据库连不上、中文乱码和端口占用
5.1 现象一:Tomcat 一启动就 500,Caused by ClassNotFoundException: com.mysql.jdbc.Driver
现象:启动 Tomcat 后访问任何需要查询数据库的页面,浏览器显示 500 Internal Server Error,Tomcat 日志里能看到 Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。
原因:项目里没有引入 MySQL 的 JDBC 驱动 jar,或者驱动 jar 在 Tomcat 运行时找不到。很多实训项目把 mysql-connector-java 的 jar 放在了项目的 lib 目录下,但没有把它添加到 Tomcat 的 classpath。
解决:确认 jar 文件在 WEB-INF/lib 下,然后在 IDE 里执行 Build Artifacts 重新构建一次;用外部 Tomcat 启动时,检查项目输出目录 target 下的 WEB-INF/lib 里有没有这个 jar。少数情况是驱动版本太老,建议换成 5.1.49 或 8.0.33 这类常见版本,不要用 5.0.x。
5.2 现象二:查出来的中文全是问号
现象:登录页能打开,管理员名字和学生的中文姓名在页面上显示为问号或乱码。
原因:字符集链路断了。这条链路是「JSP 页面编码 → 请求编码 → Tomcat 连接器编码 → 数据库连接编码 → 表字符集」,任何一环不是 UTF-8,中文就会在某一端变问号。
解决:按顺序检查三条配置。第一,jsp 文件顶部有没有 <%@ page contentType="text/html; charset=UTF-8" %>;第二,web.xml 里的 SetCharacterEncodingFilter 有没有配;第三,jdbc.url 里是否带上 characterEncoding=utf8。如果都改了还是乱码,用 Navicat 看一下表结构,如果表是 latin1 编码,直接 ALTER TABLE student CONVERT TO CHARACTER SET utf8mb4,这个操作会重建表,事先备份一下更稳妥。
5.3 现象三:本地 MySQL 8.0 导致驱动冲突,报 Public Key Retrieval is not allowed
现象:项目用 MySQL 5.7 写好,你电脑装的是 MySQL 8.0,启动后报 Public Key Retrieval is not allowed,或者 Communications link failure。
原因:MySQL 8.0 默认使用 caching_sha2_password 认证插件,而老驱动 com.mysql.jdbc.Driver 默认走 mysql_native_password,两边握手失败。
解决:两种方案任选。方案一是把驱动换成 com.mysql.cj.jdbc.Driver,并在 jdbc.url 后面加两个参数:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/dormitory_system?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true方案二是在 MySQL 里把账号认证方式改回老协议:ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; 然后 FLUSH PRIVILEGES。这个方案适合不想换驱动的老项目,但要注意 MySQL 8.0 的 mysql_native_password 插件仍然内置,因此可以随时切回去。
5.4 现象四:80/8080 端口被占用,Tomcat 反复重启也看不到新页面
现象:Tomcat 启动时日志报 Port 8080 required by Tomcat v8.5 Server at localhost is already in use,或者浏览器能打开但一直显示旧页面。
原因:8080 端口被其他进程占用了,通常是之前启动的 Tomcat 没有彻底关闭,或本地开发工具占用了该端口。反复重启看不到新页面,往往是因为 Tomcat 没杀掉,或者浏览器缓存了旧页面。
解决:在命令行里查端口占用并结束进程。
netstat -ano | findstr 8080 taskkill /F /PID 进程号修改 Tomcat 端口也可以,在 conf/server.xml 里找到 <Connector port="8080" protocol="HTTP/1.1" .../>,把 8080 改成 8088,改完重启。注意浏览器访问时也要跟着改端口。
5.5 现象五:数据被改乱没有后悔药,靠重复导入 sql 脚本找回初始状态
现象:练手的时候把宿舍分配、水电费记录改得一团糟,想恢复到处女状态,却发现系统没有提供重置功能。
原因:这是实训作业的特性,没有生产环境的备份机制。大家常把数据库当成测试环境里的黑匣子,改坏了就无从下手。
解决:SQL 脚本就是后悔药。把 2.3 节导入的那个 sql 文件再执行一次即可,但执行之前要小心:如果脚本第一行是 CREATE DATABASE 而不是 DROP DATABASE IF EXISTS,重复执行会报数据库已存在。解决方式是先手动清库再导入:
DROP DATABASE IF EXISTS dormitory_system; CREATE DATABASE dormitory_system DEFAULT CHARACTER SET utf8mb4; USE dormitory_system; SOURCE D:/backup/dormitory_system.sql;操作完成后,重新用初始账号密码登录,所有数据回到最初状态。这套「先 DROP 再建库再导入」的流程本身也值得写进操作文档,答辩时老师很吃这一套。
6. 让这份作业比同组人多走一步:连接池、超员约束与 Excel 批量导入
6.1 把裸 JDBC 换成 Druid 连接池:一个考频极高的答辩加分点
第 4 章的代码里,DBUtil.getConnection() 是最原始的写法:每次请求都 new 一个连接,用完关闭。这在实训答辩里会被追问一个问题:「高并发下你的系统支持几个人同时用?」回答不上来就是扣分点。常见做法是引入 Druid 连接池,让连接复用。
druid.driverClassName=com.mysql.jdbc.Driver druid.url=jdbc:mysql://localhost:3306/dormitory_system?characterEncoding=utf8&useSSL=false druid.username=root druid.password=123456 druid.initialSize=5 druid.maxActive=20DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/dormitory_system?characterEncoding=utf8"); dataSource.setUsername("root"); dataSource.setPassword("123456"); dataSource.setInitialSize(5); dataSource.setMaxActive(20); Connection conn = dataSource.getConnection();注意:Druid 的 jar 要放进 WEB-INF/lib,如果项目用了 Spring,直接用 DruidDataSource 的 bean 配置更省事。答辩时重点讲 initialSize 和 maxActive 这两个参数的含义即可。
6.2 给宿舍分配加一个「不可超员」约束:从代码层面堵住数据错乱
第 4.2 节的分配代码虽然用了事务和 FOR UPDATE,但表结构本身没有兜底约束。实际练习时可以直接 UPDATE 语句绕过业务代码把 used_bed 改成超过 bed_count 的值,数据就损坏了。可以加一个数据库层面的约束保证业务兜底。
ALTER TABLE dormitory ADD CONSTRAINT chk_bed_not_over CHECK (used_bed <= bed_count);MySQL 8.0 支持 CHECK 约束并会强制生效,5.7 会忽略它,但加上不会报错。这是一道不错的加分题:代码层用事务保证原子性,数据库层用约束保证最终一致性,两层都写进文档,比单纯贴出一大段代码亮眼得多。
6.3 用 Excel 批量导入学生数据:让文档里的「可用性」变成一句话
学生宿舍管理系统在实训评分里常被质疑「数据都是手动录入的,不方便」,Excel 批量导入功能就是回应这个质疑的最短路径。不需要引入 EasyExcel 这种重框架,用 POI 的入门写法就能实现:读取 Excel 每一行,拼成 INSERT SQL,用 JDBC 的 addBatch 批量执行。
String sql = "INSERT INTO student(student_id, name, gender, major, phone) VALUES (?,?,?,?,?)"; PreparedStatement ps = conn.prepareStatement(sql); for (Row row : sheet) { 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();注意:手机号这一列如果 Excel 里是数字格式,getStringCellValue 会读到科学计数法,常见做法是先把 Excel 列格式改成文本,或者在代码里用 DecimalFormat 格式化。这个坑不填,批量导入就会收获几百个手机号乱码,这是我当年实训踩过的第一道坎。
做这个项目我还有一个习惯:验收前把第 5 章的五类报错现场挨个触发一遍,记录每次修复步骤。这套「故障手册」留给下一届学弟学妹,比只交源码和数据库更能证明你真的做透了。希望这份从拆解标题到跑通系统的笔记能帮你把这段实训路走得更稳。
本文还有配套的精品资源,点击获取