一、 项目背景与意义

在数字化时代,个人财务管理的需求日益增长。传统的记账方式如纸质账本或简单的电子表格,存在数据易丢失、统计不便、缺乏可视化分析等痛点。随着移动互联网和云计算的普及,开发一款功能完善、操作便捷的个人财务管理系统,对于帮助用户清晰掌握收支状况、培养良好消费习惯、实现财务目标具有重要的现实意义。

本项目旨在设计并实现一个基于Spring Boot的个人财务管理系统。该系统将提供一个集中管理个人收入、支出、资产、负债的平台,通过数据可视化图表直观展示财务状况,并具备预算管理、报表生成等进阶功能,最终帮助用户实现科学的个人财务管理。

二、 技术栈选型

本系统采用前后端分离的架构模式,后端基于Spring Boot框架构建,前端使用Vue.js,数据库选用MySQL。具体技术栈如下:

2.1 后端技术栈

  • 核心框架: Spring Boot 2.7.x
  • 安全框架: Spring Security + JWT (JSON Web Token)
  • 数据持久层: Spring Data JPA (集成Hibernate)
  • 数据库: MySQL 8.0
  • API文档: SpringDoc OpenAPI (Swagger UI)
  • 缓存: Redis (用于会话管理或热点数据缓存)
  • 任务调度: Spring Scheduler
  • 构建工具: Maven

2.2 前端技术栈

  • 核心框架: Vue.js 3 + Composition API
  • 构建工具: Vite
  • UI组件库: Element Plus
  • 状态管理: Pinia
  • 路由: Vue Router
  • HTTP客户端: Axios
  • 图表库: ECharts

2.3 开发与部署

  • 版本控制: Git
  • 容器化: Docker, Docker Compose
  • 部署: 可部署至云服务器(如阿里云ECS)或使用容器平台。

三、 系统核心功能模块设计

系统主要分为以下几个核心模块:

  • 用户认证与授权模块: 负责用户注册、登录、JWT令牌签发与验证、权限管理。
  • 账户管理模块: 管理用户的现金账户、银行卡、信用卡、数字钱包等资产账户。
  • 收支记录模块: 核心功能,支持记录每一笔收入与支出,包含金额、分类、时间、备注、关联账户等信息。
  • 分类管理模块: 自定义收入与支出的分类树(如餐饮、交通、工资、理财收入等)。
  • 预算管理模块: 支持按周期(月、年)和分类设置预算,并实时监控预算执行情况。
  • 数据统计与报表模块: 通过图表(饼图、柱状图、趋势图)多维度展示收支对比、资产构成、消费趋势。支持导出报表。
  • 系统设置模块: 用户个人资料修改、系统参数配置等。

四、 数据库核心表设计

以下是几个核心实体对应的数据库表结构:

-- 用户表
CREATE TABLE `sys_user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '用户名',
  `password` varchar(255) NOT NULL COMMENT '加密后的密码',
  `email` varchar(100) DEFAULT NULL,
  `nickname` varchar(50) DEFAULT NULL,
  `avatar` varchar(500) DEFAULT NULL,
  `status` tinyint DEFAULT '1' COMMENT '状态:0-禁用,1-正常',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`)
) ENGINE=InnoDB COMMENT='系统用户表';

-- 账户表
CREATE TABLE `finance_account` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL COMMENT '所属用户ID',
  `account_name` varchar(100) NOT NULL COMMENT '账户名称(如:招商银行储蓄卡)',
  `account_type` varchar(20) NOT NULL COMMENT '账户类型:CASH, BANK_CARD, CREDIT_CARD, DIGITAL_WALLET',
  `balance` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '当前余额',
  `currency` varchar(10) DEFAULT 'CNY' COMMENT '货币',
  `remarks` varchar(500) DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`),
  CONSTRAINT `fk_account_user` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB COMMENT='财务账户表';

-- 收支分类表
CREATE TABLE `finance_category` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL,
  `parent_id` bigint DEFAULT '0' COMMENT '父分类ID,0表示根分类',
  `category_name` varchar(50) NOT NULL,
  `type` tinyint NOT NULL COMMENT '类型:1-收入,2-支出',
  `icon` varchar(100) DEFAULT NULL,
  `sort_order` int DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx_user_type` (`user_id`,`type`)
) ENGINE=InnoDB COMMENT='收支分类表';

