领取优惠


Java ATM机自动取款机毕业设计:从零实现一个高仿真的银行终端系统

大三那年,我也被“ATM 模拟系统”支配过:界面一跑就崩、余额能取成负数、多线程下同一账户被刷爆,答辩现场尴尬到脚趾抠地。
本笔记把踩过的坑一次性打包,带你用纯 Java SE(零框架)写出一个能跑、能看、还能防“熊孩子”的银行终端,毕业设计直接提档。

atm


一、学生项目常见“车祸”现场

  1. 逻辑漏洞

    • 取款只判断 if (money <= balance),忘了负数,结果输入 -1000,余额反涨。
    • 存款写 balance += money 后,直接打印成功,中途宕机钱就凭空消失。
  2. 安全“纸糊”

    • 卡号、密码硬编码在 main 方法,一改需求全文件搜索。
    • 多线程场景下,两个窗口同时扣款,出现“并发超支”,老师一按 F5 现场翻车。
  3. 演示“社死”

    • 控制台 Scanner 读字符串,空格一多就抛 InputMismatchException,现场重启。
    • 没有交易记录,老师问“怎么追溯?”——只能尴尬微笑。

二、技术选型:为什么只用 Java SE

方案 优点 缺点(对学生)
Java SE + 文件 语法点全覆盖,轻量,单 jar 跑 自己写序列化,IO 异常多
Spring Boot + MySQL 企业级,简历好看 配置能把新手劝退,答辩时间全调 XML
JavaFX + SQLite 界面好看 要学 UI 线程,答辩现场分辨率一变就错位

结论:毕业设计核心在“业务逻辑 + 编码规范”,Java SE 足够,把 OO、异常、并发、集合、IO 五个考点串起来就能拿高分。


三、核心实现:三张类图跑通全场

1. 账户类(Account)——只做数据,不干业务
public final class Account {
    private final String cardId;          // 卡号,final 防篡改
    private final String pin;             // 6 位密码,明文仅 Demo
    private BigDecimal balance = BigDecimal.ZERO;

    public boolean validatePin(String input) { return pin.equals(input); }

    // 余额变动统一入口,synchronized 保证线程安全
    public synchronized boolean changeBalance(BigDecimal delta) {
        BigDecimal newVal = balance.add(delta);
        if (newVal.compareTo(BigDecimal.ZERO) < 0) return false;
        balance = newVal;
        return true;
    }
    // 省略 getter / toString
}

要点

  • BigDecimal 解决 double 精度坑。
  • synchronized 直接加在对象级,毕业设计场景够用,后续可升级 ReentrantLock
2. ATM 控制器(AtmController)——流程门面
public class AtmController {
    private final Map<String, Account> accountDB = new HashMap<>();
    private final Deque<Transaction> logQueue = new ArrayDeque<>();

    public Session login(String cardId, String pin) {
        Account acc = accountDB.get(cardId);
        if (acc == null || !acc.validatePin(pin))
            throw new SecurityException("卡号或密码错误");
        return new Session(acc);   // 每次登录新建会话
    }

    public void withdraw(Session s, BigDecimal amount) {
        validateAmount(amount);
        if (!s.getAccount().changeBalance(amount.negate()))
            throw new IllegalArgumentException("余额不足");
        log(new Transaction(s.getCardId(), "WITHDRAW", amount));
    }

    private static void validateAmount(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0)
            throw new IllegalArgumentException("金额必须为正");
    }
    // 其余 deposit、queryBalance、getLogs 同理
}

要点

  • 所有业务走控制器,不暴露 Account 引用,防止外部直接改余额。
  • 交易日志先写内存队列,演示时可 flush 到文件,体现“持久化”思想。
3. 交易记录(Transaction)——值对象,不可变
public record Transaction(String cardIdoka, String type,
                          BigDecimal amount, LocalDateTime ts) {
    public Transaction(String cardId, String type, BigDecimal amount) {
        this(cardId, type, amount, LocalDateTime.now());
    }
}

record 一行写完,天然线程安全、toString/json 都省心。


四、Clean Code 示例:一个完整取款流程

