본문 바로가기
네이버클라우드/JAVA 웹 프로그래밍

JAVA 16일차 (2023-06-14) 자바 기초 DAY14_CRUD 구현 / 스태틱 필드의 한계 확인_개인 프로젝트 - 마트 관리 시스템

by prometedor 2023. 6. 14.

직원 클래스를 추가하여 관리자와 일반직원 분류

 

Member.java

package bitcamp.report.vo;

public class Member {

  // 모든 인스턴스가 공유하는 값은 스태틱 필드에 보관한다.
  private static int userId = 1;

  // 상수는 스태틱 필드로 정의한다.
  // 정보를 다룰 때는 그 정보를 갖고 있는 클래스에 그 기능을 둔다.
  // 필드도 마찬가지이다.
  // => GRASP 패턴: Information Expert
  public static final char MANAGER = '0';
  public static final char STAFF = '1';

  // 인스턴스 필드는 각각 개별적으로 유지해야 하는 값을 저장할 때 사용한다.
  // new 명령을 통해 변수를 Heap 영역에 생성한다.
  private int no;
  private String name;
  private String phone;
  private String password;
  private char position;

  // 생성자는 인스턴스를 생성한 후 필드를 초기화시키는 일을 한다.
  // 인스턴스를 사용할 때 문제가 없도록 유효한 값으로 초기화시킨다.
  // 기본 생성자(default constructor)는 개발자가 생성자를 정의하지 않을 때
  // 컴파일러가 추가해주는 생성자다.
  // 물론 개발자가 직접 추가할 수도 있다.
  public Member() {
    this.no = userId++;
  }

  // 겟터/셋터는 인스턴스 필드의 값을 설정하고 꺼내는 메서드다.
  // 보통 외부에서 직접 필드에 접근하는 것을 막았을 때 사용한다.
  public int getNo() {
    return no;
  }

  public void setNo(int no) {
    this.no = no;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getPhone() {
    return phone;
  }

  public void setPhone(String phone) {
    this.phone = phone;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public char getPosition() {
    return position;
  }

  public void setPosition(char gender) {
    this.position = gender;
  }

}

 

MemberHandler.java

package bitcamp.report.handler;

import bitcamp.report.vo.Member;
import bitcamp.util.Prompt;

public class MemberHandler {

  static final int MAX_SIZE = 100;
  static Member[] members = new Member[MAX_SIZE];
  static int length = 0;

  public static void inputMember() {
    if (!available()) {
      System.out.println("더이상 입력할 수 없습니다!");
      return;
    }

    Member m = new Member();
    m.setName(Prompt.inputString("이름? "));
    m.setPhone(Prompt.inputString("전화번호? "));
    m.setPassword(Prompt.inputString("암호? "));
    m.setPosition(inputPosition((char) 0));

    // 위에서 만든 Member 인스턴스의 주소를 잃어버리지 않게
    // 레퍼런스 배열에 담는다.
    members[length++] = m;
  }

  public static void printMembers() {
    System.out.println("---------------------------------------");
    System.out.println("번호, 이름, 전화번호, 직책");
    System.out.println("---------------------------------------");

    for (int i = 0; i < length; i++) {
      Member m = members[i];
      System.out.printf("%d, %s, %s, %s\n",
          m.getNo(), m.getName(), m.getPhone(),
          toPositionString(m.getPosition()));
    }
  }

  public static void viewMember() {
    String memberNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Member m = members[i];
      if (m.getNo() == Integer.parseInt(memberNo)) {
        System.out.printf("이름: %s\n", m.getName());
        System.out.printf("전화번호: %s\n", m.getPhone());
        System.out.printf("직책: %s\n", toPositionString(m.getPosition()));
        return;
      }
    }
    System.out.println("해당 번호의 직원이 없습니다!");
  }

  public static String toPositionString(char position) {
    return position == '0' ? "관리자" : "일반직원";
  }

  public static void updateMember() {
    String memberNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Member m = members[i];
      if (m.getNo() == Integer.parseInt(memberNo)) {
        System.out.printf("이름(%s)? ", m.getName());
        m.setName(Prompt.inputString(""));
        System.out.printf("전화번호(%s)? ", m.getPhone());
        m.setPhone(Prompt.inputString(""));
        System.out.printf("새암호? ");
        m.setPassword(Prompt.inputString(""));
        m.setPosition(inputPosition(m.getPosition()));
        return;
      }
    }
    System.out.println("해당 번호의 직원이 없습니다");
  }

