本文基于《面向对象程序设计 (Java)》课程设计要求,详细介绍一个采用MVC 架构和模块化设计的银行账户管理系统。系统实现用户登录、账户管理、资金操作(存款 / 取款 / 转账)、交易记录查询等核心功能,结合 MySQL 数据库完成数据持久化,并通过 Swing 实现图形化界面(GUI)。文中将涵盖系统设计流程、数据库建模、代码实现细节及功能测试案例,适合 Java 初学者学习企业级应用开发思路。
技术 / 工具 | 版本 | 说明 |
---|---|---|
Java | 21 | 编程语言 |
Eclipse | 2025 | 集成开发环境 |
MySQL | 8.0 | 关系型数据库 |
JDBC 驱动 | 8.0.28 | 数据库连接 |
Swing | - | 图形界面库 |
用户模块
UserService
调用UserDao.findByUsername()
查询用户,校验密码正确性。JOptionPane.showMessageDialog
)。账户模块
is_default
字段标记默认账户。Account
实体类封装数据)。资金操作模块
// AccountService转账方法(简化版)
public boolean transfer(String fromAccount, String toAccount, double amount) {
Connection conn = null;
try {
conn = DatabaseUtil.getConnection();
conn.setAutoCommit(false); // 开启事务
// 扣除转出账户余额
boolean deductResult = accountDao.updateBalance(fromAccount, account.getBalance() - amount);
// 增加转入账户余额
boolean addResult = accountDao.updateBalance(toAccount, targetAccount.getBalance() + amount);
if (deductResult && addResult) {
conn.commit(); // 事务提交
recordTransaction(fromAccount, toAccount, amount, "TRANSFER");
return true;
}
conn.rollback(); // 失败回滚
return false;
} catch (SQLException e) {
DatabaseUtil.rollbackQuietly(conn);
logger.error("转账失败:" + e.getMessage());
return false;
} finally {
DatabaseUtil.closeQuietly(conn);
}
}
交易记录模块
TransactionDao.queryByAccountNumber(String accountNumber)
查询数据库。字段名 | 类型 | 约束 | 说明 |
---|---|---|---|
id | INT | 主键,自增 | 用户唯一标识 |
username | VARCHAR(50) | 唯一非空 | 登录用户名 |
password | VARCHAR(100) | 非空 | 密码(建议加密存储) |
name | VARCHAR(50) | 非空 | 姓名 |
id_card | VARCHAR(20) | 唯一 | 身份证号 |
phone | VARCHAR(20) | 手机号 | |
create_time | TIMESTAMP | 默认 CURRENT_TIMESTAMP | 注册时间 |
status | INT | 默认 1(有效) | 账户状态 |
字段名 | 类型 | 约束 | 说明 |
---|---|---|---|
id | INT | 主键,自增 | 账户唯一标识 |
account_number | VARCHAR(20) | 唯一非空 | 账号 |
user_id | INT | 外键 | 关联用户 ID |
account_type | VARCHAR(20) | 非空 | 账户类型(如 SAVINGS/CHECKING) |
balance | DECIMAL(10,2) | 非空默认 0.00 | 余额 |
create_time | DATE | 非空 | 开户日期 |
status | VARCHAR(20) | 默认 'ACTIVE' | 账户状态 |
is_default | BOOLEAN | 默认 FALSE | 是否为默认账户 |
字段名 | 类型 | 约束 | 说明 |
---|---|---|---|
transaction_id | VARCHAR(20) | 主键 | 交易 ID(唯一标识) |
from_account | VARCHAR(20) | 外键 | 转出账号(可选) |
to_account | VARCHAR(20) | 外键 | 转入账号(可选) |
amount | DECIMAL(10,2) | 非空 | 交易金额 |
transaction_type | VARCHAR(20) | 非空 | 类型(存款 / 取款 / 转账) |
transaction_time | TIMESTAMP | 默认 CURRENT_TIMESTAMP | 交易时间 |
status | VARCHAR(20) | 默认 'SUCCESS' | 状态 |
description | VARCHAR(100) | 备注 |
-- 创建用户表
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
name VARCHAR(50) NOT NULL,
id_card VARCHAR(20) UNIQUE,
phone VARCHAR(20),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status INT DEFAULT 1
);
-- 创建账户表(关联用户表)
CREATE TABLE IF NOT EXISTS account (
id INT PRIMARY KEY AUTO_INCREMENT,
account_number VARCHAR(20) UNIQUE NOT NULL,
user_id INT NOT NULL,
account_type VARCHAR(20) NOT NULL,
balance DECIMAL(10,2) NOT NULL DEFAULT 0.00,
create_time DATE NOT NULL,
status VARCHAR(20) DEFAULT 'ACTIVE',
is_default BOOLEAN DEFAULT FALSE,
FOREIGN KEY (user_id) REFERENCES user(id)
);
-- 创建交易表(关联账户表)
CREATE TABLE IF NOT EXISTS transaction (
transaction_id VARCHAR(20) PRIMARY KEY,
from_account VARCHAR(20),
to_account VARCHAR(20),
amount DECIMAL(10,2) NOT NULL,
transaction_type VARCHAR(20) NOT NULL,
transaction_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(20) DEFAULT 'SUCCESS',
description VARCHAR(100),
FOREIGN KEY (from_account) REFERENCES account(account_number),
FOREIGN KEY (to_account) REFERENCES account(account_number)
);
package com.bank.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String accountNumber;
private int userId;
private String accountType;
private BigDecimal balance; // 使用BigDecimal避免浮点数精度问题
private Date createTime;
private String status;
private boolean isDefault;
// 构造方法、Getter/Setter省略
}
package com.bank.dao;
import com.bank.entity.Account;
import com.bank.util.DatabaseUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class AccountDao {
// 查询账户信息
public Account getAccountByNumber(String accountNumber) {
String sql = "SELECT * FROM account WHERE account_number = ?";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, accountNumber);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setAccountNumber(rs.getString("account_number"));
account.setUserId(rs.getInt("user_id"));
account.setAccountType(rs.getString("account_type"));
account.setBalance(rs.getBigDecimal("balance"));
account.setCreateTime(rs.getDate("create_time"));
account.setStatus(rs.getString("status"));
account.setDefault(rs.getBoolean("is_default"));
return account;
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
// 更新账户余额(支持事务)
public boolean updateBalance(String accountNumber, BigDecimal newBalance) {
String sql = "UPDATE account SET balance = ? WHERE account_number = ?";
try (Connection conn = DatabaseUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setBigDecimal(1, newBalance);
pstmt.setString(2, accountNumber);
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
}
package com.bank.ui;
import com.bank.service.UserService;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginUI extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
private UserService userService = new UserService();
public LoginUI() {
setTitle("银行账户管理系统 - 登录");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
usernameField = new JTextField(20);
passwordField = new JPasswordField(20);
JButton loginBtn = new JButton("登录");
loginBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String username = usernameField.getText();
String password = new String(passwordField.getPassword());
if (userService.login(username, password)) {
JOptionPane.showMessageDialog(LoginUI.this, "登录成功!");
new MainUI().setVisible(true);
dispose(); // 关闭登录窗口
} else {
JOptionPane.showMessageDialog(LoginUI.this, "用户名或密码错误!", "错误", JOptionPane.ERROR_MESSAGE);
}
}
});
add(new JLabel("用户名:"));
add(usernameField);
add(new JLabel("密码:"));
add(passwordField);
add(loginBtn);
setLocationRelativeTo(null); // 窗口居中
}
public static void main(String[] args) {
new LoginUI().setVisible(true);
}
}
测试模块 | 测试场景 | 输入数据 | 预期结果 |
---|---|---|---|
登录 | 正确用户名 / 密码 | username: testuser1 password: 123456 |
跳转主界面,显示用户信息 |
错误密码 | username: testuser1 password: wrong |
提示 “用户名或密码错误” | |
存款 | 正常存款 1000 元 | 账号: 6222021101000000001 金额: 1000 |
余额增加 1000 元,交易记录含存款类型 |
转账 | 跨账户转账 2000 元 | 转出账号: A 转入账号: B 金额: 2000 |
转出账户余额减少 2000,转入账户增加 2000,事务成功 |
取款 | 余额不足(当前余额 500 元,取款 1000 元) | 金额: 1000 | 提示 “余额不足”,余额不变 |
登录成功界面
转账操作结果
交易记录查询