Sparta/What I Learned

22.11.29

코딩하는 또롱이 2022. 11. 29. 22:44

지난주부터 시작됐던 프로젝트가 끝났다. 발표까지 전부 다!!!! 휘몰아치는 일정 속에서 나 혼자만 이렇게 숨가쁘고 힘드나 란 고민도 하면서 역시 나는 안되는건가 자책도 했었지만 결국 오기와 깡으로 독하게 존버한 보람이 있었다^^

 

처음엔 코드를 봐도 이게 무슨 말인가 왜 이렇게 되는 건가 생각을 했었지만, 마지막 최종적으로 코드 리뷰할 때 이게 이렇게 되는구나 라고 자연스럽게 머릿속에서 물 흐르듯 코드들이 재생되는걸 보고 와 나 이번 프로젝트를 통해서 코드에 대한 이해도가 조금 올랐구나 생각했다. 앞으로도 물론 많이 헤매겠지만 이번처럼 끝까지 해내고야 말겠다는 의지로 남은 기간 열심히 하면 천재는 아니더라도 열심히 해내는 사람이 되어 있을거 같아 미래가 너무 기대됐다.

 

마지막으로 우리 조가 선택했던 은행 관리 프로그램 코드를 자랑하고 사라져야지😎

 

[Main.java]

더보기
package org.example;


public class Main {
    public static void main(String[] args) {
        System.out.println("<1잘하조 은행 관리 프로그램>");
        BankManagementService bmService = new BankManagementService();
        bmService.run();
    }
}

 

[BankManagementService.java]

확실히 UI 클래스라 그런지 코드가 매우 길다^^

더보기
package org.example;

import java.util.ArrayList;
import java.util.Scanner;

public class BankManagementService {    // UI

    public void run() {
        showInitialMenu();
        int userInput = insertUserInput();

        switch (userInput) {
            case 1: // 고객으로 로그인
                customerLogin();
                break;
            case 2: // 은행으로 로그인
                bankClerkMenu();
                break;
            case 3: // 프로그램 종료
                System.out.println("프로그램이 종료됩니다.");
                System.exit(0);
                break;
        }
    }


    public void showInitialMenu() {
        System.out.println("===============");
        System.out.println("1.고객으로 로그인");
        System.out.println("2.관리자 메뉴");
        System.out.println("3.프로그램 종료");
        System.out.println("===============");
    }

    public int insertUserInput() {
        Scanner s = new Scanner(System.in);

        int userInputNumber = -1;

        try {
            userInputNumber = Integer.parseInt(s.nextLine());
        } catch (NumberFormatException e) {
            System.out.println("잘못된 입력입니다. 1~3사이 숫자로 다시 시도해주세요");
        }

        return userInputNumber;
    }


    // 고객으로 로그인
    public void customerLogin() {
        System.out.println("===============");
        System.out.printf("1. 성함을 입력해주세요 : ");

        Scanner s = new Scanner(System.in);
        String userName = s.nextLine();

        Bank bank = new Bank();


        if (bank.CheckIfAccountExistByOwnerName(userName))
            showAccountList(userName);  // 고객이 가진 계좌 보여주기
        else {
            System.out.println("등록된 사용자 이름이 아닙니다. 계좌를 생성하시겠습니까?");
            System.out.println("1. Yes \n2. 종료하기");

            int userInputNumber = Integer.parseInt(s.nextLine());

            switch (userInputNumber) {
                case 1:
                    createOwnerAccount(userName);
                    showAccountList(userName);
                    break;
                case 2:
                    System.out.println("프로그램을 종료합니다.");
                    System.exit(0);
                    break;
            }
        }

    }

    public void showAccountList(String ownerName) {

        AccountRepository accountRepository = new AccountRepository();

        System.out.println("<" + ownerName + "님의 계좌 목록>");
        ArrayList<Account> ownerAccounts = accountRepository.customerFindAccounts(ownerName); // 마스킹 처리 후 출력까지 완료

        System.out.println("계좌를 선택해주세요. 0번을 누르시면 처음화면으로 돌아갑니다.");
        // 번호를 입력받고
        Scanner s = new Scanner(System.in);

        int inputNumber = Integer.parseInt(s.nextLine());

        if (inputNumber == 0)
            run();  // 처음 화면으로

        // 그 계좌의 정보를 기반으로 다음 UI 보여줌.

        Account account = ownerAccounts.get(inputNumber - 1);
        showBankingService(account);

    }