  private static char inputPosition(char position) {
    String label;
    if (position == 0) {
      label = "직책?\n";
    } else {
      label = String.format("직책(%s)?\n", toPositionString(position));
    }

    while (true) {
      String menuNo = Prompt.inputString(label +
          "  1. 관리자\n" +
          "  2. 일반직원\n" +
          "> ");

      switch (menuNo) {
        case "1":
          return Member.MANAGER;
        case "2":
          return Member.STAFF;
        default:
          System.out.println("무효한 번호입니다.");
      }
    }
  }

  public static void deleteMember() {
    int memberNo = Prompt.inputInt("번호? ");

    int deletedIndex = indexOf(memberNo);
    if (deletedIndex == -1) {
      System.out.println("해당 번호의 직원이 없습니다!");
      return;
    }

    for (int i = deletedIndex; i < length - 1; i++) {
      members[i] = members[i + 1];
    }

    members[--length] = null;
  }

  private static int indexOf(int memberNo) {
    for (int i = 0; i < length; i++) {
      Member m = members[i];
      if (m.getNo() == memberNo) {
        return i;
      }
    }
    return -1;
  }

  private static boolean available() {
    return length < MAX_SIZE;
  }
}

 

ㄴ 주소값에 null 을 넣는 순간 null 이 된 주소 값을 가리키면 NullPointerException 이 발생함

 

ㄴ 해당 내용을 개인 프로젝트에 적용

 

복사/붙여넣기를 이용한 CRUD 구현

게시글 CRUD 기능 추가 - Value Object(Board), Handler 클래스(BoardHandler) 추가

Board.java

package bitcamp.report.vo;

public class Board {

  // 모든 인스턴스가 공유하는 값은 스태틱 필드에 보관한다.
  private static int boardNo = 1;

  private int no; // private 이라는 modifier 를 사용하여 접근 제어
  private String title;
  private String content;
  private String writer;
  private String password;
  private int viewCount;
  private long createdDate; // 밀리세컨드

  public Board() { // 생성자
    this.no = boardNo++;
    this.createdDate = System.currentTimeMillis();
  }

  // 겟터/셋터는 인스턴스 필드의 값을 설정하고 꺼내는 메서드다.
  // 보통 외부에서 직접 필드에 접근하는 것을 막았을 때 사용한다.
  public int getNo() {
    return no;
  }

  public void setNo(int no) {
    this.no = no;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }

  public String getWriter() {
    return writer;
  }

  public void setWriter(String writer) {
    this.writer = writer;
  }

  public int getViewCount() {
    return viewCount;
  }

  public void setViewCount(int viewCount) {
    this.viewCount = viewCount;
  }

  public long getCreatedDate() {
    return createdDate;
  }

  public void setCreatedDate(long createdDate) {
    this.createdDate = createdDate;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

}

 

BoardHandler.java

package bitcamp.report.handler;

import bitcamp.report.vo.Board;
import bitcamp.util.Prompt;

public class BoardHandler {

  static final int MAX_SIZE = 100;
  static Board[] boards = new Board[MAX_SIZE];
  static int length = 0;

  public static void inputBoard() {
    if (!available()) {
      System.out.println("더이상 입력할 수 없습니다!");
      return;
    }

    Board board = new Board();
    board.setTitle(Prompt.inputString("제목? "));
    board.setContent(Prompt.inputString("내용? "));
    board.setWriter(Prompt.inputString("작성자? "));
    board.setPassword(Prompt.inputString("암호? "));

    // 위에서 만든 Board 인스턴스의 주소를 잃어버리지 않게
    // 레퍼런스 배열에 담는다.
    boards[length++] = board;
  }

  public static void printBoards() {
    System.out.println("---------------------------------------");
    System.out.println("번호, 제목, 내용, 작성자, 조회수, 등록일");
    System.out.println("---------------------------------------");

    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      System.out.printf("%d, %s, %s, %s, %d, %tY-%5$tm-%5$td\n",
          board.getNo(),
          board.getTitle(),
          board.getWriter(),
          board.getViewCount(),
          board.getCreatedDate());
    }
  }

