☰
JSP+Servlet+Struts+MySQL宿舍管理系统实战:设计、部署与踩坑全解析
2026/10/8 2:36:48 网站建设 项目流程

不用太多铺垫,直接说重点:这套宿舍管理系统,技术栈就是典型的 javaweb 老三样——JSP 负责页面展示、Servlet 和 Struts 一起扛控制层逻辑、MySQL 存数据,前端再配点 JavaScript 做交互。听上去确实不够“新潮”,但这个组合恰恰是很多课程设计、毕业设计和外包项目的首选方案,因为结构直观、分层清晰、跑起来轻快,不管是学生拿来练手还是中小企业做内部系统都够用。

我去年帮人带过一套类似架构的宿舍管理系统,从需求梳理到部署上线全程走了一遍,期间踩了不少坑,也积累了很多有参考价值的细节。这篇文章不会给你讲虚的框架原理,就按我实际动手的顺序,把这个项目的设计思路、核心代码、环境配置、运行步骤和常见问题全部拆开聊一遍。新手看完可以直接照着做,有一定基础的同学也能在细节里找到自己平时容易忽略的点。

1. 项目概述与需求拆解

1.1 这个系统到底解决什么问题

宿舍管理这件事,看起来就是“记谁住哪间房”,真正落地上手之后才发现杂事一堆:新生入住要分配床位、学生调换宿舍要审批记录、电灯水管坏了要报修跟踪、辅导员要发通知公告、晚上查寝还要登记晚归情况。用 Excel 登记当然也能跑,但数据一多就乱了,尤其是“这个床位到底空不空”“这个学生住哪栋哪间”这种高频查询,表格得翻半天。

这套系统就是把上面这些线下流程搬到网页上,核心价值就三个:信息集中、流程在线、权限分明。管理员统一维护宿舍楼和房间数据,宿管处理报修和日常事务,学生在线查看自己的住宿信息、提交调宿和报修申请,每一笔操作都留痕,数据状态实时更新。

从开发者的视角看,这个项目麻雀虽小五脏俱全。它有典型的增删改查,有角色权限区分,有业务状态流转(入住、调宿、退宿、报修处理中/已完成),有文件上传(比如学生的入住照片),甚至还有图形化的床位选择。把这一套完整做下来,你对 JavaWeb 项目的理解会透彻很多——这也是为什么无数高校课程设计都选这个题目的原因。

1.2 功能模块与角色权限划分

宿舍管理系统通常涉及三类用户,每一类看到的页面和能做的操作完全不一样。

  • 管理员:系统权限最高。管理宿舍楼栋与房间信息、分配初始床位、维护学生账号、查看全站报表、发布公告、处置复杂调宿申请。
  • 宿管(楼栋管理员):负责日常事务。处理学生提交的报修单、登记晚归/外来访客、更新房间入住状态。
  • 学生:基础用户。查看自己的住宿卡片、提交调宿与报修申请、查看公告、维护个人信息(上传头像、修改联系方式)。

