420-管家婆项目详细介绍

管家婆个人财务管理系统 - 项目技术文档

目录

  1. 项目概述
  2. 技术架构说明
  3. 项目结构详解
  4. 核心功能模块
  5. 程序运行逻辑
  6. 数据库设计
  7. 关键代码解析
  8. 项目特色与亮点

1. 项目概述

1.1 项目简介

管家婆个人财务管理系统是一个基于Java Swing开发的桌面应用程序,主要用于帮助用户管理个人或家庭的收支情况。系统提供了直观的图形界面,用户可以方便地记录收入和支出,查看财务统计,实现个人财务的数字化管理。

1.2 项目功能

  • 收支记录管理:记录每笔收入和支出,包括金额、分类、账户、时间等信息
  • 分类管理:自定义收入和支出的分类,如工资、奖金、餐饮、交通等
  • 数据查询:按时间段、收支类型、分类等条件组合查询财务记录
  • 统计分析:自动计算总收入、总支出,支持图表展示
  • 数据持久化:所有数据保存在MySQL数据库中,确保数据安全

1.3 使用场景

  • 个人日常收支记录
  • 家庭财务管理
  • 学生生活费管理
  • 小型工作室财务记录

2. 技术架构说明

2.1 技术栈

  • 编程语言:Java 8
  • 用户界面:Java Swing(Java自带的桌面应用开发框架)
  • 数据库:MySQL 8.0
  • 架构模式:MVC(Model-View-Controller,模型-视图-控制器)
  • 数据库操作:Apache Commons DBUtils(简化数据库操作的工具库)
  • 图表组件:JFreeChart(用于生成图表的Java库)

2.2 MVC架构解释

MVC是一种软件设计模式,把程序分成三个部分:

  • Model(模型):负责数据处理和业务逻辑

    • domain包:定义数据结构(如账务记录、分类信息)
    • dao包:负责数据库操作(增删改查)
    • services包:处理业务逻辑
  • View(视图):负责用户界面显示

    • view包:定义所有的窗口和对话框
  • Controller(控制器):连接模型和视图,处理用户操作

    • controller包:处理用户点击按钮、选择菜单等操作

为什么使用MVC?

  • 分工明确:每个部分职责清楚,便于团队开发
  • 代码复用:同一个模型可以对应多个视图
  • 易于维护:修改界面不影响业务逻辑,修改业务逻辑不影响界面

3. 项目结构详解

3.1 整体目录结构

gjp-hl/
├── src/com/itheima/gjp/          # 源代码根目录
│   ├── app/                      # 应用程序入口
│   │   ├── MainApp.java         # 主程序启动类
│   │   └── TestDB.java          # 数据库连接测试类
│   ├── controller/               # 控制器层(MVC中的C)
│   │   ├── MainFrameContrller.java      # 主窗口控制器
│   │   ├── LedgerMngController.java     # 账务管理控制器
│   │   ├── AddLedgerController.java     # 添加账务控制器
│   │   ├── EditLedgerController.java    # 编辑账务控制器
│   │   ├── SortMngController.java       # 分类管理控制器
│   │   └── ...                          # 其他控制器
│   ├── dao/                      # 数据访问层
│   │   ├── LedgerDao.java       # 账务数据访问对象
│   │   └── SortDao.java         # 分类数据访问对象
│   ├── domain/                   # 实体类(MVC中的M)
│   │   ├── Ledger.java          # 账务实体类
│   │   ├── Sort.java            # 分类实体类
│   │   └── QueryForm.java       # 查询条件实体类
│   ├── services/                 # 业务逻辑层(MVC中的M)
│   │   ├── LedgerServices.java  # 账务业务逻辑
│   │   └── SortService.java     # 分类业务逻辑
│   ├── tools/                    # 工具类
│   │   ├── JDBCUtils.java       # 数据库连接工具
│   │   ├── DateUtils.java       # 日期处理工具
│   │   └── ...                  # 其他工具类
│   └── view/                     # 视图层(MVC中的V)
│       ├── AbstractMainFrame.java           # 主窗口抽象类
│       ├── AbstractLedgerMngDialog.java     # 账务管理对话框抽象类
│       └── ...                              # 其他视图类
├── lib/                          # 第三方依赖库
│   ├── mysql-connector-java-8.0.28.jar    # MySQL数据库驱动
│   ├── commons-dbutils-1.4.jar            # 数据库操作工具
│   ├── jfreechart-1.0.9.jar               # 图表生成库
│   └── ...                                 # 其他依赖库
├── bin/                          # 编译后的字节码文件
└── 配置文件...