  public static void viewBoard() {
    String boardNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == Integer.parseInt(boardNo)) {
        System.out.printf("제목: %s\n", board.getTitle());
        System.out.printf("내용: %s\n", board.getContent());
        System.out.printf("작성자: %s\n", board.getWriter());
        System.out.printf("조회수: %d\n", board.getViewCount());
        System.out.printf("등록일: %tY-%1$tm-%1$td\n", board.getCreatedDate());
        board.setViewCount(board.getViewCount() + 1); // 조회수 증가
        return;
      }
    }
    System.out.println("해당 번호의 게시글이 없습니다");
  }

  public static void updateBoard() {
    String boardNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == Integer.parseInt(boardNo)) {
        if (!Prompt.inputString("암호? ").equals(board.getPassword())) {
          System.out.println("암호가 일치하지 않습니다");
          return;
        }
        System.out.printf("제목(%s)? ", board.getTitle());
        board.setTitle(Prompt.inputString(""));
        System.out.printf("내용(%s)? ", board.getContent());
        board.setContent(Prompt.inputString(""));
        return;
      }
    }
    System.out.println("해당 번호의 게시글이 없습니다");
  }

  public static void deleteBoard() {
    int boardNo = Prompt.inputInt("번호? ");

    int deletedIndex = indexOf(boardNo);
    if (deletedIndex == -1) {
      System.out.println("해당 번호의 게시글이 없습니다!");
      return;
    }

    for (int i = deletedIndex; i < length - 1; i++) {
      boards[i] = boards[i + 1];
    }

    boards[--length] = null;
  }

  private static int indexOf(int boardNo) {
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == boardNo) {
        return i;
      }
    }
    return -1;
  }

  private static boolean available() {
    return length < MAX_SIZE;
  }
}

ㄴ Member.java, MemberHandler.java 의 소스코드를 약간 수정하여 Board.java, BoardHandler.java 생성

 

리팩토링

Prompt 클래스 리팩토링

package bitcamp.util;

import java.util.Scanner;

public class Prompt {

  static Scanner scanner = new Scanner(System.in);

  public static String inputString(String title, Object... args) {
    System.out.printf(title, args);
    return scanner.nextLine();
  }

  public static int inputInt(String title, Object... args) {
    // System.out.print(title);
    // return scanner.nextLine();
    return Integer.parseInt(inputString(title, args));
  }

  public static void close() {
    scanner.close();
  }

}

ㄴ Object... args 라는 Argument 추가

ㄴ print -> printf

ㄴ args 라는 parameter  추가

 

BoardHandler 클래스 리팩토링

ㄴ BoardHandler.java 의 updateBoard() 메서드를 리팩토링

=> 

ㄴ 리팩토링 결과

 

ㄴ BoardHandler.java 의 updateBoard() 메서드를 리팩토링

=> 

ㄴ 리팩토링 결과

 

ㄴ BoardHandler.java 의 deleteBoard() 메서드를 리팩토링

=> 

ㄴ 리팩토링 결과

 

App.java

ㄴ App.java 수정 => menuNo 와 해당 메뉴에 따른 기능 선언

                                 => 메뉴 노출 부분 추가

 

 

 

ㄴ 해당 내용 개인 프로젝트에 적용

 

스태틱 필드의 한계 확인

App.java

ㄴ App.java 수정 => menuNo 와 해당 메뉴에 따른 기능 선언

                                 => 메뉴 노출 부분 추가

 

 

ㄴ App.java 수정 => BoardHandler -> BoardHandler2 로 변경해줌

 

 

총정리 코드

App.java

package bitcamp.report;

import bitcamp.report.handler.MemberHandler;
import bitcamp.report.handler.itemHandler;
import bitcamp.report.handler.BoardHandler;
import bitcamp.report.handler.BoardHandler2;
import bitcamp.util.Prompt;

public class App {

    public static void main(String[] args) {

        printTitle();

        printMenu();

        while (true) {
            String menuNo = Prompt.inputString("메인> ");
            if (menuNo.equals("99")) {
                break;
            } else if (menuNo.equals("menu")) {
                printMenu();
            } else if (menuNo.equals("1")) {
                MemberHandler.inputMember();
            } else if (menuNo.equals("2")) {
                MemberHandler.printMembers();
            } else if (menuNo.equals("3")) {
                MemberHandler.viewMember();
            } else if (menuNo.equals("4")) {
                MemberHandler.updateMember();
            } else if (menuNo.equals("5")) {
                MemberHandler.deleteMember();
            } else if (menuNo.equals("6")) {
                itemHandler.inputItem();
            } else if (menuNo.equals("7")) {
                itemHandler.printItems();
            } else if (menuNo.equals("8")) {
                itemHandler.viewItem();
            } else if (menuNo.equals("9")) {
                itemHandler.updateItem();
            } else if (menuNo.equals("10")) {
                itemHandler.deleteItem();
            } else if (menuNo.equals("11")) {
                BoardHandler.inputBoard();
            } else if (menuNo.equals("12")) {
                BoardHandler.printBoards();
            } else if (menuNo.equals("13")) {
                BoardHandler.viewBoard();
            } else if (menuNo.equals("14")) {
                BoardHandler.updateBoard();
            } else if (menuNo.equals("15")) {
                BoardHandler.deleteBoard();
            } else if (menuNo.equals("16")) {
                BoardHandler2.inputBoard();
            } else if (menuNo.equals("17")) {
                BoardHandler2.printBoards();
            } else if (menuNo.equals("18")) {
                BoardHandler2.viewBoard();
            } else if (menuNo.equals("19")) {
                BoardHandler2.updateBoard();
            } else if (menuNo.equals("20")) {
                BoardHandler2.deleteBoard();
            } else {
                System.out.println(menuNo);
            }
        }

        Prompt.close();
    }