    public void createOwnerAccount(String ownerName) {
        Bank bank = new Bank();

        bank.registerAccount(ownerName);
        System.out.println("계좌가 성공적으로 생성되었습니다.\n");
    }

    public void showBankingService(Account account) {

        AccountRepository accountRepository = new AccountRepository();

        // System.out.println("이거 : " + account.getAccountNum());
        String[] linkedString = account.getAccountNum().split("-");

        Scanner s = new Scanner(System.in);

        while (true) {
            System.out.println("\n르탄 "
                    + linkedString[0] + "-" + linkedString[1] + "-" + accountRepository.accountNoMasking(linkedString[2]) + "\n");
            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("\n 0번을 누르시면 처음 화면으로 돌아갑니다.");

            int userInputNumber = Integer.parseInt(s.nextLine());

            switch (userInputNumber) {
                case 1: // 입금하기
                    System.out.println("입금하실 금액을 입력해주세요(원)");
                    int inputAmount = Integer.parseInt(s.nextLine());
                    accountRepository.depositToAccount(account.getAccountNum(), inputAmount);
                    System.out.println("입금이 완료되었습니다.");
                    break;
                case 2: // 출금하기
                    System.out.println("출금하실 금액을 입력해주세요(원)");
                    int outputAmount = Integer.parseInt(s.nextLine());
                    boolean withdrawSuccess = accountRepository.withdrawFromAccount(account.getAccountNum(), outputAmount);
                    if (withdrawSuccess) {
                        System.out.println("출금이 완료되었습니다.");
                    } else {
                        System.out.println("출금 가능한 금액이 부족합니다.");
                    }
                    break;
                case 3: // 잔액 확인하기
                    System.out.println(String.format("현재 잔액 : ₩%,d", account.getBalance()));
                    break;
                case 4: // 거래내역 확인하기
                    System.out.println("<거래내역>\n");
                    BillManager.getAllBills(account.getAccountNum());
                    break;
                case 5: // 종료하기
                    System.out.println("프로그램을 종료합니다.");
                    System.exit(0);
                    break;
                case 0: // 처음 화면으로 돌아가기
                    run();
                    break;
                default:
                    System.out.println("잘못된 입력입니다.");
                    break;
            }
        }


    }


    // 관리자 메뉴 = 은행원으로 로그인
    public void bankClerkMenu() {

        System.out.printf("관리자 비밀번호를 입력해주세요. : ");

        Scanner s = new Scanner(System.in);

        String adminPassword = s.nextLine();

        if (adminPassword.equals(Bank.adminPassword)) // 비밀번호가 맞을 때
            showAdminMenu();
        else {
            System.out.println("로그인 실패! 다시 시도하시겠습니까?");
            System.out.println("1. Yes \n2. 처음으로 돌아가기");

            int userInput = -1;

            while (true) {
                userInput = Integer.parseInt(s.nextLine());
                switch (userInput) {
                    case 1:
                        bankClerkMenu();
                        break;
                    case 2:
                        run();
                        break;
                    default:
                        System.out.println("잘못된 입력입니다.");
                }
            }
        }
    }

