简介:一套基于Java编程语言开发的综合性个人管理源码包,集成记事簿、备忘录、通讯录与记账本四大常用模块,面向Java Web方向初学者、课程实训及毕业设计参考者,可帮助掌握模型-视图-控制器架构、Servlet/JSP技术、数据库访问等核心技能。压缩包内共101个文件,大小约2.75MB,以41个JSP页面为主干,配套Java类处理后台逻辑,CSS和JavaScript完善前端交互,SQL脚本初始化数据表,PDF与Word文档说明系统设计及测试过程,目录组织清楚,适合按模块逐项学习。目前已有311人学习或下载。通过阅读源码与论文文档,能够梳理从数据库建模、JDBC增删改查到前后端联调、用户登录鉴权、附件上传的完整开发流程;文档还分析了系统各模块的职责与异常处理思路,便于在现有基础上扩展日程提醒、云同步等进阶功能,也能为同类型管理系统开发提供直接参考。
1. 拆开这个“java记事簿管理系统_备忘录管理系统_通讯录_记账本-源码+数据库+论文or文档.zip”:先判断它值不值得花两天跑通
刚接到课设任务的你,大概率在网盘里下过一个“java记事簿管理系统_备忘录管理系统_通讯录_记账本”这样的zip,文件名把内容全写明白了:Java 写的、四个业务模块、附带 MySQL 数据库脚本和一份能直接改成自己名字的论文或课程设计文档。它本质上是一套最典型的“增删改查”项目,登录之后,在记事簿里写日记,在备忘录里记待办,在通讯录里存联系人,在记账本里记收支。它的价值不在代码多高级,而在于把用户表、业务表、会话、模糊查询、分页、金额精度这些 Java Web 基础串成了一条完整链路,适合大二大三做课设、转行练手和准备补 Java 基础的人。能不能用,不取决于 zip 有多大,只取决于你能不能在两小时内让它不再报 404。
2. 把老 Java 课设跑通:JDK 1.8、Tomcat 8、MySQL 5.7 的版本匹配与启动三步
2.1 先认技术栈:从目录和配置文件判断是 Servlet+JSP 还是 Spring Boot
一个“管理系统”zip 最常见的形态有两类。老一点的课设是 Servlet + JSP + JDBC,WebContent 或 web 目录里放着 .jsp,WEB-INF/web.xml 存在,lib 下塞着 mysql-connector-java 的 jar;新一点的毕设是 Spring Boot + MyBatis,根目录有 pom.xml,包名是 com.xxx.system,带 application.yml。标题把“源码+数据库+论文or文档”放在一起却不提框架,默认是老式 Java Web 工程,但下载下来也有可能是新工程。打开后不要急着导入,先看两样东西:有没有 web.xml,有没有 pom.xml。两个都没有,说明它是 Eclipse 里直接导出的 Java 工程,导入方式又不一样。
判断技术栈不是兴趣,而是决定你要装哪些软件。Servlet+JSP 的经典搭配是 JDK 1.8、Tomcat 8.5、MySQL 5.7,再配 Eclipse 或 IDEA Ultimate。Spring Boot 方案要求 Maven 能联网拉依赖,JDK 用 8 或 11 都行。最怕的是你装了 Java 17 和 Tomcat 10,然后发现老项目的 javax.servlet 包全部报红。见到这个局面,第一反应不是改源码,而是把 JDK 换回 1.8,省去一大半麻烦。Java Web 的版本兼容规则很死板,老 Servlet 用新容器就是起不来,换成 8.5 一下子正常——这种“玄学”背后其实就是 API 包名从 javax 换成 jakarta,整个项目都要重写引用。
老 Eclipse 工程的目录结构通常是这样的:src 下放着包、Servlet 和工具类,WebContent 下有 index.jsp、WEB-INF/web.xml,还有 lib 目录。IDEA 导入这种工程,不要选 Maven,要选 New Project from Existing Sources,再一路 Next。如果 IDEA 没有自动识别出 Web 属性,项目名右键没有 Add Framework Support,就需要手动选 Web Application,否则后面运行按钮是灰的。识别成功的标志是左侧目录里出现 web/WEB-INF,同时 Artifacts 里能打出 war 包。这一步做错,后面怎么配 Tomcat 都是白费力气。
2.2 本地环境的最小配置:JDK、Tomcat、MySQL 三个版本怎么定
我一般按下面的组合搭环境,这套组合在绝大多数课设 zip 里能直接跑。JDK 用 1.8u202,装完在 IDEA 的 Project Structure 里把 Project SDK 和 Modules 的 Language level 都指到 1.8。Tomcat 用 8.5.x,配置时注意端口别和本地已有服务冲突;如果 8080 被占用,打开 conf/server.xml 把 Connector 的 port 改成 8081,shutdown 端口也换一个,避免和其它实例冲突。MySQL 用 5.7 或 8.0;5.7 对老脚本兼容最好,8.0 也能跑,但驱动要用高版本,连接串还得带时区参数。
IDEA 里运行老 Web 项目,常见做法是先配置 Tomcat Server → Local,在 Deployment 里添加 Artifact,Application context 填 /项目名。很多人启动后看到 404,就是因为把 Application context 留成了 / 根路径,而 Tomcat 实际部署路径是 /项目名。所以浏览器访问地址应该是 http://localhost:8080/项目名/,这个细节先记下来。配置完成后,Debug 模式启动 Tomcat,看到控制台输出“Server startup in xxx ms”,再去看页面,不要凭运气。
如果这个 zip 是新式 Spring Boot + MyBatis 工程,环境要求就又不一样了。只要电脑里有 JDK 1.8 以上,IDEA 里面直接 Open 这个 pom.xml,等 Maven 把依赖拉完,找到带 @SpringBootApplication 的主类直接 Run。这类工程通常内置 Tomcat,不用单独配容器。识别方法看根目录有没有 src/main/java 和 application.yml。两套环境别混用,混了会出现你配好了 Tomcat 却跑不起来一个 Maven 工程的尴尬场面。
2.3 数据库导入与配置文件的三个必改参数
数据库脚本一般在 zip 里叫 db_xxx.sql 或 note.sql,打开第一行通常就是 CREATE DATABASE 或 USE 某某库。导入用命令行最不容易出错:
mysql -uroot -p123456 < /Users/leojun/Desktop/javajishibu/note.sql-uroot是登录用户,-p123456是本机 MySQL 密码,路径要换成你解压出来的真实位置。如果脚本里有 USE 语句,它能自己切库;如果脚本没有建库语句,先手动执行一句:
CREATE DATABASE note_db DEFAULT CHARACTER SET utf8mb4; USE note_db; SOURCE /Users/leojun/Desktop/javajishibu/note.sql;utf8mb4一定不要省,老脚本喜欢用 utf8,遇到生僻字或者 emoji 会存不进去,轻则乱码重则报错。导入成功的标志是 SHOW TABLES 能看到 t_user、t_note、t_memo、t_contact、t_book 这些表。如果脚本是 Navicat 导出的,里面可能带 CREATE TABLE 语句和数据 INSERT,一行行执行就行。
配置文件是重灾区。老项目里它通常叫 db.properties 或 jdbc.properties,在 src 目录下,典型内容是这样:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/note_db?useUnicode=true&characterEncoding=utf8 username=root password=123456MySQL 5.7 用com.mysql.jdbc.Driver没问题;MySQL 8.0 要改成com.mysql.cj.jdbc.Driver,不然直接报 ClassNotFoundException。url 里的 note_db 要改成你实际建的库名,3306 是默认端口,MySQL 8.0 还要补serverTimezone=Asia/Shanghai,否则时间字段操作会抛异常。password 一定改成你本机密码,三个字段里改错任何一个,经典报错就是 Communications link failure——连接都没建立,根本轮不到 SQL 执行。
提示:改完 db.properties 必须重启 Tomcat,这个文件在应用启动时只读一次,热部署不会重新加载。我用这个坑折磨过自己整整一个小时。
启动验证也有固定顺序:先确认 MySQL 服务在跑,再确认 Tomcat 能启动,最后看页面。不要一上来就点页面,页面 404 时你不知道是哪个环节断了。Tomcat 启动日志里如果出现“Unable to load authentication”之类字样,优先回去查驱动和连接串。
3. 用四张业务表看懂四个模块:记事簿、备忘录、通讯录、记账本的数据结构怎么设计
3.1 用户表与业务表的关系:session 里的 user_id 从哪来
几乎所有管理系统的第一张表都是用户表。常见设计是 t_user,字段包括 id、username、password、real_name、create_time。它不只是用来登录验证,更重要的是给四张业务表提供外键来源。记事簿、备忘录、记账本、通讯录都会有一个 user_id 字段指向 t_user.id。登录成功后,Servlet 把当前用户主键放进 session,后续每次查询、新增、修改都带着 session 里的 userId 拼进 WHERE 条件。这个设计如果没想明白,做删除和修改时就会把别人的数据也删掉,因为你漏了 user_id 条件。
用户表本身也有坑。password 字段不要用 VARCHAR(20) 存明文,至少要在 Java 里做个 MD5 再入库,答辩时能回答“我的密码不是明文存储”。用户名的唯一性要靠数据库唯一索引保证,不能只靠 Java 代码查一遍,高并发下会撞车。create_time 建议加 DEFAULT CURRENT_TIMESTAMP,插入时少写一个参数,省得每次 setTimestamp。
登录模块的会话管理也要看时间。session.setAttribute("user_id", rs.getInt("id")) 之后,JSP 页面里用 session.getAttribute("user_id") 拿,这个 id 从终点到起点都必须是同一个数据类型。有些老代码用字符串放进去,取出来转 Integer 时报 NumberFormatException,排查半天发现是类型不一致。
3.2 记事簿与备忘录:同样“写点东西”,本质差别在时间字段
记事簿和备忘录在初看时容易设计成两张几乎一样的表。记事簿的核心字段是 id、user_id、title、content、create_time、update_time。备忘录在这之外,必须多一个 remind_time 或 alarm_time。这个字段决定了备忘录能“到点提醒”,而记事簿只是记录。如果你在论文里画用例图,两个模块用例也不一样:记事簿的行为是增删改查加搜索,备忘录的行为是到点提醒。把两张表合并,逻辑上省事,但论文没东西可写,功能演示也没有亮点。
字段设计有个细节:content 用 TEXT 不要用 VARCHAR(500),你的日记内容会超过 500 字;status 字段建议加一个,备忘录用 0/1 表示未完成/已完成,记账本用 0/1 表示未删除/已删除。很多老项目没有做逻辑删除,删掉一条记录直接 DELETE,后面想恢复数据无路可走。只加一个 0/1 字段,答辩时就能说一句“我做了逻辑删除而不是物理删除”,这句很加分。
提醒时间字段要建索引吗?用户量小的时候不用。当备忘录记录过万,每次扫描提醒都要过滤 remind_time BETWEEN 条件,没索引就是全表扫。加索引的 SQL 很简单:ALTER TABLE t_memo ADD INDEX idx_remind_time (remind_time, status)。两个字段的联合索引配合查询条件,性能差异肉眼可见。写进课程设计文档时,这一条也够你写一段“数据库优化”了。
3.3 通讯录与记账本:一对多表结构的取舍和金额字段的类型
通讯录表 t_contact,最小字段是 id、user_id、name、phone、email、remark。最容易踩的坑是手机号用 INT 存储。INT 最多存 11 位,手机号 11 位时高位溢出变成负数,所以必须用 VARCHAR(11) 或 VARCHAR(20)。字符串和数字在 MySQL 里都能做等值匹配,手机号用字符串完全不影响查询。如果联系人字段还要存微信号、QQ、地址,直接加列就行,表结构比 JSON 字段在课设里更好讲。
记账本表 t_book 的字段要有 id、user_id、type(收入/支出)、category(分类如餐饮、交通、工资)、amount、book_time、remark。amount 用 DECIMAL(10,2),不要用 DOUBLE 或 FLOAT。Double 在计算金额时有精度损失,比如 0.1 + 0.2 在二进制浮点里不等于 0.3,月度统计时出现 0.30000000000000004,答辩时一展示就露怯。DECIMAL 按十进制存储,做 SUM 不会有“小数点漂移”,这是经验,也是金融计算的基本约束。
建表脚本用 MySQL 5.7 写法大致如下:
CREATE TABLE t_book ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, type TINYINT NOT NULL COMMENT '1收入 2支出', category VARCHAR(20) DEFAULT '', amount DECIMAL(10,2) NOT NULL, book_time DATETIME DEFAULT NULL, remark VARCHAR(255) DEFAULT '', create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;ENGINE 指定 InnoDB,支持事务和外键;CHARSET 用 utf8mb4,兼容中文和特殊符号。AUTO_INCREMENT 是自增主键,插入时不传 id。type 用 TINYINT 因为只存 1 或 2,category 用 VARCHAR(20) 因为中文分类名长度有限。执行完用 DESC t_book; 验证字段,再试插入一条,确认中文不乱码。
这四张表在同一个 SQL 文件里的顺序通常是先 t_user,再业务表,因为业务表有逻辑上的依赖,虽然物理外键可以不建。老课设普遍省略 FOREIGN KEY 约束,只保留 user_id 字段,靠 Java 代码控制关联,好处是导入表时不用担心顺序,坏处是数据库层拦不住脏数据。我的习惯是:演示阶段不建物理外键,讲原理时说明白“这里用逻辑外键更贴合当前轻量级需求”。和“学生选课管理系统”那种多对多不同,个人记账类系统全是简单一对多,理解了这个,表怎么设计都不跑偏。
4. 核心功能复现:这个项目真正有价值的部分,藏在增删改查之外的三处细节
4.1 记事簿与通讯录的模糊搜索:为什么 LIKE 拼接能跑,却一定要改成参数化
“记不记得上周写过的某篇日记,标题只记得两个字?”这种需求落到代码里就是模糊搜索。常见老写法是字符串拼 SQL:SELECT * FROM t_note WHERE title LIKE '%' + keyword + '%'。能跑,但有两个隐患:第一,keyword 里有单引号或 % 时,SQL 会被截断或出注入问题;第二,中文编码没处理对时,LIKE 匹配不到结果。改成 PreparedStatement 的参数化写法,两个问题一次解决。
String sql = "SELECT * FROM t_note WHERE user_id=? AND title LIKE ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, userId); ps.setString(2, "%" + keyword + "%"); ResultSet rs = ps.executeQuery();第一个参数 userId 从 session 里取,只允许查当前用户的数据,这是权限控制的底线。第二个参数把拼好 % 的 keyword 整体作为参数传,数据库把它当普通值而不是 SQL 片段解析,单引号自动转义。LIKE 以 % 开头走不了索引,表数据少无所谓;等记录过十万,搜索明显变慢,到那时再考虑全文索引或前缀匹配。
搜索加分页是更常见的组合。如果查询还要 LIMIT ? OFFSET ?,参数顺序要格外小心:PreparedStatement 的下标从 1 开始,先传条件再传 limit,不能按 SQL 里的顺序想当然。我曾经把 LIMIT 参数放在 userId 前面,结果返回空结果集,控制台也不报错,排查了一个小时。参数下标这种低级错误,最好的排查方式是把 SQL 和参数值一起打印出来看,一看就知道问题在哪。
4.2 备忘录的到期提醒:一个 ServletContextListener 加 Timer 的最小实现
“到点提醒”是备忘录模块区别于记事本的功能,也是演示时最能拿出手的亮点。很多初版实现把提醒写在 JSP 页面加载时判断,页面一刷新才提醒一次,这不叫提醒。常规做法是应用启动时起一个后台定时任务,每 30 秒扫描一次 remind_time 是否落在当前时间前后一分钟内,命中的记录进入提醒列表。
public class RemindListener implements ServletContextListener { private Timer timer; @Override public void contextInitialized(ServletContextEvent sce) { timer = new Timer(true); timer.schedule(new TimerTask() { @Override public void run() { String sql = "SELECT id,title FROM t_memo " + "WHERE user_id=? AND status=0 " + "AND remind_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 1 MINUTE)"; // 取到结果后放入一个全局静态 List,供页面轮询 } }, 0, 30 * 1000); } @Override public void contextDestroyed(ServletContextEvent sce) { if (timer != null) { timer.cancel(); } } }new Timer(true) 的 true 表示守护线程,容器关闭时不会阻塞进程退出。30 * 1000 是扫描间隔 30 秒,按需求改;如果希望秒级提醒,改成 5 * 1000,但数据库查询频率相应变高。注意 TimerTask 里拿不到 request 和 session,只能把结果写入静态集合或数据库,再由前端 Ajax 轮询展示。另外不要在 run 方法里每次新建数据库连接,应该复用连接池的连接;没有连接池就尽量复用同一个连接并注意并发安全。
web.xml 里要注册这个监听器:
<listener> <listener-class>com.example.RemindListener</listener-class> </listener>这样应用一启动,listener 就会执行。演示时你可以在数据库里插入一条 remind_time 为当前时间加 30 秒的记录,页面上观察它是否自动出现,这是验证提醒功能最直观的方法。
4.3 记账本的金额统计:SUM 出来的是 BigDecimal,别用 Double
记账本的月度收支合计是这个模块的标配。用 SQL 统计收入总和:
SELECT COALESCE(SUM(amount), 0) AS total_income FROM t_book WHERE user_id = ? AND type = 1 AND book_time BETWEEN ? AND ?COALESCE 把没有记录时的 NULL 转成 0,避免 Java 侧拿 null 判断。问题出在 Java 侧接收结果。如果表字段是 DECIMAL,SUM 返回的是 BigDecimal,而老代码里你可能看到 getDouble("total") 或 getFloat("total"),精度就在转换时折损。保存多条明细再合计时,也不能用 double 相加,BigDecimal 的 add 才是正确姿势。
BigDecimal total = rs.getBigDecimal("total_income"); BigDecimal income = total == null ? BigDecimal.ZERO : total; BigDecimal tax = income.multiply(BigDecimal.valueOf(0.2)) .setScale(2, RoundingMode.HALF_UP);rs.getBigDecimal 直接取金额字段,避免经过 double。BigDecimal.valueOf(0.2) 用字符串方式构造小数,比 new BigDecimal(0.2) 安全,后者会把二进制浮点误差带进来。setScale(2, RoundingMode.HALF_UP) 保留两位小数并按四舍五入进位,这是财务计算的常规策略。如果合计页面显示 1089.9999999999,基本可以断定哪一步把 BigDecimal 转成了 double,改成全程 BigDecimal 就好。
月度报表还可以按 category 分组:SELECT category, SUM(amount) FROM t_book WHERE type=2 GROUP BY category ORDER BY SUM(amount) DESC。这个 SQL 在答辩时能直观展示“钱花在哪了”,配合一个柱状图就是完整的数据分析闭环。注意饮用时用 COALESCE 包装汇总列,也是写 SQL 的好习惯。
4.4 通讯录的分页:手写 PageBean 还是引入现成工具
通讯录不做分页的话,联系人少无所谓,几百条记录一次性渲染到页面,浏览器明显卡顿,“我不考虑性能”这句话答辩时不要说出口。手写分页正好考察 JDBC 的物理分页能力,套路固定:先查总条数,算总页数,再取当前页数据。
String countSql = "SELECT COUNT(*) FROM t_contact WHERE user_id=?"; String pageSql = "SELECT * FROM t_contact WHERE user_id=? LIMIT ? OFFSET ?";LIMIT 和 OFFSET 的值要在 Java 里算好,不能直接接收前端传的页码拼进去。前端传 pageNum 和 pageSize,后端计算 offset = (pageNum - 1) * pageSize。这两个参数也要用 PreparedStatement 绑定。PageBean 的核心字段无非 currentPage、pageSize、totalCount、totalPage、list,抽成一个泛型类可以复用到四个模块。
更深一点,分页和排序组合时也有坑。ORDER BY create_time DESC 的字段如果和 WHERE 字段不一致,尽量建联合索引,否则数据量大时扫描行数膨胀。手写 LIMIT 只解决物理分页,不解决深分页偏移问题,OFFSET 到几十万照样慢,那已经进入索引覆盖范围,课设阶段不必深想。演示时往联系人表插 50 条数据,每页 10 条,翻到第 3 页能正确显示 21 到 30 条,页面不报错,就说明分页逻辑通了。
5. 避坑:跑这些老 Java Web 系统最容易翻车的四个现场,按现象排查
5.1 现象:Tomcat 能启动,页面却 404
Tomcat 成功打印出“Server startup”,浏览器却 404,第一反应不是改代码,而是确认访问地址的上下文路径。IDEA 的 Deployment 里 Application context 写的是什么,浏览器就要访问 http://localhost:8080/项目名/。另一个常见原因是 Artifact 的 Output Layout 里没有把 JSP 目录打进去,或是依赖 jar 没放进 lib,导致部署出来的是一个残缺的 war。解决方法是打开 Run/Debug Configurations → Deployment,检查 Application context,再打开 Project Structure → Artifacts,看 Output Layout 里有没有 WEB-INF/lib 和对应的 jsp 目录。如果 404 页面是 Tomcat 自己的提示,而不是你的错误页,优先查部署路径而不是业务代码。
5.2 现象:数据库里中文正常,页面显示 ??? 或乱码
中文乱码涉及三个位置,缺一不可。第一个是 JSP 页面顶部 pageEncoding="UTF-8",第二个是 Servlet 里的 request.setCharacterEncoding("UTF-8"),必须在读取任何参数前调用,第三是 response.setContentType("text/html;charset=UTF-8")。Tomcat 8 之后 GET 请求默认按 UTF-8 解码,但 POST 表单提交必须靠 setCharacterEncoding,漏了就是 ???。数据库侧的 url 还要带 characterEncoding=utf8,所有环节编码一致,中文才正常。排查时先看数据库里是不是好的:数据库里好、页面乱,问题在响应输出;数据库里就是 ?,问题在连接串或建表字符集。
5.3 现象:编译报 ClassNotFoundException: com.mysql.jdbc.Driver
老 Eclipse 工程里 jar 即使出现在 Referenced Libraries,部署时也不一定复制到 WEB-INF/lib,Tomcat 运行时自然找不到驱动类。解决方法是把 mysql-connector-java 的 jar 直接复制到项目的 WEB-INF/lib 下,或者在 IDEA 的 Artifacts → Output Layout 里手动添加。还要注意 lib 里不要同时存在旧版驱动和新版驱动,两个版本类名不冲突但连接协议会互相干扰。MySQL 5.1.x 用 com.mysql.jdbc.Driver,8.0 用 com.mysql.cj.jdbc.Driver,换驱动版本时要同步改配置文件。这个报错还有变体是 No suitable driver found,多半是 url 写错前缀,比如 jdbc 写成了 jdcb,这种低级错误看一眼就能发现。
5.4 现象:数据库连不上,报 Access denied 或 Communications link failure
Access denied 是用户名密码不对,或用户没有目标库权限。先用命令行验证密码:mysql -u root -p,能进再回去改 db.properties。Communications link failure 的排查顺序更重要:第一确认 MySQL 服务启动,Windows 的服务管理器里能看到 MySQL 状态;第二确认端口是 3306,如果本机装了多个 MySQL 实例,端口可能被第二个实例改成 3307;第三确认 url 里的库名存在。改完配置文件必须重启 Tomcat,因为连接参数只在启动时加载一次。如果日志里出现 Establish SSL connection 的警告,说明连接串缺 useSSL=false 参数,加上就好,不影响功能但日志会干净很多。
6. 给这套课设长出工程味:把 JDBC 数据层换成 MyBatis-Plus 可写进简历的半小时改造
6.1 用代码生成器把四张表转成 Model 和 Mapper
老项目里的手写 DAO 读起来费劲,答辩时也容易被追问“你的数据层有没有更简洁的实现”。你可以不动业务逻辑,先把数据层换成 MyBatis-Plus 生成器,让四张表的管理代码从几百行缩到几十行。做法是先搜一下“mybatisplus根据java实体类生成创建表的sql语句”,理解它的逆向生成思路:根据数据库表生成实体类,再根据实体类生成 SQL 脚本,配合代码生成器把增删改查全部搞定。这个改造可以和旧 JDBC 代码并存,新代码负责查询,旧的 JSP 页面不用大改,风险很低。
6.2 验证方法:跑一个 Spring Boot 的冒烟测试
改造完成后,写一个 @SpringBootTest 的测试方法,调用 Mapper 里查列表和查详情的接口,控制台打印的 SQL 应该能看到表名、WHERE 条件和参数值。如果日志里表名或字段名对不上,八成是实体类缺 @TableName 注解。四张业务表各调一个查询,确保映射关系统一。看到 SQL 按预期执行完,这套系统才算真正在你机器上活过来了。这个测试不用复杂断言,只验证能查询、能插入、能更新,就够了。
6.3 答辩或面试时值得讲的三句话
第一句:“我用逻辑外键代替物理外键,降低表之间的耦合,业务层把控关联一致性。”第二句:“金额字段用 DECIMAL 存储,统计时用 BigDecimal 做精度控制,避免浮点误差。”第三句:“备忘录提醒用 ServletContextListener + Timer 实现后台周期任务,而不是靠 JSP 页面刷新触发。”这三句话我当年答辩时说了一遍,老师顺着追问的都是细节,而细节我提前准备过,问答环节反而成了最轻松的部分。做完这套改造,再把页面换成一版 Vue3 后台管理系统常用的布局和样式,它就不再是“课设项目”,而是能写进简历的“基于 Spring Boot + MyBatis-Plus 的 Java Web 管理系统”。
把环境跑通后,最深刻的教训就是:遇到问题,按容器、驱动、连接串、编码的顺序排查,比瞎改代码快十倍。这个 zip 里的项目不算高级,但它帮你把 SQL 到 Servlet、Session 到分页、精度到提醒的整条链路串起来了。当你能独立回答“为什么 DECIMAL 比 Double 适合存钱”和“为什么提醒任务要放后台线程”,这节课设就值了。希望帮到你。
本文还有配套的精品资源,点击获取