    static void printMenu() {
        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("8. 물품 조회");
        System.out.println("9. 물품 변경");
        System.out.println("10. 물품 삭제");
        System.out.println("11. 게시글 등록");
        System.out.println("12. 게시글 목록");
        System.out.println("13. 게시글 조회");
        System.out.println("14. 게시글 변경");
        System.out.println("15. 게시글 삭제");
        System.out.println("16. 공지 등록");
        System.out.println("17. 공지 목록");
        System.out.println("18. 공지 조회");
        System.out.println("19. 공지 변경");
        System.out.println("20. 공지 삭제");
        System.out.println("99. 종료");
    }

    static void printTitle() {
        System.out.println("마트 관리 시스템");
        System.out.println("---------------------------------------------------------------------");
    }
}

 

Board.java

package bitcamp.report.vo;

public class Board {

  // 모든 인스턴스가 공유하는 값은 스태틱 필드에 보관한다.
  private static int boardNo = 1;

  private int no; // private 이라는 modifier 를 사용하여 접근 제어
  private String title;
  private String content;
  private String writer;
  private String password;
  private int viewCount;
  private long createdDate; // 밀리세컨드

  public Board() { // 생성자
    this.no = boardNo++;
    this.createdDate = System.currentTimeMillis();
  }

  // 겟터/셋터는 인스턴스 필드의 값을 설정하고 꺼내는 메서드다.
  // 보통 외부에서 직접 필드에 접근하는 것을 막았을 때 사용한다.
  public int getNo() {
    return no;
  }

  public void setNo(int no) {
    this.no = no;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }

  public String getWriter() {
    return writer;
  }

  public void setWriter(String writer) {
    this.writer = writer;
  }

  public int getViewCount() {
    return viewCount;
  }

  public void setViewCount(int viewCount) {
    this.viewCount = viewCount;
  }

  public long getCreatedDate() {
    return createdDate;
  }

  public void setCreatedDate(long createdDate) {
    this.createdDate = createdDate;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

}

 

BoardHandler.java

package bitcamp.report.handler;

import bitcamp.report.vo.Board;
import bitcamp.util.Prompt;

public class BoardHandler {

  static final int MAX_SIZE = 100;
  static Board[] boards = new Board[MAX_SIZE];
  static int length = 0;

  public static void inputBoard() {
    if (!available()) {
      System.out.println("더이상 입력할 수 없습니다!");
      return;
    }

    Board board = new Board();
    board.setTitle(Prompt.inputString("제목? "));
    board.setContent(Prompt.inputString("내용? "));
    board.setWriter(Prompt.inputString("작성자? "));
    board.setPassword(Prompt.inputString("암호? "));

    // 위에서 만든 Board 인스턴스의 주소를 잃어버리지 않게
    // 레퍼런스 배열에 담는다.
    boards[length++] = board;
  }

  public static void printBoards() {
    System.out.println("---------------------------------------");
    System.out.println("번호, 제목, 내용, 작성자, 조회수, 등록일");
    System.out.println("---------------------------------------");

    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      System.out.printf("%d, %s, %s, %d, %tY-%5$tm-%5$td\n",
          board.getNo(),
          board.getTitle(),
          board.getWriter(),
          board.getViewCount(),
          board.getCreatedDate());
    }
  }