3.2 核心包说明

app包 - 应用入口

  • 包含程序的main方法,是程序启动的地方

domain包 - 实体类

  • 定义系统中的核心数据结构
  • 相当于现实世界中的"对象",如一笔账务、一个分类

dao包 - 数据访问对象

  • DAO = Data Access Object(数据访问对象)
  • 专门负责与数据库交互,执行增删改查操作
  • 把复杂的SQL语句封装成简单的Java方法

services包 - 业务逻辑

  • 处理具体的业务规则和逻辑
  • 在controller和dao之间起桥梁作用

controller包 - 控制器

  • 处理用户的操作(点击按钮、选择菜单等)
  • 调用services层处理业务,然后更新界面

view包 - 用户界面

  • 定义所有的窗口、对话框、按钮等界面元素
  • 用户看到和操作的都是这一层的内容

4. 核心功能模块

4.1 账务管理模块

功能描述: 管理所有的收入和支出记录

主要文件:

  • Ledger.java:账务实体类,定义账务记录的数据结构
  • LedgerDao.java:账务数据访问类,负责账务数据的数据库操作
  • LedgerServices.java:账务业务逻辑类
  • LedgerMngController.java:账务管理控制器

核心功能:

  • 添加账务记录
  • 编辑账务记录
  • 删除账务记录
  • 查询账务记录
  • 统计收支总额

4.2 分类管理模块

功能描述: 管理收入和支出的分类

主要文件:

  • Sort.java:分类实体类
  • SortDao.java:分类数据访问类
  • SortService.java:分类业务逻辑类
  • SortMngController.java:分类管理控制器

核心功能:

  • 添加分类
  • 编辑分类
  • 删除分类
  • 查看所有分类

4.3 数据库连接模块

功能描述: 提供数据库连接和操作功能

主要文件:

  • JDBCUtils.java:数据库连接工具类
  • 使用连接池技术提高数据库访问效率

4.4 用户界面模块

功能描述: 提供友好的图形用户界面

主要特点:

  • 主窗口:显示系统主菜单
  • 账务管理对话框:管理收支记录
  • 分类管理对话框:管理分类信息
  • 添加/编辑对话框:录入和修改数据

5. 程序运行逻辑

5.1 程序启动流程

1. 用户双击程序或运行命令
   ↓
2. 执行MainApp.java的main方法
   ↓
3. 创建MainFrameContrller对象(主窗口控制器)
   ↓
4. MainFrameContrller继承AbstractMainFrame(主窗口界面)
   ↓
5. 显示主窗口,等待用户操作

5.2 用户操作流程

以添加账务记录为例:

1. 用户点击"账务管理"按钮
   ↓
2. MainFrameContrller.ledgerMng()方法被调用
   ↓
3. 创建LedgerMngController对象,显示账务管理对话框
   ↓
4. 用户点击"添加"按钮
   ↓
5. LedgerMngController.addLedger()方法被调用
   ↓
6. 创建AddLedgerController对象,显示添加账务对话框
   ↓
7. 用户填写信息并点击"确定"
   ↓
8. AddLedgerController.confirm()方法被调用
   ↓
9. 数据验证 → 创建Ledger对象 → 调用LedgerServices.addLedger()
   ↓
10. LedgerServices调用LedgerDao.addLedger()
   ↓
11. LedgerDao执行SQL语句,将数据保存到数据库
   ↓
12. 提示用户"添加成功",关闭对话框

5.3 数据流转过程

用户界面(View) → 控制器(Controller) → 业务逻辑(Services) → 数据访问(Dao) → 数据库
     ↑                                                                                ↓
     ←←←←←←←←←←←←←←← 返回结果 ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←

5.4 UI界面

在这里插入图片描述

6. 数据库设计

6.1 数据库结构

数据库名: gjp

主要数据表:

  1. gjp_sort(分类表)

    • sid:分类ID(主键,自动递增)
    • sname:分类名称(如:工资、餐饮)
    • parent:父级分类(收入 或 支出)
    • sdesc:分类描述
  2. gjp_ledger(账务表)

    • lid:账务ID(主键,自动递增)
    • parent:收支类型(收入 或 支出)
    • money:金额
    • sid:分类ID(外键,关联gjp_sort表)
    • account:账户名称
    • createtime:创建时间
    • ldesc:账务描述

6.2 表关系说明

gjp_sort (分类表)    1    →    ∞    gjp_ledger (账务表)
    ↑                              ↓
一个分类                        多笔账务记录
可以对应                        每笔记录都属于
多笔账务记录                      一个特定分类

