
最近不少同学拿着同一个题目来找我基于 JavaWeb 和 MySQL 的 JSPServlet 智能小区物业管理系统技术标签是 Java JSP Bootstrap JavaScript Servlet MySQL。这套组合拳说它是 JavaWeb 课程设计和毕业设计的“标配全家桶”一点都不夸张。很多人的第一反应是“这题目也太老了”但真正动手做起来才会发现越经典的组合越考验基本功因为你没有现成的脚手架没有自动化装配每一步都得自己亲手来。这篇文章就是我基于这个项目标题做的完整复盘从环境搭建、数据库建模到后端分层、前端页面再到部署和常见坑位尽量把整个开发过程讲透。适合正被课设/毕设折磨的同学也适合刚学完 JavaWeb 想找一个完整项目练手的朋友。我默认你至少学过 Java 基础语法、会写简单 SQL什么是 Servlet、什么是 JSP 也有个模糊概念但不用怕我会把关键细节解释明白。1. 项目整体认知这不是在“用”技术而是在“串”技术1.1 技术栈逐项解读先把这个标题里的每个词拆开看你会发现它其实是一个很完整的教学闭环。JavaWeb不是一门具体技术而是一个统称指用 Java 生态做 Web 应用的整套体系。它包含了 Servlet、JSP、Filter、Session、Cookie、JDBC 这些东西。标题里的 JSPServlet 正是 JavaWeb 最原始的形态也是理解 Spring MVC、Spring Boot 这类框架之前必须先吃透的底层逻辑。MySQL负责数据持久化。小区物业系统的数据量不大用 MySQL 完全够用。重点是把表结构设计好把增删改查写清楚把事务和排序这些基础操作用熟。JSP Servlet是整套系统的骨架。Servlet 是后端控制器用来接收浏览器请求、调用业务逻辑、跳转页面JSP 则是视图层负责把数据渲染成 HTML 页面。这种模式在理论上叫 MVCM 是 JavaBean/DAO 封装的业务模型V 是 JSP 页面C 是 Servlet。Bootstrap是最容易被人低估的一环。很多同学觉得引入 Bootstrap 只是为了“好看一点”其实它真正解决了两个问题一是你不需要从零写 CSS用现成的栅格系统和组件就能把页面布局出来二是 Bootstrap 自带响应式设计用手机打开页面也不会乱这在答辩演示时很加分。JavaScript则用来补足“动态感”。在纯 JSPServlet 项目中每次表单提交、每次翻页都会刷新整页体验非常生硬。加入 JavaScript 后可以在前端先做一次校验不合规的表单直接挡住不用等后端返回来再提示下拉框选完房屋后自动联动业主信息这些交互也都靠 JS 实现。1.2 核心需求拆解物业系统到底要管什么“智能小区物业管理系统”听起来很宏大但落到数据库层面核心也只有几个实体业主、房屋、缴费记录、报修工单、停车位、公告。把这些搞清楚项目就有了 80% 的样子。我建议把系统角色先定成两类管理员和业主。管理员负责房屋信息录入、业主账号管理、物业费催缴、报修派单、公告发布业主负责查看自己的房产和缴费记录、在线提交报修、查看公告和投诉建议。不要一开始就贪多先把这条主线打通再考虑车位租赁、访客登记这些扩展功能。从业务流程上看整个系统就是一个闭环管理员录入房屋和业主 - 业主登录系统查看自己的缴费单 - 在线提交报修 - 管理员处理报修并反馈 - 管理员发布催费公告。每一步都是一张数据表的增删改查串联起来就是一个完整项目。1.3 为什么这套技术组合值得认真做有人会问都 202X 年了为什么不直接用 Spring Boot答案是这套项目的价值不在“新”而在“底”。JSPServlet 能让你看到 HTTP 请求从浏览器出发经过 Servlet 的 doGet/doPost再经过 DAO 到数据库最后绕回 JSP 渲染成 HTML 的完整链路。Spring Boot 帮你把细节藏起来了你反而看不到这些过程。另外这套技术栈对课程答辩非常友好。老师问你“一个请求是怎么处理的”你可以直接指着代码说先经过 web.xml 或注解里的 URL 映射到 ServletServlet 里调用 Service 层Service 调用 DAO 层最后把结果放进 request 域对象转发给 JSP 展示。这一串讲清楚基本功就过关了。2. 环境搭建与工程初始化搞定 IDEA、Tomcat、MySQL 的三方联动2.1 版本搭配别小看 JDK、Tomcat、MySQL 的兼容问题开发环境这块我实测下来最稳妥的组合是JDK 1.8 Apache Tomcat 8.5 MySQL 5.7。这套组合兼容性最好网上资料多遇到问题也好搜。MySQL 用 8.0 也行但要注意驱动和配置项有变化我会在后面详细说。先给新手一个版本对照表组件推荐版本注意事项JDK1.88u202 及以后Tomcat 9/JDK 11 也能跑但课设环境用 1.8 最稳Tomcat8.5.x支持 Servlet 3.1JSP 2.3够用MySQL5.7.448.0 需要改驱动类名和 URL 参数mysql-connector-java5.1.49对应 MySQL 5.78.0 用 mysql-connector-j 8.0.xIDEA2021 或更新社区版/专业版均可Web 开发建议专业版社区版纯手写配置也能跑MySQL 5.7.44 安装时有个容易被忽略的坑如果你选的是 ZIP 解压版不要忘记手动创建 my.ini 配置文件和 data 目录然后用mysqld --initialize-insecure初始化。命令行安装时管理员权限的 CMD 是必需的。装完后用net start mysql启动服务再用mysql -u root -p登录验证。我是建议你在这个阶段就把 root 密码设置成一个简单的比如root123开发阶段无所谓安全别把自己卡在密码上。后面项目里连接数据库的 URL、账号、密码都会写死在工具类里改来改去很容易出乱子。2.2 IDEA 里跑 JavaWeb 项目的完整配置IDEA 跑 JavaWeb 项目对新手来说最迷惑的其实就三个地方项目结构里的 Facets、Artifacts 和 Tomcat Server 配置。我拆开讲。新建项目时如果你用的是 IDEA 专业版可以直接选择 “Java Enterprise” 或者 “Java - Web Application”社区版没有 Java Enterprise 选项建议创建普通 Java 项目后再手动加 Web 支持。手动添加 Web 支持的方法是项目右键 - Add Framework Support - 勾选 Web Application。这一步会自动生成一个 web/WEB-INF/web.xml 文件。接着打开 File - Project StructureFacets确认已经加入 Web并且设置好 Web Resource Directory通常指向项目的 web 目录和 Web.xml 路径。Artifacts这一步是核心。Web 项目最终要被 Tomcat 运行需要一个打包形态IDEA 用的是 war exploded就是直接把项目目录当 war 用。点击 - Web Application: Exploded - From Module能选到当前项目。运行配置点击 “Edit Configurations” - 左上角 - Tomcat Server - Local。在 Server 页签里配置 Tomcat 安装目录在 Deployment 页签里加刚才创建的 ArtifactsApplication context 建议设置为/这样访问路径就是http://localhost:8080/不用加项目名简化后续所有路径问题。这里有一个我在教学中反复强调的实操心得如果 Artifacts 里看不到你的项目回 Facets 里检查 Web 是否和当前 Module 关联成功。关联失败往往是因为没有在 Facets 的 “Module” 下拉里选择当前模块。2.3 项目目录结构从启动第一天就分好包工程建好后先别急着写代码把包结构建出来com.bj.property ├── entity # 实体类Owner、House、Payment、Repair、Notice ├── dao # 数据访问层xxxDAO DAOImpl ├── service # 业务层xxxService ServiceImpl ├── servlet # 控制层LoginServlet、OwnerServlet、RepairServlet ... ├── util # DBUtil、DateUtil、StringUtil └── filter # 登录权限过滤器 web/ ├── static # css / js / images ├── admin # 管理员 JSP 页面 ├── owner # 业主 JSP 页面 ├── login.jsp └── index.jsp分包不只是为了美观更是为了你后期改代码时不会乱。比如以后想加一个“租赁车位”的功能你只需要加一个 ParkDao、ParkService、ParkServlet再在管理员页面加两个 JSP 入口就行不用把车位的业务逻辑塞进别的类里。这种分层感是老师评判你项目是否“正规”的重要标准。3. 数据库建模物业系统的地基决定你后面写代码的速度3.1 从业务场景推导出表结构我习惯先画一张业务链再把每个节点变成一张表小区下有很多房屋房屋归属业主业主产生缴费记录业主提交报修单管理员发布公告那么核心表就有了房屋表、业主表、缴费表、报修表、公告表外加一张管理员表用来登录后台。如果你还想做停车位管理就再加一张车位表和租赁关系表但第一版可以不急。每张表在主键之外要有完整的时间字段和管理员可操作的状态字段。比如报修单的状态至少要有“待处理/处理中/已完成”三种缴费单的状态至少要有“未缴/已缴”两种。别小看状态字段后续所有列表筛选、统计、界面标签都靠它驱动。3.2 核心表结构设计与 SQL 示例下面给出几个关键表的 MySQL 建表语句你可以直接拿来改。别把字段全设置成 varchar尽量用合适的类型这也是加分项。-- 小区业主表 CREATE TABLE t_owner ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 业主ID, owner_name VARCHAR(50) NOT NULL COMMENT 业主姓名, phone VARCHAR(20) NOT NULL COMMENT 手机号, password VARCHAR(64) NOT NULL COMMENT 登录密码, house_id INT NOT NULL COMMENT 关联房屋ID, status TINYINT DEFAULT 0 COMMENT 状态0正常 1欠费, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT业主信息表;-- 缴费记录表 CREATE TABLE t_payment ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 缴费ID, owner_id INT NOT NULL COMMENT 业主ID, house_id INT NOT NULL COMMENT 房屋ID, item_name VARCHAR(100) NOT NULL COMMENT 费用项目物业费/水费/电费, amount DECIMAL(10,2) NOT NULL COMMENT 缴费金额, status TINYINT DEFAULT 0 COMMENT 0未缴 1已缴, pay_time DATETIME DEFAULT NULL COMMENT 缴费时间, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 账单生成时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT物业缴费记录表;-- 报修工单表 CREATE TABLE t_repair ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 工单ID, owner_id INT NOT NULL COMMENT 提交业主ID, house_id INT NOT NULL COMMENT 房屋ID, title VARCHAR(100) NOT NULL COMMENT 报修标题, content TEXT NOT NULL COMMENT 报修描述, status TINYINT DEFAULT 0 COMMENT 0待处理 1处理中 2已完成 3已评价, reply_content VARCHAR(500) DEFAULT NULL COMMENT 管理员回复, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 提交时间, finish_time DATETIME DEFAULT NULL COMMENT 处理完成时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT报修工单表;剩下房屋表、公告表、管理员表结构不复杂自己照葫芦画瓢即可。我提醒几个容易被忽视的字段房屋表里要有楼栋号、单元号、房号并且建议设置一个唯一键楼栋单元房号防止录入重复公告表里要有发布者 ID 和时间别只放正文。3.3 关系设计、索引和初始化数据表与表之间的关联不要用物理外键逻辑外键就够了。物理外键在删除、批量导入时容易出问题课设项目没必要给自己增加麻烦。你只需要在查询时写 JOIN 或者用两次查询把关联表的数据带出来就行这就是“逻辑外键”。索引方面做分页列表时最常用的查询条件就是status和create_time建议给这两个字段各建一个普通索引ALTER TABLE t_payment ADD INDEX idx_status (status); ALTER TABLE t_payment ADD INDEX idx_create_time (create_time); ALTER TABLE t_owner ADD INDEX idx_house_id (house_id);初始化数据同样重要。管理员表的密码可以直接存明文比如admin / 123456但如果你想显得专业一点可以用 MD5 加密后存进去登录时把用户输入的密码也 MD5 一下再比对。房屋表和业主表先塞几条测试数据不然 JSP 列表页打开全是空的看着很影响心态。初始化 SQL 建议写成单独的init.sql文件反复重建数据库时一条命令就能搞定。4. 后端核心功能实现把 Servlet、Service、DAO 串起来4.1 先想清楚请求是怎么流转的很多同学学 Servlet 的时候只学会了一个知识写一个类继承 HttpServlet重写 doGet/doPost在 web.xml 里配一下路径。但这套东西一旦放到真实项目里请求流转路径必须想清楚。一次业主登录的完整链路是这样的浏览器提交login.jsp的表单action 指向loginServlet。Tomcat 根据映射找到对应的LoginServlet调用 doPost 方法。doPost 里调用OwnerService.login(username, password)。Service 层拼装查询条件调用OwnerDao.findByUsernameAndPassword()。DAO 层通过 JDBC 执行 SQL把结果封装成 Owner 对象返回。Service 把 Owner 对象返回给 Servlet。Servlet 做判断查询到用户则写入 session重定向到首页查询不到则把错误信息放到 request 域并“转发”回 login.jsp 显示。记住一个原则Servlet 层不要直接写 JDBC 代码DAO 层不要出现 HttpServletRequest。哪怕你为了图快直接在 Servlet 里拿到 Connection 执行 SQL我也劝你要忍一忍。因为后面每个功能都要这样写如果不开好头后期代码维护会让你怀疑人生。4.2 用 Filter 统一做登录权限控制有多个 JSP 页面以后一个很现实的问题就是用户不登录直接访问内部页面怎么办在传统 JSP 项目里最优雅的做法是用一个 Filter 统一拦截。WebFilter(/admin/*) 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; HttpSession session req.getSession(false); Object user session null ? null : session.getAttribute(adminUser); if (user null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } chain.doFilter(request, response); } }把管理员所有的 JSP 都放在/admin/目录下Filter 只拦截这个路径再配合重定向就能做到“未登录就踢回登录页”。业主端也可以用同样思路做一层只是拦截路径换成/owner/*校验的 session 属性换成 “ownerUser” 就行。这个 Filter 看着简单实际作用是巨大的。没有它你会发现每个 Servlet 里都要复制粘贴五六行判断 session 的代码改一处漏一处真心崩溃。4.3 缴费核心流程一次性事务别丢数据物业系统里面最容易出错的是缴费功能。业务需求是管理员给某业主生成一笔物业费账单或者业主在线点击“立即缴费”后系统要同时完成两件事插入一条已缴的缴费记录status1记录缴费时间 pay_time。清零该业主的欠费状态status 从 1 改成 0。这两件事必须在一个事务里完成否则就可能出现“钱扣了但记录没生成”或者“记录生成了但业主还是欠费状态”。JDBC 里的标准做法是关闭自动提交执行多条 SQL全部成功后 commit任何一步失败就 rollback。public boolean pay(Payment p) { Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); PaymentDao pdao new PaymentDao(); OwnerDao odao new OwnerDao(); pdao.updateStatus(conn, p.getId(), 1); // 更新缴费状态 odao.updateOwnerStatus(conn, p.getOwnerId(), 0); // 清零欠费 conn.commit(); return true; } catch (Exception e) { e.printStackTrace(); try { if (conn ! null) conn.rollback(); } catch (SQLException ex) { e.printStackTrace(); } return false; } finally { DBUtil.close(conn); } }注意这里的 DAO 方法要传入 Connection而不是每个 DAO 方法自己 new 一个连接。这点很关键否则多个 DAO 方法各自用不同连接事务根本控制不到一起。4.4 报修工单的业务状态机设计报修模块建议实现一个简单的状态流转给管理员和业主都提供操作按钮页面会自动根据当前状态渲染不同的按钮。状态流转逻辑如下业主提交工单初始状态 0待处理管理员查看后点击“接单”状态变成 1处理中管理员处理完成填写回复状态变成 2已完成业主看到“已完成”后可以确认关闭并评价状态变成 3已评价Servlet 里接收一个隐藏字段 action根据 action 的值调用不同的方法。比如actionaccept、actionfinish、actionclose这会比写四个 Servlet 清晰很多。JSP 页面里用 JSTL 的c:if判断状态不同状态显示不同的按钮这样整个页面才算有“智能系统”的样子。5. 前端页面Bootstrap 铺界面JavaScript 加交互5.1 用 Bootstrap 的栅格和组件搭出一套后台框架这个项目的前端不用过分追求花哨但基础审美要有。我一般先做一个后台管理模板页面左侧菜单栏、顶部导航栏、右侧内容区。Bootstrap 4 自带的 navbar、list-group、table、card、modal 基本能覆盖全部需求。关键一点是把头部和菜单部分抽取成公共 JSP 片段。比如我可以建立一个/admin/header.jsp内容包含导航和侧边栏每个具体管理页面就用% include fileheader.jsp %引入这样页面结构统一改菜单只改一处。Bootstrap 表格自带 hover 行高亮、条纹样式配合table-striped table-hover两个 class列表页瞬间就有质感。加上 “btn btn-primary btn-sm” 等按钮 class比原生的纯 HTML 按钮好看太多。5.2 JavaScript 表单校验和下拉联动纯前端校验是 JavaScript 在这类项目里最划算的用法。比如新增业主时手机号不能乱填金额不能是负数用户名不能为空。用一个简单的 JS 校验函数就能挡住大部分低级错误。script function validateForm() { var phone document.getElementById(phone).value; var reg /^1[3-9]\d{9}$/; if (!reg.test(phone)) { alert(请输入正确的手机号); return false; } var amount document.getElementById(amount).value; if (isNaN(amount) || parseFloat(amount) 0) { alert(请输入有效的金额); return false; } return true; } /script如果你是第一次接触 JavaScript这里至少掌握三个点用document.getElementById获取表单元素用正则表达式做格式匹配用alert提示错误。这些足够应付课设前端的 80% 需求。下拉联动是另一个高频需求选中“楼栋号”后“单元号”下拉框只展示该楼栋的单元。这个动作用 JSP 做也行刷新页面但体验更好的做法是拿到楼栋值后用 JavaScript 控制其他下拉框的选项显示隐藏。如果数据量大就必须用 AJAX 异步查接口动态填充。5.3 列表分页前后端一起配合数据量小的时候可以把所有记录全部查出来放在一个 JSP 页面上但一旦业主、缴费记录超过几百条不分页就很难看。分页的核心逻辑不复杂前端传页码 pageNo 和每页条数 pageSize后端 SQL 用LIMIT offSet, pageSize查询当前页数据再查一个总数SELECT COUNT(*)算总页数。int pageNo 1; int pageSize 8; try { pageNo Integer.parseInt(req.getParameter(page)); } catch (Exception e) { } int offset (pageNo - 1) * pageSize; ListPayment list paymentDao.findPage(offset, pageSize); int total paymentDao.countAll(); int pages (total pageSize - 1) / pageSize; req.setAttribute(payments, list); req.setAttribute(pages, pages); req.setAttribute(current, pageNo); req.getRequestDispatcher(/admin/payment_list.jsp).forward(req, resp);JSP 页面底部加一排翻页按钮。普通做法是直接放链接上一页、下一页、页码数字点击后重新请求同一个 Servlet只是带的 page 参数不同。用 Bootstrap 的paginationclass 美化一下翻页组件效果就很像模像样了。这里有个细节值得提页码数字不要一次性全展示只展示当前页附近的几页即可否则 100 页数据往下拉出 100 个按钮。可以用c:if控制显示范围或用 JS 在渲染时统一处理。6. 调试经验与常见问题排查实录6.1 404、405、500三种报错的定位思路开发阶段报错是常态关键是学会看颜色。404 出现先查路径再查部署405 出现通常是方法没写对500 出现优先看控制台堆栈。报错类型常见原因排查方向404URL 映射不对项目没部署成功web.xml 路径错误看浏览器地址栏和 Servlet WebServlet 的值是否完全一致405JSP 无法处理 GET 请求Servlet 只写了 doPost补 doGet 或在 servlet 里 doGet 内调用 doPost 处理方式500空指针异常、SQL 语法错误、驱动类找不到、类型转换异常看 IDEA 控制台最后一条 Exception 堆栈定位到具体 java 文件行号有时候报了 500但浏览器页面显示的是一堆英文异常信息很多人就慌了。其实异常堆栈里最有价值的就是第一行 java.lang.NullPointerException 和最后几行 at com.bj.property.dao.xxxDao.findAll(xxxDao.java:60)。前者告诉你是什么类型的错后者告诉你在哪一行出的错按这个思路去改非常快。6.2 MySQL 连接失败和中文乱码MySQL 连接失败的现象是启动项目后访问任何页面都报 SQLException。先确认这么几个东西MySQL 服务有没有启动net start mysql或者任务管理器看 mysqld 进程驱动 JAR 是否放到WEB-INF/lib目录下URL 里的端口号是不是 3306。如果 MySQL 是 8.0连接 URL 和驱动类名都要改驱动类用com.mysql.cj.jdbc.DriverURL 里要加serverTimezoneAsia/ShanghaiuseSSLfalsecharacterEncodingutf8。这是 8.0 和 5.7 最明显的区别很多同学用 5.1.49 的驱动连接 8.0 数据库就会报 “Public Key Retrieval is not allowed”。中文乱码是个老生常谈但每次都会出现的问题。统一的解决方案分三层第一层是 JSP 页面顶部声明% page contentTypetext/html;charsetUTF-8 languagejava %第二层是 Servlet 接收请求参数时先设置编码request.setCharacterEncoding(UTF-8); response.setCharacterEncoding(UTF-8);第三层是 MySQL 连接 URL 里加上useUnicodetruecharacterEncodingutf8三层配合中文基本不会再出问题。如果页面上还是显示“???”就去检查 MySQL 建表时的字符集需要确保表是 utf8mb4 而不是 latin1。6.3 实操心得真正花时间最多的地方是配置不是业务逻辑我把这个项目从头到尾做过好几遍最大的感慨是真正卡人的不是业主管理那种增删改查而是环境配置和细节调试。Tomcat 端口被占、IDEA 里工件没有部署、MySQL 密码忘了、驱动没放进 lib、日期格式一直不对……这些才是消耗时间的大头。所以我给你一个实操建议拿到项目先别急着写业务先搭一个最小的“登录 - 查出一张列表 - JSP 展示”的闭环。哪怕这个闭环里的数据是写死的只要请求能把链路跑通你自己就有了信心。然后在这个基础上加房屋管理、加缴费管理、加报修每加一块功能都是复制粘贴之前写好的套路后面反而越写越快。另一个心得是善用 IDEA 的模板。比如在 File - Settings - Editor - File and Code Templates 里把 DAO、Servlet 的标准代码模板配好每次新建类时自动生成骨架只改方法名效率翻倍。7. 打包部署与功能扩展从课程设计走向真正可用的系统7.1 打成 war 包部署到 Tomcat本地跑通之后如果想把它部署到云服务器或者找个环境做演示最直接的方式就是打 war 包。IDEA 菜单 Build - Build Artifacts - 选择 war - Build会在out/artifacts/目录下生成一个.war文件。把它拷贝到 Tomcat 的webapps/目录启动 Tomcat它会自动解压部署。访问路径默认就是/项目名_war_exploded这种如果你想简单点直接把 war 改名为ROOT.war就能通过http://服务器IP:8080/直接访问。有一点要注意本地连接的数据库地址如果是localhost部署到服务器后要把 DBUtil 里的连接地址改成服务器的实际地址否则会报连接不上。建议把数据库连接信息单独抽到一个db.properties配置文件里而不是写死在 Java 类中这样部署时只改一个文件就行。7.2 给“智能”二字加分报表统计和定时提醒很多课设题目里都带“智能”两个字但真正做出来的“智能”其实很单薄。我给你两个低成本但效果明显的落地方向。第一个是可视化报表。用一个免费的开源图表库把每月的物业费收缴金额、各楼栋的报修数量统计出来画成柱状图或折线图。后端 Servlet 里写一个统计接口用 GROUP BY 把聚合结果查出来返回 JSON 格式前端用图表库渲染。老师看到图表至少会觉得你的系统有个“数据分析”的样子。第二个是自动催费提醒。在 Java 里用ScheduledExecutorService每天定时扫描缴费表找出到期未缴的记录往待办表里插入一条提醒或者给业主的页面上推送一条未读消息。这个不需要引入额外的框架一个定时器线程就能实现。7.3 如果后续还想进阶学期结束后如果精力允许可以尝试把这个项目往 Spring Boot 方向迁移。你会发现原来的 entity 和 DAO 基本可以复用改的是 Servlet 变成 ControllerJSP 变成 Thymeleaf 或前后端分离。做过一遍 JSPServlet再学 Spring Boot 会快很多因为你已经理解了那些框架帮你省掉的部分到底是什么。我个人不太建议在课设阶段强行引入 MyBatis、Redis 这些重武器技术栈越复杂越容易翻车。先把经典的跑通、讲清楚比什么都强。最后再说一个小技巧给整个项目写一份简单的 README记录数据库初始化脚本、默认账号密码、Tomcat 端口和访问地址。这份文档不只是写给老师看的更是写给一个月后的你自己的——很多时候课设答辩完就忘光了回来再看代码全靠这份 README 唤起记忆。