    public void showAdminMenu() {
        while (true) {
            System.out.println("<관리자 메뉴>");
            System.out.println("1. 계좌 등록");
            System.out.println("2. 계좌 삭제");
            System.out.println("3. 계좌 조회");
            System.out.println("\n 0번을 누르면 처음 화면으로 돌아갑니다.");

            Scanner s = new Scanner(System.in);

            int userInput = Integer.parseInt(s.nextLine());

            Bank bank = new Bank();

            switch (userInput) {
                case 1: // 계좌 등록
                    System.out.printf("계좌를 등록할 고객님의 이름을 입력해주세요. : ");
                    String ownerNameRegister = s.nextLine();
                    bank.registerAccount(ownerNameRegister);
                    break;
                case 2: // 계좌 삭제
                    System.out.printf("계좌를 삭제할 고객님의 이름을 입력해주세요. : ");
                    String ownerNameDelete = s.nextLine();
                    ArrayList<Account> accountList = bank.findAccountByOwnerName(ownerNameDelete);

                    if (accountList.size() > 0) {
                        int accountCounter = 0;
                        for (Account account : accountList) {
                            accountCounter += 1;
                            System.out.println(accountCounter + ". 르탄 " + account.getAccountNum() + " " + account.getOwnerName());
                        }
                    } else {    // 고객의 이름에 해당하는 계좌가 없는 경우 -> 관리자 메뉴로 돌아간다.
                        System.out.println("해당하는 고객의 계좌가 존재하지 않습니다.");
                        System.out.println("관리자 메뉴로 돌아갑니다.");
                        showAdminMenu();
                    }
                    System.out.printf("삭제할 계좌의 번호를 입력해주세요. : ");
                    int accountIndex = Integer.parseInt(s.nextLine());
                    bank.removeAccount(accountList.get(accountIndex - 1).getAccountNum());
                    System.out.println("해당 계좌를 삭제했습니다.");
                    break;
                case 3: // 계좌 조회
                    System.out.println("1. 계좌번호로 계좌 조회");
                    System.out.println("2. 이름으로 계좌 조회");
                    System.out.println("3. 전체 계좌 조회");

                    int choice = Integer.parseInt(s.nextLine());

                    switch(choice){
                        case 1: // 계좌번호로 계좌 조회
                            System.out.printf("계좌번호를 입력해주세요 : ");
                            String accountNum = s.nextLine();
                            bank.findAccountByAccountNum(accountNum);
                            break;
                        case 2: // 이름으로 계좌 조회
                            System.out.printf("고객의 이름을 입력해주세요. : ");
                            String ownerName = s.nextLine();
                            ArrayList<Account> searchedAccountList = bank.findAccountByOwnerName(ownerName);

                            if (searchedAccountList.size() > 0) {
                                int accountCounter = 0;
                                for (Account account : searchedAccountList) {
                                    accountCounter += 1;
                                    System.out.println(accountCounter + ". 르탄 " + account.getAccountNum() + " " + account.getOwnerName());
                                }
                            } else {    // 찾는 계좌가 없는 경우
                                System.out.println("해당하는 고객의 계좌가 존재하지 않습니다.");
                                System.out.println("관리자 메뉴로 돌아갑니다.");
                                showAdminMenu();
                            }
                            break;
                        case 3: // 전체 계좌 조회
                            bank.findAllAccounts();
                            break;
                    }
                    break;
                case 0:
                    run();
                    break;
                default:
                    System.out.println("잘못된 입력입니다.");
            }
        }
    }
}



 

 

[Account.java]

더보기
package org.example;



import java.util.Scanner;

public class Account {

   private String ownerName;
   private String accountNum;
   private int balance;


   
   //
   // ( 요구사항 7-1 ) 계좌는 입금기능이 있다.
   public void deposit(int amount) {

      this.balance += amount;

      // 거래내역 생성
      Bill bill = new Bill(this.accountNum, "입금", amount);

      // ( 요구사항 9 ) 계좌에서 잔고의 변화가 있을 때마다 거래 내역에 기록된다.
      BillManager.recordBill(bill);

   }

   // ( 요구사항 7-2 ) 계좌는 출금 기능이 있다. ( 출금액이 계좌에 들어있는 금액보다 작을 때 )
   public void withdraw(int amount) {

      if (amount <= balance) {
         this.balance -= amount;

         Bill bill = new Bill(this.accountNum, "출금", amount);

         // ( 요구사항 9 ) 계좌에서 잔고의 변화가 있을 때마다 거래 내역에 기록된다.
         BillManager.recordBill(bill);
      }
      else {
         System.out.println("계좌의 잔고가 부족합니다."); // 여기서 인코딩 문제 생길 수 있음! (*)
      }
   }

   // (요구사항 8)
   