外键关系: gjp_ledger.sid → gjp_sort.sid

  • 这意味着每笔账务记录都必须属于一个已存在的分类
  • 删除分类前必须先删除该分类下的所有账务记录

7. 关键代码解析

7.1 程序入口代码

文件: src/com/itheima/gjp/app/MainApp.java

package com.itheima.gjp.app;

import com.itheima.gjp.controller.MainFrameContrller;

/*
 * 整个项目的起始入口
 */
public class MainApp {
    public static void main(String[] args) {
        // 开启主窗体,创建他的子类对象
        new MainFrameContrller().setVisible(true);
    }
}

代码解释:

  • 这是程序的入口点,当用户运行程序时首先执行这里
  • 创建主窗口控制器对象,并设置为可见
  • setVisible(true)让窗口显示出来

7.2 数据库连接工具类

文件: src/com/itheima/gjp/tools/JDBCUtils.java

package com.itheima.gjp.tools;

import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;

public class JDBCUtils {
    // 数据库连接配置
    public static final String DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";
    public static final String URL = "jdbc:mysql://localhost:3306/gjp?useSSL=false&serverTimezone=UTC";
    public static final String USERNAME = "root";
    public static final String PASSWORD = "123456";
    
    // 连接池配置参数
    private static final int MAX_IDLE = 3;        // 最大空闲连接数
    private static final long MAX_WAIT = 5000;    // 最大等待时间
    private static final int MAX_ACTIVE = 5;      // 最大活跃连接数
    private static final int INITIAL_SIZE = 10;   // 初始连接数
    
    // 创建数据源(连接池)
    private static BasicDataSource dataSource = new BasicDataSource();
    
    // 静态代码块,程序启动时自动执行,配置连接池
    static {
        dataSource.setDriverClassName(DRIVER_CLASS_NAME);
        dataSource.setUrl(URL);
        dataSource.setUsername(USERNAME);
        dataSource.setPassword(PASSWORD);
        
        dataSource.setMaxActive(MAX_IDLE);
        dataSource.setMaxWait(MAX_WAIT);
        dataSource.setMaxActive(MAX_ACTIVE);
        dataSource.setInitialSize(INITIAL_SIZE);
    }
    
    // 获取数据源的方法,其他类调用这个方法来获取数据库连接
    public static DataSource getDataSource() {
        return dataSource;
    }
}

关键概念解释:

  • 数据库连接池:预先创建一些数据库连接保存在"池"中,需要时取出使用,用完归还。这样比每次都创建新连接要快很多。

  • 静态代码块:用static {}包围的代码,在类被加载时自动执行一次,常用于初始化操作。

7.3 实体类代码

文件: src/com/itheima/gjp/domain/Ledger.java

package com.itheima.gjp.domain;

public class Ledger {
    private int lid;           // 账务ID
    private String parent;     // 收支类型(收入/支出)
    private double money;      // 金额
    private int sid;          // 分类ID
    private String account;    // 账户
    private String createtime; // 创建时间
    private String ldesc;      // 描述
    private String sname;      // 分类名称(从分类表关联查询得到)

    // 无参构造方法
    public Ledger() {}
    
    // 有参构造方法
    public Ledger(int lid, String parent, double money, int sid,
                  String account, String createtime, String ldesc, String sname) {
        this.lid = lid;
        this.parent = parent;
        this.money = money;
        this.sid = sid;
        this.account = account;
        this.createtime = createtime;
        this.ldesc = ldesc;
        this.sname = sname;
    }
    
    // Getter和Setter方法(用于获取和设置属性值)
    public int getLid() { return lid; }
    public void setLid(int lid) { this.lid = lid; }
    
    public String getParent() { return parent; }
    public void setParent(String parent) { this.parent = parent; }
    
    public double getMoney() { return money; }
    public void setMoney(double money) { this.money = money; }
    
    // ... 其他getter和setter方法
    
    // toString方法,用于打印对象信息(调试时很有用)
    @Override
    public String toString() {
        return "Ledger [lid=" + lid + ", parent=" + parent + ", money=" + money
                + ", sid=" + sid + ", account=" + account + ", createtime="
                + createtime + ", ldesc=" + ldesc + ", sname=" + sname + "]";
    }
}

代码解释:

  • 实体类:对应数据库表的Java类,一个对象代表表中的一行记录
  • 构造方法:用于创建对象的方法
  • Getter/Setter方法:Java的标准做法,用于访问和修改私有属性
  • toString方法:返回对象的字符串表示,便于调试

7.4 数据访问类代码

文件: src/com/itheima/gjp/dao/LedgerDao.java(部分代码)