权限控制不复杂,但一定要做干净。我的做法是在登录成功后把用户角色存进 session,然后写一个过滤器(Filter),根据请求路径前缀拦截未登录用户和管理员页面访问。比如/admin/*路径只允许管理员角色访问,普通学生访问直接重定向回登录页。这一套拦截逻辑在 Servlet 里写起来也就是二三十行代码的事,但能让整个系统的安全性上一个台阶。

注意:千万别只在前端页面里藏链接来实现权限控制。别人直接敲 URL 就能绕过,后台操作就全裸奔了。权限校验必须放在服务端拦截器里做,前端隐藏只是用户体验层面的辅助。

2. 技术选型:为什么是 JSP + Servlet + Struts + MySQL

2.1 经典 JavaWeb 技术栈的分工逻辑

刚接触 JavaWeb 的人经常搞不清 JSP 和 Servlet 到底什么关系,再加上一个 Struts 就更晕了。我习惯打个比方:Servlet 是个厨房里的厨师,收到客人点菜单(HTTP 请求)就按菜单做饭(处理业务逻辑),做完让传菜员端出去(返回响应);JSP 就是传菜员和菜品展示台,负责把做好的菜(数据)摆盘端给客人看;Struts 则是餐厅经理定的一套工作流程,规定厨师怎么接单、怎么分活、做完菜往哪递。

具体到项目里:

  • JSP 负责展示层。页面里用 JSTL 标签和 EL 表达式渲染数据,配合少量 Java 脚本片段处理临时逻辑。
  • Servlet 负责核心控制。接收 JSP 表单提交的请求,调用业务方法,然后把结果放回 request 域,转发或重定向到目标页面。
  • Struts 在这里扮演的是增强版的控制器调度器。它把请求 URL 映射到对应的 Action 类,通过struts-config.xml做集中配置,管理页面跳转的流转逻辑,比纯 Servlet 一个个写映射要规范不少。Struts 1.x 的 Action 和 ActionForm 模式,天然把表单收集和业务处理分离了,配合ActionForward统一管理跳转路径,团队协作时不会出现一个人一种跳转写法的乱象。

有些人会觉得项目 Junit 都没上还整 Struts,是不是有点重?我的看法是:正是因为它“重”,才适合拿来教学和课设。Struts 的配置驱动方式能让你理解框架的底层逻辑,等以后切 SpringMVC 的时候,你会觉得概念是相通的——DispatcherServlet 无非就是换了个马甲的 ActionServlet,配置方式不一样而已。

2.2 数据库设计的核心思路

宿舍管理系统的数据量不大,但表之间的关系要捋清楚。我设计的核心表大概有这几张:

  • user:用户表。字段包括 id、username、password、role(1管理员/2宿管/3学生)、姓名、学号、性别、手机号、头像路径。
  • building:宿舍楼表。记录楼栋编号、楼栋名称、楼层数、每层房间数。
  • dormitory:宿舍房间表。关联 building,记录房间号、所在楼层、床位数、已住人数、是否满员。
  • student_dorm:住宿关系表。这是系统里最关键的一张关联表,记录学生 id、宿舍 id、床位号、入住时间、退宿时间。为什么要单独建表而不是在学生表里直接加个宿舍字段?因为住宿是动态变化的,学生可以调宿、退宿,单独建表才能保存完整历史记录。
  • repair:报修表。学生提交的报修单,包含宿舍 id、报修内容、状态(待处理/处理中/已完成)、提交时间、处理人、处理时间。
  • notice:公告表。标题、内容、发布人、发布时间。
  • visit_record:访客登记表(可选)。来访人姓名、访问宿舍、时间、事由。

表设计就遵循一个原则:一个主题一张表,关联关系用外键或逻辑外键表达,不把多状态的业务塞进同一个字段里硬编码。比如调宿记录,很多人喜欢在student_dorm里直接 update 宿舍 id,其实更好的做法是保留旧记录,把退宿时间写上,再插入一条新记录,这样“这个学生住过哪几个宿舍”一查就有痕迹,对后续审计很有用。

数据库字符集我建议在建库时就定成 utf8mb4,别再回头改:

CREATE DATABASE dormitory_system CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

utf8mb4 能存 emoji 和生僻姓名,踩过坑的人都知道 utf8 在遇到特殊字符时有多痛苦。

3. 核心模块实现与关键代码

3.1 数据库连接封装与表结构落地

项目既然用了 MySQL,就得先解决 JDBC 连接的问题。直接在每个 Dao 类里写DriverManager.getConnection()显然不行,代码冗余不说,改个数据库密码得全项目翻。我用一个工具类封装连接,考虑到课设项目并发量不高,不引入重量级连接池,用最简单的静态初始化方式加载配置。

先写数据库配置,放在 src 根目录的db.properties文件里:

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/dormitory_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=123456

注意 URL 里几个参数的作用:useUnicode=true&characterEncoding=utf8解决中文乱码,serverTimezone=Asia/Shanghai解决 MySQL 8.x 下的时区报错。很多人连接时报The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized,就是缺了后面那个参数。

连接工具类核心代码如下:

public class DBUtil { private static final Properties props = new Properties(); static { try { InputStream in = DBUtil.class.getClassLoader().getResourceAsStream("db.properties"); props.load(in); Class.forName(props.getProperty("jdbc.driver")); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection( props.getProperty("jdbc.url"), props.getProperty("jdbc.username"), props.getProperty("jdbc.password") ); } public static void close(ResultSet rs, PreparedStatement ps, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }

Dao 层随手举个例子,查询某栋楼所有房间的方法:

public List<Dormitory> findByBuildingId(int buildingId) { String sql = "SELECT * FROM dormitory WHERE building_id = ?"; List<Dormitory> list = new ArrayList<>(); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = DBUtil.getConnection(); ps = conn.prepareStatement(sql); ps.setInt(1, buildingId); rs = ps.executeQuery(); while (rs.next()) { Dormitory d = new Dormitory(); d.setId(rs.getInt("id")); d.setRoomNo(rs.getString("room_no")); d.setCapacity(rs.getInt("capacity")); d.setCurrentCount(rs.getInt("current_count")); list.add(d); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(rs, ps, conn); } return list; }

这里想强调一个细节:在循环里面逐条拼接 SQL 字符串是新手最容易犯的错误,不仅效率差,还有 SQL 注入风险。所有动态参数一律用PreparedStatement的?占位符传参,这是 JavaWeb 开发的底线习惯。

3.2 登录鉴权与 Session 管理

登录模块是系统的门面,也是不少项目的重灾区。我的实现思路是:登录页提交用户名校验密码到 LoginServlet(或者由 Struts 的 LoginAction 处理),查询 user 表比对密码(建议 MD5 加盐存储,别明文存),成功后把用户对象和角色放进 session,同时把登录状态写进一条login_log表(记录登录时间和 IP,方便安全审计)。

Struts 的 ActionForm 在这种场景非常好用。定义一个LoginForm继承 ActionForm,字段就是 username 和 password,页面提交后 Struts 会自动把表单数据填充进 form bean,你在 Action 里直接读取就行,省去了手动request.getParameter()的流程。Action 里验证通过返回一个ActionForward指向主页,失败则返回登录页并带上错误提示。

权限拦截我用一个 Filter 实现,核心判断逻辑如下:

public class LoginFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; HttpSession session = req.getSession(); User user = (User) session.getAttribute("loginUser"); if (user == null) { resp.sendRedirect(req.getContextPath() + "/login.jsp"); return; } String uri = req.getRequestURI(); if (uri.contains("/admin/") && user.getRole() != 1) { resp.sendRedirect(req.getContextPath() + "/unauthorized.jsp"); return; } chain.doFilter(request, response); } }

在web.xml里把这个 Filter 映射到所有请求,白名单路径(login.jsp、LoginAction、静态资源)放行。用 Struts 项目记得把 Filter 的 URL 匹配范围写成/do/*这类,别拦截到静态资源导致页面样式全丢。

3.3 宿舍分配与调换业务

宿舍分配是这类系统的核心业务,也是最容易出逻辑漏洞的地方。常见的规则有几种:同性别必须分到同一栋楼或同一楼层(看学校要求)、每间房入住人数不能超过床位数、调宿目标房间必须还有空余床位。

我实现分配的时候画了一个状态机:学生初始是“未分配”,进入分配操作后给一个“已锁定床位”的中间状态,确认支付或确认信息后变为“已入住”。为什么要搞这个中间状态?因为分配需要两个动作:界面先展示空床位让学生选,学生点选后再写库。如果不锁床位而直接写库,两个人同时选同一张床就会产生“超卖”问题。解决思路也很简单,在student_dorm表里给bed_no和dorm_id加唯一索引,数据库层面兜底,谁后到谁失败。

床位选择这个交互,热搜词里提到的“JSP 图片如何对坐标定位”就在这里派上用场。我做的方案是:宿舍总平面图放成一张 JSP 展示的图片,每个床位的位置提前在配置里记录好中心点坐标(像素值),JavaScript 在图片的onclick事件里拿到点击位置的 offsetX 和 offsetY,找预置床位坐标表里最近的那个,渲染成高亮选中态,最后把选中的床位 id 提交给后台。

这里有个小坑:图片的ontent坐标在页面缩放或不同分辨率下会偏移,处理办法是用图片的naturalWidth除以当前 clientWidth 得到一个缩放比,把鼠标坐标换算回图片原始坐标系再匹配床位坐标点,实测下来误差可以控制在几个像素以内。

调宿流程相对复杂一点,涉及两张以上表的更新。我的做法是:学生提交调宿申请时把student_dorm表原记录的leave_time字段更新为当前时间,同时插入目的宿舍的新记录。两件事要么一起成功要么一起失败,所以必须放在事务里:

public boolean transferDorm(int studentId, int newDormId, int newBedNo) { Connection conn = null; try { conn = DBUtil.getConnection(); conn.setAutoCommit(false); String sql1 = "UPDATE student_dorm SET leave_time=NOW() WHERE student_id=? AND leave_time IS NULL"; PreparedStatement ps1 = conn.prepareStatement(sql1); ps1.setInt(1, studentId); ps1.executeUpdate(); String sql2 = "UPDATE dormitory SET current_count=current_count-1 WHERE id=(SELECT dorm_id FROM student_dorm WHERE student_id=? AND leave_time IS NULL)"; // ... 更新旧宿舍人数、插入新记录、更新新宿舍人数 conn.commit(); return true; } catch (SQLException e) { try { if (conn != null) conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); return false; } finally { try { if (conn != null) conn.setAutoCommit(true); } catch (SQLException e) { e.printStackTrace(); } DBUtil.close(null, null, conn); } }

事务、事务、事务。重要的事情说三遍。不开启事务,调宿做到一半报错,旧宿舍退了、新宿舍没进,学生就变成“流浪汉”数据了,这种 bug 坑人于无形,排查起来极花时间。

3.4 报修流程与公告模块

报修模块的逻辑相对简单,本质是一个多状态的可追踪工单。表设计里我用状态字段区分:0 待处理、1 处理中、2 已完成。学生在自己的页面里提交报修单,填宿舍号、故障描述,可选上传现场照片。宿管端有一个工作台,按状态分页展示报修单,点“接单”把状态改成 1,维修完成后点“完成”并填写处理备注。全程时间线记录在repair_log表里。

这里分享一个体验优化的小技巧:当学生提交报修成功或宿管更新状态时,调一次 JavaScript 弹窗提示并局部刷新列表,而不是整个页面跳转刷新。我用的方案是在 JSP 里提前渲染一个隐藏的div容器,用fetch异步请求 Action 接口返回的 JSON 数据,然后用 JavaScript 动态拼接 HTML 对应更新 DOM。比例才几十行代码,但用户体验比传统 form 提交好太多。

公告模块就更常规了,管理员发布、列表展示、详情查看三件套。唯一建议是公告表加一个top_flag置顶字段,发布时置顶的重要通知排在列表前面,这个需求是真实学校管理中一定会遇到的。

4. 项目环境搭建与运行部署

4.1 JDK + Tomcat + MySQL 环境安装要点

这类 JavaWeb 项目跑起来最怕的就是环境不干净。结合最近不少人卡在 MySQL 安装这一步,我先说数据库。

MySQL 5.7 和 8.0 的安装路径不太一样。5.7 建议直接用mysql-5.7.44-winx64.zip解压版(微软官方不再直接提供 exe 安装包之后,zip 方式是很多教程的选择),解压后执行:

cd D:\mysql-5.7.44-winx64\bin mysqld --initialize-insecure net start mysql

--initialize-insecure会生成一个 root 用户且密码为空的数据目录,初装阶段方便登录,后续用ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码';设置密码。

MySQL 8.0 就用常规的 exe 安装包一路 Next,选 Server Only 即可。8.0 默认密码策略较强,设置密码时注意大小写字母加数字和特殊符号的组合。如果后续连接报Public Key Retrieval is not allowed,在 JDBC URL 后面追加allowPublicKeyRetrieval=true即可解决。

JDK 和 Tomcat 相对简单但版本要匹配:JDK 8 搭配 Tomcat 8.5/9.0,JDK 11 也兼容 Tomcat 9。JDK 版本别追求最新,因为老项目的编译目标可能停在 1.8,高版本的 javac 默认模块化行为有时会出幺蛾子。Tomcat 解压后配置环境变量CATALINA_HOME,bin/startup.bat能启动,浏览器访问http://localhost:8080看到猫脸页面就算成功。

建议:把 MySQL 的 bin 目录和 Tomcat 的 bin 目录都加进 PATH 环境变量里,命令行敲mysql和catalina run会方便非常多。

4.2 IDEA 导入项目与运行配置

网上搜“idea 运行 javaweb 项目配置”的人特别多,我在这把流程捋顺一遍。假设你拿到的是一个传统的 JavaWeb 项目目录(带 src、web/WEB-INF、jsp 页面这些)。

第一步,IDEA 里File -> New -> Project from Existing Sources,选项目根目录,选 Eclipse 或 Maven 导入均可。传统项目没有 Maven 的 pom.xml,就选 Eclipse 导入方式,一路 Next。

第二步,配置工程的 SDK:File -> Project Structure -> Project,设置 Project SDK 为本地 JDK(建议 1.8),Language Level 选 8。如果项目采用了 Java EE 特性和 Servlet 依赖,还要在Modules -> Dependencies勾选或者单独添加。

第三步,把依赖 jar 包加进 libraries。传统项目的 jar 藏在 web/WEB-INF/lib 里,IDEA 通常会自动识别,如果没有,点击+ -> Java,选中 lib 目录批量引入。注意mysql-connector-java.jar、struts.jar、jstl.jar和standard.jar这四样必须有,缺了任何一个启动时或页面上都会报错。

第四步,配置 Tomcat 运行环境。点击顶部工具栏的Add Configuration -> Tomcat Server -> Local,在Application server里选中本机 Tomcat 目录。切到Deployment标签,点+ -> Artifact,选项目的war exploded包,Application context 建议设为/dormitory。

第五步,启动前再检查一件事:项目的 web.xml 里如果有<welcome-file-list>指定了登录页,确认路径没错;没有的话就手动访问http://localhost:8080/dormitory/login.jsp。

4.3 完整运行步骤参考

我把从零开始跑通项目的完整步骤按顺序整理一下,方便对着操作:

  1. 安装 JDK,配置JAVA_HOME环境变量。
  2. 安装 MySQL,建库建表,把项目里的init.sql脚本执行入库(这一步注意 SQL 文件编码,用 utf8 保存,导入前source时若有中文乱码先执行SET NAMES utf8mb4;)。
  3. 解压 Tomcat,双击bin/startup.bat确认能启动。
  4. 打开 IDEA,导入项目前文步骤配置。
  5. 打开db.properties,按本机实际情况改用户名密码。
  6. IDEA 配置 Tomcat 后,启动项目。
  7. 浏览器访问登录页,用预设管理员账号(比如 admin/admin123)登录测试。

5. 高频踩坑与排查实录

5.1 MySQL 安装与连接报错

关于 MySQL 的安装,最近好几个同学遇到同一个问题:net start mysql提示服务名无效,或者服务启动后马上停止。前者多半是因为没有执行mysqld --install注册服务,后者最常见的原因是 my.ini 配置文件里的basedir和datadir路径写错了,或者 data 目录权限不对。我的建议是初装别急于自定义 my.ini,先用默认参数初始化跑通再说。

连接层面的高频报错,我整理了一个速查表:

报错信息原因解决方法
Access denied for user 'root'@'localhost'密码错误或空密码未设置用--defaults-file跳过权限校验重置 root
The server time zone value ...MySQL 时区未设置JDBC URL 加serverTimezone=Asia/Shanghai
Unknown database数据库名写错或未建库先执行建库 SQL
Public Key Retrieval is not allowedMySQL 8.0 客户端连接策略URL 加allowPublicKeyRetrieval=true
ClassNotFoundException: com.mysql.jdbc.Driver驱动包缺失或包名错误确认 MySQL 8.x 要用com.mysql.cj.jdbc.Driver
Loading class ... is deprecated驱动类名过时换成cj版驱动类名即可

5.2 JSP 中文乱码与路径问题

中文乱码是 JavaWeb 的老大难,归纳起来其实只有三个源头,逐个解决就能彻底根治。

第一,页面显示乱码。JSP 文件头必须有:

<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

第二,请求参数乱码(表单提交中文变问号)。在web.xml里配置一个全局编码过滤器:

<filter> <filter-name>encodingFilter</filter-name> <filter-class>com.dorm.filter.EncodingFilter</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>

filter 类里实现request.setCharacterEncoding(encoding)即可。

第三,数据库存取乱码。前面已经提到了,建库用 utf8mb4,JDBC URL 带上characterEncoding=utf8。这三层都处理干净,中文不会再出错。

路径问题是另一大痛点。JSP 页面里引用的 CSS、JS、图片一定要用绝对路径。传统项目里,我习惯在页面顶端用${pageContext.request.contextPath}拼出项目根路径,再拼资源路径。直接写css/style.css这种相对路径,在 JSP 转发后经常因为路径深度变化导致 404。这个问题遇到多的人,几乎都会在第 N 次犯时想砸电脑。

5.3 Struts 配置注意事项

用 Struts 1.x 的朋友可能遇到过:页面能打开,但一提交表单就 404 或者提示No action instance associated with this request. 这类问题的排查次序是固定的:

先看web.xml里 ActionServlet 的映射路径,然后是struts-config.xml的路径,最后看表单里 action 属性是否匹配。比如web.xml里配置的是:

<servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>

那么 JSP 里的表单 action 就必须写成xxx.do,而struts-config.xml里的<action path="/xxx">不需要带.do后缀,这个对应关系搞反的人可不少。

另一个棘手问题是struts-config.xml中 action 的scope属性。表单 bean(FormBean)的 scope 默认是 session,如果你设置了scope="session"但页面跳转返回时没清理,会导致表单数据残留,比如修改人员信息时,再打开一个新表单发现还带着上一个人的数据。解决办法:设置scope="request",或者在使用完的 Action 里调用session.removeAttribute手动清理。

6. 项目复盘与扩展方向

6.1 我在这个项目里踩过的坑

自己完整做一遍这种项目,跟看教程完全不是一回事。分享几个印象比较深的坑。

第一个坑是床位分配的唯一约束。最初没有想并发的问题,也没加唯一索引,结果测试的时候用两个浏览器登录两个账号同时选同一个床位,居然都成功了,数据库里出现了两条相同 dorm_id + bed_no 的记录。后来在student_dorm的表结构上加了唯一索引UNIQUE KEY uk_dorm_bed (dorm_id, bed_no),并且把写入操作包进事务里。原理就是数据库层面的兜底,哪怕上层逻辑有漏洞,数据库也不会让你写入脏数据。

第二个坑是报修单状态记录没有留时间线。一开始只在 repair 表里存放当前状态,后来宿管反馈说看不到“谁在什么时候处理过”,只能通过日志补。后来加了repair_log表,任何状态变化都插入一条记录。凡是涉及“状态流转”的业务,从一开始就应该设计独立的日志表,别偷懒。

第三个坑是 JSP 页面里大段 Java 脚本片段非常难维护。刚开始写页面习惯在<% %>里写循环、if、拼接 HTML,后来越改越乱,缩进都对不上。后来把所有 Java 脚本替换成 JSTL 配合 EL 表达式,页面清爽了一大截。如果你的项目里 JSP 出现了大量<% %>,建议尽早重构掉,纯标签化的页面可读性和可维护性完全不一样。

6.2 后续可以怎么升级

项目基础搭好了,往上升级的方向其实也很明确。

  • 持久层从 JDBC 升级成 MyBatis 或 JPA,消除样板代码。
  • 控制层从 Struts 迁移到 SpringMVC,体验注解式开发带来的效率提升。
  • 权限控制引入 Shiro 或 Spring Security,不再手写 Filter。
  • 前端引入 Vue + Element UI,页面交互做成分离开发的前后端架构。
  • 加上 Redis 做宿舍空床位的缓存查询,减轻 MySQL 压力。
  • 部署环境从单机 Tomcat 迁移到 Docker 加 Nginx,应对更大并发。

这些方向不一定马上做,但脑子里要有这个升级路线图。很多同学毕业设计做完就扔一边,真正面试时被问到“你这个系统有什么可以改进的”,能说出一两条实际可行的升级方案,印象分会大不一样。

这套系统给我最大的体会是:技术没有新旧之分,关键看是否适合你当下的需求。JSP+Servlet+Struts 的组合虽然不高端,但它把 JavaWeb 的核心原理展示得明明白白,能让你理解 HTTP 请求到后端响应的完整链路。把这个项目吃透,后面学什么框架都只是换工具,底层逻辑是不变的。如果你正在做类似的课设或者想找一套能动手的 JavaWeb 完整案例,按这篇文章的思路打磨一遍,你对 Web 开发的认知会上一个台阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询