简介:这是一份基于Java的记账系统毕业设计资源,面向Java初学者及需要完整项目参考的高校学生,可帮助理解从需求分析到部署上线的全流程。资源共280个文件,压缩包约71.94MB,包含java源码、sql数据库脚本、xml配置文件、js/css前端资源,以及mp4部署视频、docx说明文档等,覆盖项目开发与运行所需的主要文件类型。目前已有187人学习下载。源码部分体现了MVC设计模式、Spring相关框架及MyBatis/Hibernate持久层操作的实践用法,SQL脚本涵盖用户信息与账目记录的CRUD操作,便于直接导入数据库验证功能;部署文档与视频则逐步演示环境配置、项目启动及常见排错思路,适合跟随复现。通过研究该项目,学习者能够掌握Java Web开发中的请求处理、数据交互和项目部署流程,是毕业设计或课程实践较为完整的参考资料。
1. 毕设季的记账系统:为什么这类项目最值得自己动手写一遍
每年毕业设计选题里,「基于Java的记账系统」都是出现频率最高的题目之一,因为它的业务边界清晰、技术栈通用、演示效果好,从学生到评委都能一眼看懂。记账系统的核心需求无非是用户注册登录、收支流水管理、分类统计、图表展示这几件事,但恰恰是这些看似简单的功能,把 Java 后端开发的主干知识全串起来了:Servlet 或 Spring Boot 的请求处理、MySQL 的表设计与事务、JDBC 或 MyBatis 的持久层操作、前端页面的数据渲染。你把这个项目完整做一遍,Java 课设、毕业答辩、甚至初级 Java 岗位的面试项目经验,就都有东西可讲了。
需要说明的是,网上流传的「源代码+数据库+部署文档+部署视频」这类压缩包,质量参差不齐,很多是早期 SSH/SSM 框架的老项目,JDK 版本和 Tomcat 版本都很旧。我写这篇笔记的目的,不是让你去下载某个来路不明的包交差,而是把这类项目从零到部署的完整路径拆开讲清楚——拿到任意一份记账系统源码,你能看懂它的结构、改得动它的代码、知道数据库脚本怎么导入、部署文档里哪些坑是文档没写但你一定会踩的。下面从技术选型开始,一步一步落到可复现的命令和配置上。
2. 记账系统的技术选型:先定骨架,再谈功能
2.1 Java 版本与框架选择:Spring Boot 还是 SSM
记账系统在毕设里最常见的两种骨架,一种是传统的 SSM(Spring + Spring MVC + MyBatis),另一种是 Spring Boot + MyBatis Plus。如果你手里的源码是 2018 年以前的,大概率是前者,用 XML 配置数据源、配置web.xml、还要手动打 WAR 包丢进 Tomcat。而 2020 年以后的毕业设计,主流已经切到 Spring Boot,内嵌 Tomcat,mvn package出一个 JAR 直接java -jar就能跑。我一般建议选 Spring Boot,不是因为 SSM 不能做,而是部署文档和答辩演示的容错率高很多——少一个外部 Tomcat 的版本兼容问题,就少一个翻车点。
JDK 版本也要注意。很多老源码是基于 JDK 8 写的,用了javax.*包路径;如果你本机装的是 JDK 17 或更高,Spring Boot 2.x 项目大概率能跑,但 Spring Boot 1.x 的项目会因为javax.servlet迁移到jakarta.servlet直接起不来。拿到源码第一件事不是看业务代码,而是看pom.xml里的<parent>版本和 JDK 编译版本,这决定了你后面所有步骤是否顺利。以下是一个典型的 Spring Boot 记账系统依赖清单:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.3.2</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>依赖版本这里说几个关键点。Spring Boot 2.7.18 是 2.x 系列的最终维护版本,稳定且兼容 JDK 8 到 JDK 21,适合绝大多数毕设场景。mysql-connector-j是 MySQL 官方驱动的新坐标,老项目里写的mysql-connector-java也能用,但如果你的 MySQL 是 8.0 以上版本,建议直接用新坐标,避免驱动类名加载问题。Lombok 不是必须的,但如果源码里大量使用了@Data注解,而你本机 IDE 没装 Lombok 插件,编译会直接报找不到getter/setter,这个属于新手最常见的玄学问题之一——代码看起来没问题,一跑就红。
2.2 数据库选型与表结构设计:收支两条线的核心模型
记账系统的数据库表一般不会超过 5 张:用户表、支出分类表、收入分类表、账单流水表,可能再加一个系统配置表。表数量少不代表设计可以随意,因为整个系统的业务逻辑都压在流水表和分类表的关联上。以常见的account_bill流水表为例,核心字段应该有id、user_id、type(0 支出 / 1 收入)、category_id、amount、record_date、remark、create_time这几个。
这里最容易出错的是金额字段类型。我见过很多课设源码把amount设计成double,这会导致统计报表时出现0.1 + 0.2 = 0.30000000000000004这类精度问题。正确的做法是用decimal(10,2),既保证精度,也符合财务场景的直觉。另一个高发问题是record_date用varchar存储,排序和按月统计时会非常痛苦,date类型才是正解。下面给出一份可以直接导入 MySQL 的核心建表脚本:
CREATE DATABASE IF NOT EXISTS account_system DEFAULT CHARACTER SET utf8mb4; USE account_system; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '登录名', `password` varchar(64) NOT NULL COMMENT 'MD5或BCrypt后的密码', `nickname` varchar(32) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; CREATE TABLE `t_category` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `name` varchar(32) NOT NULL COMMENT '分类名,如餐饮', `type` tinyint(1) NOT NULL COMMENT '0支出 1收入', `sort` int(11) DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收支分类表'; CREATE TABLE `t_bill` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `type` tinyint(1) NOT NULL COMMENT '0支出 1收入', `category_id` int(11) NOT NULL, `amount` decimal(10,2) NOT NULL COMMENT '金额,单位元', `record_date` date NOT NULL COMMENT '消费日期', `remark` varchar(255) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_user_date` (`user_id`, `record_date`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账单流水表';这个脚本里有两个容易被忽略的设计细节。第一,t_bill表加了联合索引idx_user_date,因为记账系统最频繁的查询就是「某用户某段时间的流水」,没有这个索引,数据量到几千条以后按月统计就会明显变慢。第二,外键我没有建,原因是毕设项目里 MyBatis 关联查询足够用,而外键会在删除分类时带来一堆约束问题。通常的做法是在 Service 层手动检查分类下有没有关联账单,有就拒绝删除,这样既满足业务校验,又避免数据库层面的级联操作给你埋雷。
3. 本地跑通记账系统源码:从导入到启动的三步操作
3.1 导入数据库脚本并初始化测试数据
拿到一个毕设压缩包,解压后通常会看到sql目录或db目录,里面放着.sql文件。先别急着用 Navicat 双击运行,老项目的脚本经常没有CREATE DATABASE语句,直接导入到默认库会导致后面连接串里的库名对不上。第一步应该是打开 SQL 文件看前三行,确认有没有建库语句、用的什么字符集。如果没有建库语句,就用命令行手动建库再导入:
mysql -uroot -p # 输入密码后执行: # CREATE DATABASE account_system DEFAULT CHARACTER SET utf8mb4; # USE account_system; # source /path/to/account.sql;如果你用的是 Navicat 或 DataGrip,可以直接新建查询窗口执行整个.sql文件。导入完成后,重点检查三张表的数据量:用户表应该有一条测试账号,分类表应该有几条默认分类,账单表有若干条模拟流水。很多压缩包自带的 SQL 脚本里,默认分类是直接写在t_category里的,而用户表只有一条admin/123456。这类账号密码通常是明文存储的,不需要纠结安全性,毕设答辩时能登录进去就行。
导入阶段还有一个高频翻车点:SQL 文件里的表名或字段名用了 MySQL 保留字,比如order、desc、rank。如果导入时报语法错误,或者启动后查询报错,优先怀疑保留字问题,解决办法是给字段名加反引号,或者在实体类里用@TableField注解做映射。遇到这种问题不要慌,SQL 脚本是文本文件,用编辑器全局搜索保留字就能定位。
3.2 修改配置文件并启动 Spring Boot 项目
数据库导入成功后,下一步就是改配置启动。Spring Boot 项目的核心配置在src/main/resources/application.yml或application.properties里。毕设源码里最常见的坑是数据库密码、端口、字符集三处配置和你本地环境不匹配。下面是一份标准配置:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/account_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.account.entityurl里的serverTimezone=Asia/Shanghai是 MySQL 8.x 必须加的,不加会报The server time zone value 'Öйú±ê׼ʱ¼ä'之类的错误,这个报错信息看起来像乱码,其实只是时区问题。useSSL=false是避免本地 MySQL 没有配 SSL 证书时连接被拒。driver-class-name这里用的是com.mysql.cj.jdbc.Driver,对应 MySQL 8.x 驱动;如果驱动是 5.x,应该写成com.mysql.jdbc.Driver。这两者混用的错误信息非常相似,看到ClassNotFoundException先检查驱动坐标和类名是否匹配。
改完配置直接启动是很危险的操作,建议先跑一次编译,确认依赖能拉下来:
mvn clean compile mvn spring-boot:run日志出现Started Application in x.xxx seconds说明启动成功。如果mvn命令不存在,用 IDE 右侧的 Maven 面板点spring-boot:run也可以。启动失败时优先看日志里Caused by后面的第一行,那里才是真正的原因,而不是看前面一大段堆栈。我遇到过最典型的场景是端口被占用——Port 8080 was already in use,解决方法是改server.port为 8081,或者杀掉占用进程。
3.3 用测试账号验证核心业务链路
项目启动后,浏览器访问http://localhost:8080/login,用 SQL 里预置的账号登录。如果页面 404,先看控制台日志里 Tomcat 实际监听的端口是多少,Spring Boot 的context-path如果被配置过,访问路径会多一层前缀。比如server.servlet.context-path: /account,那就得访问http://localhost:8080/account/login。这一步卡住的人不少,因为源码里application.yml往往带了这个配置,而部署文档里可能没写。
登录成功后不要急着截图,把三条核心链路走一遍:新增一笔支出、新增一笔收入、查看统计报表。我通常在新增账单时会顺手测一下金额输入0.001和-50的情况,看系统有没有做后端校验。很多毕设源码只在前端用 JS 限制输入,接口层直接信任参数,这种项目答辩时一旦被评委问到「负数金额怎么处理」,就会变成黑匣子——你完全不知道业务到底怎么设计的。好的实现应该在后端用@DecimalMin("0.01")或手动判断金额小于等于零时抛出业务异常。
4. 数据库与部署文档里的避坑指南:4 个必踩的经典问题
4.1 MySQL 8.0 的密码加密方式导致 JDBC 连接失败
用 MySQL 8.0 跑老项目,最容易遇到的怪事是账号密码明明正确,Navicat 能连上,但 Java 程序一连就报Access denied for user 'root'@'localhost'。原因不是密码错了,而是 MySQL 8.0 默认的caching_sha2_password认证插件和旧版 JDBC 驱动不兼容。现象是驱动版本是 5.x 或者连接串里没指定allowPublicKeyRetrieval=true,服务端拒绝握手。
解决方式有两种。第一种最省事,在 JDBC URL 里加allowPublicKeyRetrieval=true,配合useSSL=false就能连上。第二种是一劳永逸地改掉 root 用户的认证插件:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码'; FLUSH PRIVILEGES;改完之后重启应用,连接就稳定了。这里要提醒一点:如果你做的是答辩演示,现场用的数据库可能是你自己电脑上现成的 MySQL 实例,第二种方案改完不影响其他项目,但如果你用的是学校机房统一装的 MySQL 5.5,那根本不会遇到这个问题——所以遇到报错先SELECT VERSION();看版本,再决定走哪条路。
4.2 数据库脚本导入成功但表里没数据
有人导入 SQL 文件后,表结构全在,但登录时提示用户名或密码错误。打开t_user表一看,是空的。原因是毕设压缩包里的 SQL 脚本可能只包含建表语句,测试数据在另一个data.sql里,或者根本没有测试数据,需要你手动注册一个账号。这类问题在老旧的数据集里很常见,文档里写的「默认账号 admin/123456」只是说明书的理想状态,实际操作中以数据库里的记录为准。我的做法是直接往表里插一条密码是 MD5 的记录:
INSERT INTO t_user (username, password, nickname) VALUES ('admin', MD5('123456'), '管理员');注意,老项目密码存储通常是MD5(密码),但有些源码注册时用的是MD5(密码+盐)。如果你往库里手动插了 MD5 记录却登录不上去,很可能就是加盐问题。这时候去翻源码里注册逻辑那段,看它是怎么拼接字符串的,再按同样的规则生成一条密码记录插入。不要试图从登录页绕过,登录逻辑是绕不过去的。
4.3 部署文档里的环境版本和你的本机不一致
随源码附带的部署文档,写的基本都是作者当时的环境:JDK 1.8、Tomcat 8.5、MySQL 5.7。你手上如果是 JDK 17 加 MySQL 8.0,按文档步骤走大概率翻车。部署文档的正确用法不是照着执行,而是对照着查差异。我会先看文档里的环境列表,再跑三个命令确认本机版本:
java -version mvn -version mysql --version版本差异带来的典型症状有:JDK 17 下 Spring Boot 2.x 启动时报IllegalAccessError;MySQL 8.0 下 JDBC 驱动报时区错误;Tomcat 10 下部署 WAR 包报jakarta.servlet找不到。这些问题的共同规律是「版本跨越太大,不是改一个配置就能解决的」。遇到这种情况,建议直接用 IDE 内置的 JRE 或单独装一个 JDK 8 来跑项目,而不是硬着头皮让老项目适配新环境——毕设项目的时间应该花在业务功能上,不该花在环境兼容性排查上。
4.4 数据库连接池的连接数耗尽导致页面卡死
记账系统在演示时偶尔会出现一种现象:前几分钟操作正常,某一次点击后页面一直转圈,后台日志疯狂输出Connection refused或wait connection timeout。这通常不是代码问题,而是数据库连接池设置不合理。Spring Boot 默认用的是 HikariCP,默认最大连接数maximum-pool-size是 10。如果代码里存在连接未释放的情况,比如SqlSession没有关闭,或者 MyBatis 的@Mapper方法在循环中被调用且事务切面异常,连接池很快会被占满。
解决方法是先在配置里把maximum-pool-size调大观察,但这只是临时手段,根治还是要查代码里哪里漏了关闭资源。MyBatis-Plus 环境下,DefaultDBTypeHandler和BaseMapper的常规查询都会自动管理连接,真正容易漏的是手动拿SqlSessionTemplate执行的代码。如果你在私有方法里写了SqlSession session = sqlSessionFactory.openSession()却忘了在finally里session.close(),那恭喜你,复现这个问题只需要连续点几十次页面。
提示:排查连接池问题最直接的方式是看 HikariCP 日志里
Pool stats这行,active和awaiting两个数字会告诉你连接是泄漏了还是只是暂时不够用。
5. 记账系统的进阶改造:从毕设到可演示的项目亮点
5.1 把明文密码升级为 BCrypt 加密
答辩时评委大概率会问一个问题:密码是怎么存储的?如果源码里是 MD5 明文,答不上来会很尴尬。我一般会建议在毕设基础上做一个最小改造——把注册和登录逻辑里的MD5换成BCryptPasswordEncoder。Spring Security 不需要完全引入,只需要引入spring-security-crypto这个轻量依赖就能使用BCryptPasswordEncoder。改造点只有两个:注册时调用encode(),登录时调用matches():
// 注册 String rawPassword = user.getPassword(); user.setPassword(passwordEncoder.encode(rawPassword)); // 登录 boolean ok = passwordEncoder.matches(rawPassword, userFromDb.getPassword());这个改造的收益非常大,因为它不需要动数据库表结构,只把密码字段的长度从 32 改成 60(BCrypt 哈希长度是 60 个字符),再改一下 Service 里的两个方法即可。答辩时你就可以明确地说:项目采用了 BCrypt 加盐哈希存储密码,即使数据库泄露,也无法反推出原始密码。这个亮点在老项目中是加分项,因为大多数同学的毕设还在用 MD5。
5.2 增加月度统计接口并用 ECharts 展示报表
记账系统做完增删改查只能算及格,想做出彩还要有一个可视化统计页面。常见做法是在后端写一个按月统计的 SQL,前端引入 ECharts 的 CDN 渲染柱状图和饼图。统计接口的核心 SQL 如下:
SELECT c.name AS categoryName, SUM(b.amount) AS totalAmount FROM t_bill b LEFT JOIN t_category c ON b.category_id = c.id WHERE b.user_id = #{userId} AND b.type = 0 AND b.record_date BETWEEN #{startDate} AND #{endDate} GROUP BY b.category_id ORDER BY totalAmount DESC;这里有个容易被忽略的细节:GROUP BY后面要跟的是b.category_id,但SELECT列表里的c.name依赖b.category_id到c.id的关联,MySQL 在ONLY_FULL_GROUP_BY模式下会报错。解决方法是把c.name也放进GROUP BY,或者用ANY_VALUE(c.name)。这个坑如果遇到了,SQL 报错信息会给出具象提示,别被一大段 explain 分析带偏思路。
前端拿到 JSON 数据后,用 ECharts 的pie系列渲染即可。这里我不贴完整前端代码,核心思路是:后端返回[{categoryName: "餐饮", totalAmount: 1200}]这样的结构,前端用map拆成name数组和value数组,塞进series里。如果想增加演示效果,再在同一页放一个折线图展示近 6 个月支出趋势,评委的注意力就会从「你这项目是不是抄的」转移到「这功能是怎么实现的」——后者显然更好应对。
5.3 用部署视频验证环境的完整闭环
压缩包里通常带一个部署视频,很多人把这视频当成摆设。实际上,部署视频是最好的验收标准——你按照视频里的步骤在你的电脑上完整走一遍,能不能跑通,跑通后访问路径是否一致,这些都能在答辩前暴露出来。我的习惯是:把视频里的操作步骤整理成文字清单,每完成一步打一个勾。清单大致是:装 JDK 8 并配置环境变量 → 装 MySQL 5.7 或 8.0 → 导入 SQL 脚本 → 修改application.yml数据库账号密码 →mvn spring-boot:run→ 浏览器访问登录页。
这个过程里如果某一步和视频对不上,优先怀疑版本差异,不要怀疑自己操作错了。比如视频里用的 IDEA 2019,你用的是 IDEA 2024,界面长得完全不一样,但 Maven 面板的位置和功能没有本质变化。如果视频里用mvn clean package打出 JAR 再用java -jar启动,你也可以直接用mvn spring-boot:run节省打包时间,两者效果等价,只是演示时后者多占一个控制台窗口。到了答辩现场,演示环境不要临时切换,就用你反复跑过的那一套。毕设翻车的高发区不是项目本身,而是现场网络连不上 CDN、演示机没装 JDK、数据库端口被占用这类外部小问题——提前用部署视频闭环一遍,这些就都有后悔药可吃。
6. 部署时最容易被忽视的 JAR 包启动参数与数据持久化
说到部署,Spring Boot 项目的最终形态通常是一个可执行 JAR。很多人的毕设演示是在 IDE 里点启动按钮完成的,这没问题,但如果你想把项目部署到服务器上,或者需要演示给评委看「我的项目能在生产环境跑」,就必须学会用命令行启动 JAR。打包命令是mvn clean package -DskipTests,产物在target/目录下,文件名形如account-system-0.0.1-SNAPSHOT.jar。用java -jar启动时,两个参数必须认真对待:端口和数据库配置。
application.yml里的配置是编译进 JAR 的,部署时如果想覆盖,可以在启动命令后追加参数。常见做法是用--server.port=8081覆盖端口,用--spring.datasource.url覆盖数据库地址。这在迁移服务器时特别有用,因为你不需要重新打包,只要改命令行参数即可:
java -jar account-system-0.0.1-SNAPSHOT.jar \ --server.port=8080 \ --spring.datasource.url='jdbc:mysql://192.168.1.10:3306/account_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false' \ --spring.datasource.username=root \ --spring.datasource.password=yourpassword这里要注意 shell 里单引号和双引号的区别。URL 里没有空格和特殊字符时用双引号包起来最保险,尤其是密码里含&或$时,一定要用单引号包住整个值,否则 shell 会做变量展开,导致连接串被截断。这个坑我在帮别人排查时见过好几次,症状是启动时日志里打印的 URL 和你输入的不一样,后面跟着一段诡异的字符。
数据持久化方面,如果你的演示环境用的是 Docker 跑 MySQL,一定要给容器挂载数据卷。很多人在本地用 MySQL 服务没问题,换到 Docker 后忘了挂载-v,结果每次docker-compose down之后数据全丢,又要重新导入 SQL。正确做法是在docker-compose.yml里声明volumes:
mysql: image: mysql:8.0 restart: always environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: account_system TZ: Asia/Shanghai ports: - "3306:3306" volumes: - ./mysql-data:/var/lib/mysql每次容器重建后,数据库文件依然在./mysql-data里,数据不会丢。这在答辩前一天尤其重要——如果熬夜往系统里录了一堆演示数据,结果第二天容器重启后数据清零,那种挫败感我经历过一次后,就再也不敢不挂数据卷了。毕设项目不容易,能在细节上少踩一个坑,就多一分从容,希望这篇笔记里的选型和排错思路能帮到你,让你的记账系统从「能跑」变成「讲得清楚、经得起问」。
本文还有配套的精品资源,点击获取