☰
Spring Boot + React前后端分离家庭理财系统:部署与避坑全指南
2026/10/9 3:09:33 网站建设 项目流程

简介:一套基于前后端分离架构的Java家庭理财系统完整源码包,面向具备Java基础、希望学习Spring Boot与Spring Cloud微服务项目的开发者,以及需要快速搭建个人财务记录与分析场景的实践者。系统覆盖支出与收入统计、类型图表分析、股市与基金走势追踪、已买股票及基金管理、外债记录、固定资产与房贷车贷核算,以及月末和年末报表等家庭理财核心模块。包内共246个文件,主要包含57个java后端业务类、66个js与58个jsx前端页面组件、18个xml配置、12个less样式、9个yml服务配置,以及sql数据库脚本等,压缩包仅4.48MB,结构紧凑、层次清晰。当前已有537人学习下载,适合通过阅读源码掌握多模块业务落地、前后端数据交互、微服务环境搭建与报表展示等实用技能。

1. 这套 Java 家庭理财系统:Spring Boot + React 前后端分离到底值不值得下

如果你搜到这个资源,多半正在做 Java 课程设计,或者想找个前后端分离的真实项目练手。这套家庭理财系统源码不是那种只有几个页面的玩具 demo,它把支出、收入、股票、基金、外债、固定资产、月末年末报表全串在了一条业务链上,后端用 Spring Boot 2.0.7 + SpringCloud Finchley.SR2,前端用 React 16 + Ant Design Pro 4.0,Redis 做缓存、RabbitMQ 走消息,数据库用 MySQL 5.7。换句话说,这是一个「麻雀虽小但五脏俱全」的企业级骨架,你改一改就能直接当课设答辩项目,或者作为 Spring Boot 微服务入门的学习蓝本。本文不打算念 PPT,我会直接把这个项目从技术选型、本地启动、模块拆解到常见报错,一条条掰开讲清楚,照着做就能跑起来。

2. 技术栈和项目架构:为什么这套系统要用前后端分离加微服务

2.1 前后端分离结构怎么理解

这套项目不是把 Java 页面塞进 JSP 里,而是完全的前后端分离。后端只提供 RESTful API,前端是一个独立的 React 工程。两者通过 JSON 交互,所以你在源码里会看到一个后端模块和一个前端工程目录,需要分别启动。

为什么要这么设计?先看业务场景。家庭理财涉及收支流水、图表统计、股票基金行情同步,还有月末年末报表。如果做成单体 JSP,页面渲染、数据计算、报表聚合全部耦合在一起,改一个饼图样式可能要把整个 tomcat 重启一遍。前后端分离后,前端只管渲染 Echarts 图表,后端只处理数据和业务逻辑,联调时只要接口约定好,两端可以并行开发。这也是为什么这套系统后端自带 Swagger 风格的接口文档配置,前端有独立的 mock 数据目录。

2.2 版本选型为什么是这些数字

这套系统的版本号很有讲究,值得先看懂再动手。Spring Boot 用的是 2.0.7,SpringCloud 是 Finchley.SR2,这两个版本是官方测试过的稳定搭配。如果你的机器上装了更高版本的 JDK,这里就是一个大坑——JDK 11 以上跑 Spring Boot 2.0.7 经常出现反射相关的兼容性问题,后面我会详细说。数据库用 MySQL 5.7.30,Redis 6.0.8,这两个都是当时主流的生产版本。RabbitMQ 3.4 负责异步消息,主要是通知类场景。

有人可能会问,现在都 Spring Boot 3 了,为什么还要用 2.0.7?答案很简单:这套源码是课程设计型的完整工程,它选的不是最新,而是最稳。3.x 的配置项好多都改了,比如spring.fastdfs.nginx.host这类自定义配置在 2.x 里是常见写法,拿到 3.x 上跑反而会大量报错。所以如果你只是要一个能跑能答辩的项目,请严格按它的原版 JDK 1.8 + MySQL 5.7 + Redis 6 来搭环境。

2.3 目录结构里藏着哪些模块

下载源码后,你看到的不是一个扁平目录,而是几个层次分明的工程。后端工程里按职责做了分包,常见结构是 controller、service、mapper、entity 四层。业务上分为用户管理、支出管理、收入管理、股票基金、外债、固定资产、报表几大块,其中 UserIncomeServiceImpl.java、UserExpensesServiceImpl.java、UserExpensesController.java 这几个文件是核心入口——支出和收入是系统的地基,其他模块都建立在它们之上。

