ATM系统练习
需求:设计ATM系统,能够完成基本的注册、登陆、查询、存款、取款、转账、修改密码、注销等基本功能。
ATM系统技术选型分析:
①面向对象编程:每个用户账户都是一个对象:所以需要设计账户类Account用于创建账户对象封装账户信息。
②使用集合容器:系统需要提供一个容器用于存储这些账户对象的信息,我们选ArrayList集合。
③程序流程控制:需要结合分支、循环、跳转关键字等相关操作控制程序的业务逻辑。
④使用常见API:登录信息的内容比较,业务数据的分析,处理等都需要用到String等常用API来解决。
一、系统准备、首页设计
系统准备内容分析:
① 每个用户的账户信息都是一个对象,需要提供账户类。
② 需要准备一个容器,用于存储系统全部账户对象信息。
③ 首页只需要包含:登录和注册2个功能。
实现步骤:
① 定义账户类,用于后期创建账户对象封装用户的账户信息。
② 账户类中的信息至少需要包含(卡号、姓名、密码、余额、取现额度)
③ 需要准备一个ArrayList的集合,用于存储系统用户的账户对象。
④ 需要展示欢迎页包含2个功能:注册功能、登录账户。
二、用户注册功能实现
用户注册功能分析:注册功能其实就是就是往系统的集合容器中存入一个新的账户对象的信息。
注册功能实现步骤:
① 定义方法完成注册
② 键盘录入姓名、密码、确认密码(需保证两次密码一致)、每次取款额度(最低1000元)
③ 生成账户卡号,卡号必须由系统自动生成8位数字(必须保证卡号的唯一)
注:注册账户方法内调用生成账号的方法,生成账号的方法内调用根据账号查询账户的方法,将各个需要重复使用且逻辑划分清晰的业务做成方法,等待调用。
④ 创建Account账户类对象用于封装账户信息(姓名、密码、卡号)
⑤ 把Account账户类对象存入到集合accounts中去。
三、用户登陆功能实现
用户登陆功能分析:
① 定义方法
② 让用户键盘录入卡号,根据卡号查询账户对象。
③ 如果没有找到了账户对象,说明卡号不存在,提示继续输入卡号。
④ 如果找到了账户对象,说明卡号存在,继续输入密码。
⑤ 如果密码不正确,提示继续输入密码
⑥ 如果密码正确,提示登陆成功!
四、用户操作页、查询账户、退出账户功能实现
用户操作页设计、查询账户、退出账户功能分析:
① 用户登录成功后,需要进入用户操作页。
② 查询就是直接展示当前登录成功的账户对象的信息。
③ 退出账户是需要回到首页的。
五、存款功能实现
存款功能分析:
① 存款就是拿到当前账户对象。
② 然后让用户输入存款的金额。
③ 调用账户对象的setMoney方法将账户余额修改成存钱后的余额。
④ 存钱后需要查询一下账户信息,确认是否存钱成功了!
六、取款功能实现
取款功能分析:
① 取款需要先判断账户是否有钱。
② 有钱则拿到自己账户对象。
③ 然后让用户输入取款金额
④ 判断取款金额是否超过了当次限额,以及余额是否足够
⑤ 满足要求则调用账户对象的setMoney方法完成金额的修改。
七、转账功能实现
转账功能分析:
① 转账功能需要判断系统中是否有2个账户对象及以上。
② 同时还要判断自己账户是否有钱。
③ 接下来需要输入对方卡号,判断对方账户是否存在。
④ 对方账户存在还需要认证对方户主的姓氏。
⑤ 满足要求则可以把自己账户对象的金额修改到对方账户对象中去。
八、密码修改、销户功能实现
密码修改、销户功能分析:
① 修改密码就是把当前对象的密码属性使用set方法进行更新。
② 销户是从集合对象中删除当前对象,并回到首页。
示例代码如下:
账户类
publicclassAccount { privateStringuserId; // 登陆账号privateStringuserName; // 用户名privateStringuserPassword; // 登陆密码privatedoublemoney; // 账户余额privatedoublequoteMoney; // 每次取款额度// 构造函数缺省为无参构造函数/*getter、setter方法*/publicStringgetUserId() { returnuserId; } publicvoidsetUserId(StringuserId) { this.userId=userId; } publicStringgetUserName() { returnuserName; } publicvoidsetUserName(StringuserName) { this.userName=userName; } publicStringgetUserPassword() { returnuserPassword; } publicvoidsetUserPassword(StringuserPassword) { this.userPassword=userPassword; } publicdoublegetMoney() { returnmoney; } publicvoidsetMoney(doublemoney) { this.money=money; } publicdoublegetQuoteMoney() { returnquoteMoney; } publicvoidsetQuoteMoney(doublequoteMoney) { this.quoteMoney=quoteMoney; } }
主程序
publicclassATMSystem { publicstaticvoidmain(String[] args) { // 1.定义账户类// 2.定义一个集合容器,负责存储全部的Account对象,完成相关业务操作ArrayList<Account>accountsList=newArrayList<>(); // 3.展示系统的首页Scannersc=newScanner(System.in); while (true) { System.out.println("*********ATM系统**********"); System.out.println("1:账户登陆"); System.out.println("2:账户注册"); System.out.println("请选择执行命令数字:"); intcommand=sc.nextInt(); // 接收命令// 判断执行命令switch (command) { case1: // 用户登陆login(accountsList, sc); break; case2: // 用户注册register(accountsList, sc); break; default: //输入错误System.out.println("您输入的命令有误,请重新输入!"); } } } /*** create by: 全聚德在逃烤鸭、* description: 用户登陆功能* create time: 2022/4/11 0011 14:02** @param accountsList* @param sc* @return void*/privatestaticvoidlogin(ArrayList<Account>accountsList, Scannersc) { System.out.println("********系统登陆**********"); // 1.判断账户集合中是否存在账户,若不存在账户,则不允许登陆if (accountsList.size() ==0) { System.out.println("当前系统中无用户,请先注册"); return; // 卫语言风格,结束方法的执行,返回主调程序 } OUT: while (true) { // 2.登陆功能System.out.println("请您输入登陆账号:"); StringuserId=sc.next(); // 判断登陆账号是否存在Accountaccount=getAccountByUserId(accountsList, userId); // 调用根据登陆账号查询账户对象的方法// 若返回值不为null,说明账户存在,要求用户输入密码if (account!=null) { while (true) { // 输入密码System.out.println("请输入您的登陆密码:"); StringuserPassword=sc.next(); // 判断当前输入的密码是否正确if (account.getUserPassword().equals(userPassword)) { // 密码输入正确,登陆成功,给出相应提示System.out.println(account.getUserName() +"先生/女生,登陆成功!您的卡号是:"+account.getUserId()); // 调用展示登陆页面的方法,展示操作页面showUserCommand(sc, accountsList, account); return; // 退出当前系统登陆方法,返回上一级调用方法 } else { // 密码输入错误,重新输入并给出相应提示System.out.println("密码输入错误,请重新输入"); } } } else { // 若返回值为null,说明没有查到此登陆账号对应的账户,即账户不存在System.out.println("账号不存在!"); while (true) { System.out.println("1:重新输入"); System.out.println("2:回到主页面"); System.out.println("请选择执行命令数字:"); intcommand=sc.nextInt(); // 判断执行命令switch (command) { case1: // 跳出本次OUT标记的while循环,重新输入登陆账号continueOUT; case2: // 结束当前方法,返回主调程序return; default: // 输入有误,重新选择执行命令数字System.out.println("您输入的命令有误,请重新输入!"); } } } } } /*** create by: 全聚德在逃烤鸭、* description: 展示登录后的操作页面* create time: 2022/4/11 0011 14:37** @param sc* @param accountsList* @param account* @return void*/privatestaticvoidshowUserCommand(Scannersc, ArrayList<Account>accountsList, Accountaccount) { while (true) { System.out.println("******用户操作页面*******"); 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.println("请选择执行命令数字:"); intcommand=sc.nextInt(); // 判断执行命令switch (command) { case1: // 查询账户showAccount(account); break; case2: // 存款depositMoney(sc, account); break; case3: // 取款drawMoney(sc, account); break; case4: // 转账transferMoney(sc, accountsList, account); break; case5: // 修改密码updatePassword(sc, account); return; // 使用return而不是break,修改完密码后不是返回用户操作主页面,而是需要返回ATM系统主页面,选择登陆或者注册case6: // 退出登陆System.out.println("退出成功!"); return; // 退出当前用户操作页面方法,返回上一级调用方法case7: // 注销账户booleanisDelete=deleteAccount(sc, accountsList, account); // 判断是否注销成功if (isDelete) { // 注销成功,返回ATM主页面return; } else { // 注销失败,返回用户操作页面break; } default: // 输入有误,重新选择执行命令数字System.out.println("您输入的命令有误,请重新输入!"); } } } /*** create by: 全聚德在逃烤鸭、* description: 用户注销功能* create time: 2022/4/11 0011 19:42** @param sc* @param accountsList* @param account* @return boolean*/privatestaticbooleandeleteAccount(Scannersc, ArrayList<Account>accountsList, Accountaccount) { System.out.println("******注销账户*******"); // 定义while循环,当输入命令有误时,重复输入while (true) { System.out.println("确定要注销"+account.getUserName() +"账户?Y/N"); Stringrs=sc.next(); switch (rs) { case"Y": // 确定注销// 判断当前账户是否还有余额if (account.getMoney() >0) { // 若存在余额,则不允许销户System.out.println("当前账户余额为"+account.getMoney() +"元,不允许销户!"); returnfalse; // 注销失败,返回false } else { accountsList.remove(account); // 将该Account对象从Account集合中删除System.out.println("注销成功!"); returntrue; // 注销成功,返回true } case"N": // 取消注销returnfalse; // 注销失败,返回falsedefault: System.out.println("您输入的命令有误,请重新输入!"); } } } /*** create by: 全聚德在逃烤鸭、* description: 修改密码功能* create time: 2022/4/11 0011 19:21** @param sc* @param account* @return void*/privatestaticvoidupdatePassword(Scannersc, Accountaccount) { System.out.println("******修改账户密码*******"); // 定义while循环,当原密码输入错误时,重复输入原密码while (true) { System.out.println("请输入当前账户密码:"); StringuserPassword=sc.next(); // 判断用户输入当前密码是否正确if (account.getUserPassword().equals(userPassword)) { // 账户原密码输入正确,进行下一步操作// 定义while循环,当两次新密码输入不一致时,重复输入新密码while (true) { System.out.println("请输入新密码:"); StringpasswordNew=sc.next(); System.out.println("请再次输入新密码:"); StringpasswordNewAgain=sc.next(); // 判断两次输入新密码是否一致if (passwordNew.equals(passwordNewAgain)) { // 两次输入新密码一致,进行下一步操作// 将账户密码更改为新密码account.setUserPassword(passwordNew); System.out.println("密码修改成功!"); return; // 结束当前修改密码的方法,返回上一级调用的方法 } else { // 两次输入新密码不一致,给出相应说明并提示重新输入System.out.println("两次输入新密码不一致,请重新输入!"); } } } else { // 账户原密码输入错误,给出相应说明并提示重新输入System.out.println("账户原密码输入错误,请重新输入!"); } } } /*** create by: 全聚德在逃烤鸭、* description: 用户转账功能* create time: 2022/4/11 0011 16:32** @param sc* @param accountsList* @param account* @return void*/privatestaticvoidtransferMoney(Scannersc, ArrayList<Account>accountsList, Accountaccount) { System.out.println("******账户转账*******"); // 判断账户集合中是否至少存在两个账户(否则无法转账)if (accountsList.size() <2) { System.out.println("当前系统中不足2个账户,无法进行转账"); return; // 结束当前转账方法,返回上一级调用方法 } // 判断当前账户是否有余额if (account.getMoney() ==0) { System.out.println("余额不足,无法转账"); return; // 结束当前转账方法,返回上一级调用方法 } while (true) { // 开始转账业务System.out.println("请输入转入账户的账号:"); StringanotherUserId=sc.next(); // 判断输入卡号是否为当前账号if (account.getUserId().equals(anotherUserId)) { // 若输入账号为当前账号,则不允许转账并给出相应提示System.out.println("无法给当前账号转账,请重试!"); continue; // 结束当次循环,重新要求用户输入转入账户的账户 } // 判断输入卡号是否存在AccountanotherAccount=getAccountByUserId(accountsList, anotherUserId); // 调用根据登陆账号查询账户对象的方法if (anotherAccount!=null) { // 若返回值不为空,说明账户存在,可以进行下一步// 验证转入账户的姓氏StringanotherName=anotherAccount.getUserName(); // 要转入账户的账户全名Stringtip="*"+anotherName.substring(1); // 要转入账户的账户验证名System.out.println("请输入"+tip+"的姓氏:"); StringfirstName=sc.next(); // 判断输入的姓氏是否正确if (anotherName.startsWith(firstName)) { // 姓氏输入正确,可以转账while (true) { doublemoney=account.getMoney(); // 当前账户余额System.out.println("请输入转账金额:"); doubletransferMoney=sc.nextDouble(); // 判断余额是否足够if (money>=transferMoney) { // 余额足够,可以转账money-=transferMoney; // 该账户转账后的账户余额account.setMoney(money); // 将该账户余额更新doubleanotherAccountMoney=anotherAccount.getMoney(); // 要转入的账户的余额anotherAccountMoney+=transferMoney; // 要转入的账户转账后的账户余额anotherAccount.setMoney(anotherAccountMoney); // 将要转入的账户余额更新System.out.println("转账成功,当前账户余额为"+account.getMoney() +"元"); return; // 转账业务完成,结束当前方法,返回上一级调用方法 } else { // 余额不足,给出相应说明并提示重新输入System.out.println("余额不足,当前余额为"+account.getMoney() +"元,请重新输入!"); } } } else { // 输入错误,给出相应说明并提示重新输入System.out.println("姓氏输入错误,请重新输入!"); } } else { // 否则说明账户不存在,给出相应说明并提示重新输入System.out.println("账户不存在,请重新输入!"); } } } /*** create by: 全聚德在逃烤鸭、* description: 用户取款功能* create time: 2022/4/11 0011 15:23** @param sc* @param account* @return void*/privatestaticvoiddrawMoney(Scannersc, Accountaccount) { System.out.println("******账户取款*******"); doublemoney=account.getMoney(); // 判断当前账户内是否有余额可取(余额大于等于100)if (money<100) { // 余额不足100元,给出相应提示System.out.println("您的账户当前余额为:"+money+"元,余额不足100元无法取出"); return; } while (true) { System.out.println("您的账户当前余额为:"+money+"元,请输入取款金额:"); doubledrawMoney=sc.nextDouble(); // 判断取款输入的金额是否超过每次取款限额if (drawMoney>account.getQuoteMoney()) { // 超过取款金额,给出结论并提示重新输入System.out.println("您当前取款金额为"+drawMoney+"元,超出每次取款额度"+account.getQuoteMoney() +"元,请重新输入:"); } else { // 继续判断取款输入的金额是否超过每次账户余额if (drawMoney>money) { // 超过账户余额,给出结论并提示重新输入System.out.println("您当前取款金额为"+drawMoney+"元,超出账户余额"+money+"元,请重新输入:"); } else { // 账户内有余额可取,且取款金额不超过每次取款限额且不超过账户余额,允许取款money-=drawMoney; // 取款后的账户余额account.setMoney(money); // 将该账户余额更新System.out.println("取款成功!当前账户信息如下:"); showAccount(account); // 调用展示账户信息的方法,查询余额是否正确更新return; // 取款完毕,结束当前取款方法,返回上一级调用方法 } } } } /*** create by: 全聚德在逃烤鸭、* description: 用户存款功能* create time: 2022/4/11 0011 15:03** @param sc* @param account* @return void*/privatestaticvoiddepositMoney(Scannersc, Accountaccount) { System.out.println("******账户存款*******"); System.out.println("请输入存款金额:"); doubledepositMoney=sc.nextDouble(); // 将存款后的金额更新到账户中doublemoney=account.getMoney() +depositMoney; // 存款后的账户余额account.setMoney(money); // 将该账户余额更新System.out.println("存款成功!当前账户信息如下:"); showAccount(account); // 调用展示账户信息的方法,查询余额是否正确更新 } /*** create by: 全聚德在逃烤鸭、* description: 查询当前账户信息* create time: 2022/4/11 0011 14:49** @param account* @return void*/privatestaticvoidshowAccount(Accountaccount) { System.out.println("******当前账户信息*******"); System.out.println("登陆账号:"+account.getUserId()); System.out.println("用户名:"+account.getUserName()); System.out.println("账户余额:"+account.getMoney()); System.out.println("每次取款额度:"+account.getQuoteMoney()); } /*** create by: 全聚德在逃烤鸭、* description: 用户注册功能* create time: 2022/4/11 0011 9:21** @param accountsList Account类型的ArrayList集合* @param sc 扫描器* @return void*/privatestaticvoidregister(ArrayList<Account>accountsList, Scannersc) { System.out.println("*********系统注册**********"); // 1.创建一个账户对象,用于后续封装账户信息Accountaccount=newAccount(); // 2.接收将当前注册账户的各种信息,并将其封装到该账户对象中去System.out.println("请输入用户名:"); StringuserName=sc.next(); account.setUserName(userName); // 定义while循环,当输入密码出现问题时,再次输入while (true) { System.out.println("请输入登陆密码:"); StringuserPassword=sc.next(); System.out.println("请再次输入登陆密码:"); StringuserPasswordAgain=sc.next(); // 判断两次输入密码是否一致,若一致,则将密码信息封装,否则重新输入并给出提示if (userPassword.equals(userPasswordAgain)) { account.setUserPassword(userPassword); break; // 密码录入完毕,跳出while循环 } else { System.out.println("两次密码输入不一致,请重新输入!"); } } // 定义while循环,当输入账户每次取款额度出现问题时,再次输入while (true) { System.out.println("请输入账户每次取款额度(最低1000元):"); doublequoteMoney=sc.nextDouble(); // 判断每次取款额度是否符合要求(最低1000元),若符合,则将每次取款额度信息封装,否则重新输入并给出提示if (quoteMoney>=1000.0) { account.setQuoteMoney(quoteMoney); break; // 每次取款额度录入完毕,跳出while循环 } else { System.out.println("您输入的每次取款额度有误,最低1000元,请重新输入!"); } } //调用随机获取一个八位且与其他账户不重复的登陆账号的方法,生成该账户对象的登陆账号StringuserId=getRandomUserId(accountsList); account.setUserId(userId); // 3.将该账户对象添加到账户类型的集合中去accountsList.add(account); System.out.println("恭喜您,"+userName+"先生/女生,注册成功!您的登陆账号是:"+userId); } /*** create by: 全聚德在逃烤鸭、* description: 随机获取一个八位且与其他账户不重复的登陆账号* create time: 2022/4/11 0011 10:07** @param accountsList* @return java.lang.String*/privatestaticStringgetRandomUserId(ArrayList<Account>accountsList) { Randomr=newRandom(); while (true) { // 账号重复时,重新生成,直到不重复为止// 定义一个变量用于存储随机生成的八位账号StringuserId=""; // 定义变量初始值时,为"",里面不要带空格,否则空格也会出现在账号中// 随机生成一个八位账号for (inti=0; i<8; i++) { intnumber=r.nextInt(9) +1; userId+=number; } // 调用根据账号查询账户对象的方法,判断生成的八位账号是否与其他账户的账户重复Accountaccount=getAccountByUserId(accountsList, userId); // 判断根据生成的账号是否查询到对应账户,如果查到说明该账户已经存在,需要重新生成,否则说明该账号有效if (account==null) { returnuserId; // 该账号没有重复,有效,将账号返回 } } } /*** create by: 全聚德在逃烤鸭、* description: 根据账号查询账户对象 若存在则返回该账户对象,否则返回null* create time: 2022/4/11 0011 10:16** @param accountsList* @param userId* @return com.ieheima.atm.Account*/privatestaticAccountgetAccountByUserId(ArrayList<Account>accountsList, StringuserId) { // 遍历集合中所有的账户,查询是否有此账号对应的账户for (inti=0; i<accountsList.size(); i++) { Accountaccount=accountsList.get(i); // 如果第i个索引位置对应的账户的账户与查询用的账号一致,说明此账户就是要查找的账户if (account.getUserId().equals(userId)) { returnaccount; // 将此账户返回 } } returnnull; // 遍历结束后,仍然没有找到符合条件的账户,则表示集合中没有该账户,将null返回 } }