本教程将通过一个完整的ATM模拟系统项目,带你深入了解Java的核心概念和实际应用。
这个ATM系统将涵盖以下功能:
使用Java Swing或JavaFX实现图形界面:
import javax.swing.*; public class ATMGUI { public static void main(String[] args) { JFrame frame = new JFrame("ATM系统"); // 添加各种GUI组件 frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }
使用资源束实现国际化:
import java.util.Locale; import java.util.ResourceBundle; ResourceBundle bundle = ResourceBundle.getBundle("Messages", Locale.CHINA); String welcomeMessage = bundle.getString("welcome");
将ATM系统改为客户端-服务器架构:
如果多个用户同时访问,需要考虑:
完善异常处理机制:
try { // 可能出错的代码 } catch (SpecificException e) { // 特定异常处理 } catch (Exception e) { // 通用异常处理 } finally { // 清理资源 }
确保所有用户输入都经过验证:
用户登录验证
账户余额查询
存款和取款操作
账户间转账
交易记录查询
密码修改功能
我们的ATM模拟系统需要实现以下核心功能:
用户认证:通过卡号和密码验证用户身份
账户管理:包括存款、取款、转账等操作
交易记录:记录所有交易操作并支持查询
安装JDK(建议JDK 8或更高版本)
选择开发工具(IntelliJ IDEA、Eclipse或VS Code)
创建Java项目:
新建一个名为AdvancedATM
的Java类
创建两个辅助类:BankAccount
和Transaction
密码管理:允许用户修改密码
数据持久化:虽然本示例使用内存存储,但了解数据库连接也很重要
与前面的验证码程序一样,我们需要:
安装JDK(建议JDK 8或更高版本)
选择开发工具(IntelliJ IDEA、Eclipse或VS Code)
创建Java项目:
新建一个名为AdvancedATM
的Java类
创建两个辅助类:BankAccount
和Transaction
class BankAccount {
private String cardNumber; // 卡号
private String pin; // 密码
private String holderName; // 持卡人姓名
private double balance; // 账户余额
private List transactionHistory; // 交易记录
// 构造方法
public BankAccount(String cardNumber, String pin, String holderName, double balance) {
this.cardNumber = cardNumber;
this.pin = pin;
this.holderName = holderName;
this.balance = balance;
this.transactionHistory = new ArrayList<>();
}
// 存款方法
public void deposit(double amount) {
this.balance += amount;
}
// 取款方法
public boolean withdraw(double amount) {
if (amount > balance) {
return false;
}
this.balance -= amount;
return true;
}
// 其他getter和setter方法...
}
class Transaction {
private String timestamp; // 交易时间
private String description; // 交易描述
private double amount; // 交易金额
private double balanceAfter; // 交易后余额
// 构造方法
public Transaction(String timestamp, String description, double amount, double balanceAfter) {
this.timestamp = timestamp;
this.description = description;
this.amount = amount;
this.balanceAfter = balanceAfter;
}
// getter方法...
}
主类负责整个系统的流程控制,包含以下关键组件:
账户存储:使用Map
存储所有银行账户
交易记录:使用List
存储所有交易
当前账户:跟踪当前登录的用户
日期格式化:统一交易时间格式
输入扫描器:处理用户输入
private static void initializeAccounts() {
accounts.put("123456", new BankAccount("123456", "1111", "张三", 5000.0));
accounts.put("654321", new BankAccount("654321", "2222", "李四", 10000.0));
}
private static void showLoginMenu() {
System.out.println("\n===== ATM 登录系统 =====");
System.out.println("1. 登录账户");
System.out.println("2. 退出系统");
System.out.print("请选择: ");
int choice = getIntInput(1, 2);
switch (choice) {
case 1:
login();
break;
case 2:
System.out.println("感谢使用ATM系统,再见!");
System.exit(0);
}
}
private static void showMainMenu() {
System.out.println("\n===== ATM 主菜单 =====");
System.out.println("1. 查询余额");
System.out.println("2. 存款");
System.out.println("3. 取款");
System.out.println("4. 转账");
System.out.println("5. 交易记录");
System.out.println("6. 修改密码");
System.out.println("7. 退出账户");
System.out.print("请选择: ");
int choice = getIntInput(1, 7);
switch (choice) {
case 1:
checkBalance();
break;
// 其他case分支...
}
}
private static void login() {
System.out.println("\n===== 账户登录 =====");
System.out.print("请输入卡号: ");
String cardNumber = scanner.nextLine();
System.out.print("请输入密码: ");
String pin = scanner.nextLine();
if (accounts.containsKey(cardNumber)) {
BankAccount account = accounts.get(cardNumber);
if (account.getPin().equals(pin)) {
currentAccount = account;
System.out.println("登录成功!欢迎," + account.getHolderName());
logTransaction("登录系统");
} else {
System.out.println("密码错误!");
}
} else {
System.out.println("卡号不存在!");
}
}
private static void deposit() {
System.out.println("\n===== 存款操作 =====");
System.out.print("请输入存款金额: ");
double amount = getDoubleInput(0.01, 10000.00);
currentAccount.deposit(amount);
System.out.printf("存款成功!当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("存款", amount);
}
private static void withdraw() {
System.out.println("\n===== 取款操作 =====");
System.out.print("请输入取款金额: ");
double amount = getDoubleInput(0.01, currentAccount.getBalance());
if (currentAccount.withdraw(amount)) {
System.out.printf("取款成功!当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("取款", -amount);
} else {
System.out.println("取款失败,余额不足!");
}
}
private static void transfer() {
System.out.println("\n===== 转账操作 =====");
System.out.print("请输入目标账户卡号: ");
String targetCardNumber = scanner.nextLine();
if (!accounts.containsKey(targetCardNumber)) {
System.out.println("目标账户不存在!");
return;
}
if (targetCardNumber.equals(currentAccount.getCardNumber())) {
System.out.println("不能转账给自己!");
return;
}
System.out.print("请输入转账金额: ");
double amount = getDoubleInput(0.01, currentAccount.getBalance());
BankAccount targetAccount = accounts.get(targetCardNumber);
if (currentAccount.withdraw(amount)) {
targetAccount.deposit(amount);
System.out.printf("转账成功!向 %s 转账 ¥%.2f%n",
targetAccount.getHolderName(), amount);
System.out.printf("当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("转出到 " + targetAccount.getHolderName(), -amount);
targetAccount.logTransaction("从 " + currentAccount.getHolderName() + " 转入", amount);
} else {
System.out.println("转账失败,余额不足!");
}
}
private static void showTransactionHistory() {
System.out.println("\n===== 交易记录 =====");
System.out.println("时间\t\t\t操作\t\t金额\t\t余额");
for (Transaction t : currentAccount.getTransactionHistory()) {
System.out.printf("%s\t%s\t\t%s\t%.2f%n",
t.getTimestamp(),
t.getDescription(),
t.getAmount() >= 0 ? "+" + t.getAmount() : t.getAmount(),
t.getBalanceAfter());
}
}
private static void changePin() {
System.out.println("\n===== 修改密码 =====");
System.out.print("请输入当前密码: ");
String currentPin = scanner.nextLine();
if (!currentAccount.getPin().equals(currentPin)) {
System.out.println("当前密码错误!");
return;
}
System.out.print("请输入新密码: ");
String newPin = scanner.nextLine();
System.out.print("请再次输入新密码: ");
String confirmPin = scanner.nextLine();
if (!newPin.equals(confirmPin)) {
System.out.println("两次输入的密码不一致!");
return;
}
currentAccount.setPin(newPin);
System.out.println("密码修改成功!");
logTransaction("修改密码");
}
// 获取整数输入
private static int getIntInput(int min, int max) {
while (true) {
try {
int input = Integer.parseInt(scanner.nextLine());
if (input >= min && input <= max) {
return input;
}
System.out.printf("请输入%d-%d之间的数字: ", min, max);
} catch (NumberFormatException e) {
System.out.print("无效输入,请重新输入: ");
}
}
}
// 获取浮点数输入
private static double getDoubleInput(double min, double max) {
while (true) {
try {
double input = Double.parseDouble(scanner.nextLine());
if (input >= min && input <= max) {
return input;
}
System.out.printf("请输入%.2f-%.2f之间的金额: ", min, max);
} catch (NumberFormatException e) {
System.out.print("无效输入,请重新输入: ");
}
}
}
在本项目中,我们使用了Java集合框架中的两个重要接口:
Map接口:HashMap
用于存储账户信息
private static Map accounts = new HashMap<>();
List接口:ArrayList
用于存储交易记录
private static List transactionHistory = new ArrayList<>();
封装:将数据和操作数据的方法封装在类中
单一职责原则:每个类只负责一个功能领域
开闭原则:对扩展开放,对修改关闭
当前系统使用内存存储数据,程序退出后数据会丢失。可以改进为:
使用文件存储账户和交易数据
使用数据库(如MySQL)存储数据
实现序列化/反序列化机制
开发服务器端处理业务逻辑
客户端通过网络与服务器通信
使用Socket或RESTful API实现
使用synchronized
关键字保护共享资源
使用并发集合如ConcurrentHashMap
实现线程安全的数据访问
检查数值范围
处理格式异常
防止SQL注入(如果使用数据库)
通过这个ATM模拟系统项目,你已经接触到了Java编程的许多核心概念。接下来可以:
学习Java Web开发(Servlet, JSP, Spring框架)
探索Java网络编程
研究多线程和并发编程
了解设计模式和架构思想
附录:完整ATM系统代码
import java.util.*;
import java.time.*;
import java.time.format.*;
public class AdvancedATM {
// 账户信息存储
private static Map accounts = new HashMap<>();
// 交易历史记录
private static List transactionHistory = new ArrayList<>();
// 当前登录账户
private static BankAccount currentAccount = null;
// 日期时间格式化
private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 输入扫描器
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
initializeAccounts(); // 初始化测试账户
while (true) {
if (currentAccount == null) {
showLoginMenu();
} else {
showMainMenu();
}
}
}
// 初始化测试账户
private static void initializeAccounts() {
accounts.put("123456", new BankAccount("123456", "1111", "张三", 5000.0));
accounts.put("654321", new BankAccount("654321", "2222", "李四", 10000.0));
}
// 登录菜单
private static void showLoginMenu() {
System.out.println("\n===== ATM 登录系统 =====");
System.out.println("1. 登录账户");
System.out.println("2. 退出系统");
System.out.print("请选择: ");
int choice = getIntInput(1, 2);
switch (choice) {
case 1:
login();
break;
case 2:
System.out.println("感谢使用ATM系统,再见!");
System.exit(0);
}
}
// 主菜单
private static void showMainMenu() {
System.out.println("\n===== ATM 主菜单 =====");
System.out.println("1. 查询余额");
System.out.println("2. 存款");
System.out.println("3. 取款");
System.out.println("4. 转账");
System.out.println("5. 交易记录");
System.out.println("6. 修改密码");
System.out.println("7. 退出账户");
System.out.print("请选择: ");
int choice = getIntInput(1, 7);
switch (choice) {
case 1:
checkBalance();
break;
case 2:
deposit();
break;
case 3:
withdraw();
break;
case 4:
transfer();
break;
case 5:
showTransactionHistory();
break;
case 6:
changePin();
break;
case 7:
logout();
break;
}
}
// 登录功能
private static void login() {
System.out.println("\n===== 账户登录 =====");
System.out.print("请输入卡号: ");
String cardNumber = scanner.nextLine();
System.out.print("请输入密码: ");
String pin = scanner.nextLine();
if (accounts.containsKey(cardNumber)) {
BankAccount account = accounts.get(cardNumber);
if (account.getPin().equals(pin)) {
currentAccount = account;
System.out.println("登录成功!欢迎," + account.getHolderName());
logTransaction("登录系统");
} else {
System.out.println("密码错误!");
}
} else {
System.out.println("卡号不存在!");
}
}
// 查询余额
private static void checkBalance() {
System.out.println("\n===== 账户余额 =====");
System.out.printf("当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("查询余额");
}
// 存款功能
private static void deposit() {
System.out.println("\n===== 存款操作 =====");
System.out.print("请输入存款金额: ");
double amount = getDoubleInput(0.01, 10000.00);
currentAccount.deposit(amount);
System.out.printf("存款成功!当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("存款", amount);
}
// 取款功能
private static void withdraw() {
System.out.println("\n===== 取款操作 =====");
System.out.print("请输入取款金额: ");
double amount = getDoubleInput(0.01, currentAccount.getBalance());
if (currentAccount.withdraw(amount)) {
System.out.printf("取款成功!当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("取款", -amount);
} else {
System.out.println("取款失败,余额不足!");
}
}
// 转账功能
private static void transfer() {
System.out.println("\n===== 转账操作 =====");
System.out.print("请输入目标账户卡号: ");
String targetCardNumber = scanner.nextLine();
if (!accounts.containsKey(targetCardNumber)) {
System.out.println("目标账户不存在!");
return;
}
if (targetCardNumber.equals(currentAccount.getCardNumber())) {
System.out.println("不能转账给自己!");
return;
}
System.out.print("请输入转账金额: ");
double amount = getDoubleInput(0.01, currentAccount.getBalance());
BankAccount targetAccount = accounts.get(targetCardNumber);
if (currentAccount.withdraw(amount)) {
targetAccount.deposit(amount);
System.out.printf("转账成功!向 %s 转账 ¥%.2f%n",
targetAccount.getHolderName(), amount);
System.out.printf("当前余额: ¥%.2f%n", currentAccount.getBalance());
logTransaction("转出到 " + targetAccount.getHolderName(), -amount);
targetAccount.logTransaction("从 " + currentAccount.getHolderName() + " 转入", amount);
} else {
System.out.println("转账失败,余额不足!");
}
}
// 显示交易记录
private static void showTransactionHistory() {
System.out.println("\n===== 交易记录 =====");
System.out.println("时间\t\t\t操作\t\t金额\t\t余额");
for (Transaction t : currentAccount.getTransactionHistory()) {
System.out.printf("%s\t%s\t\t%s\t%.2f%n",
t.getTimestamp(),
t.getDescription(),
t.getAmount() >= 0 ? "+" + t.getAmount() : t.getAmount(),
t.getBalanceAfter());
}
}
// 修改密码
private static void changePin() {
System.out.println("\n===== 修改密码 =====");
System.out.print("请输入当前密码: ");
String currentPin = scanner.nextLine();
if (!currentAccount.getPin().equals(currentPin)) {
System.out.println("当前密码错误!");
return;
}
System.out.print("请输入新密码: ");
String newPin = scanner.nextLine();
System.out.print("请再次输入新密码: ");
String confirmPin = scanner.nextLine();
if (!newPin.equals(confirmPin)) {
System.out.println("两次输入的密码不一致!");
return;
}
currentAccount.setPin(newPin);
System.out.println("密码修改成功!");
logTransaction("修改密码");
}
// 退出账户
private static void logout() {
System.out.println("\n正在退出账户...");
logTransaction("退出系统");
currentAccount = null;
}
// 记录交易
private static void logTransaction(String description) {
logTransaction(description, 0);
}
private static void logTransaction(String description, double amount) {
Transaction t = new Transaction(
LocalDateTime.now().format(dtf),
description,
amount,
currentAccount.getBalance()
);
currentAccount.addTransaction(t);
transactionHistory.add(t);
}
// 获取整数输入
private static int getIntInput(int min, int max) {
while (true) {
try {
int input = Integer.parseInt(scanner.nextLine());
if (input >= min && input <= max) {
return input;
}
System.out.printf("请输入%d-%d之间的数字: ", min, max);
} catch (NumberFormatException e) {
System.out.print("无效输入,请重新输入: ");
}
}
}
// 获取浮点数输入
private static double getDoubleInput(double min, double max) {
while (true) {
try {
double input = Double.parseDouble(scanner.nextLine());
if (input >= min && input <= max) {
return input;
}
System.out.printf("请输入%.2f-%.2f之间的金额: ", min, max);
} catch (NumberFormatException e) {
System.out.print("无效输入,请重新输入: ");
}
}
}
}
// 银行账户类
class BankAccount {
private String cardNumber;
private String pin;
private String holderName;
private double balance;
private List transactionHistory;
public BankAccount(String cardNumber, String pin, String holderName, double balance) {
this.cardNumber = cardNumber;
this.pin = pin;
this.holderName = holderName;
this.balance = balance;
this.transactionHistory = new ArrayList<>();
}
// 存款
public void deposit(double amount) {
this.balance += amount;
}
// 取款
public boolean withdraw(double amount) {
if (amount > balance) {
return false;
}
this.balance -= amount;
return true;
}
// 添加交易记录
public void addTransaction(Transaction t) {
transactionHistory.add(t);
}
// Getter方法
public String getCardNumber() { return cardNumber; }
public String getPin() { return pin; }
public String getHolderName() { return holderName; }
public double getBalance() { return balance; }
public List getTransactionHistory() { return transactionHistory; }
// Setter方法
public void setPin(String pin) { this.pin = pin; }
}
// 交易记录类
class Transaction {
private String timestamp;
private String description;
private double amount;
private double balanceAfter;
public Transaction(String timestamp, String description, double amount, double balanceAfter) {
this.timestamp = timestamp;
this.description = description;
this.amount = amount;
this.balanceAfter = balanceAfter;
}
// Getter方法
public String getTimestamp() { return timestamp; }
public String getDescription() { return description; }
public double getAmount() { return amount; }
public double getBalanceAfter() { return balanceAfter; }
}