   // ( 요구사항 11 ) 계좌는 모든 거래 내역을 조회할 수 있다.     
   public void getAllBills() {
      BillManager.getAllBills(accountNum);
   }


   // Constructor
   public Account(String ownerName, String accountNum){
      this.ownerName = ownerName;
      this.accountNum = accountNum;
      this.balance = 0;
   }

   // Getter
   public String getOwnerName() {
      return this.ownerName;
   }
   public String getAccountNum() {
      return this.accountNum;
   }
   public int getBalance() { return this.balance; }

}


 

 

[AccountRepository.java]

더보기
package org.example;

import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AccountRepository {

    // 계좌를 다 가지고 있음.
    static ArrayList<Account> accounts = new ArrayList<>();

    // (요구사항 1) 은행은 계좌를 등록한다 ( 단, 계좌번호는 정규 표현식으로 제한 )
    public void registerAccount(String ownerName, String accountNum) {
        // 계좌 생성
        Account account = new Account(ownerName, accountNum);

        // 계좌를 account arraylist에 저장한다.
        accounts.add(account);
    }


    public void removeAccount(String accountNum) {
        if(CheckIfAccountExistsByAccountNum(accountNum)) {
            for (Account account : accounts) {
                if (accountNum.equals(account.getAccountNum())) {
                    accounts.remove(account);
                    break;
                }
            }
        } else {
            System.out.println("삭제할 계좌가 존재하지 않습니다.");
        }
    }

    // 계좌는 입금기능이 있다.
    public void depositToAccount(String accountNum, int amount){

        if(CheckIfAccountExistsByAccountNum(accountNum)) {
            for (Account account : accounts) {
                if (accountNum.equals(account.getAccountNum())) {
                    account.deposit(amount);
                }
            }
        } else {
            System.out.println("입금할 계좌가 존재하지 않습니다.");
        }
    }

    // 계좌는 출금기능이 있다.

    public boolean withdrawFromAccount(String accountNum, int amount){

        for (Account account : accounts) {
            if (accountNum.equals(account.getAccountNum())) {
                if (account.getBalance() >= amount) {
                    account.withdraw(amount);
                    return true;    // 출금 성공
                } else {  // 잔액 부족으로 출금 불가
                    return false;
                }
            }
        }
        return false;
    }

    public boolean CheckIfAccountExistsByAccountNum(String accountNum){
        for(Account account : accounts){
            if(accountNum.equals(account.getAccountNum()))
                return true;
        }
        return false;
    }

    public boolean CheckIfAccountExistByOwnerName(String ownerName){
        for(Account account : accounts){
            if(ownerName.equals(account.getOwnerName()))
                return true;
        }
        return false;
    }


    // ( 요구사항 3 ) 은행은 계좌번호로 계좌를 찾을 수 있다.
    public void findAccountByAccountNum(String accountNum) {

        if(CheckIfAccountExistsByAccountNum(accountNum)) {
            for (Account account : accounts) {
                if (accountNum.equals(account.getAccountNum())) {
                    System.out.println("르탄 " + account.getAccountNum() + " " + account.getOwnerName());
                    break;
                }
            }
        }
        else {
            System.out.println("찾는 계좌가 존재하지 않습니다.");
        }
    }

    // ( 요구사항 4 ) 은행은 계좌의 소유자 명으로 계좌를 찾을 수 있다.
    public ArrayList<Account> findAccountByOwnerName(String ownerName) {

        ArrayList<Account> ownerAccounts = new ArrayList<>();

        if (accounts.size() != 0) {
            for (Account account : accounts) {
                if (ownerName.equals(account.getOwnerName()))
                    ownerAccounts.add(account);
            }
        } else {
            System.out.println("은행에 등록된 계좌가 존재하지 않습니다.");
        }
        return ownerAccounts;
    }

    public Account getAccountInfoByAccountNum(String accountNum){
        for ( Account account : accounts ){
            if ( accountNum.equals(account.getAccountNum()))
                return account;
        }
        return null;
    }



    // ( 요구사항 5 ) 은행은 모든 계좌의 목록을 조회할 수 있다.
    public void findAllAccounts() {
        if (accounts.size() != 0) {
            int accountCounter = 0;
            for (Account account : AccountRepository.accounts) {
                accountCounter += 1;
                System.out.println(accountCounter + ". 르탄 " + account.getAccountNum() + " " + account.getOwnerName());
            }
        } else {
            System.out.println("등록된 계좌가 존재하지 않습니다.");
        }
    }

    //고객이 조회할때 : 고객은 자신의 계좌만 조회 가능 but 정규 표현식이 필요 +마스킹 처리
    //split 으로 "-" 제거후 LinkedString [0,1,2]에 삼등분해서 담아놓고 2번 인덱스만 마스킹처리 후 인덱스 0 + 1+ 2 하는방식
    public ArrayList<Account> customerFindAccounts(String customerName) {

        ArrayList<Account> ownerAccounts = new ArrayList<>();

        int accountCounter = 0;

        for (Account account : accounts) {
            if (customerName.equals(account.getOwnerName())) {

                ownerAccounts.add(account);
                accountCounter += 1;

                String[] linkedString = account.getAccountNum().split("-");
                System.out.println( accountCounter + ". 르탄 "
                            + linkedString[0]+"-"+linkedString[1] + "-" + accountNoMasking(linkedString[2])
                            + "\n");
            }
        }
        return ownerAccounts;
    }
    //고객조회시 마스킹 처리 로직
    public String accountNoMasking(String accountNo){
        // 계좌번호는 숫자만 파악하므로
        String regex = "(^[0-9]+)$";

        Matcher matcher = Pattern.compile(regex).matcher(accountNo);
        if(matcher.find()) {
            int length = accountNo.length();
            if(length >= 5) {
                char[] c = new char[5];
                Arrays.fill(c, '*');

                return accountNo.replace(accountNo, accountNo.substring(0, length-5) + String.valueOf(c));
            }
        }
        return accountNo;
    }
}

 

 