  public static void viewBoard() {
    String boardNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == Integer.parseInt(boardNo)) {
        System.out.printf("제목: %s\n", board.getTitle());
        System.out.printf("내용: %s\n", board.getContent());
        System.out.printf("작성자: %s\n", board.getWriter());
        System.out.printf("조회수: %d\n", board.getViewCount());
        System.out.printf("등록일: %tY-%1$tm-%1$td\n", board.getCreatedDate());
        board.setViewCount(board.getViewCount() + 1); // 조회수 증가
        return;
      }
    }
    System.out.println("해당 번호의 게시글이 없습니다");
  }

  public static void updateBoard() {
    String boardNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == Integer.parseInt(boardNo)) {
        if (!Prompt.inputString("암호? ").equals(board.getPassword())) {
          System.out.println("암호가 일치하지 않습니다");
          return;
        }
        board.setTitle(Prompt.inputString("제목(%s)? ", board.getTitle()));
        board.setContent(Prompt.inputString("내용(%s)? ", board.getContent()));
        return;
      }
    }
    System.out.println("해당 번호의 게시글이 없습니다");
  }

  public static void deleteBoard() {

    int deletedIndex = indexOf(Prompt.inputInt("번호? "));
    if (deletedIndex == -1) {
      System.out.println("해당 번호의 게시글이 없습니다!");
      return;
    }

    for (int i = deletedIndex; i < length - 1; i++) {
      boards[i] = boards[i + 1];
    }

    boards[--length] = null;
  }

  private static int indexOf(int boardNo) {
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == boardNo) {
        return i;
      }
    }
    return -1;
  }

  private static boolean available() {
    return length < MAX_SIZE;
  }
}

 

BoardHandler2.java

package bitcamp.report.handler;

import bitcamp.report.vo.Board;
import bitcamp.util.Prompt;

public class BoardHandler2 {

  static final int MAX_SIZE = 100;
  static Board[] boards = new Board[MAX_SIZE];
  static int length = 0;

  public static void inputBoard() {
    if (!available()) {
      System.out.println("더이상 입력할 수 없습니다!");
      return;
    }

    Board board = new Board();
    board.setTitle(Prompt.inputString("제목? "));
    board.setContent(Prompt.inputString("내용? "));
    board.setWriter(Prompt.inputString("작성자? "));
    board.setPassword(Prompt.inputString("암호? "));

    // 위에서 만든 Board 인스턴스의 주소를 잃어버리지 않게
    // 레퍼런스 배열에 담는다.
    boards[length++] = board;
  }

  public static void printBoards() {
    System.out.println("---------------------------------------");
    System.out.println("번호, 제목, 내용, 작성자, 조회수, 등록일");
    System.out.println("---------------------------------------");

    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      System.out.printf("%d, %s, %s, %d, %tY-%5$tm-%5$td\n",
          board.getNo(),
          board.getTitle(),
          board.getWriter(),
          board.getViewCount(),
          board.getCreatedDate());
    }
  }

  public static void viewBoard() {
    String boardNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == Integer.parseInt(boardNo)) {
        System.out.printf("제목: %s\n", board.getTitle());
        System.out.printf("내용: %s\n", board.getContent());
        System.out.printf("작성자: %s\n", board.getWriter());
        System.out.printf("조회수: %d\n", board.getViewCount());
        System.out.printf("등록일: %tY-%1$tm-%1$td\n", board.getCreatedDate());
        board.setViewCount(board.getViewCount() + 1); // 조회수 증가
        return;
      }
    }
    System.out.println("해당 번호의 게시글이 없습니다");
  }

  public static void updateBoard() {
    String boardNo = Prompt.inputString("번호? ");
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == Integer.parseInt(boardNo)) {
        if (!Prompt.inputString("암호? ").equals(board.getPassword())) {
          System.out.println("암호가 일치하지 않습니다");
          return;
        }
        board.setTitle(Prompt.inputString("제목(%s)? ", board.getTitle()));
        board.setContent(Prompt.inputString("내용(%s)? ", board.getContent()));
        return;
      }
    }
    System.out.println("해당 번호의 게시글이 없습니다");
  }

  public static void deleteBoard() {

    int deletedIndex = indexOf(Prompt.inputInt("번호? "));
    if (deletedIndex == -1) {
      System.out.println("해당 번호의 게시글이 없습니다!");
      return;
    }

    for (int i = deletedIndex; i < length - 1; i++) {
      boards[i] = boards[i + 1];
    }

    boards[--length] = null;
  }

  private static int indexOf(int boardNo) {
    for (int i = 0; i < length; i++) {
      Board board = boards[i];
      if (board.getNo() == boardNo) {
        return i;
      }
    }
    return -1;
  }

  private static boolean available() {
    return length < MAX_SIZE;
  }
}