前端工程基于 Ant Design Pro 4.0 搭建,页面结构按业务划分,比如支出页面、收入页面、股市页面、基金页面、报表页面。这种分包方式的好处是,你想改哪块业务,从前端页面到后端接口是一条直线,不用满工程翻代码。你就把后端当成一个大工厂,每个 controller 是一个车间,service 是车间里的具体工序,mapper 是仓库管理员——数据进出全靠它。

我刚拿到这套源码的时候,最先做的事不是执行任何代码,而是把后端 application.yml 从头到尾读了一遍。里面写了端口、数据库连接池、Redis 地址、RabbitMQ 地址、还有静态资源映射路径。这一步不能省,因为很多启动失败的问题,根源都在这个配置文件里。

3. 把项目跑起来:本地部署步骤与参数调优

3.1 环境准备清单

开始部署之前,先把环境检查一遍。这套系统依赖的东西比较多,如果漏装任何一个,启动时都会报莫名其妙的错。下面是我建议的安装清单和版本匹配,直接对着来。

依赖组件推荐版本用途
JDK1.8.0_251运行后端 Spring Boot,其他版本会踩兼容性坑
Maven3.6.3构建后端工程、管理依赖
MySQL5.7.30持久化业务数据
Redis6.0.8缓存用户会话、热点数据、排行榜
RabbitMQ3.4异步消息队列,用于通知类业务
Nginx1.14.2静态页面代理、反向代理后端接口
Node.js8.x 或 10.x构建 React 前端工程

提示:Node 版本千万别装最新的 18 或 20,Ant Design Pro 4.0 构建时对 Node 版本有隐性要求,太高会直接构建失败。这个坑我后面排查章节细说。

3.2 后端启动步骤与参数说明

后端启动的第一个关键操作是导入数据库脚本。在源码的 sql 目录下找到建库建表脚本,用 MySQL 命令行或者 Navicat 执行。然后修改后端工程里的 application.yml,核心配置如下。

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/family_finance?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver redis: host: localhost port: 6379 database: 0 rabbitmq: host: localhost port: 5672 username: guest password: guest

这段配置里有几个容易踩的雷区。useSSL=false建议保留,如果改成 true,而本机 MySQL 没配 SSL 证书,连接会直接失败。serverTimezone=Asia/Shanghai必须带上,否则日期字段查询结果会比实际时间少 8 小时,做月末报表的时候数据永远对不上。RabbitMQ 的 guest 账号默认只能在 localhost 登录,不要自作主张改成远程 IP。

配置文件改好后,在 maven 窗口先执行clean,再执行install,跳过测试用例,命令是mvn clean install -DskipTests。这一步会把所有依赖 jar 包装进本地仓库。如果网络不好,第一次构建可能耗时很久,这是正常现象,不需要焦虑。构建成功后再启动 Spring Boot 的 main 方法,或者用mvn spring-boot:run。启动完成后,观察控制台。

Tomcat started on port(s): 8080 (http) with context path '' Started FamilyFinanceApplication in 12.345 seconds

看到这行日志,说明后端就绪了。但这一步不是终点,还要做一个验证。打开浏览器,访问http://localhost:8080/actuator/health。如果返回{"status":"UP"},证明 Spring Boot 和数据库连接、Redis 连接都正常。如果 status 是 DOWN,按下面的启动排查清单检查。

检查项正常标志常见的错误标志
MySQL 服务3306 端口可连接Communications link failure
Redis 服务6379 端口可连接,redis-cli ping返回 PONGUnable to connect to Redis
RabbitMQ5672 端口可连接Connection refused
数据库脚本表存在且数据可查询Table doesn't exist

补充一个我实际遇到过的问题。数据库脚本成功执行后,访问登录接口仍然报 401。后来发现是脚本里密码字段的加密方式与后端代码的加密方式不一致——建表脚本用的明文,而后端登录校验用的是 MD5 加盐密文。遇到这种情况,别急着改代码,先到数据库里看种子数据的密码是不是已经被加密过。一般课设项目的 sql 脚本里都会自带一条管理员账号,比如 admin / admin123,但密码字段可能是一串 32 位 MD5 值。如果你发现是明文,就找后端里密码校验的工具类,把管理员密码生成一份密文再 update 进去,这是最稳妥的做法。

3.3 前端启动步骤与参数说明

后端跑通之后,进入前端工程目录。安装依赖,构建并启动开发服务器。

npm config set registry https://registry.npm.taobao.org npm install npm start

