简介:本资源是一套完整的个人理财管理系统毕业设计实现方案,面向计算机专业本科生及Java全栈初学者,解决日常收支记录、账单分析与可视化展示等实际财务管理需求。系统采用前后端分离架构,后端基于SpringBoot构建RESTful接口,前端使用Vue实现响应式交互,数据持久化依托MySQL数据库,技术栈覆盖企业级开发主流组合。压缩包共75个文件,包含20个Java后端逻辑类、15个JavaScript工具与API调用脚本、12个Vue组件页面、10张界面截图(PNG/JPG)用于效果参考,以及pom.xml、application.properties、package.json等核心配置文件,整体大小仅2.98MB,结构清晰、开箱即用。已有106人下载学习,配套提供系统说明文档、管理员功能清单(含登录注册、账单增删导出、消费对比与统计分析)及完整可运行源码,便于快速部署、二次开发或课程设计参考。
1. 项目概述:一个全栈个人理财管理系统的诞生
最近在整理自己的技术项目库,翻出了几年前做的一个个人理财管理系统,当时是为了解决自己“钱花哪儿了”的痛点,用Java+SpringBoot+Vue这套经典技术栈完整撸了一遍。没想到这个项目后来成了我面试、带新人、技术分享的“常客”,也收到了不少朋友的反馈和优化建议。今天,我就把这个项目的核心设计思路、技术实现细节以及那些“踩坑”后总结的经验,系统地梳理出来。无论你是想学习全栈开发、寻找一个完整的毕业设计/课程设计项目,还是想自己动手搭建一个实用的个人财务工具,这篇文章都能给你提供一份可以直接“抄作业”的详细指南。
这个系统本质上是一个单用户、轻量级的个人财务数据中心。它的核心目标不是像专业财务软件那样处理复杂的会计准则,而是帮助普通用户(尤其是程序员和技术爱好者)清晰地记录每一笔收支,并通过可视化的图表,直观地了解自己的消费习惯、资产构成和财务趋势。整个项目从前端到后端再到数据库,麻雀虽小五脏俱全,涵盖了用户认证、数据增删改查、报表生成、文件导出等常见业务场景,非常适合用来练手和深入理解Web应用的全链路开发。
2. 系统核心需求与功能模块拆解
在动手写代码之前,明确需求是关键。个人理财管理,听起来简单,但细想起来功能点不少。我把它拆解成了几个核心模块,每个模块都对应着用户的一个具体使用场景。
2.1 用户核心诉求分析
首先,我们得站在用户的角度想问题。一个为自己或家庭服务的理财系统,用户最需要什么?
- 便捷的记录:随时随地(主要是电脑前)能快速记下一笔开销或收入,操作不能太繁琐。
- 清晰的分类:吃饭、交通、购物、工资、理财收益……钱必须分门别类,后续分析才有意义。
- 多维度的统计:不能只看总数。我需要知道“这个月在餐饮上花了多少?”、“今年和去年同期的支出对比如何?”、“我的钱主要流向了哪几个类别?”
- 直观的可视化:数字是冰冷的,图表是鲜活的。饼图看消费比例,折线图看趋势变化,柱状图做对比,一目了然。
- 数据的安全与可携带性:数据是自己的心血,不能丢。最好能支持导出(比如Excel),方便备份或二次分析。
基于这些诉求,我设计了下面几个功能模块。
2.2 后台管理功能模块设计
后台(SpringBoot)主要负责数据处理、业务逻辑和API提供。我将其划分为以下几个核心领域:
用户与认证模块:这是系统的守门人。虽然是个单用户系统,但良好的认证架构是基础。我实现了基于JWT(JSON Web Token)的登录认证。用户输入用户名密码,后端验证成功后,生成一个加密的Token返回给前端。前端后续的每次请求都在HTTP头中携带这个Token,后端过滤器进行校验。这样做的好处是无状态,适合前后端分离架构。这里的一个实操心得是:Token的过期时间不宜设置过长(如24小时),以增加安全性;同时,在用户操作时(如每次请求成功)可以动态刷新Token有效期,提升用户体验。
账目核心管理模块:这是系统的“心脏”。核心实体是Transaction(交易记录),每条记录包含:金额、类型(收入/支出)、分类(餐饮、交通等)、账户(微信、支付宝、现金等)、时间、备注。这里的设计关键点在于分类和账户的灵活性与可维护性。我没有把分类写死在代码里,而是做成了可配置的数据字典表。这样用户未来可以自己添加“宠物”、“学习”等个性化分类,而无需修改代码。
数据统计与分析模块:这是系统的“大脑”。它提供各种维度的聚合查询API。例如:
GET /api/analysis/monthly?year=2023:获取2023年每个月的收支总览。GET /api/analysis/category?startDate=xxx&endDate=xxx:获取指定时间段内各分类的支出占比。GET /api/analysis/trend?categoryId=1&period=month:获取某个分类下,按月的消费趋势。
这些API的响应数据格式,都经过精心设计,以便前端ECharts等图表库能直接使用。一个重要的细节:统计查询往往涉及数据库的聚合函数(SUM, GROUP BY)和日期处理,要特别注意SQL性能,尤其是数据量积累后。对transaction_time字段建立索引是必须的。
系统工具模块:包括数据导出功能(将交易记录导出为Excel或CSV),以及系统初始化(首次使用时,自动创建默认的分类和账户数据)。导出功能使用了Apache POI库来生成Excel文件,这里要注意处理中文文件名和单元格格式,避免乱码。
2.3 前端交互与可视化模块设计
前端(Vue)负责呈现和交互,目标是清爽、易用、响应快。
页面路由与布局:采用Vue Router管理路由,整体是一个单页面应用(SPA)。布局上分为:顶部导航栏、左侧菜单栏、主内容区。菜单包括“仪表盘”、“账目管理”、“分类管理”、“统计报表”、“数据导出”等。
账目CRUD界面:这是最常用的页面。采用表格展示记录,支持按时间、分类、类型筛选。添加/编辑表单使用弹窗(Dialog)组件,表单验证使用async-validator或Vue自带的校验规则,确保金额为数字、时间为合法日期等。
仪表盘与可视化:这是系统的“门面”。使用ECharts库绘制图表。
- 概览卡片:显示本月总收入、总支出、结余等关键数字。
- 消费分类饼图:直观展示钱花在了哪里。
- 月度收支趋势折线图:展示近半年或一年的收支变化曲线。
- 账户余额柱状图:展示各支付账户当前的余额情况(需手动或通过导入维护初始余额)。
一个提升体验的技巧:图表数据在页面加载时异步请求。为了应对可能的加载延迟,可以给图表容器添加一个骨架屏(Skeleton)效果,提升感知速度。同时,为图表添加“刷新”按钮和“时间范围选择器”,让用户能主动控制查看的数据区间。
3. 技术栈选型与架构设计解析
为什么选Java+SpringBoot+Vue?这不是盲目跟风,而是基于项目特性和技术生态的综合考量。
3.1 后端技术栈:SpringBoot的敏捷之道
- Java 8/11:稳定、生态成熟、人才基数大。虽然内存占用比一些新语言高,但对于个人项目和小型系统,其稳定性和丰富的库支持是首要优势。
- SpringBoot 2.x:它极大地简化了Spring应用的初始搭建和开发过程。“约定大于配置”的理念,让我能快速集成Web、安全、数据访问等组件。通过
spring-boot-starter-web,spring-boot-starter-security,spring-boot-starter-data-jpa等几个依赖,核心框架就搭好了。 - Spring Data JPA (Hibernate):作为ORM框架,它让我能用对象操作数据库,无需写繁琐的SQL。定义好
Transaction、Category等实体类,配置好关系(如@ManyToOne),基础的增删改查方法几乎不用写。对于复杂的统计查询,则可以灵活使用@Query注解编写JPQL或原生SQL。注意:JPA在处理复杂联表查询时,需要注意N+1问题,可以通过@EntityGraph或手动编写JOIN FETCH的JPQL来优化。 - MySQL:最流行的开源关系型数据库,足以支撑个人应用的数据存储。表结构设计清晰,建立适当的索引(如交易时间、用户ID),性能完全不是问题。
- JWT (jjwt库):用于实现无状态认证,轻量且安全。
- Lombok:开发神器,通过
@Data、@Getter、@Setter等注解减少大量样板代码,让实体类和DTO类非常简洁。 - Apache POI:处理Excel导出的标准Java库。
后端项目结构通常如下:
src/main/java/com/yourname/finance/ ├── config/ // 配置类(安全、Web、Swagger等) ├── controller/ // REST API控制器 ├── dto/ // 数据传输对象(请求/响应) ├── entity/ // JPA实体类 ├── repository/ // 数据访问层(JPA Repository接口) ├── service/ // 业务逻辑层接口 ├── service/impl/ // 业务逻辑层实现 └── utils/ // 工具类(JWT、Excel导出等)3.2 前端技术栈:Vue的渐进式体验
- Vue 2.x / 3.x:我最初用的是Vue 2,其响应式系统和组件化开发模式,对于构建这种交互复杂的中后台管理界面非常高效。如果现在新做,我会选择Vue 3 + Composition API,逻辑组织更灵活。Vue的学习曲线相对平缓,文档完善,是快速上手的绝佳选择。
- Element UI / Ant Design Vue:这是UI组件库。我选用的是Element UI,因为它与Vue生态集成好,组件丰富(Table, Form, Dialog, DatePicker等),风格简洁,能极大提升开发效率。不用从零开始写样式和交互。
- Vue Router:管理前端路由,实现SPA的无刷新页面切换。
- Vuex (Pinia):状态管理库。用于集中管理用户登录状态、全局的账目分类数据等。Vue 2时代用Vuex,Vue 3推荐使用更简洁的Pinia。
- Axios:Promise-based的HTTP客户端,用于向后端发起API请求。可以统一配置请求拦截器(自动添加Token)和响应拦截器(处理通用错误)。
- ECharts:百度出品的强大图表库,文档和示例非常丰富,能够轻松实现各种复杂的统计图表。
前端项目结构通常如下:
src/ ├── api/ // 所有后端API的封装函数 ├── assets/ // 静态资源(图片、样式) ├── components/ // 可复用组件(如Chart.vue, FilterBar.vue) ├── router/ // 路由配置 ├── store/ // Vuex/Pinia状态管理 ├── utils/ // 工具函数(日期格式化、金额格式化等) ├── views/ // 页面级组件(Dashboard.vue, Transaction.vue) └── App.vue & main.js3.3 前后端分离与API设计规范
项目采用经典的前后端分离架构。前端独立部署,通过HTTP API与后端通信。这种架构职责清晰,便于并行开发和独立部署。
API设计遵循RESTful风格,力求直观:
GET /api/transactions:获取交易列表(可分页、过滤)POST /api/transactions:创建一笔交易PUT /api/transactions/{id}:更新指定交易DELETE /api/transactions/{id}:删除指定交易GET /api/analysis/category:获取分类统计
所有API返回统一格式的JSON响应体,便于前端处理:
{ "code": 200, // 业务状态码,200成功,400客户端错误,500服务器错误等 "message": "操作成功", // 提示信息 "data": {} // 成功时的响应数据 }这种封装能让前端在axios拦截器中统一处理非200状态码的请求,弹出错误提示。
4. 核心功能实现与关键代码剖析
理论说再多,不如看代码。我们来深入几个核心功能的实现细节。
4.1 后端:JPA实体关系映射与业务逻辑
首先看核心的Transaction实体类(使用了Lombok):
@Entity @Table(name = "t_transaction") @Data public class Transaction { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private BigDecimal amount; // 金额,使用BigDecimal避免精度丢失 private Integer type; // 类型:1-收入, 2-支出 private String remark; // 备注 private LocalDateTime transactionTime; // 交易时间 @ManyToOne @JoinColumn(name = "category_id") private Category category; // 关联分类 @ManyToOne @JoinColumn(name = "account_id") private Account account; // 关联账户 // 关联用户(如果是多用户系统) // @ManyToOne // private User user; }关键点:@ManyToOne定义了多笔交易属于一个分类/账户。JPA会自动管理外键。BigDecimal是处理金融金额的唯一正确选择,float和double会存在精度损失问题。
业务逻辑层TransactionService中的一个统计方法示例:
@Service public class TransactionServiceImpl implements TransactionService { @Autowired private TransactionRepository transactionRepository; @Override public Map<String, Object> getMonthlySummary(Integer year) { if (year == null) { year = LocalDate.now().getYear(); // 默认当前年 } // 使用JPQL进行分组统计,计算每月收支 List<Object[]> monthlyData = transactionRepository.findMonthlySummaryByYear(year); List<String> months = new ArrayList<>(); List<BigDecimal> incomeList = new ArrayList<>(); List<BigDecimal> expenseList = new ArrayList<>(); for (Object[] row : monthlyData) { months.add(row[0].toString() + "月"); // 月份 incomeList.add((BigDecimal) row[1]); // 收入 expenseList.add((BigDecimal) row[2]); // 支出 } Map<String, Object> result = new HashMap<>(); result.put("months", months); result.put("income", incomeList); result.put("expense", expenseList); return result; // 这个Map结构非常适合前端ECharts绘制折线图 } }对应的Repository接口中定义了查询方法:
@Repository public interface TransactionRepository extends JpaRepository<Transaction, Long> { @Query("SELECT MONTH(t.transactionTime) as month, " + "SUM(CASE WHEN t.type = 1 THEN t.amount ELSE 0 END) as income, " + "SUM(CASE WHEN t.type = 2 THEN t.amount ELSE 0 END) as expense " + "FROM Transaction t " + "WHERE YEAR(t.transactionTime) = :year " + "GROUP BY MONTH(t.transactionTime) " + "ORDER BY month") List<Object[]> findMonthlySummaryByYear(@Param("year") Integer year); }这里有个坑:JPQL中的CASE WHEN语句和聚合函数SUM的结合使用,是实现按条件聚合的关键。确保数据库中的transaction_time字段有索引,否则全年数据分组计算可能会慢。
4.2 前端:Vue组件与ECharts集成
以仪表盘页面的月度趋势图组件MonthlyTrendChart.vue为例:
<template> <div ref="chartRef" style="width: 100%; height: 400px;"></div> </template> <script> import * as echarts from 'echarts'; import { getMonthlySummary } from '@/api/analysis'; // 导入API函数 export default { name: 'MonthlyTrendChart', data() { return { chartInstance: null, year: new Date().getFullYear() // 默认当前年 }; }, mounted() { this.initChart(); this.fetchData(); }, beforeDestroy() { // 组件销毁时,销毁图表实例,防止内存泄漏 if (this.chartInstance) { echarts.dispose(this.chartInstance); } }, methods: { initChart() { // 基于DOM元素初始化ECharts实例 this.chartInstance = echarts.init(this.$refs.chartRef); // 可以先设置一个基础的、带加载动画的配置 this.chartInstance.setOption({ title: { text: '月度收支趋势', left: 'center' }, tooltip: { trigger: 'axis' }, legend: { data: ['收入', '支出'], top: '30' }, grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true }, xAxis: { type: 'category', data: [] }, // 数据从后端获取后更新 yAxis: { type: 'value' }, series: [ { name: '收入', type: 'line', smooth: true, data: [] }, { name: '支出', type: 'line', smooth: true, data: [] } ] }); }, async fetchData() { try { const response = await getMonthlySummary(this.year); // 调用API const { months, income, expense } = response.data; // 动态更新图表配置 this.chartInstance.setOption({ xAxis: { data: months }, series: [ { data: income }, { data: expense } ] }); } catch (error) { console.error('获取月度数据失败:', error); this.$message.error('图表数据加载失败'); } } } }; </script>关键点:
- 生命周期管理:在
mounted中初始化图表,在beforeDestroy中销毁,这是防止内存泄漏的最佳实践。 - 异步数据加载:使用
async/await处理API请求,使代码更清晰。 - 图表实例复用:初始化一次
chartInstance,后续通过setOption更新数据,而不是重新初始化,性能更好。 - 错误处理:对API请求进行
try...catch,并给用户友好的提示。
4.3 安全与认证:JWT的实践
在Spring Security配置中,我们需要放行登录接口,并配置一个JWT过滤器来处理其他请求。
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationFilter jwtAuthenticationFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() // 禁用CSRF,因为使用JWT无状态 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话 .and() .authorizeRequests() .antMatchers("/api/auth/login").permitAll() // 登录接口放行 .antMatchers("/api/**").authenticated() // 其他API需要认证 .anyRequest().permitAll() // 其他请求(如下载导出文件)可酌情放行 .and() .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); // 添加JWT过滤器 } // 密码编码器 @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }JwtAuthenticationFilter会从请求头Authorization中提取Token,进行解析和验证,如果有效则将用户信息设置到Spring Security的上下文中,供后续业务使用。
一个重要的安全细节:用户密码在存入数据库前,必须使用BCryptPasswordEncoder进行哈希加密,绝对不要明文存储。
5. 数据库设计与优化要点
数据库是系统的基石,设计好坏直接影响性能和扩展性。
5.1 核心表结构设计
主要包含以下几张表:
t_user: 用户表(id, username, password(加密), email等)t_category: 分类表(id, name, type(收入/支出), icon, sort_order)t_account: 账户表(id, name, type(现金/银行卡/支付宝等), balance, remark)t_transaction: 交易记录表(id, amount, type, category_id, account_id, transaction_time, remark, create_time)- (可选)
t_budget: 预算表(id, category_id, amount, month, year)
建表SQL示例(MySQL):
CREATE TABLE `t_transaction` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `amount` decimal(15,2) NOT NULL COMMENT '金额', `type` tinyint(4) NOT NULL COMMENT '1收入 2支出', `remark` varchar(500) DEFAULT '' COMMENT '备注', `transaction_time` datetime NOT NULL COMMENT '交易时间', `category_id` bigint(20) NOT NULL COMMENT '分类ID', `account_id` bigint(20) NOT NULL COMMENT '账户ID', `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), KEY `idx_transaction_time` (`transaction_time`), -- 对交易时间建索引 KEY `idx_category_id` (`category_id`), KEY `idx_account_id` (`account_id`), CONSTRAINT `fk_transaction_category` FOREIGN KEY (`category_id`) REFERENCES `t_category` (`id`), CONSTRAINT `fk_transaction_account` FOREIGN KEY (`account_id`) REFERENCES `t_account` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='交易记录表';5.2 性能与数据一致性考量
- 索引策略:如上所示,在
transaction_time,category_id,account_id上建立索引,能极大加速按时间查询、按分类/账户筛选以及统计分组查询的速度。 - 金额字段:使用
DECIMAL(15,2)类型,15位精度,小数点后2位,足够存储个人财务金额并保证精确计算。 - 外键约束:虽然有些项目为了“灵活”会去掉外键,但我建议在个人项目中保留。它能保证数据的参照完整性,避免产生“幽灵”记录(分类被删了,交易记录还指向它)。对于小型应用,外键的性能开销可以接受。
- 软删除考虑:业务上,用户可能误删记录。一种常见的做法是添加一个
is_deleted字段(默认为0),执行删除时只是更新这个标志位为1。这样数据可以恢复。但需要注意的是,所有查询语句都需要加上WHERE is_deleted = 0的条件。这是一个典型的空间换时间与安全的权衡。
6. 开发、部署与运维实战
6.1 本地开发环境搭建
- 后端:安装JDK 8+,Maven,MySQL。导入项目后,修改
application.yml中的数据库连接信息。直接运行主类的main方法即可启动SpringBoot应用。 - 前端:安装Node.js和npm。进入前端目录,运行
npm install安装依赖,然后运行npm run serve启动开发服务器。前端默认会代理API请求到后端地址(在vue.config.js中配置),解决跨域问题。 - 数据库初始化:项目应包含一个
schema.sql和data.sql。首次启动时,可以配置SpringBoot自动建表并插入初始数据(如默认的分类和账户)。注意:生产环境不要用update模式,应该使用规范的迁移工具(如Flyway或Liquibase)。
6.2 项目构建与打包
- 后端:在项目根目录执行
mvn clean package,会在target目录生成一个可执行的*.jar文件。这个jar包包含了所有依赖,可以直接用java -jar your-app.jar运行。 - 前端:执行
npm run build,会在dist目录生成静态资源文件(HTML, JS, CSS)。这些文件需要被部署到一个HTTP服务器上(如Nginx)。
6.3 生产环境部署(以Linux服务器为例)
- 服务器准备:购买一台云服务器,安装好JDK、MySQL、Nginx。
- 部署后端:
- 将打包好的
jar文件上传到服务器。 - 可以使用
systemd创建一个服务来管理SpringBoot应用,实现开机自启和状态监控。 - 创建服务文件
/etc/systemd/system/finance-api.service:[Unit] Description=Personal Finance Management API After=network.target [Service] User=your_user ExecStart=/usr/bin/java -jar /path/to/your/finance-api.jar SuccessExitStatus=143 Restart=always RestartSec=10 [Install] WantedBy=multi-user.target - 然后执行
sudo systemctl daemon-reload,sudo systemctl start finance-api,sudo systemctl enable finance-api。
- 将打包好的
- 部署前端:
- 将
dist文件夹内的所有文件上传到服务器,例如放到/var/www/finance/目录下。 - 配置Nginx,将请求代理到前端静态资源或后端API。
server { listen 80; server_name your_domain.com; # 你的域名或IP # 前端静态资源 location / { root /var/www/finance; index index.html; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } # 反向代理到后端API location /api/ { proxy_pass http://localhost:8080; # 后端SpringBoot应用地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } - 重启Nginx:
sudo systemctl restart nginx。
- 将
6.4 常见问题与排查技巧实录
在开发和部署过程中,你几乎一定会遇到下面这些问题:
问题1:前端页面能打开,但所有API请求都报404或跨域错误。
- 排查:打开浏览器开发者工具的“网络(Network)”标签,查看请求的URL是否正确,响应状态码是什么。
- 解决:
- 开发环境:确认
vue.config.js中的proxy配置正确指向了后端地址和端口。 - 生产环境:确认Nginx配置中
location /api/的proxy_pass指向了正确的后端服务地址和端口(确保后端服务已启动)。跨域问题通常由Nginx反向代理解决,如果仍有问题,检查SpringBoot后端是否配置了CORS(在生产环境中,更推荐用Nginx解决)。
- 开发环境:确认
问题2:图表显示“暂无数据”或数据不对。
- 排查:首先检查浏览器控制台是否有JS错误。然后查看API请求是否成功返回了数据,数据格式是否符合ECharts的要求。
- 解决:在
fetchData方法中打印或调试response.data,确保其结构(如months,income)与setOption中期望的结构一致。日期格式不匹配是常见问题,确保后端返回的月份数据是前端能识别的字符串或数字。
问题3:数据库查询速度慢,特别是统计报表。
- 排查:使用MySQL的
EXPLAIN命令分析慢查询SQL。检查是否在transaction_time等常用查询字段上建立了索引。 - 解决:为
transaction_time,category_id,user_id等字段添加复合索引。对于非常复杂的历史全量统计,可以考虑在业务低峰期预计算一些汇总数据,存入缓存(如Redis)或单独的统计表。
问题4:上传到服务器后,前端页面样式错乱或JS加载失败。
- 排查:检查Nginx配置的
root目录是否正确,文件权限是否足够(通常nginx用户需要有读取权限)。检查浏览器控制台是否有资源加载失败的404错误。 - 解决:确保
npm run build命令执行成功,dist目录内容完整。使用chmod或chown命令调整/var/www/finance目录的权限。有时需要配置Nginx的mime.types来正确识别文件类型,不过通常默认配置即可。
问题5:SpringBoot应用启动失败,端口被占用或数据库连接不上。
- 排查:查看SpringBoot启动日志。使用
netstat -tlnp | grep :8080查看端口占用情况。检查application.yml中的数据库IP、端口、用户名、密码是否正确,以及MySQL是否允许远程连接(生产环境建议只监听本地127.0.0.1,通过Nginx代理)。 - 解决:杀死占用端口的进程,或修改SpringBoot的
server.port配置。确保数据库服务已启动,且防火墙规则允许访问。
这个项目从构思到上线,是一个完整的全栈开发闭环。它涉及的需求分析、技术选型、编码实现、调试部署,正是现代Web开发的典型流程。过程中遇到的每一个报错、每一个性能瓶颈,都是宝贵的学习经验。当你亲手让这个系统跑起来,并开始记录自己的第一笔收支时,那种成就感是无可替代的。希望这份超详细的拆解,能帮你少走弯路,更快地构建出属于自己的数字产品。
本文还有配套的精品资源,点击获取