-- 收支记录表(核心业务表)
CREATE TABLE `finance_record` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL,
  `account_id` bigint NOT NULL COMMENT '关联账户ID',
  `category_id` bigint NOT NULL COMMENT '分类ID',
  `type` tinyint NOT NULL COMMENT '记录类型:1-收入,2-支出',
  `amount` decimal(15,2) NOT NULL COMMENT '金额,正数',
  `record_time` datetime NOT NULL COMMENT '交易时间',
  `description` varchar(500) DEFAULT NULL COMMENT '描述/备注',
  `tags` varchar(255) DEFAULT NULL COMMENT '标签,逗号分隔',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_user_time` (`user_id`,`record_time`),
  KEY `idx_account` (`account_id`),
  KEY `idx_category` (`category_id`),
  CONSTRAINT `fk_record_account` FOREIGN KEY (`account_id`) REFERENCES `finance_account` (`id`),
  CONSTRAINT `fk_record_category` FOREIGN KEY (`category_id`) REFERENCES `finance_category` (`id`),
  CONSTRAINT `fk_record_user` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB COMMENT='收支记录表';

-- 预算表
CREATE TABLE `finance_budget` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `user_id` bigint NOT NULL,
  `category_id` bigint NOT NULL COMMENT '预算针对的分类(0表示总预算)',
  `budget_amount` decimal(15,2) NOT NULL COMMENT '预算金额',
  `period_type` varchar(10) NOT NULL COMMENT '周期类型:MONTH, YEAR',
  `period_value` varchar(20) NOT NULL COMMENT '周期值,如2025-08',
  `actual_amount` decimal(15,2) DEFAULT '0.00' COMMENT '实际已发生金额',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_category_period` (`user_id`,`category_id`,`period_type`,`period_value`),
  CONSTRAINT `fk_budget_category` FOREIGN KEY (`category_id`) REFERENCES `finance_category` (`id`),
  CONSTRAINT `fk_budget_user` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB COMMENT='预算表';

五、 核心代码实现示例

5.1 实体类 (JPA Entity)

// 收支记录实体
@Entity
@Table(name = "finance_record")
@Data
@EqualsAndHashCode(callSuper = false)
public class FinanceRecord extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "account_id", nullable = false)
    private FinanceAccount account;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id", nullable = false)
    private FinanceCategory category;

    @Column(nullable = false)
    private Integer type; // 1-收入,2-支出

    @Column(nullable = false, precision = 15, scale = 2)
    private BigDecimal amount;

    @Column(name = "record_time", nullable = false)
    private LocalDateTime recordTime;

    private String description;
    private String tags;
}

5.2 数据访问层 (Repository)

@Repository
public interface FinanceRecordRepository extends JpaRepository<FinanceRecord, Long>, JpaSpecificationExecutor<FinanceRecord> {

    // 查询指定用户某时间范围内的收支记录
    List<FinanceRecord> findByUserAndRecordTimeBetweenOrderByRecordTimeDesc(User user, LocalDateTime start, LocalDateTime end);

    // 统计指定用户某时间段内的总收入/总支出
    @Query("SELECT SUM(fr.amount) FROM FinanceRecord fr WHERE fr.user = :user AND fr.type = :type AND fr.recordTime BETWEEN :start AND :end")
    BigDecimal sumAmountByUserAndTypeAndPeriod(@Param("user") User user,
                                               @Param("type") Integer type,
                                               @Param("start") LocalDateTime start,
                                               @Param("end") LocalDateTime end);
}

5.3 业务逻辑层 (Service)

@Service
@RequiredArgsConstructor
@Slf4j
public class FinanceRecordService {

    private final FinanceRecordRepository recordRepository;
    private final FinanceAccountService accountService;