package com.itheima.gjp.dao;

import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import com.itheima.gjp.domain.Ledger;
import com.itheima.gjp.tools.JDBCUtils;

public class LedgerDao {
    // 创建QueryRunner对象,用于执行SQL语句
    private QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
    
    /*
     * 添加账务记录的方法
     * 参数:Ledger对象,包含要添加的账务信息
     */
    public void addLedger(Ledger ledger) {
        try {
            // 准备SQL插入语句
            String sql = "INSERT INTO gjp_ledger (parent,money,sid,account,createtime,ldesc)" +
                        "values(?,?,?,?,?,?)";
            
            // 准备参数数组,对应SQL语句中的?号占位符
            Object[] params = {
                ledger.getParent(),     // 收支类型
                ledger.getMoney(),      // 金额
                ledger.getSid(),        // 分类ID
                ledger.getAccount(),    // 账户
                ledger.getCreatetime(), // 时间
                ledger.getLdesc()       // 描述
            };
            
            // 执行SQL语句
            qr.update(sql, params);
            
        } catch(SQLException e) {
            // 如果出现SQL异常,转换为运行时异常抛出
            throw new RuntimeException(e);
        }
    }
    
    /*
     * 查询账务记录的方法
     * 参数:QueryForm对象,包含查询条件
     * 返回:List<Ledger>集合,包含查询结果
     */
    public List<Ledger> queryLedgerByQueryForm(QueryForm form) {
        // 动态构建SQL语句
        List<String> params = new ArrayList<String>();
        StringBuilder builder = new StringBuilder();
        
        // 基本查询条件(时间范围)
        builder.append("SELECT * FROM gjp_ledger WHERE createtime between ? and ?");
        params.add(form.getBegin());  // 开始时间
        params.add(form.getEnd());    // 结束时间
        
        // 根据用户选择的收支类型添加条件
        if(form.getParent().equals("收入") || form.getParent().equals("支出")) {
            builder.append(" and parent = ?");
            params.add(form.getParent());
        }
        
        // 根据用户选择的分类添加条件
        if(!form.getSname().equals("-请选择-")) {
            // 根据分类名称查找分类ID
            int sid = sortDao.getSidBySname(form.getSname());
            builder.append(" and sid=?");
            params.add(sid + "");
        }
        
        try {
            // 执行查询,BeanListHandler会自动将结果集转换为Ledger对象列表
            List<Ledger> list = qr.query(builder.toString(), 
                                       new BeanListHandler<Ledger>(Ledger.class),
                                       params.toArray());
            return list;
        } catch(SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

关键概念解释:

  • QueryRunner:Apache Commons DBUtils提供的工具类,简化了数据库操作
  • 占位符(?):SQL语句中的?代表参数,可以防止SQL注入攻击
  • BeanListHandler:自动将数据库查询结果转换为Java对象列表
  • 动态SQL:根据不同条件拼接不同的SQL语句

7.5 控制器代码

文件: src/com/itheima/gjp/controller/AddLedgerController.java(部分代码)

package com.itheima.gjp.controller;

import javax.swing.JDialog;
import javax.swing.JOptionPane;
import com.itheima.gjp.domain.Ledger;
import com.itheima.gjp.services.LedgerServices;
import com.itheima.gjp.view.AbstractOperationLedgerDialog;

public class AddLedgerController extends AbstractOperationLedgerDialog {
    private LedgerServices ledgerService = new LedgerServices();

    public AddLedgerController(JDialog dialog) {
        super(dialog);
        titleLabel.setText("添加账务");
        super.setTitle("添加账务");
    }

    /*
     * 用户点击"确定"按钮时调用的方法
     */
    @Override
    public void confirm() {
        // 1. 获取用户输入的数据
        String parent = parentBox.getSelectedItem().toString();  // 收支类型
        String sname = sortBox.getSelectedItem().toString();     // 分类名称
        String account = accountTxt.getText().trim();            // 账户
        String moneyStr = moneyTxt.getText().trim();            // 金额(字符串)
        String createtime = createtimeTxt.getText();            // 时间
        String ldesc = ldescTxt.getText();                      // 描述
        
        // 2. 数据验证
        if(parent.equals("-请选择-")) {
            JOptionPane.showMessageDialog(this, "请选择收支类型");
            return;
        }
        
        if(sname.equals("-请选择-")) {
            JOptionPane.showMessageDialog(this, "请选择分类");
            return;
        }
        
        if(account == null || account.equals("")) {
            JOptionPane.showMessageDialog(this, "请填写账户");
            return;
        }
        
        // 验证金额是否为有效数字
        double money = 0.0;
        try {
            money = Double.parseDouble(moneyStr);
            if(money <= 0) {
                JOptionPane.showMessageDialog(this, "金额必须大于0");
                return;
            }
        } catch(NumberFormatException e) {
            JOptionPane.showMessageDialog(this, "请输入有效的金额");
            return;
        }
        
        // 3. 根据分类名称获取分类ID
        int sid = sortService.getSidBySname(sname);
        
        // 4. 创建Ledger对象,封装用户输入的数据
        Ledger ledger = new Ledger(0, parent, money, sid, account, createtime, ldesc, sname);
        
        // 5. 调用业务逻辑层,保存数据
        ledgerService.addLedger(ledger);
        
        // 6. 提示用户操作成功
        JOptionPane.showMessageDialog(this, "添加账务成功", "操作成功", JOptionPane.PLAIN_MESSAGE);
        
        // 7. 关闭当前对话框
        this.dispose();
    }
    
    /*
     * 收支类型改变时调用的方法(实现下拉框联动)
     */
    @Override
    public void changeParent() {
        String parent = parentBox.getSelectedItem().toString();
        
        if(parent.equals("-请选择-")) {
            // 如果收支类型是"请选择",分类也显示"请选择"
            sortBox.setModel(new DefaultComboBoxModel(new String[] {"-请选择-"}));
        }
        
        if(parent.equals("收入") || parent.equals("支出")) {
            // 根据收支类型,从数据库查询对应的分类列表
            List<Object> list = sortService.querySortNameByParent(parent);
            list.add(0, "-请选择-");  // 在列表开头添加"请选择"选项
            sortBox.setModel(new DefaultComboBoxModel(list.toArray()));
        }
    }
}

代码解释:

  • 数据验证:检查用户输入是否合法,如必填项是否为空、金额是否为有效数字等
  • 异常处理:使用try-catch处理可能出现的数字格式异常
  • 下拉框联动:当收支类型改变时,分类下拉框的内容也相应改变
  • 对话框:使用JOptionPane显示提示信息和错误信息

8. 项目特色与亮点

8.1 技术特色

  1. 标准MVC架构

    • 代码结构清晰,各层职责明确
    • 便于维护和扩展
    • 符合企业级开发规范
  2. 数据库连接池技术

    • 提高数据库访问效率
    • 合理管理数据库连接资源
    • 支持高并发访问
  3. 动态SQL构建

    • 支持多条件组合查询
    • 灵活的查询功能
    • 安全的参数化查询,防止SQL注入
  4. 面向对象设计

    • 使用继承和多态特性
    • 抽象类和接口的合理运用
    • 代码复用性强

8.2 功能特色

  1. 用户友好的界面

    • 直观的图形界面
    • 合理的布局设计
    • 清晰的操作流程
  2. 灵活的分类管理

    • 支持自定义收支分类
    • 收入和支出分别管理
    • 分类与账务记录的关联
  3. 强大的查询功能

    • 时间段查询
    • 收支类型筛选
    • 分类筛选
    • 多条件组合查询
  4. 实时统计功能

    • 自动计算总收入和总支出
    • 支持图表展示
    • 数据可视化

8.3 代码质量

  1. 良好的注释

    • 详细的方法注释
    • 清晰的业务逻辑说明
    • 便于理解和维护
  2. 异常处理

    • 完善的错误处理机制
    • 用户友好的错误提示
    • 程序稳定性好
  3. 代码规范

    • 统一的命名规范
    • 合理的包结构
    • 清晰的类设计

8.4 学习价值

  1. Java基础知识应用

    • 面向对象编程
    • 集合框架使用
    • 异常处理机制
    • 文件I/O操作
  2. 数据库应用

    • SQL语句编写
    • JDBC编程
    • 数据库设计
    • 事务处理
  3. GUI编程

    • Swing组件使用
    • 事件处理机制
    • 布局管理
    • 用户交互设计
  4. 软件工程实践

    • MVC架构设计
    • 分层开发
    • 代码组织
    • 项目管理

总结

管家婆个人财务管理系统是一个功能完整、结构清晰的Java桌面应用程序。它不仅实现了个人财务管理的基本功能,还展示了现代软件开发的最佳实践。通过学习这个项目,可以深入理解Java编程、数据库应用、GUI开发和软件架构设计等多个方面的知识。

项目的成功运行证明了其技术方案的可行性和代码实现的正确性。无论是作为学习Java编程的实践项目,还是作为个人财务管理的实用工具,都具有很好的价值和意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值