目录
前言
上一周对ATM机模拟系统做了项目需求分析(Java实现ATM机模拟系统(week1)-CSDN博客),这周来做部分的实现。
项目规划(第二周)
-
完成操作页面展示
-
完成用户的登录。注册等用户基本操作
-
学习I/O,要求用户数据必须持久化(也可使用jdbc+mysql)
-
做好类的封装,自定义异常处理
具体实现
用户大类
AccountOperations接口
该接口主要定义了对帐户进行的操作方法,包括以下
- 创建账户
- 登录账户
- 退出账户
- 保存账户信息
- 调出账户信息
package Account.Operations.Method;
import Account.Account;
import Area.Area;
import java.io.FileNotFoundException;
public interface AccountOperations {
public Account createAccount( Area area); // 创建账户
public Account landAccount( String accountNumber, String cipher); // 登录账户
public void logOut( Account account) throws FileNotFoundException; // 退出账户
public void saveAccountInformation( Account account);
public Account retrieveAccountInformation( String accountNumber, String cipher);
}
UserOperations接口
该接口主要定义了用户执行的操作方法,目前包括以下
- 存款
- 取款
- 查询余额
- 修改密码
package Account.Operations.Method;
import Account.Account;
import Currency.Money;
public interface UserOperations {
public void saveMoney( Money money, Account account); // 存钱
public void withdraw( Money money, Account account); // 取钱
public boolean checkBalance(Account account); // 查询余额
public void changeCipher( Account account); // 修改密码
}
Operations类(实现类)
该类用于实现以上两个接口的方法
package Account.Operations;
import Account.Account;
import Account.Operations.Method.AccountOperations;
import Account.Operations.Method.UserOperations;
import Area.Area;
import Currency.Money;
import OperationInterface.LoginInterface;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.util.Scanner;
public class Operations implements AccountOperations, UserOperations {
Operations operations = new Operations();
LoginInterface loginInterface = new LoginInterface();
@Override
public Account createAccount( Area area) {
Scanner s = new Scanner(System.in);
// 给出账号
System.out.println("输入本人身份证号码:");
String id = s.next();
// 给出手机号
System.out.println("输入本人手机号:");
String mobileNumber = s.next();
StringBuilder ac = new StringBuilder();
ac.append(area.obtainNumber());
SecureRandom num = new SecureRandom();
for( int i = 0; i < 11; i++) {
int t = num.nextInt(10);
ac.append(t);
}
String accountNumber = ac.toString();
// 输入密码
String cipher =s.next();
// 创建一个账号,并且初始化账号, 并且返回一个账号
return new Account( accountNumber, cipher, 0.0, 0.0, 0, id, mobileNumber);
}
@Override
public Account landAccount( String accountNumber, String cipher) {
// 直接调用retrieveAccountInformation()方法调出相应账户
Account account = retrieveAccountInformation( accountNumber, cipher);
if( account == null ) {
System.out.println("输入账号密码有误,请重新输入!!!");
// 返回登录操作继续输入账号和密码
Scanner s = new Scanner(System.in);
// 如果有什么其他操作, 如 创建账号、修改密码操作, 加这里
/* ········· */
// 利用递归函数重复输入,直到能匹配到账号为止
account = landAccount( s.next(), s.next());
}
return account;
}
@Override
public void logOut( Account account) throws FileNotFoundException {
// 将目前的账号清空, 重复利用
account = null;
System.out.println("账号退出成功!!!");
// 退出账号后的后续操作写这里
/* ······ */
//返回登录界面
loginInterface.loginInterface();
//operations.landAccount() ; //
}
@Override
public void saveAccountInformation( Account account) {
// 为这个账户创建一个文本文档,存放账户信息
String address = "E:\\Account\\" + account.getAccountNumber() + ".txt";
File save = new File(address);
// 如果文件已经存在,直接覆盖掉之前的信息保存
if( save.exists() ) {
try (FileOutputStream fileOut = new FileOutputStream(address) ) {
ObjectOutputStream oos = new ObjectOutputStream(fileOut);
oos.writeObject(account);
oos.close();
fileOut.close();
System.out.println("账户信息保存成功");
} catch (IOException e) {
throw new RuntimeException("账户信息保存失败");
}
}
// 如果文件不存在,者创建一个新文件存放账户信息
else {
try {
if( save.createNewFile() ) {
try (FileOutputStream fileOut = new FileOutputStream(address) ) {
ObjectOutputStream oos = new ObjectOutputStream(fileOut);
oos.writeObject(account);
oos.close();
fileOut.close();
System.out.println("账户信息保存成功");
} catch (IOException e) {
throw new RuntimeException("账户信息保存失败");
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@Override
public Account retrieveAccountInformation( String accountNumber, String cipher) {
String address = "E:\\Account";
// 读取指定路径目录
File dictionary = new File(address);
// 将该目录中的文件读入到list中
File[] list = dictionary.listFiles();
Account result = null;
if( list != null ) {
// 通过循环遍历目录中的文件,进行逐个查找
for( File t : list) {
Path find = Path.of(t.getAbsolutePath());
String content = null;
try {
content = new String(Files.readAllBytes(find));
} catch (IOException e) {
throw new RuntimeException(e);
}
if( content.contains(accountNumber) && content.contains(cipher) ) {
// 将目标文件信息读取到一个Account对象中
try (FileInputStream in = new FileInputStream(address + "\\" + t.getName())) {
ObjectInputStream oos = new ObjectInputStream(in);
try {
result = (Account) oos.readObject();
} catch (ClassNotFoundException e) {
throw new ClassCastException("读取用户信息失败!!!");
}
in.close();
oos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
}
}
}
else {
System.out.println("目录为空!!!");
}
return result;
}
@Override
public void saveMoney(Money money, Account account) {
Scanner s = new Scanner(System.in);
System.out.println("放入所存金额:");
account.setDeposit(account.getDeposit() + money.MoneyExchange( money, s.nextInt()));
// 这里也可以采用一个 try - catch 块处理 saveAccountInformation方法中遇到的异常,目前未采用
saveAccountInformation(account);
System.out.println("存储成功!!!");
}
@Override
public void withdraw(Money money, Account account) {
Scanner s = new Scanner(System.in);
System.out.println("输入要取出金额:");
int draw = s.nextInt();
if( draw > account.getDeposit() ) {
System.out.println("余额不足!!!");
}
else {
// 账户中的货币都是以人民币形式存储的,所以要把取出(存入)的货币转化成人民币
account.setDeposit(account.getDeposit() - money.MoneyExchange( money, s.nextInt()));
}
}
@Override
public void changeCipher(Account account) {
Scanner s = new Scanner(System.in);
System.out.println("请输入本用户身份证号:");
String id = s.next();
System.out.println("请输入本用户手机号:");
String mobileNumber = s.next();
String address = "E:\\Account";
File file = new File(address);
File[] list = file.listFiles();
if( list != null ) {
// 通过循环遍历目录中的文件,进行逐个查找
for( File t : list) {
Path find = Path.of(t.getAbsolutePath());
String content = null;
try {
content = new String(Files.readAllBytes(find));
} catch (IOException e) {
throw new RuntimeException(e);
}
if( content.contains(id) && content.contains(mobileNumber) ) {
// 将目标文件信息读取到一个Account对象中
try (FileInputStream in = new FileInputStream(address + "\\" + t.getName())) {
ObjectInputStream oos = new ObjectInputStream(in);
try {
Account result = (Account) oos.readObject();
System.out.println("请输入新密码(由六位数组成):");
result.setCipher(s.next());
System.out.println("密码更改成功!!!");
// 保存信息
saveAccountInformation(result);
} catch (ClassNotFoundException e) {
throw new ClassCastException("更改密码时读取用户信息失败!!!");
}
in.close();
oos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
}
}
}
else {
System.out.println("目录为空!!!");
}
}
public boolean checkBalance(Account account) {
Account result = retrieveAccountInformation( account.getAccountNumber(), account.getCipher());
if ( result != null ) {
System.out.println("账户余额为:" + result.getDeposit() + "RMB");
return true;
}
else {
System.out.println("账户余额查询失败,请重新输入账号和密码!!!");
return false;
// 如果查询失败可根据用户选择进行继续查询,这里通过返回值判断是否查询成功
}
}
}
Account类
该类是对账户的定义,包括了账户应当具有的属性
包括但不限于
- 账号
- 密码
- 手机号
- 余额
- 年利率(待商榷)
- 时间(待商榷)
- 用户id
package Account;
import java.io.Serializable;
// 因为要实现账户保存,所以要接Serializable接口
public class Account implements Serializable {
private String accountNumber;
private String cipher;
private Double deposit;
private Double annualInterestRate;
private int time;
private final String id;
private final String mobileNumber;
public Account(String accountNumber, String cipher, Double deposit, Double annualInterestRate, int time, String id, String mobileNumber) {
this.accountNumber = accountNumber;
this.cipher = cipher;
this.deposit = deposit;
this.annualInterestRate = annualInterestRate;
this.time = time;
this.id = id;
this.mobileNumber = mobileNumber;
}
@Override
public String toString() {
return "Account{" +
"accountNumber='" + accountNumber + '\'' +
", cipher='" + cipher + '\'' +
", deposit=" + deposit +
", annualInterestRate=" + annualInterestRate +
", time=" + time +
'}';
}
private int getTime() {
return time;
}
public String getAccountNumber() {
return accountNumber;
}
public String getCipher() {
return cipher;
}
public Double getAnnualInterestRate() {
return annualInterestRate;
}
public Double getDeposit() {
return deposit;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public void setDeposit(Double deposit) {
this.deposit = deposit;
}
public void setAnnualInterestRate(Double annualInterestRate) {
this.annualInterestRate = annualInterestRate;
}
public void setTime(int time) {
this.time = time;
}
public void setCipher(String cipher) {
this.cipher = cipher;
}
public String getId() {
return id;
}
public String getMobileNumber() {
return mobileNumber;
}
}
User类
该类是面向用户的,主要实现了用户使用系统时的操作逻辑,通过用户输入的操作数来执行对应的操作。
package User;
import Account.Account;
import Account.Operations.Operations;
import OperationInterface.LoginInterface;
import OperationInterface.MainInterface;
import OperationInterface.RegistrationInterface;
import java.io.FileNotFoundException;
import java.util.Scanner;
import static java.lang.System.exit;
public class User {
public void userOperation() throws FileNotFoundException {
// 跳出首页画面提示用户
/* ······· */
Scanner s = new Scanner(System.in);
Account account = null;
Operations operation = new Operations();
System.out.println("输入 1 登录账户 输入 2 创建新账户 ");
int userOperation = s.nextInt();
if(userOperation == 1){
LoginInterface loginInterface = new LoginInterface();
loginInterface.loginInterface();
Operations operations = new Operations();
//调用登录方法
//operations.landAccount(); //
//如何判断登录成功?成功则进入主界面
MainInterface mainInterface = new MainInterface();
mainInterface.mainInterface(); //展示主界面
}else if (userOperation == 2){
RegistrationInterface registrationInterface = new RegistrationInterface();
registrationInterface.registrationInterface();
Operations operations = new Operations();
//调用创建账户方法
//operations.createAccount();
}else {
System.out.println("您进行的操作不合法!");
}
// 以下可以根据页面直接加操作
/* ············· */
}
public void mainInterfaceOperation(){//主界面操作
Scanner scanner = new Scanner(System.in) ;
Operations operations = new Operations();
int n = scanner.nextInt();
if (n == 1){//调用存款方法
//operations.saveMoney(); //
}else if(n == 2){//调用取款方法
//operations.withdraw(); //
}else if(n == 3){//调用查询余额方法
//operations.checkBalance() ;///
}else if(n == 4){//调用货币交换方法 !!未实现
}else if(n == 5){//调用修改密码方法
//operations.changeCipher();
}else if(n == 6){//调用操作日志查询方法 !!未实现
}else if(n == 7){//调用退出账户方法,返回登录界面
//operations.logOut(); ///
}else if(n == 8){//退出系统,即终止程序运行
exit(0) ;
}
}
}
Area类 (父类)
在创建账户时,需要根据用户所在地区给出前几位数字,我们用一个Area父类来实现这一功能,每个不同的地区均是其子类
package Area;
public class Area {
public String name;
public Area(String name) {
this.name = name;
}
public String obtainNumber() {
return null;
}
}
货币大类
本周货币大类不在需要实现的范围内,故只进行了简单的架构
Money类(抽象类)
主要实现货币交换的方法,每个不同的币种均是其子类
package Currency;
public abstract class Money {
public Double exchangeRate; // 汇率, 人民币与该货币的比
public abstract Double MoneyExchange( Money money, int num); // 某货币交换成人民币
public abstract Double ExchangeMoney( Money money, int num);// 人民币交换成某货币
}
操作界面
目前实现了三个界面
- 登录界面
- 注册界面
- 主界面
界面的实现极其简单,无非是几个文件创建和输出的事情罢了。
LoginInterface类
package OperationInterface;
import java.io.*;
public class LoginInterface {
public void loginInterface() throws FileNotFoundException {
File file = new File("Login.txt"); //创建File类对象,并给出其相对路径,否则默认创建在当前路径下
if (file.exists()) { //调用exists方法,判断文件是否存在
fileInput(file); //如已存在,直接打开
} else { //如不存在,执行创建操作
try {
file.createNewFile();
fileInput(file);
} catch (Exception e) {
System.out.println("系统故障!");
}
}
}
private void fileInput(File file) {
FileReader f = null;//文件读取对象
BufferedReader f1 = null;//字符流对象
try {
f = new FileReader(file);
f1 = new BufferedReader(f);
//循环打印cc文件中的每行数据
String str = null;
while ((str = f1.readLine()) != null) {
System.out.println(str);
}
} catch (Exception e) {
System.out.println("系统故障!");
} finally {
try {
f1.close();
f.close();
} catch (Exception e2) {
System.out.println("系统故障!");
}
}
}
}
MainInterface类
package OperationInterface;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class MainInterface {
public void mainInterface() throws FileNotFoundException {
File file = new File("Main.txt"); //创建File类对象,并给出其相对路径,否则默认创建在当前路径下
if (file.exists()) { //调用exists方法,判断文件是否存在
fileInput(file); //如已存在,直接打开
} else { //如不存在,执行创建操作
try {
file.createNewFile();
fileInput(file);
} catch (Exception e) {
System.out.println("系统故障!");
}
}
}
private void fileInput(File file) {
FileReader f = null;//文件读取对象
BufferedReader f1 = null;//字符流对象
try {
f = new FileReader(file);
f1 = new BufferedReader(f);
//循环打印cc文件中的每行数据
String str = null;
while ((str = f1.readLine()) != null) {
System.out.println(str);
}
} catch (Exception e) {
System.out.println("系统故障!");
} finally {
try {
f1.close();
f.close();
} catch (Exception e2) {
System.out.println("系统故障!");
}
}
}
}
RegistrationInterface类
package OperationInterface;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class RegistrationInterface {
public void registrationInterface() throws FileNotFoundException {
File file = new File("Registration.txt"); //创建File类对象,并给出其相对路径,否则默认创建在当前路径下
if (file.exists()) { //调用exists方法,判断文件是否存在
fileInput(file); //如已存在,直接打开
} else { //如不存在,执行创建操作
try {
file.createNewFile();
fileInput(file);
} catch (Exception e) {
System.out.println("系统故障!");
}
}
}
private void fileInput(File file) {
FileReader f = null;//文件读取对象
BufferedReader f1 = null;//字符流对象
try {
f = new FileReader(file);
f1 = new BufferedReader(f);
//循环打印cc文件中的每行数据
String str = null;
while ((str = f1.readLine()) != null) {
System.out.println(str);
}
} catch (Exception e) {
System.out.println("系统故障!");
} finally {
try {
f1.close();
f.close();
} catch (Exception e2) {
System.out.println("系统故障!");
}
}
}
}
三个界面的txt文档设计
//登录界面
登录
账号:
密码:
//注册界面
注册
请输入身份证号:
请输入手机号:
请输入密码:
//主界面
欢迎
1.存款 2.取款
3.查询余额 4.货币交换
5.更改密码 6.操作日志查询
7.退出账户 8.退出系统
后言
本周主要实现了用户的部分基本操作,采用的主要手段为文件操作(文件的写入与读取也有博客记录Java文件操作(从创建文件到简单输入输出流)-CSDN博客),用于存储数据,设计操作界面等。在和朋友进行合作开发的过程中,我们也遇到了许多问题,比如当我们分析完项目需求后,双方就开始着手写代码实现,却没有提前沟通好代码逻辑,导致虽然写了注释,互相读代码时也遇到了不小的障碍(所以大家千万别学我们)
新手上路,水平有限,如有错误,还望海涵并指出!
与君共勉!