第一条命令设置镜像源,国内网络下速度快很多;第二条安装全部 npm 依赖,Ant Design Pro 项目依赖数量比较多,八百到一千个包很正常,装几分钟才到 100% 都是常见情况;第三条启动开发服务器,默认端口是 8000。启动成功后控制台会显示Project is running at http://localhost:8000/。

前端启动后还需要确认一个代理配置。在config/config.ts或者.umirc.ts里找到 proxy 配置,确认前端请求的/api前缀能不能转发到后端 8080 端口。常见写法是这样:

proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, }, }

changeOrigin: true很关键。后端接口在鉴权时如果校验了请求头里的 Host,不加这个字段转发就会被后端判定为非法请求。很多新手前端页面能打开,但所有接口都返回跨域错误或 403,问题几乎都出在这个参数上。

前端启动后,浏览器访问http://localhost:8000,能看到登录页面就说明 web 层通了。然后输入管理员账号密码,如果登录成功跳转到首页,并且首页上的本日支出、本月收入、股市走势图等卡片都有数据,就说明整个链路——浏览器到前端、前端到后端、后端到数据库——全部打通了。

3.4 Nginx 部署方式

如果你只是本地开发,开发服务器就够了。但如果你想模拟真实部署,或者答辩时直接通过域名访问,那么可以用 Nginx 做静态托管和反向代理。把前端工程执行npm run build,产物在dist目录下。然后写一份 Nginx 配置。