// 客户端代码,main 方法片段
1. 读卡号、密码  
2. 调用 AtmController.login → 拿到 Session  
3. 循环菜单:  
   3.1 选 1 查询 → controller.queryBalance(session)  
   3.2 选 2 取款 →  
       - 控制台读金额 → new BigDecimal(input)  
       - controller.withdraw(session, amount)  
       - 打印“出钞口请取走现金 ¥xxx”  
   3.3 选 3 退卡 → break,session 失效  

每个方法 < 20 行,拒绝“一大坨 main”。


五、安全性 & 健壮性 checklist

  1. 输入校验

    • 金额必须 > 0,正则 \d{1,8}(\.\d{0,2})? 防字母。
    • 密码连续输错 3 次锁定卡号,用 AtomicInteger 计数。
  2. 并发安全

    • Account.changeBalance 已同步;
    • 控制器里再加一层 synchronized (account) 双保险,演示时老师拿 JMeter 多线程刷也稳。
  3. 异常链

    • 业务抛 IllegalArgumentException,最外层统一 catch 打印“友好提示”,堆栈留 log 文件,老师问“怎么排错?”直接翻日志。
  4. 边界用例

    • 余额 0 元取 1 分 → 提示“余额不足”。
    • 输入 0.333 → 精度截断到分,BigDecimal.setScale(2, HALF_UP)。

六、生产环境避坑指南(毕业级也适用)

  1. 拒绝硬编码

    • 卡号、密码放 config.properties,用 Properties 类加载。
    • 每日限额、单笔限额也抽出来,老师问“怎么改限额?”改配置即可。
  2. 日志不能 System.out.println

    • 引入 java.util.logginglogback-core(纯 JavaSE 也能用),一行 LOG.log(Level.INFO, "withdraw {0} by {1}", new Object[]{amount, cardId}); 逼格瞬间满。
  3. 线程中断别吞

    • 文件刷盘时 Thread.sleep(500) 必须包 try{...} catch (InterruptedException e){ Thread.currentThread().interrupt(); },老师问“中断信号怎么处理?”答得上口。
  4. 资源关闭

    • 读写文件用 try-with-resources,自动关流,省得答辩时被问“内存泄漏怎么办?”

七、可扩展方向(把答辩老师问倒)

  1. 转账功能

    • 控制器新增 transfer(Session from, String toCardId, BigDecimal amount)事务性使用 synchronized (fromAccount) { synchronized (toAccount) { ... } },注意顺序防死锁。
  2. PIN 加密

    • 密码存 BCrypt 哈希,登录时 BCrypt.checkpw(input, hashed);引入 jbcrypt 单 jar 即可。
  3. 持久化存储

    • 账户快照用 ObjectOutputStreamaccounts.dat,启动时 readObject 恢复;
    • 交易流水追加写 CSV,演示完直接 Excel 打开,老师直呼专业。
  4. 图形界面

    • 学完 JavaSE 后可平滑迁移 JavaFX,控制器层零改动,只换 UI 交互,体现“前后端分离”思想。

八、打包 & 演示小技巧

  • maven-assembly-plugin 一键打可执行 jar:java -jar atm.jar 直接跑,教室电脑没 IDEA 也能秀。
  • 提前录屏 2 分钟,现场万一投影挂掉,放视频保底。
  • 把“多线程扣款”脚本也带上,老师想看并发效果时当场跑,稳。

九、小结:从“能跑”到“能吹”

把 Account 做成不可变数据 + 同步写余额,Controller 当门面统一校验,Transaction 用记录对象把日志串起来,一套组合拳下来,代码量不到 800 行,却覆盖了 OO、并发、异常、IO、集合五大考点。答辩时老师问“如果余额字段被反射改掉怎么办?”你还能笑着接茬“可以加 SecurityManager 或者把 balance 放 AtomicReference 里 CAS 保证。”——毕业设计直接优秀。

下一步,不妨给系统加上转账、加密和数据库,把它当成真正的“迷你银行”练手项目。祝你一次通过,早日把键盘收入囊中!

领取优惠


Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