新手向:实现ATM模拟系统

本教程将通过一个完整的ATM模拟系统项目,带你深入了解Java的核心概念和实际应用。

这个ATM系统将涵盖以下功能:

7.2 图形用户界面

使用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);
    }
}

7.3 多语言支持

使用资源束实现国际化:

复制代码
import java.util.Locale;
import java.util.ResourceBundle;

ResourceBundle bundle = ResourceBundle.getBundle("Messages", Locale.CHINA);
String welcomeMessage = bundle.getString("welcome");

7.4 网络功能

将ATM系统改为客户端-服务器架构:

第八章:常见问题与调试技巧

8.1 并发访问问题

如果多个用户同时访问,需要考虑:

8.3 异常处理

完善异常处理机制:

复制代码
try {
    // 可能出错的代码
} catch (SpecificException e) {
    // 特定异常处理
} catch (Exception e) {
    // 通用异常处理
} finally {
    // 清理资源
}

结语:Java学习的进阶

8.2 输入验证

确保所有用户输入都经过验证:

  • 用户登录验证

  • 账户余额查询

  • 存款和取款操作

  • 账户间转账

  • 交易记录查询

  • 密码修改功能


    第一章:项目概述与环境搭建

    1.1 ATM系统功能分析

    我们的ATM模拟系统需要实现以下核心功能:

  • 用户认证:通过卡号和密码验证用户身份

  • 账户管理:包括存款、取款、转账等操作

  • 交易记录:记录所有交易操作并支持查询

  • 安装JDK(建议JDK 8或更高版本)

  • 选择开发工具(IntelliJ IDEA、Eclipse或VS Code)

  • 创建Java项目

    • 新建一个名为AdvancedATM的Java类

    • 创建两个辅助类:BankAccountTransaction

  • 密码管理:允许用户修改密码

  • 数据持久化:虽然本示例使用内存存储,但了解数据库连接也很重要

    1.2 开发环境准备

    与前面的验证码程序一样,我们需要:

  • 安装JDK(建议JDK 8或更高版本)

  • 选择开发工具(IntelliJ IDEA、Eclipse或VS Code)

  • 创建Java项目

    • 新建一个名为AdvancedATM的Java类

    • 创建两个辅助类:BankAccountTransaction

第二章:核心类与数据结构设计

2.1 BankAccount类 - 银行账户模型

复制代码
  class BankAccount {
      private String cardNumber;  // 卡号
      private String pin;         // 密码
      private String holderName;  // 持卡人姓名
      private double balance;     // 账户余额
      private List<Transaction> 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方法...
  }

2.2 Transaction类 - 交易记录模型

复制代码
  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方法...
  }

2.3 主类AdvancedATM的设计

主类负责整个系统的流程控制,包含以下关键组件:

  • 账户存储 :使用Map存储所有银行账户

  • 交易记录 :使用List存储所有交易

  • 当前账户:跟踪当前登录的用户

  • 日期格式化:统一交易时间格式

  • 输入扫描器:处理用户输入

    复制代码
    private static void initializeAccounts() {
        accounts.put("123456", new BankAccount("123456", "1111", "张三", 5000.0));
        accounts.put("654321", new BankAccount("654321", "2222", "李四", 10000.0));
    }

    3.2 登录菜单实现

    复制代码
    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);
        }
    }

    3.3 主菜单实现

    复制代码
    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分支...
        }
    }

    第四章:核心功能实现

    4.1 用户登录功能

    复制代码
    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("卡号不存在!");
        }
    }

    4.2 存款功能实现

    复制代码
    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);
    }

    4.3 取款功能实现

    复制代码
    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("取款失败,余额不足!");
        }
    }

    4.4 转账功能实现

    复制代码
    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("转账失败,余额不足!");
        }
    }

    第五章:辅助功能实现

    5.1 交易记录功能

    复制代码
    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());
        }
    }

    5.2 密码修改功能

    复制代码
    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("修改密码");
    }

    5.3 输入验证工具方法

    复制代码
    // 获取整数输入
    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概念应用

    6.1 集合框架的使用

    在本项目中,我们使用了Java集合框架中的两个重要接口:

  • Map接口HashMap用于存储账户信息

    复制代码
    private static Map<String, BankAccount> accounts = new HashMap<>();
  • List接口ArrayList用于存储交易记录

    复制代码
    private static List<Transaction> transactionHistory = new ArrayList<>();
  • 封装:将数据和操作数据的方法封装在类中

  • 单一职责原则:每个类只负责一个功能领域

  • 开闭原则:对扩展开放,对修改关闭


    第七章:项目扩展与改进方向

    7.1 数据持久化

    当前系统使用内存存储数据,程序退出后数据会丢失。可以改进为:

  • 使用文件存储账户和交易数据

  • 使用数据库(如MySQL)存储数据

  • 实现序列化/反序列化机制

  • 开发服务器端处理业务逻辑

  • 客户端通过网络与服务器通信

  • 使用Socket或RESTful API实现

  • 使用synchronized关键字保护共享资源

  • 使用并发集合如ConcurrentHashMap

  • 实现线程安全的数据访问

  • 检查数值范围

  • 处理格式异常

  • 防止SQL注入(如果使用数据库)

结语:Java学习的进阶之路

通过这个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<String, BankAccount> accounts = new HashMap<>();
    // 交易历史记录
    private static List<Transaction> 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<Transaction> 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<Transaction> 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; }
}
相关推荐
s15335几秒前
C++STL-deque
开发语言·c++
此乃大忽悠2 分钟前
身份认证缺陷
java·数据库·webgoat·身份认证缺陷
Honyee12 分钟前
java使用UCanAccess操作Access
java·后端
Devil枫13 分钟前
Kotlin项目实战与总结
开发语言·jvm·kotlin
秋千码途13 分钟前
小架构step系列10:日志热更新
java·linux·微服务
她说人狗殊途16 分钟前
浅克隆 深克隆
java
timing99418 分钟前
SQLite3 中列(变量)的特殊属性
java·jvm·sqlite
SimonKing24 分钟前
你的Redis分布式锁还在裸奔?看门狗机制让锁更安全!
java·后端·程序员
yeziyfx30 分钟前
kotlin中集合的用法
android·开发语言·kotlin
你喜欢喝可乐吗?1 小时前
RuoYi-Cloud 验证码处理流程
java·spring cloud·微服务·vue