ATM柜员机模拟系统Java课设:Swing与MyBatis实战

发布时间:2026/10/24 21:12:50
ATM柜员机模拟系统Java课设:Swing与MyBatis实战 简介这是一份完整的JAVA课程设计报告——ATM柜员机模拟系统适合Java初学者及高校学生完成课程设计时参考。报告围绕用户登录、账户查询、存款、取款、更改密码等核心功能从需求分析、实验目的、功能图到界面设计与功能实现逐层展开重点剖析了数据管理、界面布局、安全机制和异常处理等重难点并附有取钱/存钱关键代码、逻辑校验及SQL语句帮助读者掌握Java面向对象编程、Swing图形界面开发和数据库交互的实际应用。压缩包内为1个docx文档大小1.21MB内含实验目的、功能分析、重难点剖析、功能图、窗口切换与功能界面说明等完整章节结构清晰便于直接查阅和修改。目前已有387人学习下载可快速了解ATM模拟系统的完整设计思路用于课程设计、毕业设计参考或Java综合实践复习。1. 选题先看需求ATM柜员机模拟系统为什么值得做成Java课设做Java课程设计的人十个里有八个会先想到管理系统图书管理、学生管理、成绩管理一拉表格铺一铺就完事。ATM柜员机模拟系统这个题看着不新鲜但它是少数能把Java核心能力全串起来的选题Swing做界面、事件驱动做交互、MyBatis做持久化、业务校验做严谨性。这篇方案面向正在做这个课设的人按需求分析、界面设计、功能实现、避坑排查、验收答辩的顺序讲透照着这套结构写报告、搭代码、应付答辩都够用。无论你是初次接触Java的在校生还是想快速出一套可演示课设方案的开发者把需求先立住后面每一步都不会白做。2. 需求分析与总体架构六个核心模块和三层设计的拆分思路2.1 实验目的与课程考核点这门课设到底在考什么ATM柜员机模拟系统的课程设计报告开篇需求分析经常写得很笼统一句“模拟真实ATM功能”就带过了。但你要搞清楚老师评审这门课设时看的是几件事能不能用Java写出完整的面向对象程序懂不懂GUI开发的基本套路有没有基本的软件工程意识。素材里的实验目的其实拆得很清楚第一条是掌握Java基本语法和面向对象思想这条对应的就是类的划分和封装第二条是熟悉Swing框架和GUI开发对应的是窗口、组件、事件处理第三条是软件设计基本原则模块化、抽象、信息隐藏第四条是解决实际问题能力第五条是团队协作。我把这五条对应成课设报告里的实际产出写需求分析的时候就不会空洞面向对象思想 → 代码里有没有抽象出用户、交易、业务服务这些类Swing框架 → 登录界面、主菜单、功能窗口的组件与事件软件工程概念 → 需求分析、设计、编码、测试的完整流程实际问题解决 → 校验、异常、数据持久化的处理团队协作 → 小组分工记录和任务拆解表需求分析部分如果只是抄功能列表答辩时老师一问“为什么这么设计”就卡壳。正确的做法是把每个需求对应到一个实际场景比如登录功能对应的是“卡号和密码输入后系统验证是否匹配”取款对应的是“先检查余额再扣款”。这样写出来的需求分析才有说服力。2.2 功能模块分析登录、查询、存取款、转账、改密的边界划分ATM柜员机模拟系统的主要功能素材里列得很明确用户登录、账户查询、存款、取款、修改密码、退出系统。转账功能在需求分析里被提到但在功能列表里没有单独列界面设计部分又说有转账窗口所以完整功能图应该包含转账模块。我在实际组织项目结构时会按功能边界把模块拆成这样模块功能点数据操作校验规则登录模块卡号密码验证查用户表非空、匹配查询模块显示当前余额查用户表无存款模块更新余额更新用户表非空、数值、整百取款模块扣减余额更新用户表非空、数值、整百、余额足转账模块转给指定卡号查询更新两个账户对方存在、金额合法、余额足改密模块验证原密码设置新密码更新用户表原密码正确、两次一致这个表不仅是功能分析也是后面数据库设计的基础。每个模块对应哪些SQL操作、需要哪些校验都是一目了然的。2.3 重难点优先级排序先界面还是先逻辑还是先数据素材里的1.3节列了七个重难点用户界面设计、账户管理和交易逻辑、数据持久化、异常处理和日志、性能优化、安全考虑、测试。课设时间有限不可能全部做深我一般会按这样的优先级排第一优先级是用户界面设计和交易逻辑。界面是门面老师打开程序第一眼看到的就是界面交易逻辑是核心存钱取钱的正确性决定系统能不能用。第二优先级是数据持久化数据要能存下来程序关了再开余额还在。第三优先级才是异常处理、日志、安全这些加分项。性能优化在课设场景里基本不用做单用户本地程序谈不上并发。安全方面密码加密存储可以提一下思路但课设里明文存储也能接受重点是让老师看到你有这个意识。测试放在最后但一定要做素材里明确提到了单元测试、集成测试和功能测试答辩时有测试记录会很加分。这样排完优先级你的开发计划就有了时间分配先做界面框架搭起来再做业务逻辑再接入数据库最后补测试和文档。不会出现做了两周发现方向错了的翻车情况。3. 界面设计与窗口切换Swing布局与CardLayout的落地写法3.1 登录界面与主菜单的事件驱动模型ATM柜员机模拟系统的界面结构很清晰素材里说了是1个主窗口加5个功能窗口主窗口用多个按钮做窗口切换。这里的关键设计是CardLayout布局管理器。为什么用CardLayout而不是直接new多个JFrame窗口这是课程设计里最常见的翻车点。如果用多个JFrame关闭一个窗口再打开另一个程序会有多个顶层窗口焦点管理和内存控制都很麻烦看起来也像多个互不相关的程序。用CardLayout的话所有界面都是一张牌切换就是翻牌状态共享简单很多。我一般会在主视图类里这样组织// 主窗口容器CardLayout负责页面切换 CardLayout cardLayout new CardLayout(); JPanel cardPanel new JPanel(cardLayout); cardPanel.add(loginPanel, 登录); cardPanel.add(menuPanel, 菜单); cardPanel.add(queryPanel, 查询); cardPanel.add(depositPanel, 存款); cardPanel.add(withdrawPanel, 取款); cardPanel.add(transferPanel, 转账); cardPanel.add(changePwdPanel, 改密);登录成功后的跳转逻辑就是通过cardLayout.show(contentPane, 菜单)来切页面。这里有一个设计要点所有功能面板都持有同一个CardLayout和Container的引用这样才能在任意子页面里触发跳转。素材里ChangeMoneyPanel的构造方法就传入了contentPane和cardLayout这正是为了在业务完成后能切回菜单页。3.2 功能界面的组件组织复用面板与背景绘制看素材里的ChangeMoneyPanel代码最有意思的设计是存款和取款共用了同一个面板通过构造参数type区分。这是典型的复用思路两个功能界面结构一模一样只有一个字不同没必要写两套相似的代码。这个面板的组件布局逻辑是一个提示标签、一个金额输入框、一个业务按钮“存入”或“取款”、一个返回按钮。提示文案通过type的第一个字动态拼接比如传入“存入”就显示“请输入存款金额”传入“取款”就显示“请输入取款金额”。这个细节很多人不注意把文案写死最后只能复制粘贴改文案。事件处理上两个按钮分别绑定了监听器业务按钮调用业务层方法弹窗显示结果成功则触发返回按钮返回按钮切回菜单页并清空输入框这里的页面残留问题要重点做切页之后必须清空文本输入框否则下次切回来旧数据还在用户会以为发生了什么灵异事件。背景绘制用了自定义paintComponent加载一张图片这是让课设界面脱离“白底灰按钮”廉价感最简单的方式。注意getResource的路径要放在resources目录下路径写错会在运行时报空指针这个问题后面避坑章节细说。3.3 功能界面细节查询、转账、改密的组件设计查询界面最简单一个标签加一个文本显示当前余额就够了。转账界面需要两个输入框加一个确认按钮对方卡号和转账金额。改密界面是三个密码框原密码、新密码、确认新密码必须用JPasswordField而不是JTextField否则密码明文显示答辩时容易被老师挑刺。每个功能界面上最好放一个统一的返回按钮并保持位置一致这个交互细节虽然简单但能让整个系统看起来像一个产品而不是一堆窗口拼凑。素材里每个面板都是手动setLayout(null)然后定坐标虽然不优雅但课设管够好处是布局完全可控坏处是窗口拉大后组件位置固定不做自适应。我建议做界面时先画一张草图把登录页、菜单页、五个功能页都标出来以及每个页面的跳转关系。这张草图放进课设报告的界面设计章节比贴一堆代码截图更直观老师一眼就能看懂你的设计思路。4. 功能实现与数据校验存取款逻辑、MyBatis映射与SQL设计4.1 存取款面板代码一个面板复用两种业务素材里给出了完整的ChangeMoneyPanel实现这是整个系统里最值得讲清楚的一段代码。我用它来说明组件布局、事件绑定和业务层调用的完整写法import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Objects; public class ChangeMoneyPanel extends JPanel { private final Image backgroundImage; public ChangeMoneyPanel(String type, Container contentPane, CardLayout cardLayout, MainView mainView) { setLayout(null); final String substring type.substring(0, 1); JLabel label new JLabel(请输入 substring 款金额,ATM机 substring 款必须是整百的); JLabel moneyLabel new JLabel(substring 款金额); final JTextField moneyText new JTextField(); JButton enterButton new JButton(type); final JButton backButton new JButton(返回); backgroundImage new ImageIcon(Objects.requireNonNull( getClass().getResource(/images/9602.gif_wh860.gif))).getImage(); label.setLocation(0, 30); label.setSize(700, 50); label.setForeground(Color.white); label.setFont(new Font(黑体, Font.BOLD, 30)); moneyLabel.setLocation(160, 150); moneyLabel.setSize(160, 50); moneyLabel.setForeground(Color.white); moneyLabel.setFont(new Font(黑体, Font.BOLD, 30)); moneyText.setLocation(310, 150); moneyText.setSize(250, 50); moneyText.setFont(new Font(黑体, Font.BOLD, 30)); enterButton.setLocation(150, 300); enterButton.setSize(180, 60); enterButton.setFont(new Font(黑体, Font.BOLD, 30)); backButton.setLocation(390, 300); backButton.setSize(180, 60); backButton.setFont(new Font(黑体, Font.BOLD, 30)); enterButton.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent e) { if (type.equals(存入)) { HandleServiceImpl handleService new HandleServiceImpl(); ResultBoolean booleanResult handleService.addMoney( mainView.currentId, moneyText.getText().trim()); JOptionPane.showMessageDialog(mainView, booleanResult.massage, 提示, JOptionPane.INFORMATION_MESSAGE); if (booleanResult.data) { backButton.doClick(); } } else { HandleServiceImpl handleService new HandleServiceImpl(); ResultBoolean booleanResult handleService.minusMoney( mainView.currentId, moneyText.getText().trim()); JOptionPane.showMessageDialog(mainView, booleanResult.massage, 提示, JOptionPane.INFORMATION_MESSAGE); if (booleanResult.data) { backButton.doClick(); } } } }); backButton.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent e) { mainView.setTitle(菜单); cardLayout.show(contentPane, 菜单); moneyText.setText(); } }); add(label); add(moneyLabel); add(moneyText); add(enterButton); add(backButton); } Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (backgroundImage ! null) { g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this); } } }这段代码的设计核心有三点。第一面板通过构造参数type区分业务存款和取款的界面与事件逻辑复用同一套代码这是面向对象里对复用的直观体现。第二业务成功后通过backButton.doClick()触发返回既完成了页面切换又保证了输入框被清空这个技巧比手动调用show再清空少写三行代码还顺手解决了状态残留问题。第三Result 封装统一了返回值结构data字段表示业务是否成功massage字段承载给用户看的提示信息界面层拿到这个对象直接弹窗不需要自己拼接提示文案。你可能会注意到按钮事件里每次new一个HandleServiceImpl这是从素材代码里原样拿来的。课程设计里这样写没问题但答辩被问到“为什么不复用同一个业务对象”时你要能解释业务服务内部维护了SqlSessionFactory每次操作都打开独立的SqlSession用完即关所以每次新建服务对象不会产生状态问题。4.2 业务逻辑校验层金额合法性检查的设计顺序业务层的逻辑校验是ATM课设的核心也是最能体现思路严谨性的部分。素材里addMoney和minusMoney方法的校验顺序值得仔细分析。Override public ResultBoolean addMoney(Long id, String money) { if (money.equals()) { return new ResultBoolean(不能为空, false); } if (!StringUtils.isStrictlyNumeric(money)) { return new ResultBoolean(含有非法字符, false); } if (Double.parseDouble(money) % 100 ! 0) { return new ResultBoolean(ATM中只支持百元大钞零钱请前往柜台领取, false); } SqlSession sqlSession sqlSessionFactory.openSession(); MysqlOperateMapper userMapper sqlSession.getMapper(MysqlOperateMapper.class); userMapper.addMoneyById(id, new BigDecimal(money)); sqlSession.commit(); sqlSession.close(); return new ResultBoolean(存款成功, true); } Override public ResultBoolean minusMoney(Long id, String money) { if (!StringUtils.isStrictlyNumeric(money)) { return new ResultBoolean(含有非法字符, false); } if (money.equals()) { return new ResultBoolean(不能为空, false); } if (Double.parseDouble(money) % 100 ! 0) { return new ResultBoolean(ATM中只支持百元大钞零钱请前往柜台领取, false); } SqlSession sqlSession sqlSessionFactory.openSession(); MysqlOperateMapper userMapper sqlSession.getMapper(MysqlOperateMapper.class); User user userMapper.selectById(id); if (user.getMoney().compareTo(new BigDecimal(money)) 0) { return new ResultBoolean(余额不足, false); } userMapper.minusMoneyById(id, new BigDecimal(money)); sqlSession.commit(); sqlSession.close(); return new ResultBoolean(取款成功, true); }校验顺序有讲究。存款方法先判空再判非法字符再判整百这个顺序是对的空字符串根本不会通过数字校验先查空能提前拦截非法字符检查用isStrictlyNumeric保证输入纯数字防止SQL注入和类型转换异常整百校验放在最后因为此时已经确定输入是合法数字取模运算不会出意外。取款方法里有个小问题先判非法字符再判空空字符串也会被isStrictlyNumeric拦截所以不会走到后面。但如果你把参数trim过的空串传进来StringUtils.isStrictlyNumeric对空串的返回值在不同版本里可能不一样稳妥的做法是统一先判空。我在自己的项目里会把两个方法的校验顺序统一成空值 → 非法字符 → 整百 → 余额逻辑更清晰也好记。余额不足的判断用compareTo而不是直接用比较运算符这是BigDecimal的正确用法。用或比较浮点数有精度问题素材里刻意写了注释说明compareTo的返回值语义这个做法值得保留。金额落库时也全部转成BigDecimal这是金融场景的基本素养。4.3 SQL与数据持久化Mapper层的更新操作与事务控制数据持久化部分用的是MyBatis框架映射器里写SQL更新数据库。素材里给了两条SQL实现存款和取款的核心数据操作update idaddMoneyById update tb_user set money money #{money} where id #{id} /update update idminusMoneyById update tb_user set money money - #{money} where id #{id} /update这两条SQL是典型的原子更新写法。注意update语句中money money #{money}这个写法是在数据库端做金额累加而不是先查出余额、在Java里计算、再更新回数据库。这样的好处是避免了并发场景下丢失更新虽然课设里不会真遇到并发但答辩时能说出“用数据库端原子更新避免并发问题”会让老师觉得你有工程意识。存储过程或者触发器在这个系统里用不上MyBatis加Mapper已经够了。SqlSessionFactory应该做成单例整个应用只创建一个避免反复建立数据库连接造成的资源浪费。每次业务操作打开一个SqlSession操作完必须commit再close这两步缺一不可。素材里还有一个细节值得学习更新之前严格校验但校验失败的方法已经在commit之前return了所以不会留下未提交的半成品事务。转账功能在SQL层面的设计会更复杂一点需要先查目标账户是否存在再同时扣减转出方余额和增加转入方余额。这个操作要放到同一个事务里任何一步失败都要回滚保证两边资金不变。课设里可以实现一个transfer方法用sqlSession控制事务边界这是比存款取款更锻炼人的模块。4.4 异常处理与日志金融场景下的容错思路ATM系统是金融场景异常处理不能只靠try-catch把错误吞掉。素材里没有详细展开异常处理但需求分析明确提到了“完善的异常处理机制”和“详细的日志记录功能”这是课设报告的加分点。我通常会这样处理业务层代码里数据库操作部分包一层try-catch捕获异常后回滚事务并返回一个包含错误信息的Result对象。界面层不直接处理SQL异常只展示Result里的信息。SqlSession在finally块里关闭避免连接泄漏。日志方面不需要引入log4j这样的大框架用System.out打印关键操作路径加一个简单的时间戳足以应付课设的日志要求。一个值得注意的容错点是用户输入金额后点击按钮如果业务层抛出未捕获异常程序会直接闪退。所以赶在业务代码之前先在按钮事件里对输入框内容做一次trim和长度检查超过10位数字的金额直接提示“金额过大”把异常拦截在业务代码之外。这个处理能让程序在大多数异常输入下都稳定运行演示的时候不会当场翻车。5. 常见问题与避坑排查ATM模拟系统五个最易翻车的点5.1 金额计算用Double导致精度丢失现象存了100元再存0.1元查余额显示200.09999999999总数不对。原因浮点数在计算机底层用二进制表示0.1这类十进制小数无法精确表示累加必然产生误差。金融场景必须用精确十进制运算。解决金额从用户输入到数据库存储全程用BigDecimalSQL层面的累加用money #{money}数据库端操作禁用Double和float。注意BigDecimal之间比较用compareTo不要用equals因为equals还比较精度位数比较结果可能与直觉不符。5.2 MyBatis事务未提交导致数据不更新现象点击“存入”弹窗显示“存款成功”返回菜单再查余额数字没变。重启程序后数据也没变。原因MyBatis默认事务不会自动提交执行update之后如果漏了sqlSession.commit()数据只停留在内存里SqlSession关闭时未提交的更改被丢弃。解决每个业务方法里执行Mapper方法后必须立刻commit最后再close。我习惯把这个流程固定成模板先openSession然后try-finally包裹业务操作success则commitcatch到异常则rollbackfinally里close。把这个模板背熟基本不会出现这种翻车。5.3 图片资源路径写错导致空指针现象程序启动白屏或直接抛NullPointerException堆栈指向ImageIcon那一行。原因getClass().getResource(images/xxx.gif)找不到资源返回nullnew ImageIcon(null)不会报错但Image.getImage()返回nullpaintComponent里drawImage直接抛NPE。解决资源文件放到src/main/resources目录下路径写/images/xxx.gif注意斜杠表示classpath根路径。不要用相对路径因为相对路径依赖当前工作目录用IDE和打包成jar时行为不一致。如果程序在启动时加载所有面板资源路径错误会导致窗口都弹不出来所以这个错误越早暴露越好。5.4 输入校验顺序颠倒导致误判现象输入“”空字符串提示“含有非法字符”输入“-50”提示“非法字符”输入“50.5元”提示“非法字符”。提示语与用户预期不符。原因isStrictlyNumeric要求字符串全部是数字连小数点都不接受所以带小数点的金额会被判为非法字符。但用户输入“50.5”时提示“非法字符”不如提示“只支持百元大钞”直观。校验顺序决定了错误提示的优先级。解决统一校验顺序先判空值给出“不能为空”再判格式给出“金额必须为数字”最后判整百给出“该ATM只支持百元面额”。每个校验分支独立返回不要合并判断条件这样提示信息对用户更友好面对答辩追问时也能说清楚。5.5 转账时对方账户不存在导致系统崩溃现象输入不存在的卡号转账点击确认程序抛出异常界面卡死。原因转账逻辑里先查目标账户没判断查询结果是否为null就继续操作或者SQL层面做了关联查询但映射结果为空。这属于防御性编程缺失。解决在转账方法里先查目标账户返回null时直接回滚事务并返回“对方账户不存在”。任何从数据库查出来的对象都可能是null养成先判空再操作的习惯这类崩溃就能避免。改密模块同理查不到当前用户时也要处理不能默认用户一定存在。6. 测试用例与答辩准备这样验收你的课设才站得住6.1 按功能模块设计测试用例测试部分是需求分析里明确要求的不能只写一句“测试通过”。我在课设里会准备一张测试用例表每个功能模块列三到五条用例覆盖正常路径和异常路径模块输入预期结果实测是否一致登录正确卡号正确密码跳转主菜单显示用户名是登录正确卡号错误密码提示“密码错误”是登录空卡号或空密码提示“不能为空”是存款输入1000提示“存款成功”余额加1000是存款输入150提示“只支持百元大钞”是取款余额充足时取100提示“取款成功”余额减100是取款余额不足时取10000提示“余额不足”是转账输入存在的卡号提示“转账成功”双方余额更新是转账输入不存在的卡号提示“对方账户不存在”是改密原密码正确且两次一致提示“修改成功”旧密码失效是改密原密码错误提示“原密码错误”是改密两次新密码不一致提示“两次密码不一致”是答辩时可以现场演示这张表里的几条用例边操作边解说预期结果和实际结果。最好选择一条异常路径来演示比如余额不足因为正常路径任何人看一眼代码都会写异常路径才能体现边界考虑。6.2 答辩演示的四个加分技巧答辩时间通常只有五到十分钟演示顺序比内容顺序重要。我建议按“登录 → 查询 → 存款 → 取款 → 转账 → 改密”的操作用例走一遍每切换一个模块时解释窗口跳转的实现方式重点在存款和取款的校验逻辑处停下来说两句不用长篇大论。第二个技巧是提前准备好数据库截图。答辩现场最怕数据库连接失败或数据被改乱一张存有测试数据的MySQL截图放在报告附录里既能证明数据持久化真实可用又能防止现场环境翻车。第三个技巧是准备一张功能图和一张架构图。功能图对应需求分析章节的图1-1架构图对应三层结构Swing界面层、业务逻辑层、MyBatis数据访问层。答辩老师问“系统怎么组织的”时直接把架构图拿出来讲比临场翻代码有说服力得多。第四个技巧是熟悉自己的代码。我见过最惨的答辩现场是同学自己写的代码被老师追问到某个方法逻辑时反应半天。你至少要吃透存款和取款这两段代码的每一行因为那是素材里唯一给出完整代码的模块也是演示中老师最可能追问的地方。这次课设做完后我发现表面看是做一个ATM模拟系统实际练的是需求分析怎么落到代码、界面复用怎么设计、校验顺序怎么排列、事务边界怎么控制。从那以后我每做一个Java项目都强制自己先写一张功能模块表再动代码宁可多花半小时理清边界也不在写代码时反复返工。希望这份方案能帮你在课程设计和答辩时少踩几个坑把功夫花在真正加分的地方。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询