🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度
在实际计算机专业毕业设计选题和实现过程中,很多同学面临的第一个难题不是写代码,而是如何找到一个合适的题目,并快速搭建起一个可运行、可演示、能通过查重和答辩的完整项目。无论是Java、Python、PHP还是Node.js技术栈,从零开始构思一个“个人记账系统”这类经典题目,到最终完成代码、文档和部署,中间涉及环境配置、框架选型、数据库设计、功能实现、论文撰写和查重等多个环节,任何一个环节卡住都可能影响毕业进度。
本文将以“大学生个人记账系统”为具体案例,串联起从选题分析、技术选型、环境搭建、核心功能实现到论文撰写的全流程。无论你擅长Java Spring Boot、Python Django、PHP Laravel还是Node.js Express,都能从中找到对应的实现路径和避坑指南。我们将重点关注那些在毕设中高频出现但容易被忽略的细节,例如Java项目的内存溢出(OutOfMemoryError)、Python打包成exe的依赖问题、PHP表单验证码集成、Node.js版本管理(nvm)和环境变量配置错误等。通过这篇指南,你将掌握的不只是一个记账系统的代码,更是一套应对计算机毕设的通用工程方法和问题排查能力。
1. 理解毕设核心要求与“个人记账系统”选题价值
在开始写任何代码之前,必须明确毕业设计的目标。它不是一个单纯的编程作业,而是一个综合性的工程实践,需要体现你对软件工程生命周期(需求、设计、实现、测试、部署)的理解和应用能力。
1.1 为什么“个人记账系统”是经典的毕设选题
“个人记账系统”看似简单,但它几乎涵盖了本科阶段所学的大部分核心知识点,并且业务逻辑清晰,易于扩展和演示,这使其成为一个经久不衰的优秀选题。
- 需求明确,业务场景贴近生活:记账的核心功能(收入/支出记录、分类、统计、报表)易于理解,评委老师也能快速get到你的项目价值。你可以很容易地阐述项目的背景和意义。
- 技术栈覆盖全面:
- 前端:可以选择传统的JSP/Thymeleaf,也可以使用Vue.js、React等现代框架,或者直接采用微信小程序、Uni-app等跨端方案。
- 后端:Java (Spring Boot)、Python (Django/Flask)、PHP (ThinkPHP/Laravel)、Node.js (Express/Koa) 均可胜任。
- 数据库:必然涉及MySQL、PostgreSQL等关系型数据库,用于存储用户、账目、分类等数据。
- 附加技术点:可以引入图表库(ECharts)进行数据可视化、集成第三方登录、实现数据导出(Excel/PDF)、添加缓存(Redis)等来提升项目深度。
- 易于实现和演示:核心的增删改查(CRUD)操作是基础,在此基础上可以增加预算管理、多账本、报表分析等进阶功能,工作量可控且能体现技术能力。
- 论文有内容可写:从需求分析、系统设计、数据库设计、详细实现到系统测试,每个阶段都有丰富的素材可以填充到论文中。
1.2 毕设成功的关键:超越“功能实现”
很多同学把毕设等同于“把功能做出来”,但评委更关注的是你如何“工程化”地完成一个项目。以下几点是区分普通项目和优秀项目的关键:
- 清晰的架构与分层:你的代码是否遵循了MVC、前后端分离等设计模式?业务逻辑、数据访问、控制层是否清晰分离?
- 规范的数据库设计:是否有合理的ER图?表结构是否遵循了三大范式?是否考虑了索引、事务和数据的完整性约束?
- 完备的异常处理与日志:程序是否会因为一个空指针或数据库连接失败而崩溃?是否有日志记录关键操作和错误信息,便于排查问题?
- 基本的安全考虑:用户密码是否加密存储?是否有防止SQL注入、XSS攻击的措施?敏感操作(如删除)是否有确认机制?
- 可部署与可维护性:项目是否有清晰的依赖说明(如
pom.xml,package.json,requirements.txt)?是否有部署文档?配置是否与代码分离?
2. 技术选型与环境准备:避开第一个大坑
选择熟悉或市场需求旺盛的技术栈。环境配置是毕设的第一道坎,很多同学在这里浪费大量时间。
2.1 主流技术栈对比与选型建议
| 技术栈 | 适合场景 | 优势 | 毕设中常见坑 |
|---|---|---|---|
| Java (Spring Boot) | 中大型应用,企业级开发,对性能、稳定性要求高。 | 生态成熟,资料极多,架构清晰,易于体现工程能力。 | 1. 依赖冲突。2. 配置复杂。3.OutOfMemoryError: Java heap space(内存溢出)。 |
| Python (Django/Flask) | 快速原型开发,数据分析、机器学习结合类项目。 | 开发效率高,语法简洁,库丰富。 | 1. 虚拟环境管理。2. 部署时依赖问题。3. 打包成exe(PyInstaller)时体积大、兼容性问题。 |
| PHP (Laravel/ThinkPHP) | 快速构建Web应用,尤其适合内容管理类。 | 部署简单(LAMP),入门快,模板引擎易用。 | 1. 版本兼容性(PHP5 vs PHP7/8)。2. 表单安全(CSRF、验证码集成)。3. 现代PHP项目结构理解。 |
| Node.js (Express/Koa) | 高并发I/O密集型应用,全栈JavaScript开发。 | 异步非阻塞,适合实时应用,前后端语言统一。 | 1.Node版本管理(nvm)。2.node-sass等C++模块编译失败。3. 回调地狱或异步流程控制。 |
选型建议:优先选择你课程中学过或自己最熟悉的技术栈。如果都不熟,Java Spring Boot和Python Django是资料最全、社区最活跃的选择,能帮你减少很多“找不到答案”的困境。
2.2 环境准备清单与排错指南
无论选择哪种技术栈,请严格按照以下清单准备环境,并保存好对应的版本号,这在论文的“开发环境”章节和日后排查问题时至关重要。
通用准备:
- 代码编辑器/IDE:IntelliJ IDEA (Java), PyCharm (Python), VS Code (全栈)。确保安装对应语言插件。
- 版本控制:安装Git,并在GitHub/Gitee上创建项目仓库。这是好习惯,也能防止代码丢失。
- 数据库:安装MySQL 5.7或8.0,并安装一个图形化管理工具(如Navicat, DBeaver)。
分技术栈准备:
Java (Spring Boot) 环境
# 1. 安装JDK 8或11(建议11,长期支持版本) # 下载并设置JAVA_HOME环境变量 # 验证 java -version # 2. 安装Maven 3.6+ # 下载并设置MAVEN_HOME,将bin目录加入PATH # 验证 mvn -v # 3. 使用Spring Initializr (https://start.spring.io) 生成项目 # 选择: Project: Maven, Language: Java, Spring Boot: 2.7.x 或 3.x # Dependencies: Spring Web, Spring Data JPA, MySQL Driver, Lombok(可选)常见坑1:Java内存溢出(OutOfMemoryError)在IDEA中运行Spring Boot项目时,如果数据量较大或存在内存泄漏,可能遇到。
- 现象:应用突然崩溃,日志中出现
java.lang.OutOfMemoryError: Java heap space。 - 解决:调整JVM启动参数。在IDEA的
Run/Debug Configurations的VM options中增加:-Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m - 预防:查询大数据集时使用分页;及时关闭数据库连接和IO流;定期检查是否有静态集合类持续增长。
Python (Django) 环境
# 1. 安装Python 3.8+ # 验证 python --version pip --version # 2. 强烈建议使用虚拟环境 # 创建 python -m venv venv # 激活 (Windows) venv\Scripts\activate # 激活 (Mac/Linux) source venv/bin/activate # 3. 安装Django和驱动 pip install django==4.2.* pymysql常见坑2:Python打包成exe问题如果你想将Django管理脚本或一个辅助工具打包成exe方便答辩演示,使用PyInstaller。
- 现象:打包后exe文件巨大(几百MB),或运行时提示缺少模块。
- 解决:
- 在虚拟环境中打包,确保环境干净。
- 使用
--onefile生成单文件,但体积大。使用--onedir生成文件夹,体积稍小。 - 在
.spec文件中手动隐藏不需要的库,或使用pipenv等工具管理更精确的依赖。 - 对于Django项目,打包非Web应用部分,Web部分仍需通过
python manage.py runserver运行。
PHP (Laravel) 环境
# 1. 安装PHP 8.1+ # 验证 php -v # 2. 安装Composer (依赖管理工具) # 验证 composer --version # 3. 使用Composer创建Laravel项目 composer create-project --prefer-dist laravel/laravel my-bookkeeping常见坑3:PHP表单验证码集成使用第三方包如gregwar/captcha。
- 安装:
composer require gregwar/captcha - 在控制器中生成并存储验证码:
// 在控制器方法中 use Gregwar\Captcha\CaptchaBuilder; public function captcha() { $builder = new CaptchaBuilder; $builder->build(); Session::put('captcha', $builder->getPhrase()); // 存储到session return response($builder->output())->header('Content-type', 'image/jpeg'); } - 在视图中显示:
<img src="{{ url('captcha') }}" onclick="this.src='{{ url('captcha') }}?'+Math.random()"> - 验证用户输入:
if (Session::get('captcha') != $request->input('captcha')) { // 验证失败 }
Node.js (Express) 环境
# 1. 使用nvm管理Node版本(避免权限和版本冲突问题) # 安装nvm (Windows: nvm-windows, Mac/Linux: 脚本安装) # 使用nvm安装Node nvm install 16.14.0 # 安装一个LTS版本 nvm use 16.14.0 # 使用该版本 # 2. 验证安装 node -v npm -v # 3. 创建Express项目 npm init -y npm install express mysql2 cors body-parser # 安装常用包常见坑4:Node环境与命令找不到
- 现象:
node: 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称... - 原因:Node.js未安装,或安装后未将安装目录(如
C:\Program Files\nodejs\)添加到系统的PATH环境变量中。 - 解决:重新安装Node.js,安装时务必勾选“Add to PATH”选项,或手动添加环境变量。常见坑5:node-sass 编译错误
- 现象:
node-sass@4.14.1: Node Sass is no longer supported... - 原因:
node-sass已废弃,应使用sass(纯JS实现)。 - 解决:将
package.json中的node-sass依赖替换为sass,并更新代码中的引用(如果使用Webpack等,配置也需要调整)。
3. “个人记账系统”核心功能设计与实现
我们以最常见的Java Spring Boot + Vue.js 前后端分离架构为例,拆解核心模块的实现。其他技术栈的思路完全一致,只是语法和框架API不同。
3.1 数据库设计(MySQL)
一个精简但完整的数据结构是项目的基石。至少需要以下表:
-- 用户表 CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '密码(加密存储)', `email` varchar(100) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -- 账目分类表 CREATE TABLE `category` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '所属用户ID', `name` varchar(20) NOT NULL COMMENT '分类名称(如:餐饮、交通)', `type` tinyint(1) NOT NULL COMMENT '类型:1-收入,0-支出', `icon` varchar(50) DEFAULT NULL COMMENT '图标类名', PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`), CONSTRAINT `fk_category_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账目分类表'; -- 账目记录表(核心表) CREATE TABLE `record` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `category_id` int(11) NOT NULL COMMENT '分类ID', `amount` decimal(10,2) NOT NULL COMMENT '金额', `remark` varchar(255) DEFAULT NULL COMMENT '备注', `record_date` date NOT NULL COMMENT '记录日期', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_user_date` (`user_id`,`record_date`), KEY `fk_record_category` (`category_id`), CONSTRAINT `fk_record_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`), CONSTRAINT `fk_record_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='账目记录表';设计要点:
- 密码加密:
password字段使用BCrypt等强哈希算法加密,切勿明文存储。 - 外键约束:使用外键确保数据完整性,
ON DELETE CASCADE表示用户删除时,其分类和记录一并删除。 - 索引:为
user_id和record_date等查询条件添加索引,提升查询性能。 - 金额字段:使用
DECIMAL(10,2),避免浮点数精度问题。
3.2 后端Spring Boot核心代码实现
1. 实体类(Entity)使用JPA注解映射数据库表。
// User.java @Entity @Table(name = "user") @Data // Lombok注解,自动生成getter/setter public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(unique = true, nullable = false) private String username; @Column(nullable = false) private String password; private String email; @Column(name = "create_time", updatable = false, insertable = false) private LocalDateTime createTime; } // Record.java @Entity @Table(name = "record") @Data public class Record { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne @JoinColumn(name = "user_id", nullable = false) private User user; @ManyToOne @JoinColumn(name = "category_id", nullable = false) private Category category; @Column(nullable = false, precision = 10, scale = 2) private BigDecimal amount; private String remark; @Column(name = "record_date", nullable = false) private LocalDate recordDate; @Column(name = "create_time", updatable = false, insertable = false) private LocalDateTime createTime; }2. 数据访问层(Repository)Spring Data JPA会自动实现基本CRUD。
// RecordRepository.java public interface RecordRepository extends JpaRepository<Record, Integer> { // 根据用户ID和日期范围查询记录 List<Record> findByUserIdAndRecordDateBetween(Integer userId, LocalDate start, LocalDate end); // 根据用户ID和分类查询某月的记录 @Query("SELECT r FROM Record r WHERE r.user.id = :userId AND r.category.id = :categoryId AND YEAR(r.recordDate) = :year AND MONTH(r.recordDate) = :month") List<Record> findByUserAndCategoryAndMonth(@Param("userId") Integer userId, @Param("categoryId") Integer categoryId, @Param("year") int year, @Param("month") int month); }3. 服务层(Service)处理业务逻辑,如统计。
// RecordService.java @Service public class RecordService { @Autowired private RecordRepository recordRepository; public Map<String, BigDecimal> getMonthlySummary(Integer userId, int year, int month) { List<Record> records = recordRepository.findByUserIdAndRecordDateBetween( userId, LocalDate.of(year, month, 1), LocalDate.of(year, month, 1).with(TemporalAdjusters.lastDayOfMonth()) ); BigDecimal totalIncome = BigDecimal.ZERO; BigDecimal totalExpense = BigDecimal.ZERO; for (Record r : records) { if (r.getCategory().getType() == 1) { // 1代表收入 totalIncome = totalIncome.add(r.getAmount()); } else { totalExpense = totalExpense.add(r.getAmount()); } } Map<String, BigDecimal> summary = new HashMap<>(); summary.put("income", totalIncome); summary.put("expense", totalExpense); summary.put("balance", totalIncome.subtract(totalExpense)); return summary; } }4. 控制层(Controller)提供RESTful API接口。
// RecordController.java @RestController @RequestMapping("/api/record") public class RecordController { @Autowired private RecordService recordService; @GetMapping("/monthly-summary") public Result getMonthlySummary(@RequestParam int year, @RequestParam int month, HttpSession session) { // 从session中获取当前登录用户ID (需实现登录拦截器) Integer userId = (Integer) session.getAttribute("userId"); if (userId == null) { return Result.error("未登录"); } Map<String, BigDecimal> summary = recordService.getMonthlySummary(userId, year, month); return Result.success(summary); } @PostMapping public Result addRecord(@RequestBody Record record, HttpSession session) { Integer userId = (Integer) session.getAttribute("userId"); // ... 参数校验 record.setUser(new User(userId)); // 设置关联用户 // ... 保存记录 return Result.success("添加成功"); } } // Result.java 统一响应封装 @Data class Result { private int code; private String msg; private Object data; public static Result success(Object data) { /*...*/ } public static Result error(String msg) { /*...*/ } }5. 配置文件(application.yml)
spring: datasource: url: jdbc:mysql://localhost:3306/account_book?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: update # 首次启动可设为update自动建表,生产环境改为validate或none show-sql: true # 开发时显示SQL,便于调试 properties: hibernate: format_sql: true server: port: 80803.3 前端Vue.js核心页面示例
使用Element UI组件库快速搭建。
<!-- RecordList.vue --> <template> <div> <el-table :data="recordList" style="width: 100%"> <el-table-column prop="recordDate" label="日期" width="120"></el-table-column> <el-table-column prop="category.name" label="分类" width="120"></el-table-column> <el-table-column prop="amount" label="金额" width="120"> <template slot-scope="scope"> <span :style="{color: scope.row.category.type === 1 ? 'green' : 'red'}"> {{ scope.row.category.type === 1 ? '+' : '-' }}{{ scope.row.amount }} </span> </template> </el-table-column> <el-table-column prop="remark" label="备注"></el-table-column> <el-table-column label="操作" width="150"> <template slot-scope="scope"> <el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.row.id)">删除</el-button> </template> </el-table-column> </el-table> <!-- 统计卡片 --> <el-row :gutter="20" style="margin-top: 20px;"> <el-col :span="8"> <el-card> <div>本月收入</div> <div style="font-size: 24px; color: green;">{{ summary.income }}</div> </el-card> </el-col> <el-col :span="8"> <el-card> <div>本月支出</div> <div style="font-size: 24px; color: red;">{{ summary.expense }}</div> </el-card> </el-col> <el-col :span="8"> <el-card> <div>本月结余</div> <div style="font-size: 24px;">{{ summary.balance }}</div> </el-card> </el-col> </el-row> </div> </template> <script> import axios from 'axios'; export default { data() { return { recordList: [], summary: { income: 0, expense: 0, balance: 0 } }; }, mounted() { this.fetchRecords(); this.fetchSummary(); }, methods: { fetchRecords() { axios.get('/api/record', { params: { /* 日期参数 */ } }) .then(res => { this.recordList = res.data.data; }) .catch(err => { console.error('获取记录失败', err); }); }, fetchSummary() { const now = new Date(); axios.get('/api/record/monthly-summary', { params: { year: now.getFullYear(), month: now.getMonth() + 1 } }).then(res => { this.summary = res.data.data; }); }, handleDelete(id) { this.$confirm('确认删除该记录?', '提示', { type: 'warning' }) .then(() => { axios.delete(`/api/record/${id}`).then(() => { this.$message.success('删除成功'); this.fetchRecords(); this.fetchSummary(); // 重新统计 }); }); } } }; </script>4. 运行验证、部署与论文整合
4.1 本地运行验证清单
- 后端启动:运行Spring Boot的
main方法,控制台无报错,打印出Tomcat启动在8080端口。 - 数据库连接:检查数据库是否成功创建表(
ddl-auto: update模式下)。 - API测试:使用Postman或浏览器访问
http://localhost:8080/api/record/monthly-summary?year=2024&month=5(需先实现登录)。应返回JSON数据或未登录提示。 - 前端启动:在Vue项目根目录运行
npm run serve,访问http://localhost:8081。 - 功能走查:
- 用户注册、登录。
- 添加收入/支出记录。
- 查询、编辑、删除记录。
- 查看统计图表(如果集成ECharts)。
4.2 常见问题排查表
| 问题现象 | 可能原因 | 检查点与解决方案 |
|---|---|---|
| 后端启动失败,端口被占用 | 8080端口已被其他程序(如旧Tomcat)使用。 | 1. 更改application.yml中的server.port。2. 命令行执行 netstat -ano | findstr :8080找到进程并结束。 |
| 数据库连接失败 | 1. MySQL服务未启动。 2. 用户名密码错误。 3. 时区或编码配置错误。 | 1. 检查MySQL服务状态。 2. 核对 application.yml中的连接字符串。3. 连接字符串加上 &serverTimezone=Asia/Shanghai。 |
| 前端访问后端API跨域(CORS)错误 | 浏览器安全策略阻止不同源(端口、域名)的请求。 | 在后端Spring Boot中添加全局CORS配置:@Beanpublic WebMvcConfigurer corsConfigurer() { ... } |
| 页面显示正常,但操作后数据不更新 | 1. 前端API请求地址错误。 2. 后端接口返回了错误但前端未处理。 3. 数据库操作失败但被吞异常。 | 1. 打开浏览器开发者工具(F12),查看Network标签页的请求和响应。2. 查看后端控制台日志。 |
| 论文查重率过高 | 1. 代码截图过多且未处理。 2. 需求分析、设计等章节直接复制了网络资料。 | 1. 代码部分只放核心片段,或转为伪代码/流程图描述。 2. 所有文字部分必须自己重新组织语言描述。 3. 使用学校指定的查重系统(如知网)提前自查。 |
4.3 项目部署(以Linux服务器为例)
- 后端打包:在Spring Boot项目根目录执行
mvn clean package -DskipTests,在target目录生成*.jar文件。 - 前端构建:在Vue项目根目录执行
npm run build,生成dist静态文件目录。 - 服务器准备:确保服务器有Java运行环境(JRE)、Nginx(用于托管前端和反向代理后端)。
- 部署后端:将jar包上传至服务器,使用
nohup java -jar your-app.jar --spring.profiles.active=prod > app.log 2>&1 &后台运行。 - 部署前端:将
dist目录内容上传至Nginx的HTML目录(如/usr/share/nginx/html)。 - 配置Nginx:编辑Nginx配置,将API请求反向代理到后端Java应用。
server { listen 80; server_name your-domain.com; # 或服务器IP location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } location /api/ { proxy_pass http://localhost:8080/; # 转发到后端 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
4.4 论文整合与答辩准备要点
- 结构清晰:摘要、绪论、需求分析、系统设计(总体设计、数据库设计)、系统实现(核心模块截图+关键代码说明)、系统测试、总结与展望。
- 图文并茂:使用流程图(系统架构图、业务流程图)、ER图、类图、时序图等UML图,以及系统界面截图。
- 代码说明:不要大段贴代码。选择最核心的1-2个类或方法,说明其设计思路和关键逻辑。
- 测试章节:设计测试用例表(功能、性能、界面),并附上测试结果截图。
- 答辩演示:
- 准备一个干净的、数据充实的演示环境。
- 演练核心功能流程:登录 -> 添加记录 -> 查询统计 -> 图表展示。
- 准备好应对老师的技术提问:为什么选这个技术?数据库表为什么这样设计?如何保证安全?如果用户量大了怎么优化?
5. 扩展方向与最佳实践
完成基础功能后,可以从以下方向提升项目深度,这在答辩时是重要的加分项。
5.1 功能扩展建议
- 数据可视化:集成ECharts,实现月度支出趋势图、分类占比饼图。
- 预算管理:为每个分类设置月度预算,超支时提醒。
- 多账本支持:允许用户创建多个账本(如个人账本、家庭账本)。
- 数据导入导出:支持从Excel/CSV导入历史数据,导出报表为PDF。
- 数据备份与恢复:提供数据库备份文件下载和恢复功能。
- 移动端适配:使用响应式设计或开发微信小程序版本。
5.2 工程最佳实践
- 配置分离:将数据库密码等敏感信息从代码中移除,使用
application-prod.yml并通过环境变量注入。 - 统一异常处理:使用
@ControllerAdvice和@ExceptionHandler捕获全局异常,返回友好的JSON错误信息。 - 接口文档:使用Swagger或Knife4j自动生成API文档,便于前后端联调和答辩展示。
- 单元测试:为Service层关键方法编写JUnit单元测试,体现测试意识。
- 日志记录:使用SLF4J + Logback,合理设置日志级别,记录操作日志和错误日志。
- 代码风格:遵循阿里巴巴Java开发规范等,保持代码整洁。
通过以上步骤,你不仅完成了一个“个人记账系统”的毕业设计,更实践了一个完整Web应用的开发流程。记住,毕业设计的核心价值在于展示你系统化解决问题的能力,而不仅仅是编码能力。从明确需求、技术选型、环境搭建、编码实现、调试排错到文档撰写,每一步的思考和决策过程,都是你向评委展示自己专业素养的机会。
🚀 30+款热门AI模型一站整合,DeepSeek/GLM/Qwen 随心用,限时 5 折。 👉 点击领海量免费额度