简介:这是一套面向Java Web初学者的Servlet+JSP+MySQL宿舍管理系统实战项目,适合刚接触Web开发、需要完整练手案例的学生与自学者。项目围绕宿舍信息管理展开,涵盖用户注册登录、宿舍数据增删改查等核心业务,帮助理解Servlet处理请求、JSP渲染视图、JDBC操作MySQL的完整链路。压缩包共63个文件,约10.01MB,包含18个java源码与18个class编译文件、5个jsp页面、3个jar依赖,以及sql建表脚本、配置说明docx、功能描述txt和演示mp4,另附4张png界面截图,便于对照运行效果。资源还提供数据库设计、Servlet编写、JSP页面创建、数据库连接与错误处理等开发流程说明,并涉及session保持登录状态、MVC分层组织代码等进阶思路。目前已有1160人学习下载,可作为课程设计或毕业设计的起步模板,帮助快速搭建可运行环境并掌握前后端与数据库协作方式。
1. 从一份老派 JSP 宿舍管理系统说起:它到底能跑通什么
如果你手头正好有一套008_java+jsp+mysql简单宿舍管理系统.zip,解压后看到sushe代码目录、nafeng.sql数据脚本、详细配置.docx和几段演示视频,那你拿到的不是一份“过时玩具”,而是一条完整的 Java Web 请求链路标本。它用最原始的 Servlet + JSP + MySQL 组合,把用户注册、登录、宿舍信息增删改查这些动作串了起来,没有 Spring、没有 MyBatis、没有前后端分离,所有逻辑都摊在明面上。对刚接触 Java Web 的人来说,这种“裸奔式”结构反而最容易看清 HTTP 请求怎么进 Servlet、JDBC 怎么连数据库、JSP 怎么把结果渲染成 HTML。它适合想搞懂 MVC 雏形、需要交课程设计、或者准备面试时被问到“Servlet 生命周期”却答不踏实的人。你不需要先学一堆框架,只要装好 JDK、Tomcat 和 MySQL,就能把这份代码跑起来,亲眼看到数据从表单进、从页面出。
2. 把项目跑起来:JDK、Tomcat 与 MySQL 的版本咬合
2.1 环境选型:为什么这套代码挑 Tomcat 8/9 而不是 10
这份系统用的是javax.servlet包,不是jakarta.servlet。Tomcat 10 之后 Servlet API 的包名整体迁移到了jakarta.*,如果你直接把sushe丢进 Tomcat 10 的webapps,启动时大概率报ClassNotFoundException: javax.servlet.http.HttpServlet。常见做法是选 Tomcat 8.5 或 9.0,这两个版本仍然使用javax.servlet,和代码里的import javax.servlet.*完全对得上。JDK 方面,代码没有用到模块化特性,JDK 8 最稳,JDK 11 也能跑,但别上 JDK 17 以上,老版本 Tomcat 对高版本 JDK 的反射限制会带来额外麻烦。MySQL 用 5.7 或 8.0 都行,区别在 JDBC 驱动类名和连接串参数,后面会具体说。
先确认三个东西的版本:
java -version # 期望输出:java version "1.8.0_xxx" 或 "11.0.x" mysql --version # 期望输出:mysql Ver 14.14 Distrib 5.7.xx 或 8.0.xx # Tomcat 解压后查看 RELEASE-NOTES 里的版本号 cat apache-tomcat-9.0.xx/RELEASE-NOTES | head -5这三条命令分别确认 JDK、MySQL 客户端和 Tomcat 的大版本。版本对不上,后面连数据库和部署都会出玄学问题。
2.2 导入 nafeng.sql:建库、建表与字符集确认
压缩包里的nafeng.sql是数据库脚本,通常包含CREATE DATABASE、USE、CREATE TABLE和若干INSERT初始化数据。导入前先看一眼文件头部,确认库名和字符集:
head -30 nafeng.sql # 关注:CREATE DATABASE 后面跟的库名、DEFAULT CHARACTER SET 是什么如果脚本里写的是utf8而不是utf8mb4,在 MySQL 8.0 下也能执行,但存中文时建议手动改成utf8mb4。导入命令:
mysql -u root -p < nafeng.sql # 输入密码后无报错即导入成功 mysql -u root -p -e "SHOW DATABASES;" # 确认脚本里创建的库已经出现导入完成后,进库看一眼表结构,重点确认宿舍信息表的字段名,因为后面 Servlet 里的 SQL 语句要和字段严格对应:
USE nafeng; SHOW TABLES; DESC 宿舍信息表名; -- 常见字段:id、dorm_id、room_type、capacity、remark字段名对不上,Servlet 里的rs.getString("xxx")就会抛SQLException,这是新手最容易卡住的地方。
2.3 改 JDBC 配置:驱动类名、URL 参数与 MySQL 8 的时区坑
代码里连接数据库的配置一般写在一个工具类或db.properties里。你需要改三处:驱动类名、URL、账号密码。MySQL 5.7 和 8.0 的驱动类名不同:
| MySQL 版本 | 驱动类名 | URL 关键参数 |
|---|---|---|
| 5.7 | com.mysql.jdbc.Driver | useUnicode=true&characterEncoding=utf8 |
| 8.0 | com.mysql.cj.jdbc.Driver | 追加serverTimezone=Asia/Shanghai |
MySQL 8.0 不配serverTimezone会报The server time zone value 'xxx' is unrecognized,这是血泪经验里排第一的翻车点。配置示例:
// DBUtil.java 片段 String driver = "com.mysql.cj.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/nafeng?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false"; String user = "root"; String password = "你的密码"; Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, password);useSSL=false是为了避开 MySQL 8.0 默认要求 SSL 连接带来的SSL connection error,本地开发关掉即可。characterEncoding=utf8保证中文不乱码。改完配置,把mysql-connector-java的 jar 包放进WEB-INF/lib,版本要和 MySQL 服务端匹配,8.0 服务端配 8.0 驱动。
2.4 部署到 Tomcat 并验证登录页
把sushe目录整个复制到 Tomcat 的webapps下,启动 Tomcat:
# Linux/Mac ./apache-tomcat-9.0.xx/bin/startup.sh # Windows apache-tomcat-9.0.xx\bin\startup.bat # 看日志确认无异常 tail -f apache-tomcat-9.0.xx/logs/catalina.out浏览器访问http://localhost:8080/sushe/,如果出现登录页,说明 JSP 编译和 Servlet 映射都通了。用nafeng.sql里初始化的账号登录,能进主页就代表整条链路跑通。如果 404,检查web.xml里的url-pattern和访问路径是否一致;如果 500,看catalina.out里的堆栈,八成是 JDBC 配置或字段名问题。
3. 拆开 sushe 代码:Servlet 请求流转与 JSP 原生界面怎么配合
3.1 一个登录请求的完整路径:从 form 到 doPost 再到 session
登录功能是理解这套代码的最佳入口。JSP 登录页里有一个<form action="LoginServlet" method="post">,提交后 Tomcat 根据web.xml或注解把请求交给LoginServlet的doPost方法。doPost里做三件事:取参数、查数据库、写 session。
// LoginServlet.java 核心逻辑 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); UserDao dao = new UserDao(); User user = dao.login(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("currentUser", user); response.sendRedirect("index.jsp"); } else { request.setAttribute("msg", "用户名或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); } }setCharacterEncoding("UTF-8")必须在getParameter之前调用,否则中文用户名会乱码。sendRedirect和forward的区别在这里很关键:登录成功用重定向,防止刷新页面重复提交;登录失败用转发,保留request域里的错误提示。session.setAttribute把用户对象存进去,后续页面用session.getAttribute("currentUser")判断是否登录,这就是最原始的登录态保持。
3.2 宿舍信息 CRUD:DAO 层 SQL 与 JSP 列表渲染的字段对齐
宿舍信息的增删改查集中在DormServlet和对应的 DAO 类里。查询列表的 SQL 通常是SELECT * FROM dorm,然后在 JSP 里用 JSTL 或脚本片段遍历。原生 JSP 项目里常见的是脚本片段:
<%-- dormList.jsp 片段 --%> <%@ page import="java.util.List" %> <%@ page import="com.sushe.entity.Dorm" %> <% List<Dorm> list = (List<Dorm>) request.getAttribute("dormList"); for (Dorm d : list) { %> <tr> <td><%= d.getDormId() %></td> <td><%= d.getRoomType() %></td> <td><%= d.getCapacity() %></td> <td> <a href="DormServlet?action=edit&id=<%= d.getId() %>">编辑</a> <a href="DormServlet?action=delete&id=<%= d.getId() %>" onclick="return confirm('确认删除?')">删除</a> </td> </tr> <% } %>这里action=edit和action=delete是 Servlet 内部的分支判断依据,doGet里根据action参数决定调哪个方法。字段对齐是重点:JSP 里d.getDormId()对应实体类属性,实体类属性对应数据库字段,任何一环名字不一致都会导致页面显示null或直接报错。删除操作加confirm是基本防护,避免误点。
3.3 原生 JSP 的界面组织:include 复用与表单提交路径
这套系统的界面没有用任何前端框架,页面之间的复用靠<%@ include file="header.jsp" %>这种静态包含。头部导航、底部版权信息抽成单独文件,每个页面引入,改一处全站生效。表单提交路径要特别注意相对路径问题:如果 JSP 在子目录里,action="DormServlet"可能解析到错误位置,稳妥做法是用<%= request.getContextPath() %>/DormServlet。
<form action="<%= request.getContextPath() %>/DormServlet?action=add" method="post"> 宿舍号:<input type="text" name="dormId" required> 房间类型:<input type="text" name="roomType"> 容纳人数:<input type="number" name="capacity"> <input type="submit" value="提交"> </form>request.getContextPath()返回项目部署名(这里是/sushe),拼出来的路径在任何目录层级下都正确。required是 HTML5 原生校验,减少空提交。提交后DormServlet的doPost里根据action=add走插入逻辑,插入完重定向回列表页,形成闭环。
4. 避坑与排查:这份老代码最容易翻车的五个地方
4.1 中文乱码:POST 和 GET 要分开治
现象:登录页输入中文用户名,后台收到的是????或乱码字符串。原因:POST 请求体默认编码不是 UTF-8,GET 请求的参数编码取决于 Tomcat 的server.xml里Connector的URIEncoding配置。解决:POST 在 Servlet 第一行加request.setCharacterEncoding("UTF-8");GET 要么改 Tomcatserver.xml给 Connector 加URIEncoding="UTF-8",要么在代码里用new String(request.getParameter("xxx").getBytes("ISO-8859-1"), "UTF-8")手动转。数据库连接串里的characterEncoding=utf8也要确认加上。
4.2 驱动加载失败:ClassNotFoundException 的三种可能
现象:启动或首次访问时报java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。原因:一是 jar 包没放进WEB-INF/lib;二是放错了位置,放到了 Tomcat 的lib下但版本冲突;三是 MySQL 8.0 用了旧驱动类名。解决:确认WEB-INF/lib下有mysql-connector-java-x.x.x.jar,MySQL 8.0 把类名改成com.mysql.cj.jdbc.Driver。如果项目用了 Maven,检查pom.xml里依赖的scope是不是provided,那会导致打包时 jar 不进WEB-INF/lib。
4.3 时区报错:MySQL 8.0 的 serverTimezone 必填
现象:连接数据库时抛The server time zone value '?D1ú±ê×?ê±??' is unrecognized。原因:MySQL 8.0 驱动要求明确指定时区,不指定就取系统默认,而 Windows 中文系统的时区名驱动识别不了。解决:URL 里加serverTimezone=Asia/Shanghai。如果还报错,检查 MySQL 服务端的default-time-zone设置,或者临时用serverTimezone=UTC先跑通,但存时间会有 8 小时偏差,生产环境别这么干。
4.4 404 与 500:路径映射和空指针的快速定位
现象:访问某个功能页报 404,或者提交表单后报 500。原因:404 通常是web.xml里url-pattern和表单action不一致,或者 JSP 文件放错目录;500 多半是 DAO 里rs.getString("字段名")字段名写错,或者session.getAttribute取出来是null还直接调方法。解决:404 先看 Tomcat 日志里请求的 URI,和web.xml对照;500 看catalina.out里的完整堆栈,定位到具体行号。空指针问题在取 session 属性后加判空,或者用拦截器统一处理登录校验。
4.5 删除后列表不刷新:重定向与浏览器缓存的配合
现象:点击删除后数据库确实删了,但页面列表还是旧数据。原因:删除操作后用了forward回列表页,或者浏览器缓存了之前的 GET 请求结果。解决:删除成功后用response.sendRedirect("dormList.jsp")重定向,强制浏览器发起新请求。如果还不行,在列表页 JSP 头部加禁用缓存的响应头:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0);5. 进阶用法:用 MVC 分层重构与 JDBC 工具类收口
5.1 把散落的 JDBC 代码抽成工具类
原始代码里每个 DAO 方法都写一遍Class.forName、getConnection、close,重复且容易漏关连接。我一般会抽一个DBUtil,用静态块加载驱动,提供getConnection和close方法:
public class DBUtil { private static final String DRIVER = "com.mysql.cj.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/nafeng?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false"; private static final String USER = "root"; private static final String PWD = "你的密码"; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new RuntimeException("驱动加载失败", e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PWD); } public static void close(Connection conn, PreparedStatement ps, ResultSet rs) { try { if (rs != null) rs.close(); } catch (SQLException ignored) {} try { if (ps != null) ps.close(); } catch (SQLException ignored) {} try { if (conn != null) conn.close(); } catch (SQLException ignored) {} } }静态块保证驱动只加载一次,close方法按ResultSet、Statement、Connection顺序关闭,避免资源泄漏。DAO 里只写 SQL 和参数绑定,代码量能砍掉三分之一。
5.2 用 PreparedStatement 替换字符串拼接 SQL
原始代码里如果有"SELECT * FROM user WHERE username='" + username + "'"这种写法,必须换成PreparedStatement。一是防 SQL 注入,二是避免用户名里带单引号导致语法错误:
String sql = "SELECT * FROM user WHERE username=? AND password=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); ResultSet rs = ps.executeQuery();?是占位符,setString按位置绑定,驱动会自动处理转义。这是从“能跑”到“能看”的关键一步,面试被问到 JDBC 和 Statement 区别时也有实打实的代码支撑。
5.3 验证重构是否成功的三个检查点
重构完别急着说“好了”,按这三步走一遍:第一,登录、增删改查每个功能点手动点一遍,确认页面无报错;第二,看 Tomcat 日志里有没有SQLException或连接泄漏警告;第三,把DBUtil里的密码故意改错,确认报错信息清晰指向连接失败,而不是一堆看不懂的堆栈。从那以后我每次改完 JDBC 相关代码,都强制走一遍“错密码测试”,确保异常处理没被吞掉。希望这份拆解能帮你把这份 JSP 宿舍管理系统真正跑通、改顺。
本文还有配套的精品资源,点击获取