    @Transactional
    public FinanceRecord createRecord(FinanceRecordCreateDTO createDTO, Long userId) {
        User user = // ... 获取当前用户
        FinanceAccount account = accountService.getAccountByIdAndUser(createDTO.getAccountId(), user);
        FinanceCategory category = // ... 获取分类

        // 构建记录
        FinanceRecord record = new FinanceRecord();
        record.setUser(user);
        record.setAccount(account);
        record.setCategory(category);
        record.setType(createDTO.getType());
        record.setAmount(createDTO.getAmount());
        record.setRecordTime(createDTO.getRecordTime());
        record.setDescription(createDTO.getDescription());
        record.setTags(createDTO.getTags());

        // 更新账户余额
        BigDecimal balanceChange = createDTO.getType() == 1 ? createDTO.getAmount() : createDTO.getAmount().negate();
        accountService.updateBalance(account.getId(), balanceChange);

        return recordRepository.save(record);
    }

    // 获取月度收支统计
    public MonthlyStatDTO getMonthlyStat(Long userId, YearMonth yearMonth) {
        LocalDateTime start = yearMonth.atDay(1).atStartOfDay();
        LocalDateTime end = yearMonth.atEndOfMonth().atTime(23, 59, 59);

        BigDecimal totalIncome = recordRepository.sumAmountByUserAndTypeAndPeriod(userId, 1, start, end);
        BigDecimal totalExpense = recordRepository.sumAmountByUserAndTypeAndPeriod(userId, 2, start, end);

        MonthlyStatDTO stat = new MonthlyStatDTO();
        stat.setYearMonth(yearMonth);
        stat.setTotalIncome(totalIncome != null ? totalIncome : BigDecimal.ZERO);
        stat.setTotalExpense(totalExpense != null ? totalExpense : BigDecimal.ZERO);
        stat.setBalance(stat.getTotalIncome().subtract(stat.getTotalExpense()));
        return stat;
    }
}

5.4 控制器层 (Controller)

@RestController
@RequestMapping("/api/finance/records")
@RequiredArgsConstructor
@Tag(name = "收支记录管理")
public class FinanceRecordController {

    private final FinanceRecordService recordService;

    @PostMapping
    @Operation(summary = "新增收支记录")
    public ResponseEntity<FinanceRecordVO> createRecord(@Valid @RequestBody FinanceRecordCreateDTO createDTO,
                                                         @AuthenticationPrincipal UserDetails userDetails) {
        Long userId = Long.parseLong(userDetails.getUsername());
        FinanceRecord record = recordService.createRecord(createDTO, userId);
        return ResponseEntity.ok(FinanceRecordVO.fromEntity(record));
    }

    @GetMapping("/monthly-stat")
    @Operation(summary = "获取月度收支统计")
    public ResponseEntity<MonthlyStatDTO> getMonthlyStat(@RequestParam @DateTimeFormat(pattern = "yyyy-MM") YearMonth yearMonth,
                                                         @AuthenticationPrincipal UserDetails userDetails) {
        Long userId = Long.parseLong(userDetails.getUsername());
        MonthlyStatDTO stat = recordService.getMonthlyStat(userId, yearMonth);
        return ResponseEntity.ok(stat);
    }
}

六、 总结与展望

本文详细阐述了一个基于Spring Boot的个人财务管理系统的设计与实现,涵盖了项目背景、技术栈选型、核心功能模块、数据库设计以及关键代码示例。该系统采用主流的Java技术栈,架构清晰,具备良好的可扩展性和可维护性。

未来,可以考虑从以下几个方面进行功能增强:

  • 多端同步: 开发移动端App(React Native/Flutter),实现数据云端同步。
  • 智能分析: 集成机器学习算法,对消费行为进行分析,提供个性化的省钱建议和财务规划。
  • 账单导入: 支持从银行短信、邮件或账单文件(CSV、PDF)自动解析并导入交易记录。
  • 多用户/家庭账本: 支持创建家庭账本,实现家庭成员间的财务共享与协作。
  • 投资跟踪: 增加股票、基金等投资资产的跟踪与盈亏计算功能。

通过持续迭代,该系统有望成为一个功能全面、体验优秀的个人财务管理工具。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