server { listen 80; server_name localhost; root /usr/share/nginx/html/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

try_files这一行是前端路由的关键。React 项目用的是 history 路由,刷新某个子页面时 Nginx 会去磁盘找对应的路径,找不到就直接 404。加了try_files $uri $uri/ /index.html会让所有请求回退到首页,由前端路由接管。如果你部署后刷页面就白屏,一定先检查这一行有没有写。

4. 核心业务模块拆解:收支、股票基金、外债与报表怎么落地

4.1 支出与收入:系统的主干逻辑

这套系统的业务主脑是支出和收入,所有的图表分析、报表统计都派生自这两个模块。支出模块在 UserExpensesServiceImpl.java 里,它不只是简单的增删改查,还把支出数据按「本日、本月、本年」三个粒度做了聚合,同时生成支出类型分析图。

后端做了一个典型的 service 层聚合操作,大致逻辑如下。

public Map<String, Object> getExpenseSummary(String userId) { Map<String, Object> result = new HashMap<>(); // 本日支出:查当天0点到当前时间的数据 BigDecimal todayExpense = expensesMapper.sumByDateRange(userId, DateUtils.getTodayStart(), new Date()); // 本月支出:查本月1号到当前时间 BigDecimal monthExpense = expensesMapper.sumByDateRange(userId, DateUtils.getMonthStart(), new Date()); // 本年支出:查本年1月1号 BigDecimal yearExpense = expensesMapper.sumByDateRange(userId, DateUtils.getYearStart(), new Date()); result.put("today", todayExpense); result.put("month", monthExpense); result.put("year", yearExpense); return result; }

这个代码看起来简单,但有三点值得注意。第一,三个统计都复用了同一个 sumByDateRange 方法,只是入参不同,这比写三个 SQL 要优雅得多,也给后续维护留了余地。第二,DateUtils 里求「今天开始」「本月开始」「本年开始」的方法,注意是用 Calendar 还是 LocalDate。JDK 1.8 环境里两种都能用,但Calendar.getInstance()在多线程环境下如果被静态共享,会出现日期错乱。第三,SQL 里对日期的比较用的是>=和< 第二天零点,而不是<=当天 23:59:59,避免秒级精度导致边界数据被漏掉。

收入模块 UserIncomeServiceImpl.java 走的也是类似逻辑,但聚合维度稍微少一些,只做了本月和本年统计。为什么收入不按「本日」统计?因为系统设计者的业务逻辑是:工资、理财收益等收入不是每天都有,按「日」统计没有实际意义。这是一个很真实的取舍,做课设时你在论文里能把这种设计思路写出来,答辩成绩会不一样。

4.2 股票和基金:行情数据怎么展示

股票模块和基金模块是这类系统里最抓眼球的部分。很多同学以为它是实时对接了股票 API,实际上课设项目大概率是从接口拉一次缓存下来,或者内置了模拟数据。你去看工程里的定时任务或初始化逻辑,会发现它的设计思路是每隔一段时间刷新一次行情数据,存入 Redis 或 MySQL,前端展示时直接读库。

已买股票、已买基金这两个子功能的增删改查是真实业务。用户的每一笔交易记录会有买入价格、数量、买入日期,系统根据最新行情计算浮动盈亏。这块的核心参数在交易表里,关键字段包括代码、名称、方向、价格、数量、手续费、时间戳。

这里我多说一句,很多课设代码里「计算当前市值」是写死的假数据,不是通过实时接口算的。如果你仔细读接口,发现它从后端返回的 currentPrice 是固定值,不要觉得被坑了——这是课设项目的普遍情况,因为对接实时行情接口需要申请 API key,且调用次数有限。答辩时你说清楚「当前是演示数据,预留了替换为真实行情的接口位」,老师反而会觉得你考虑周全。

4.3 外债和固定资产:容易被忽略但工作量大的模块

外债模块分借出和借入两本账,这个设计对家庭理财场景很实用。借出是别人欠你的钱,借入是你欠别人的钱,两个方向不能混在一起,否则月末报表里资产负债情况全乱。这个模块还涉及还款计划,还款日期到了需要提醒,Redis 在这里起了缓存作用,RabbitMQ 在这里扮演了生成通知的角色。

固定资产模块又分房贷车贷和全款两类,是设计和实现里最繁琐的部分。房贷车贷要维护贷款总额、已还期数、每期还款金额、剩余本金;全款资产要记录购买日期、购置价格、当前估值。月末报表会把这些资产汇总,算出家庭净资产趋势。这一类实体的数据模型通常更复杂,嵌套了好几层,写 mapper XML 的时候容易因为字段没映射全导致报表计算出 null。

4.4 报表:月末与年末的核心实现

这套系统的报表模块是整份源码的「权力中心」,它把前面所有业务模块的数据汇总起来。月末报表统计当月的支出、收入、结余,按支出类型算占比;年末报表在这基础上加上了全年的趋势比对、资产负债汇总。

报表逻辑常见的实现方式是用一个专门的 Service 类,调用多个 mapper 的方法取数,再在内存里做汇总。这种方式的好处是不需要写复杂 SQL,逻辑都在 Java 里可控,坏处是如果数据量大,内存开销会高,但对于家庭个人记账的场景绰绰有余。关键实现思路是先汇总支出明细,再汇总收入明细,再查固定资产和外债数据,把它们全部封装成一个报表 VO 对象返回前端。前端用 Echarts 渲染柱状图和饼图时,最需要的字段就是分类名、金额、占比,正好和这个 VO 对应。

5. 部署避坑指南:五个常见问题与排查方法

5.1 启动时报「No active profile set」和端口占用

现象:后端启动,控制台提示No active profile set, falling back to default profiles: default,紧接着报Port 8080 was already in use。

原因:存在两个问题。第一个是 application.yml 里没有配置 spring.profiles.active,系统只能走默认配置。第二个是 8080 端口被占用了,一般是之前残留的 Java 进程没退干净。

解决:端口被占用时,Linux/Mac 执行lsof -i:8080找到进程 PID 后 kill 掉,Windows 执行netstat -ano | findstr 8080找到 PID 后用任务管理器结束。profile 的问题不用太紧张,如果没有多环境配置需求,默认配置可以直接用,但建议在 yml 里加一行spring.profiles.active: dev让日志更清晰。

5.2 MySQL 连接报「Public Key Retrieval is not allowed」

现象:后端启动连数据库时,控制台报错Public Key Retrieval is not allowed。

原因:MySQL 5.7 及以上版本默认使用 caching_sha2_password 插件,JDBC 第一次连接需要获取 RSA 公钥,但连接串里没有授权允许。之前我遇到过一个人,明明其他项目都能连数据库,偏偏这个工程报错,他还以为数据库坏了。实际上是他直接复制的配置文件没改连接串,而原来的项目用的是 mysql_native_password 用户。

解决:在 jdbc 连接串最后加一个参数。

jdbc:mysql://localhost:3306/family_finance?useSSL=false&allowPublicKeyRetrieval=true

allowPublicKeyRetrieval=true明确允许 JDBC 从服务器获取公钥。如果加了还报错,就检查 MySQL 用户插件类型,执行ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的密码';。

5.3 前端 npm install 安装到一半卡死

现象:执行npm install后进度条长时间停在某一处,或者报错ETIMEDOUT。

原因:npm 默认源在国外,访问不稳定是常见问题,不是在下载超大文件。

解决:把 npm 源切到国内镜像,然后删除 node_modules 重新装。

npm config set registry https://registry.npm.taobao.org rm -rf node_modules package-lock.json npm install

这里特别提醒:不要手动删除单个依赖包名然后重新装,有时候 node_modules 里的残留会导致依赖树不一致,干脆整体删除再来一遍最干净,这个逻辑和 Maven 里mvn clean是一样的。

5.4 登录后页面能打开但所有列表接口返回 404

现象:前端登录成功,也跳转到了首页,但页面上所有表格都报 404,控制台里能看到/api/expense/list这个请求是 404。

原因:实际是前端请求路径和后端 controller 映射的路径不一致。Ant Design Pro 里的 request 默认会带/api前缀,如果后端的 @RequestMapping 没有包含这个前缀,Spring Boot 就找不到对应的处理函数。

解决:优先看前端 request 工具里有没有封装统一前缀,如果有,后端所有 Controller 的类上就统一加/api前缀。不要逐个接口去加,在application.yml里配置全局路由前缀是最省事的。

server: servlet: context-path: /api

加了 context-path 之后,所有接口路径会自动带/api前缀,前端无需改动。但要注意,这种方式会造成静态资源路径也要加/api才能访问,如果是前后端分离项目,本项目的后端可能不托管页面,影响不大。

5.5 Node 版本过高导致前端构建直接崩溃

现象:执行npm start时,报错SyntaxError: Unexpected token '?'或者Digital Envelope routines::unsupported。

原因:Node 17 及以上版本使用 OpenSSL 3.0,而 Ant Design Pro 4.0 依赖的 webpack 4.x 还在用 OpenSSL 1.x 的 hash 算法。前端构建工具链太老,跟新版 Node 的底层库不兼容。这个报错极其经典,几乎所有玩 webpack4 老项目的人都会碰到。

解决:最省心的方法是把 Node 版本切到 10.x 或 12.x,用 nvm 来管理。

nvm install 12.22.12 nvm use 12.22.12

如果你不想切换 Node 版本,可以尝试在启动命令前加一个环境变量:

export NODE_OPTIONS=--openssl-legacy-provider npm start

这个方案能让你不用换 Node 版本就绕过 OpenSSL 的问题,但治标不治本。后面的依赖安装或者升级时还会不会有其他兼容性问题,谁也说不准。从稳定性角度,我强烈建议直接切 Node 12。

6. 进阶用法:把「月末报表」扩展成 Excel 导出与全年动态对比

这套系统的报表模块虽然功能已经比较完整,但它呈现方式局限在网页图表里。如果你想在答辩时展示额外的工程能力,或者这个系统你自己真的要用起来,我建议加一个数据导出功能——把当月报表直接导出成 Excel 文件。这是一个封闭业务闭环的硬需求:报表只停留在屏幕上,你就没法做二次加工或者打印。

实现思路不复杂。后端在报表接口旁边新增一个导出接口,用 POI 或者 EasyExcel 生成文件流返回给前端。推荐用 EasyExcel,依赖轻量、API 简单,对课程设计来说更容易讲清楚。核心代码如下。

@GetMapping("/report/export") public void exportMonthlyReport(@RequestParam String month, HttpServletResponse response) throws IOException { // 查本月收支汇总 ReportVO report = reportService.generateMonthlyReport(month); List<ExpenseItem> expenseList = report.getExpenseList(); response.setContentType("application/vnd.ms-excel"); response.setCharacterEncoding("utf-8"); String fileName = URLEncoder.encode("月末报表_" + month + ".xlsx", "UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=" + fileName); ExcelWriter writer = EasyExcel.write(response.getOutputStream(), ExpenseItem.class) .sheet("支出明细") .build(); WriteSheet sheet = EasyExcel.writerSheet("支出明细").build(); writer.write(expenseList, sheet); writer.finish(); }

这段代码做了一件事:查询指定月份的所有支出数据,以 Excel 附件形式返回给前端。contentType用来告诉浏览器这是一个需要下载的文件;filename用 URLEncoder 编码,避免浏览器把中文文件名解析成乱码;EasyExcel.write方法的第一个参数直接是 response 的输出流,意味着文件不会落地到服务器磁盘,而是实时吐给前端。这个细节在答辩时值得单独讲,因为它体现了你对内存和 IO 的理解。

前端页面加一个下载按钮,请求这个接口时会弹出文件保存框。这样一来,数据分析就不局限于网页内了,你完全可以把数据放进本地的 Excel 里做二次透视。整套系统从数据录入、图表展示、报表汇总到导出存档就形成了完整的闭环。从那以后,我做这类管理系统的课设项目,都强制把「导出」功能加进交付清单里,因为数据出得去,系统才真正有用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询