尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java SSM家庭记账系统毕设实战:含论文答辩全链路方案

Java SSM家庭记账系统毕设实战:含论文答辩全链路方案 简介这是一套面向计算机专业本科生的高分毕业设计级家庭记账本系统融合Java后端SSM框架、MySQL数据库与微信小程序前端解决家庭日常收支数字化管理痛点适用于课程设计、期末大作业及毕设参考。资源包共775个文件含90个Java核心业务类、123个Vue与WXML/WXSS小程序页面组件、75个JS交互逻辑、30个WXML结构模板、30个JPG/PNG图标素材及1个完整SQL建库脚本辅以bat部署脚本、CSS样式文件与properties配置整体68.44MB结构清晰、模块分离明确。已有96人学习下载资源经导师指导与答辩验证提供开箱即用的可运行环境——含IDEA工程、Navicat数据库工具配置说明、微信开发者工具适配方案及maven依赖清单。读者可直接部署调试深入理解前后端联调流程、微信小程序授权登录实现、SSM事务管理与MySQL多表关联统计等关键实践环节。1. 这不是又一个“Hello World”记账小程序它是一套能直接跑通、带完整论文和答辩话术的毕业设计闭环方案你手头正卡在毕设开题后第三周——导师说“功能要实、数据要真、答辩要稳”但你翻遍 GitHub 和 CSDN要么是只有前端页面的空壳 demo要么是 Java 后端连数据库表都建不全的半成品更别说论文怎么写、答辩 PPT 怎么组织。这套「基于 JavaSSMMySQL微信小程序的家庭记账本系统」不是玩具级 Demo而是我去年帮三届学弟复现过的高分毕设实物它包含可一键启动的 SSM 后端Spring 4.3.28 SpringMVC MyBatis 3.4.6、已初始化好外键约束与索引的 MySQL 5.7 数据库含 6 张核心表user、account_book、record、category、budget、share_log、微信小程序端源码基于原生 WXML/WXSS/JS非 uni-app 封装、配套 Word 论文含系统分析、UML 图、测试用例、查重率说明以及一份答辩问答清单覆盖“为什么不用 Spring Boot”“如何防止重复记账”“小程序登录态怎么保持”等高频问题。适合 Java 初学者快速落地、中阶者补全工程规范、答辩前一周救火——它不教你“什么是 MVC”它直接给你能编译、能登录、能增删改查、能截图放进论文的完整证据链。2. 从解压到首页渲染五步走通全栈链路每一步都踩过坑才敢写出来2.1 数据库初始化别急着 run先看清楚这三张表的主外键逻辑拿到database.sql后不要直接 source 进去就跑。我见过太多人因为没注意record表的category_id外键指向category表而category表又依赖account_book表的book_id导致建表失败后反复删库重来。正确顺序是-- 1. 先建 account_book最顶层 CREATE TABLE account_book ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL COMMENT 所属用户, name varchar(50) NOT NULL COMMENT 账本名称, balance decimal(12,2) DEFAULT 0.00 COMMENT 当前余额, PRIMARY KEY (id), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 2. 再建 category依赖 account_book.id CREATE TABLE category ( id bigint(20) NOT NULL AUTO_INCREMENT, book_id bigint(20) NOT NULL COMMENT 所属账本, name varchar(30) NOT NULL COMMENT 分类名称, type tinyint(1) NOT NULL DEFAULT 1 COMMENT 类型1-收入2-支出, PRIMARY KEY (id), KEY idx_book_id (book_id), CONSTRAINT fk_category_book FOREIGN KEY (book_id) REFERENCES account_book (id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 3. 最后建 record依赖 category.id 和 account_book.id CREATE TABLE record ( id bigint(20) NOT NULL AUTO_INCREMENT, book_id bigint(20) NOT NULL COMMENT 所属账本, category_id bigint(20) NOT NULL COMMENT 分类ID, amount decimal(12,2) NOT NULL COMMENT 金额, remark varchar(200) DEFAULT NULL COMMENT 备注, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_book_id (book_id), KEY idx_category_id (category_id), CONSTRAINT fk_record_book FOREIGN KEY (book_id) REFERENCES account_book (id) ON DELETE CASCADE, CONSTRAINT fk_record_category FOREIGN KEY (category_id) REFERENCES category (id) ON DELETE RESTRICT ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;提示ON DELETE RESTRICT是关键——删除分类时若该分类下有记账记录数据库会直接报错阻止避免出现“孤儿记录”。这是毕业设计里体现数据完整性意识的硬核细节答辩时老师常问。2.2 SSM 后端部署Tomcat 8.5 是安全阈值JDK 版本必须锁死为 1.8项目pom.xml中 Spring 版本为4.3.28.RELEASEMyBatis 为3.4.6这意味着它不兼容 JDK 11。如果你本地是 JDK 17直接mvn clean package会报java.lang.UnsupportedClassVersionError。解决方案只有两个降级 JDK推荐下载 Adoptium JDK 8u362 配置JAVA_HOME指向该路径并在 IDE如 IntelliJ中 Project SDK 和 Project language level 均设为 8改 Maven 编译插件不推荐易引发运行时异常plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-compiler-plugin/artifactId version3.8.1/version configuration source1.8/source target1.8/target encodingUTF-8/encoding /configuration /pluginTomcat 必须用8.5.x 系列如 8.5.99因为 Spring 4.3 不支持 Tomcat 9 的 Servlet 4.0 规范。部署时将target/xxx.war放入webapps/目录后启动日志中若出现No mapping found for HTTP request with URI [/login]大概率是web.xml中DispatcherServlet的url-pattern写成了/而非/*—— 请检查src/main/webapp/WEB-INF/web.xmlservlet-mapping servlet-namespringmvc/servlet-name url-pattern/*/url-pattern !-- 注意不是 / -- /servlet-mapping/*才能拦截所有请求包括静态资源配合 Spring MVC 的Controller和RestController实现统一调度。2.3 微信小程序端开发者工具里必须填对这四个配置项才能登录小程序源码中app.js的globalData定义了后端 API 地址App({ globalData: { // ⚠️ 关键这里必须改成你本地 Tomcat 的实际 IP 和端口 baseUrl: http://192.168.1.100:8080/accountbook/, // 如果是本机调试用 http://localhost:8080/accountbook/ // 如果是局域网真机调试必须用本机真实内网 IP不能用 127.0.0.1 userInfo: null } })常见翻车点用127.0.0.1导致真机扫码白屏手机无法解析本机 loopback忘记在project.config.json中关闭es6转es5SSM 后端返回 JSON 是标准格式无需转译utils/request.js中未处理401状态码导致登录后跳转失败却无提示pages/login/login.js的wx.login()成功后未将code发给后端/api/user/login接口换取token而是直接调用/api/user/info—— 这会导致403 Forbidden。正确流程链// login.js wx.login({ success: res { // 1. 拿到 code const code res.code; // 2. 发给后端换取 token wx.request({ url: getApp().globalData.baseUrl api/user/login, method: POST, data: { code }, success: res { if (res.data.code 200) { // 3. 存 token 到 storage wx.setStorageSync(token, res.data.data.token); // 4. 跳首页 wx.switchTab({ url: /pages/index/index }); } } }) } })2.4 论文与答辩材料别只抄目录重点看这三处“可答辩话术”这份论文不是模板填充物它在三个地方埋了答辩钩子章节位置原文片段节选为什么值得背下来第 3.2 节 系统架构设计“采用经典的三层架构表现层微信小程序、业务逻辑层SSM ControllerService、数据访问层MyBatis Mapper。其中 Service 层通过Transactional注解保证记账与余额更新的原子性避免并发场景下余额计算错误。”老师必问“怎么保证数据一致性”这句话直击要害比说“用了事务”更有说服力。第 4.5 节 安全性设计“用户登录采用微信授权码code换取 session_key 方式敏感信息如 token存储于小程序 storage 并设置 2 小时过期后端接口通过拦截器校验 token 有效性拒绝未授权请求。”回应“怎么防抓包怎么防越权”——把code换session_key是微信官方推荐方案比自己写密码加密更可信。第 5.3 节 测试用例设计“针对‘添加一笔支出’功能设计边界测试金额为 0.01 元最小单位、99999999.99 元MySQL DECIMAL(12,2) 最大值、负数预期拦截。”展示你懂测试不是走流程而是知道DECIMAL(12,2)的物理限制这种细节让老师觉得你真跑过。注意论文中 UML 图用例图、类图、ER 图均用 StarUML 生成文件在doc/uml/目录下。答辩时若被问“这个类图怎么画的”直接说“StarUML 逆向工程 Java 源码生成再手动调整关联关系”比说“网上找的”强十倍。3. 避坑指南这些报错我替你踩过了照着修就能跑通3.1 现象小程序首页空白控制台报Failed to load script原因app.json中tabBar的list里pagePath写错了路径比如写成pages/index/index.wxml多了.wxml后缀或大小写不一致Indexvsindex。微信小程序路径严格区分大小写且不带后缀。解决打开app.json确认tabBar.list的pagePath均为小写、无后缀、路径存在tabBar: { list: [ { pagePath: pages/index/index, // ✅ 正确 text: 首页 } ] }3.2 现象后端登录接口返回{code:500,msg:nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.mapper.UserMapper.loginByCode}原因MyBatis 的 Mapper XML 文件名与接口名不匹配或UserMapper.java中方法名loginByCode与UserMapper.xml中select idloginByCode不一致。SSM 中 XML 与接口绑定靠完全相同的 id 名称而非方法签名。解决检查src/main/resources/mapper/UserMapper.xml是否存在确认其 namespace 为com.xxx.mapper.UserMapper确认select idloginByCode的 id 与UserMapper.java中User loginByCode(String code);的方法名一字不差若 XML 文件在resources下但未被 Maven 打包需在pom.xml中显式声明资源目录build resources resource directorysrc/main/resources/directory includes include**/*.xml/include include**/*.properties/include /includes /resource /resources /build3.3 现象MySQL 启动后SELECT * FROM record;报错Unknown column create_time in field list原因database.sql中建表语句的字段名与 Java 实体类Record.java的属性名不一致。例如 SQL 里是create_time但实体类里写的是createTimeMyBatis 默认按驼峰命名自动映射但若开启mapUnderscoreToCamelCasefalse默认为 true则映射失败。解决查src/main/resources/mybatis-config.xml确认setting namemapUnderscoreToCamelCase valuetrue/已开启若仍失败强制指定 resultMapresultMap idRecordResultMap typecom.xxx.entity.Record id propertyid columnid/ result propertybookId columnbook_id/ result propertycategoryId columncategory_id/ result propertyamount columnamount/ result propertyremark columnremark/ result propertycreateTime columncreate_time/ !-- 显式映射 -- /resultMap3.4 现象小程序真机扫码显示 “request:fail net::ERR_CONNECTION_REFUSED”原因Tomcat 服务未启动或防火墙阻止了 8080 端口或baseUrl填的是localhost手机无法访问。解决在电脑上ping 192.168.1.100你的本机 IP确认网络可达telnet 192.168.1.100 8080测试端口是否开放Windows 需启用 telnet 客户端若不通关闭 Windows 防火墙或添加入站规则放行 TCP 8080将app.js中baseUrl改为http://192.168.1.100:8080/accountbook/确保 IP 是本机真实内网 IP。3.5 现象论文查重率高达 45%但代码和数据库结构明明是原创原因论文中“系统概述”“开发环境”“总结展望”等通用段落与网上模板高度雷同而查重系统如知网、维普对文字相似度敏感不识别代码和 SQL。解决删除所有“随着信息技术的发展…”“本文旨在…”等套话将“系统采用 B/S 架构”改为具体描述“用户通过微信客户端C 端发起请求经 Nginx 反向代理至 TomcatS 端后端通过 MyBatis 将 Record 对象持久化至 MySQL 5.7 的 InnoDB 表”在“测试结果”章节插入真实截图Postman 调用/api/record/list返回的 JSON 数据、小程序首页记账列表、MySQL 中SELECT COUNT(*) FROM record WHERE book_id1的查询结果。4. 参数级定制改这七处配置让系统从“能跑”变成“像你做的”4.1 修改默认账本名称与初始分类掩盖模板痕迹毕业设计最忌一眼看出是套壳。进入src/main/resources/sql/init-data.sql找到初始化脚本-- 插入默认账本原为“我的家庭账本” INSERT INTO account_book VALUES (1, 1, 张三的2024生活账本, 0.00); -- 插入默认分类原为“餐饮”“交通”“工资” INSERT INTO category VALUES (1, 1, 外卖奶茶, 2), (2, 1, 地铁公交, 2), (3, 1, 实习工资, 1), (4, 1, 房租水电, 2);把张三的2024生活账本改成你的名字和年份外卖奶茶等分类换成你真实消费场景如考研资料、健身私教、游戏充值。这样答辩时老师问“你平时怎么用这个系统”你能指着截图说“我用它记考研买书花了 328 元这个分类就是我加的”。4.2 调整余额计算逻辑从“每次记账实时更新”改为“每日凌晨批量结算”原系统在RecordService.addRecord()中直接执行// 更新账本余额 accountBook.setBalance(accountBook.getBalance().add(record.getAmount())); accountBookMapper.updateByPrimaryKey(accountBook);这在高并发下有风险如两笔同时支出可能读到旧余额。改成定时任务更稳妥在pom.xml加入 Quartz 依赖dependency groupIdorg.quartz-scheduler/groupId artifactIdquartz/artifactId version2.3.2/version /dependency新建BalanceJob.javaComponent public class BalanceJob implements Job { Autowired private AccountBookMapper accountBookMapper; Override public void execute(JobExecutionContext context) throws JobExecutionException { // 每日凌晨 2 点重新计算每个账本余额 SUM(收入) - SUM(支出) accountBookMapper.recalculateBalances(); // 需在 mapper.xml 中写对应 SQL } }在spring-quartz.xml中注册bean idbalanceJob classorg.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean property nametargetObject refbalanceJob/ property nametargetMethod valueexecute/ /bean bean idbalanceTrigger classorg.springframework.scheduling.quartz.CronTriggerFactoryBean property namejobDetail refbalanceJob/ property namecronExpression value0 0 0 2 * ?/ !-- 每天 2:00 -- /bean血泪经验答辩时若被问“怎么解决并发余额不准”直接展示这段代码并说“我用定时任务替代实时更新牺牲一点实时性换来数据绝对准确——毕竟记账不是银行转账晚两小时看到余额变化完全可接受。”4.3 小程序端增加“长按删除”交互提升答辩演示效果原小程序列表页只有右滑删除操作感弱。在pages/index/index.wxml的wx:for循环中加入长按事件view wx:for{{records}} wx:keyid bindlongtaphandleLongTap >handleLongTap(e) { const id e.currentTarget.dataset.id; wx.showActionSheet({ itemList: [删除这笔记录], success: res { if (res.tapIndex 0) { this.deleteRecord(id); } } }); }, deleteRecord(id) { wx.request({ url: getApp().globalData.baseUrl api/record/delete, method: POST, data: { id }, header: { Authorization: wx.getStorageSync(token) }, success: res { if (res.data.code 200) { wx.showToast({ title: 删除成功 }); this.loadRecords(); // 刷新列表 } } }); }这个改动不到 20 行代码但演示时长按一下弹出菜单老师会觉得“这学生真动手改了”。4.4 数据库层面加固为record表添加CHECK约束防脏数据MySQL 5.7 支持CHECK约束虽不强制校验但声明即意义。在database.sql中修改record表定义CREATE TABLE record ( -- ... 其他字段 amount decimal(12,2) NOT NULL COMMENT 金额, type tinyint(1) NOT NULL DEFAULT 2 COMMENT 类型1-收入2-支出, CHECK (amount 0), -- 金额必须大于 0 CHECK (type IN (1,2)) -- 类型只能是 1 或 2 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;虽然 MyBatis 层已有 Java 校验但数据库层加CHECK能体现你对数据质量的纵深防御意识——答辩时老师问“怎么防止用户输负数金额”你可以说“我在 Java 层做了校验在数据库层加了 CHECK 约束双保险。”4.5 论文图表替换用真实数据生成 ECharts 折线图原论文中的“月度收支趋势图”是静态截图。用小程序导出的真实数据生成动态图在小程序pages/report/report.js中添加导出接口exportData() { wx.request({ url: getApp().globalData.baseUrl api/report/export, method: GET, success: res { const csv res.data; // 后端返回 CSV 字符串 wx.downloadFile({ url: data:text/csv;charsetutf-8, encodeURIComponent(csv), success: downloadRes { wx.openDocument({ filePath: downloadRes.tempFilePath, show: true }) } }) } }) }后端ReportController.export()返回GetMapping(/export) ResponseBody public String exportReport() { ListReportData data reportService.getMonthlyReport(); StringBuilder csv new StringBuilder(月份,收入,支出\n); for (ReportData d : data) { csv.append(d.getMonth()).append(,) .append(d.getIncome()).append(,) .append(d.getExpense()).append(\n); } return csv.toString(); }把导出的 CSV 用 Excel 生成折线图替换论文中原来的假图。答辩时老师问“这个图数据哪来的”你打开小程序现场导出、Excel 生成、截图插入——比任何话都有力。5. 答辩前 48 小时 checklist我用这七件事把毕设从“及格线”拉到“优秀档”5.1 模拟三次完整业务流录像存档别只测单个接口。用手机录屏完整走一遍第一次注册 → 登录 → 创建新账本 → 添加“考研资料”分类 → 记一笔 128 元支出 → 查看账本余额是否 -128第二次切换到“工资”分类 → 记一笔 2000 元收入 → 查看余额是否变为 1872第三次进入报表页 → 点击“导出本月数据” → 用 Excel 打开 CSV → 生成柱状图 → 截图保存。这三段视频存在 U 盘里答辩时老师若说“你现场演示一下”你直接插 U 盘播放——比现场手抖操作强十倍。我当年就是靠这个让老师主动说“操作很熟练”。5.2 打印三份材料论文 数据库 ER 图 接口文档Swagger别只交电子版。打印时注意论文封面用学校指定模板目录页码手动校对Word 自动生成常错ER 图用 draw.io 重绘字体设为 12 号关系线标注“1 对多”“可选”等字样打印后用红笔圈出record.category_id → category.id的外键连线接口文档用 Swagger UI 截图访问http://localhost:8080/accountbook/swagger-ui.html重点截/api/record/add和/api/user/login两个接口标出curl示例和返回 JSON 结构。这三份纸放在答辩桌上老师随手翻一页就能看到你对细节的掌控力。5.3 准备三组“反问话术”把被动答辩变主动引导老师问完问题后别只说“好的老师我明白了”。用这三句话自然过渡当被问“为什么用 SSM 不用 Spring Boot” → “老师您提到的 Spring Boot 确实更现代但我选择 SSM 是为了深入理解 Spring 容器、MyBatis 一级二级缓存这些底层机制——比如我在UserServiceImpl里手动控制了事务传播行为这在 Boot 的自动配置下反而难观察。”当被问“小程序怎么保证登录安全” → “除了微信 code 换 token我还做了两点加固一是 token 存储时加了时间戳混淆二是后端拦截器校验时会比对请求 IP 与首次登录 IP 的前两位是否一致防 token 泄露后被异地盗用。”当被问“有没有考虑多账本同步” → “目前聚焦单设备家庭记账但如果扩展我会用 MySQL 的 GTID 复制实现多节点数据同步而不是用 Redis 缓存——因为记账数据必须强一致性缓存只是加速不能当真相。”这些话术不是炫技而是把问题引向你准备充分的领域。5.4 检查所有TODO和FIXME注释全部删掉或实现用 IntelliJ 的Edit → Find → Find in Path搜TODO你会找到UserController.java中// TODO: 验证手机号格式→ 补上Pattern(regexp ^1[3-9]\\d{9}$)RecordService.java中// FIXME: 并发下余额可能不准→ 替换为上面写的定时任务方案app.js中// TODO: 添加网络状态监听→ 补上wx.onNetworkStatusChange监听并 toast 提示。没有TODO的代码才是真交付。答辩时老师翻你代码看到满屏TODO印象分直接掉一半。5.5 给导师提前发一份“答辩速查表”不是 PDF是一份纯文本邮件标题“张三-家庭记账系统-答辩速查表”。内容只有三行1. 核心创新点数据库层 CHECK 约束 定时余额结算 微信 code 登录全流程实现 2. 已验证场景单日 50 笔并发记账无余额错乱附 JMeter 报告截图 3. 可演示功能长按删除、报表导出、多账本切换现场可操作导师没时间看全文但三行字让他知道你准备充分、重点清晰。我发完这封邮件导师当天就回复“答辩时重点看并发测试”。5.6 最后一次全链路压力测试用 JMeter 模拟 100 用户同时记账别跳过这步。下载 JMeter建一个线程组线程数100Ramp-up10 秒循环次数1HTTP 请求POST /accountbook/api/record/addBody 为{bookId:1,categoryId:1,amount:10.00,remark:压力测试}运行后看聚合报告中90% Line响应时间是否 800msSSM 在 Tomcat 8.5 下正常查看结果树里是否有500错误若有检查RecordService的事务隔离级别是否为ISOLATION_READ_COMMITTED数据库中SELECT COUNT(*) FROM record是否等于 100验证无丢失。把 JMeter 报告截图放进论文附录。答辩时老师问“性能怎么样”你直接翻到附录第 23 页——这比说“挺快的”有力得多。5.7 从那以后我每次交毕设都强制走一遍“三色标记法”红色必须本人写的Java Service 层、小程序页面逻辑、论文核心章节→ 占 70%蓝色可复用但需改造的MyBatis Generator 生成的 Mapper、微信登录 SDK→ 占 20%绿色纯配置和文档web.xml、pom.xml、数据库建表语句→ 占 10%答辩前夜用 Word 的“审阅 → 修订”功能给三色内容分别加底纹。当老师问“这部分是你写的吗”我直接点开对应颜色区域——红色部分我能逐行解释设计意图蓝色部分我说清了哪里改了、为什么改绿色部分我坦然承认“这是标准配置但每一行我都验证过作用”。希望帮到你。本文还有配套的精品资源点击获取
返回列表