[Bank.java]

더보기
package org.example;

import java.util.ArrayList;
import java.util.Random;

public class Bank {
    private AccountRepository accountRepository;
    private String bankName;

    static String adminPassword = "8016";   // 은행 관리자 비밀번호

    Bank() {
        accountRepository = new AccountRepository();
        bankName = "르탄";   // 우리 세계에서는 르탄은행만 있습니다.
    }

    // ( 요구사항 1 ) 은행은 계좌를 등록한다 ( 단, 계좌번호는 정규 표현식으로 제한 )
    public void registerAccount(String ownerName){
        // 1. 계좌번호 만드는 로직
        String accountNum = createAccountNum();

        accountRepository.registerAccount(ownerName, accountNum);
    }


    //계좌번호 생성시 앞자리 4자리 은행 고유값 + 중간 4자리는 일정하게 증가 +뒷5자리는 난수로 구성
    static int counter = 1;
    private String createAccountNum(){
        /* 계좌번호 생성 로직 = 정규 표현식 */
        Random random = new Random();
        int createNum = 0;
        String ranNum = "";
        String randomNum = "";
        for (int i=0; i<5; i++) {
            createNum = random.nextInt(9);
            ranNum = Integer.toString(createNum);
            randomNum += ranNum;
        }
        String onlyBankNum = "8016";
        String countAccountNum = String.format("%04d",counter);

        counter++;
        String accountNum = onlyBankNum+"-"+countAccountNum+"-"+randomNum;
        return accountNum;
    }


    // ( 요구사항 2 ) 은행은 계좌를 관리(삭제)한다.


    // 계좌를 삭제하는 경우
    public void removeAccount(String accountNum){
        accountRepository.removeAccount(accountNum);
    }

    // 요구사항 3. 은행은 계좌번호로 계좌를 찾을 수 있다.
    public void findAccountByAccountNum(String accountNum){
        accountRepository.findAccountByAccountNum(accountNum);
    }

    // 요구사항 4. 은행은 계좌의 소유명으로 계좌를 찾을 수 있다.
    public ArrayList<Account> findAccountByOwnerName(String ownerName){
        return accountRepository.findAccountByOwnerName(ownerName);
    }

