目录
ATM系统练习
需求:设计ATM系统,能够完成基本的注册、登陆、查询、存款、取款、转账、修改密码、注销等基本功能。
一、系统准备、首页设计
系统准备内容分析:
① 每个用户的账户信息都是一个对象,需要提供账户类。
② 需要准备一个容器,用于存储系统全部账户对象信息。
③ 首页只需要包含:登录和注册2个功能。
实现步骤:
① 定义账户类,用于后期创建账户对象封装用户的账户信息。
② 账户类中的信息至少需要包含(卡号、姓名、密码、余额、取现额度)
③ 需要准备一个ArrayList的集合,用于存储系统用户的账户对象。
④ 需要展示欢迎页包含2个功能:注册功能、登录账户。
二、用户注册功能实现
用户注册功能分析:注册功能其实就是就是往系统的集合容器中存入一个新的账户对象的信息。
注册功能实现步骤:
① 定义方法完成注册
② 键盘录入姓名、密码、确认密码(需保证两次密码一致)、每次取款额度(最低1000元)
③ 生成账户卡号,卡号必须由系统自动生成8位数字(必须保证卡号的唯一)
④ 创建Account账户类对象用于封装账户信息(姓名、密码、卡号)
⑤ 把Account账户类对象存入到集合accounts中去。
三、用户登陆功能实现
用户登陆功能分析:
① 定义方法
② 让用户键盘录入卡号,根据卡号查询账户对象。
③ 如果没有找到了账户对象,说明卡号不存在,提示继续输入卡号。
④ 如果找到了账户对象,说明卡号存在,继续输入密码。
⑤ 如果密码不正确,提示继续输入密码
⑥ 如果密码正确,提示登陆成功!
四、用户操作页、查询账户、退出账户功能实现
用户操作页设计、查询账户、退出账户功能分析:
① 用户登录成功后,需要进入用户操作页。
② 查询就是直接展示当前登录成功的账户对象的信息。
③ 退出账户是需要回到首页的。
五、存款功能实现
存款功能分析:
① 存款就是拿到当前账户对象。
② 然后让用户输入存款的金额。
③ 调用账户对象的setMoney方法将账户余额修改成存钱后的余额。
④ 存钱后需要查询一下账户信息,确认是否存钱成功了!
六、取款功能实现
取款功能分析:
① 取款需要先判断账户是否有钱。
② 有钱则拿到自己账户对象。
③ 然后让用户输入取款金额
④ 判断取款金额是否超过了当次限额,以及余额是否足够
⑤ 满足要求则调用账户对象的setMoney方法完成金额的修改。
七、转账功能实现
转账功能分析:
① 转账功能需要判断系统中是否有2个账户对象及以上。
② 同时还要判断自己账户是否有钱。
③ 接下来需要输入对方卡号,判断对方账户是否存在。
④ 对方账户存在还需要认证对方户主的姓氏。
⑤ 满足要求则可以把自己账户对象的金额修改到对方账户对象中去。
八、密码修改、销户功能实现
密码修改、销户功能分析:
① 修改密码就是把当前对象的密码属性使用set方法进行更新。
② 销户是从集合对象中删除当前对象,并回到首页。
示例代码如下:
账户类
public class Account {
private String userId; // 登陆账号
private String userName; // 用户名
private String userPassword; // 登陆密码
private double money; // 账户余额
private double quoteMoney; // 每次取款额度
// 构造函数缺省为无参构造函数
/*
getter、setter方法
*/
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public double getQuoteMoney() {
return quoteMoney;
}
public void setQuoteMoney(double quoteMoney) {
this.quoteMoney = quoteMoney;
}
}
主程序
public class ATMSystem {
public static void main(String[] args) {
// 1.定义账户类
// 2.定义一个集合容器,负责存储全部的Account对象,完成相关业务操作
ArrayList<Account> accountsList = new ArrayList<>();
// 3.展示系统的首页
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("*********ATM系统**********");
System.out.println("1:账户登陆");
System.out.println("2:账户注册");
System.out.println("请选择执行命令数字:");
int command = sc.nextInt(); // 接收命令
// 判断执行命令
switch (command) {
case 1:
// 用户登陆
login(accountsList, sc);
break;
case 2:
// 用户注册
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
*/
private static void login(ArrayList<Account> accountsList, Scanner sc) {
System.out.println("********系统登陆**********");
// 1.判断账户集合中是否存在账户,若不存在账户,则不允许登陆
if (accountsList.size() == 0) {
System.out.println("当前系统中无用户,请先注册");
return; // 卫语言风格,结束方法的执行,返回主调程序
}
OUT:
while (true) {
// 2.登陆功能
System.out.println("请您输入登陆账号:");
String userId = sc.next();
// 判断登陆账号是否存在
Account account = getAccountByUserId(accountsList, userId); // 调用根据登陆账号查询账户对象的方法
// 若返回值不为null,说明账户存在,要求用户输入密码
if (account != null) {
while (true) {
// 输入密码
System.out.println("请输入您的登陆密码:");
String userPassword = 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("请选择执行命令数字:");
int command = sc.nextInt();
// 判断执行命令
switch (command) {
case 1:
// 跳出本次OUT标记的while循环,重新输入登陆账号
continue OUT;
case 2:
// 结束当前方法,返回主调程序
return;
default:
// 输入有误,重新选择执行命令数字
System.out.println("您输入的命令有误,请重新输入!");
}
}
}
}
}
/**
* create by: 全聚德在逃烤鸭、
* description: 展示登录后的操作页面
* create time: 2022/4/11 0011 14:37
*
* @param sc
* @param accountsList
* @param account
* @return void
*/
private static void showUserCommand(Scanner sc, ArrayList<Account> accountsList, Account account) {
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("请选择执行命令数字:");
int command = sc.nextInt();
// 判断执行命令
switch (command) {
case 1:
// 查询账户
showAccount(account);
break;
case 2:
// 存款
depositMoney(sc, account);
break;
case 3:
// 取款
drawMoney(sc, account);
break;
case 4:
// 转账
transferMoney(sc, accountsList, account);
break;
case 5:
// 修改密码
updatePassword(sc, account);
return; // 使用return而不是break,修改完密码后不是返回用户操作主页面,而是需要返回ATM系统主页面,选择登陆或者注册
case 6:
// 退出登陆
System.out.println("退出成功!");
return; // 退出当前用户操作页面方法,返回上一级调用方法
case 7:
// 注销账户
boolean isDelete = 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
*/
private static boolean deleteAccount(Scanner sc, ArrayList<Account> accountsList, Account account) {
System.out.println("******注销账户*******");
// 定义while循环,当输入命令有误时,重复输入
while (true) {
System.out.println("确定要注销" + account.getUserName() + "账户?Y/N");
String rs = sc.next();
switch (rs) {
case "Y":
// 确定注销
// 判断当前账户是否还有余额
if (account.getMoney() > 0) { // 若存在余额,则不允许销户
System.out.println("当前账户余额为" + account.getMoney() + "元,不允许销户!");
return false; // 注销失败,返回false
} else {
accountsList.remove(account); // 将该Account对象从Account集合中删除
System.out.println("注销成功!");
return true; // 注销成功,返回true
}
case "N":
// 取消注销
return false; // 注销失败,返回false
default:
System.out.println("您输入的命令有误,请重新输入!");
}
}
}
/**
* create by: 全聚德在逃烤鸭、
* description: 修改密码功能
* create time: 2022/4/11 0011 19:21
*
* @param sc
* @param account
* @return void
*/
private static void updatePassword(Scanner sc, Account account) {
System.out.println("******修改账户密码*******");
// 定义while循环,当原密码输入错误时,重复输入原密码
while (true) {
System.out.println("请输入当前账户密码:");
String userPassword = sc.next();
// 判断用户输入当前密码是否正确
if (account.getUserPassword().equals(userPassword)) { // 账户原密码输入正确,进行下一步操作
// 定义while循环,当两次新密码输入不一致时,重复输入新密码
while (true) {
System.out.println("请输入新密码:");
String passwordNew = sc.next();
System.out.println("请再次输入新密码:");
String passwordNewAgain = 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
*/
private static void transferMoney(Scanner sc, ArrayList<Account> accountsList, Account account) {
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("请输入转入账户的账号:");
String anotherUserId = sc.next();
// 判断输入卡号是否为当前账号
if (account.getUserId().equals(anotherUserId)) { // 若输入账号为当前账号,则不允许转账并给出相应提示
System.out.println("无法给当前账号转账,请重试!");
continue; // 结束当次循环,重新要求用户输入转入账户的账户
}
// 判断输入卡号是否存在
Account anotherAccount = getAccountByUserId(accountsList, anotherUserId); // 调用根据登陆账号查询账户对象的方法
if (anotherAccount != null) { // 若返回值不为空,说明账户存在,可以进行下一步
// 验证转入账户的姓氏
String anotherName = anotherAccount.getUserName(); // 要转入账户的账户全名
String tip = "*" + anotherName.substring(1); // 要转入账户的账户验证名
System.out.println("请输入" + tip + "的姓氏:");
String firstName = sc.next();
// 判断输入的姓氏是否正确
if (anotherName.startsWith(firstName)) { // 姓氏输入正确,可以转账
while (true) {
double money = account.getMoney(); // 当前账户余额
System.out.println("请输入转账金额:");
double transferMoney = sc.nextDouble();
// 判断余额是否足够
if (money >= transferMoney) { // 余额足够,可以转账
money -= transferMoney; // 该账户转账后的账户余额
account.setMoney(money); // 将该账户余额更新
double anotherAccountMoney = 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
*/
private static void drawMoney(Scanner sc, Account account) {
System.out.println("******账户取款*******");
double money = account.getMoney();
// 判断当前账户内是否有余额可取(余额大于等于100)
if (money < 100) { // 余额不足100元,给出相应提示
System.out.println("您的账户当前余额为:" + money + "元,余额不足100元无法取出");
return;
}
while (true) {
System.out.println("您的账户当前余额为:" + money + "元,请输入取款金额:");
double drawMoney = 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
*/
private static void depositMoney(Scanner sc, Account account) {
System.out.println("******账户存款*******");
System.out.println("请输入存款金额:");
double depositMoney = sc.nextDouble();
// 将存款后的金额更新到账户中
double money = 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
*/
private static void showAccount(Account account) {
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
*/
private static void register(ArrayList<Account> accountsList, Scanner sc) {
System.out.println("*********系统注册**********");
// 1.创建一个账户对象,用于后续封装账户信息
Account account = new Account();
// 2.接收将当前注册账户的各种信息,并将其封装到该账户对象中去
System.out.println("请输入用户名:");
String userName = sc.next();
account.setUserName(userName);
// 定义while循环,当输入密码出现问题时,再次输入
while (true) {
System.out.println("请输入登陆密码:");
String userPassword = sc.next();
System.out.println("请再次输入登陆密码:");
String userPasswordAgain = sc.next();
// 判断两次输入密码是否一致,若一致,则将密码信息封装,否则重新输入并给出提示
if (userPassword.equals(userPasswordAgain)) {
account.setUserPassword(userPassword);
break; // 密码录入完毕,跳出while循环
} else {
System.out.println("两次密码输入不一致,请重新输入!");
}
}
// 定义while循环,当输入账户每次取款额度出现问题时,再次输入
while (true) {
System.out.println("请输入账户每次取款额度(最低1000元):");
double quoteMoney = sc.nextDouble();
// 判断每次取款额度是否符合要求(最低1000元),若符合,则将每次取款额度信息封装,否则重新输入并给出提示
if (quoteMoney >= 1000.0) {
account.setQuoteMoney(quoteMoney);
break; // 每次取款额度录入完毕,跳出while循环
} else {
System.out.println("您输入的每次取款额度有误,最低1000元,请重新输入!");
}
}
//调用随机获取一个八位且与其他账户不重复的登陆账号的方法,生成该账户对象的登陆账号
String userId = 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
*/
private static String getRandomUserId(ArrayList<Account> accountsList) {
Random r = new Random();
while (true) { // 账号重复时,重新生成,直到不重复为止
// 定义一个变量用于存储随机生成的八位账号
String userId = ""; // 定义变量初始值时,为"",里面不要带空格,否则空格也会出现在账号中
// 随机生成一个八位账号
for (int i = 0; i < 8; i++) {
int number = r.nextInt(9) + 1;
userId += number;
}
// 调用根据账号查询账户对象的方法,判断生成的八位账号是否与其他账户的账户重复
Account account = getAccountByUserId(accountsList, userId);
// 判断根据生成的账号是否查询到对应账户,如果查到说明该账户已经存在,需要重新生成,否则说明该账号有效
if (account == null) {
return userId; // 该账号没有重复,有效,将账号返回
}
}
}
/**
* create by: 全聚德在逃烤鸭、
* description: 根据账号查询账户对象 若存在则返回该账户对象,否则返回null
* create time: 2022/4/11 0011 10:16
*
* @param accountsList
* @param userId
* @return com.ieheima.atm.Account
*/
private static Account getAccountByUserId(ArrayList<Account> accountsList, String userId) {
// 遍历集合中所有的账户,查询是否有此账号对应的账户
for (int i = 0; i < accountsList.size(); i++) {
Account account = accountsList.get(i);
// 如果第i个索引位置对应的账户的账户与查询用的账号一致,说明此账户就是要查找的账户
if (account.getUserId().equals(userId)) {
return account; // 将此账户返回
}
}
return null; // 遍历结束后,仍然没有找到符合条件的账户,则表示集合中没有该账户,将null返回
}
}