    // 요구사항 5. 은행은 모든 계좌의 목록을 조회할 수 있다.
    public void findAllAccounts(){
        accountRepository.findAllAccounts();
    }

    public boolean CheckIfAccountExistByOwnerName(String ownerName){
        return accountRepository.CheckIfAccountExistByOwnerName(ownerName);
    }


}

 

 

[Bill.java]

더보기
package org.example;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class Bill {

    // ( 요구사항 10 ) 계좌의 거래 내역은 거래 일자, 거래 시간, 계좌번호, 입금/출금 여부, 거래 금액, 은행 명으로 구성된다.
    private String dealDate;   // 거래 일자 <- 시스템에서 하믄 됨 ( 파라미터로 받을필요 x )
    private String dealTime;   // 거래 시간 <- 시스템에서 하믄 됨 ( 파라미터로 받을필요 x )
    private String accountNum; // 계좌 번호 <- Account 의 deposit / withdraw에서 넘겨줘야함. 메시지로
    private String depositOrWithdraw;  // 입금/출금 여부 <- deposit / withdraw에서 받음.
    private int dealAmount;    // 거래 금액 <- Account의 deposit/withdraw에서 넘겨줌
    private String bankName;   // 은행 이름 : 르탄 은행으로 고정


    // Constructor
    Bill(String accountNum, String depositOrWithdraw, int dealAmount ){
        this.accountNum = accountNum;
        this.depositOrWithdraw = depositOrWithdraw; // "입금", "출금"만 가능.
        this.dealAmount = dealAmount;
        // dealDate 초기화 로직 ( 현재 시간 메모장 서비스에서 LocalDate 사용한거처럼 )
        // 현재 날짜 구하기 (시스템 시계, 시스템 타임존)
        LocalDate nowMonth = LocalDate.now();
        DateTimeFormatter formatterMonth = DateTimeFormatter.ofPattern("yyyy/MM/dd");//포멧
        this.dealDate = nowMonth.format(formatterMonth); // 저장
        // dealTime 초기화 로직
        // 현재 시간
        LocalTime nowTime = LocalTime.now();
        DateTimeFormatter formatterTime = DateTimeFormatter.ofPattern("HH:mm:ss");
        this.dealTime= nowTime.format(formatterTime);
        this.bankName = "르탄";  // 우리 세계에서는 르탄 은행만 있습니다.
    }


    // Getter
    public String getDealDate() {
        return this.dealDate;
    }

    public String getDealTime(){
        return this.dealTime;
    }

    public String getAccountNum(){
        return this.accountNum;
    }

    public String getDepositOrWithdraw(){
        return this.depositOrWithdraw;
    }

    public int getDealAmount(){
        return this.dealAmount;
    }

    public String getBankName(){
        return this.bankName;
    }

}

 

 

[BillManager.java]

더보기
package org.example;

import java.util.ArrayList;

public class BillManager {

    private static ArrayList<Bill> bills = new ArrayList<>();

    public static void getAllBills(String accountNum) {
        for ( Bill bill : bills ) {
            if(bill.getAccountNum().equals(accountNum) )
            {
                AccountRepository accountRepository = new AccountRepository();

                String[] linkedString = accountNum.split("-");

                String AccountNumMasking = linkedString[0]+"-"+linkedString[1] + "-" + accountRepository.accountNoMasking(linkedString[2]);

                System.out.println(String.format("은행 : %s, 계좌번호 : %s, 입/출금 여부 : %s, 거래 금액 : ₩%,d, 거래일자 : %s, 거래 시간  : %s"  ,
                        bill.getBankName(),AccountNumMasking,bill.getDepositOrWithdraw(),bill.getDealAmount(),bill.getDealDate(),bill.getDealTime()));
            }
        }
    }

    public static void recordBill(Bill bill){
        bills.add(bill);
    }

}

'Sparta > What I Learned' 카테고리의 다른 글

22.12.1  (0) 2022.12.02
22.11.30  (0) 2022.11.30
22.11.28  (0) 2022.11.29
22.11.27  (2) 2022.11.28
22.11.25  (1) 2022.11.25