본문 바로가기
자바/실습(Practice)

게시판 (BBS with NIO)

by 피톤치즈 2017. 2. 5.
반응형

들어가기 전에
JAVA기능은

  • NIO 파일 입출력 이용
  • Calendar class를 이용한 날짜 표기

BBS with NIO

  1. JAVA파일 입출력방식 중 NIO를 사용하여 게시판 작성.

  2. class 구성

    • 사용자의 명령을 입력 받는 main_bbs
    • bbs의 기능(C,R,U,D) 구현 (CRUD인데 함수명은 remove를 사용) 하는 bbs_controller
    • 파일 읽기 쓰기 기능을 하는 file_util
  3. 시스템 구성

    • 글번호, 글쓴이, 제목, 내용, 시간이 1개의 글정보로 구성.
    • 각 항목을 구분하는 DATA_SPLIT, 내용의 줄변경을 표시하는 NEW_LINE, 게시글정보의 끝을 알려주는 END_LINE은 상수로 사용
    • 메뉴는 create, remove, update, read, list, exit으로 구성
      • 여기서 list는 전체글의 글번호, 글쓴이, 제목을 보여줌.
    • 파일은 게시판 글수를 가지는 파일과 전체 내용을 저장하는 파일로 구성.
  4. 1차 완성본으로 예외처리나 중복구문, 좋지 않은 소스코드등은 포함되어 있음.

  5. 코드 설명

    • main_bbs의 main부분.
BbsController control = new BbsController();
Scanner scanner = new Scanner(System.in);

String command = "";    //명령어를 입력받을 변수 선언

boolean flag = true;    //시스템(?)의 끝을 알기 위한 변수 선언
while(flag) {            //게시판 동작이 계속되면 무한루프.
    print_menu();        //메뉴 프린트

    System.out.println("명령어를 입력하세요");
    command = scanner.nextLine();

    if ( command.equals("create")) {
        create(scanner, control);
    }
    else if ( command.equals("remove")) {
        remove(scanner, control);
    }
    else if ( command.equals("update")) {
        update(scanner, control);
    }
    else if ( command.equals("read")) {
        read(scanner, control);
    }
    else if ( command.equals("list")) {
        list(control);
    }
    else if ( command.equals("exit")) {
        flag = false;
        System.out.println("Turn Off. see you!");
    }
    else    //잘못입력하면 출력
    {
        System.out.println("");
        System.out.println("잘못입력... 재입력...");
        System.out.println("");
    }
}
  • main_bbs의 Create (생성)
public static void create(Scanner scanner, BbsController control) {

    String Input = ""; 
    String scanline = "";

    System.out.println("제목을 입력하세요.");
    scanline = scanner.nextLine();
    Input = scanline + DATA_SPLIT;

    System.out.println("작성자를 입력하세요.");
    scanline = scanner.nextLine();
    Input += scanline + DATA_SPLIT;

    System.out.println("내용을 입력하세요.(입력 완료 : wq)");

    //내용입력... wq를 입력해야만 루틴멈춤.
    boolean in = true;
    while (in) {
        scanline = scanner.nextLine();

        if ( Arrays.equals(scanline.toCharArray(), "wq".toCharArray())) {
            in = false;
            Input += DATA_SPLIT;
        }else {
            Input = Input+ scanline + NEW_LINE;
        }
    }

    String str = FileUtil.readNioBbs(DIR, IDX_NAME);    //미리저장된 게시글이 있는지 파악

    int count = 0;
    if ( isDigit(str) == true && str.length() != 0) {
        count = Integer.parseInt(str);
        count++;    //미리 저장된것이 있다면 갯수에 1 추가.
    }
    else {
        count = 1;
    }

    Input = count + DATA_SPLIT + Input;    //글번호 앞에 추가.

    Input = Input + control.getDate() + END_LINE;    //입력일자 추가후 게시글 정보 마지막을 더함.

    control.createBbs(Input);    //파일 저장.

    System.out.println(".....저장완료......");
}
  • main_bbs의 Read(읽기)
public static void read(Scanner scanner, BbsController control) {
    System.out.println("글번호를 입력하세요.");
    String tStr = "";
    int idx = 2;

    while(idx > 0) {    //숫자를 입력하지 않았을 경우 1번 기회를 더줌.
        tStr = scanner.nextLine();
        if ( isDigit(tStr) == true) {
            idx = -1;
        }
        else {
            System.out.println("숫자를 입력해주세요.");
            idx--;
        }
    }
    if ( idx == -1) {    //제대로 입력되었으면.
        String str = control.readBbs(tStr);    //파일에서 같은 글번호가 있는지 확인
        if ( str == null)
        {
            System.out.println("입력한 글번호는 없습니다");
        }
        else
        {
            print(str);        //같은 게시글번호가 있으면 프린트.
            //이부분은 공유된 소스에 있으니 설명 생략.
        }
    }
    else {
        System.out.println("사용방법을 확인해주세요.");
    }
}
  • main_bbs의 Update(수정)
public static void update(Scanner scanner, BbsController control) {
    System.out.println("글번호를 입력하세요.");
    String tStr = "";
    int idx = 2;
    int num = 0;

    while(idx > 0) {    //숫자 입력을 확인하고 잘못입력시 기회 더줌.
        tStr = scanner.nextLine();
        if ( isDigit(tStr) == true) {
            num = Integer.parseInt(tStr);
            idx = -1;
        }
        else {
            System.out.println("숫자를 입력해주세요.");
            idx--;
        }
    }
    if ( idx == -1) {    //제대로 입력되면..
        String str = control.readBbs(tStr);
        if ( str == null)
        {
            System.out.println("입력한 글번호는 없습니다");
        }
        else
        {
            print(str);    //수정하고자하는 글 내용 보여줌.
            System.out.println("수정하시겠습니까?? (yes? no?)");
            tStr = scanner.nextLine();
        }
    }
    else {
        System.out.println("사용방법을 확인해주세요.");
    }
    if (tStr.equals("yes") == true) {    //수정을 원하면..

        String Input = ""; 
        String scanline = "";

        //이곳은 create 부분과 거의 같음.
        System.out.println("제목을 입력하세요.");
        scanline = scanner.nextLine();
        Input = scanline + DATA_SPLIT;

        System.out.println("작성자를 입력하세요.");
        scanline = scanner.nextLine();
        Input += scanline + DATA_SPLIT;
        boolean in = true;
        System.out.println("내용을 입력하세요.(입력 완료 : wq");

        while (in) {
            scanline = scanner.nextLine();

            if ( Arrays.equals(scanline.toCharArray(), "wq".toCharArray())) {
                in = false;
                Input += DATA_SPLIT;
            }else {
                Input = Input+ scanline + NEW_LINE;
            }
        }

        Input = num + DATA_SPLIT + Input;

        Input = Input + control.getDate();    //여기서는 게시글 끝 구분자를 넣지 않음.

        control.updateBbs(num + "", Input);

        System.out.println(".....수정완료......");
    }
}
  • main_bbs의 Remove (삭제)
public static void remove(Scanner scanner, BbsController control) {

    System.out.println("글번호를 입력하세요.");
    String tStr = "";
    int idx = 2;
    int num = 0;

    while(idx > 0) {    //글번호 이므로 숫자 입력을 체크
        tStr = scanner.nextLine();
        if ( isDigit(tStr) == true) {
            num = Integer.parseInt(tStr);
            idx = -1;
        }
        else {
            System.out.println("숫자를 입력해주세요.");
            idx--;
        }
    }
    if ( idx == -1) {    //숫자면..
        String str = control.readBbs(tStr);
        if ( str == null)
        {
            System.out.println("입력한 글번호는 없습니다");
        }
        else
        {
            print(str);        //내용 보여줌.
            System.out.println("정말 삭제 하시겠습니까?? (yes? no?)");
            tStr = scanner.nextLine();
        }
    }
    else {
        System.out.println("사용방법을 확인해주세요.");
    }
    if (tStr.equals("yes") == true) {    //삭제를 원하면.
        control.removeBbs(num);    //삭제.

        System.out.println(".....수정완료......");
    }
}
  • main_bbs의 List(전체 글 리스트)
public static void list(BbsController control) {
    String[] printAll = control.listBbs().split(END_LINE);    //파일에서 전체 글 받음.

    for (String item : printAll) {
        prints(item);    //글번호, 글쓴이, 글제목만 프린트.
    }
}
  • BbsController의 create
public void createBbs(String str) {
    String cont = str;
    //파일 저장
    FileUtil.writeNioBbs(DIR, NAME, cont);

    //게시판 갯수저장
    count++;
    FileUtil.writeNioOverwrite(DIR, IDX_NAME, count + "");
}
  • BbsController의 read
public String readBbs(String search) {
    String str = "";
    // 파일 내용 읽음
    str = FileUtil.readNioBbs(DIR, NAME);
    //각 게시글 단위로 분리
    String[] sArr = str.split(END_LINE);

    for ( int i = 0; i < sArr.length; i++)
    {
        String[] sArr2 = sArr[i].split(DATA_SPLIT);
        String temp = sArr2[0].replace(DATA_SPLIT, "");
        //같은 번호 있는지 체크
        if ( Arrays.equals(temp.toCharArray(), search.toCharArray()) ) {
            //있으면 게시글내용 리턴
            return sArr[i];
        }
    }
    //같은 번호 없으면 null 리턴
    return null;
}
  • BbsController의 update
public void updateBbs(String search, String content) {
    String str = "";
    //파일에서 읽어옴.
    str = FileUtil.readNioBbs(DIR, NAME);
    String[] sArr = str.split(END_LINE);
    str = "";
    for ( int i = 0; i < sArr.length; i++)
    {
        String[] sArr2 = sArr[i].split(DATA_SPLIT);
        String temp = sArr2[0].replace(DATA_SPLIT, "");
        //같은 게시글 번호 확인
        if ( Arrays.equals(temp.toCharArray(), search.toCharArray()) ) {
            //있으면 수정한 정보로 대체
            sArr[i] = content;
        }
        //위에서 split으로 구분했으므로 추가.
        str += sArr[i] + END_LINE;
    }
    //내용 덮어씀
    FileUtil.writeNioOverwrite(DIR, NAME, str);
}
  • BbsController의 remove
public void removeBbs(int number) {
    String str = "";
    //파일 읽어옴.
    str = FileUtil.readNioBbs(DIR, NAME);
    String[] sArr = str.split(END_LINE);
    str = "";
    for ( int i = 0; i < sArr.length; i++)
    {
        String[] sArr2 = sArr[i].split(DATA_SPLIT);
        String temp = sArr2[0].replace(DATA_SPLIT, "");
        //같은 글번호가 있는지 확인.
        if ( temp.equals(number+"") == false ) {
            //같은 글번호내용을 제외하고 나머지 문자열 읽음.
            str += sArr[i] + END_LINE;
        }
    }
    //삭제된 게시글 외의 글정보 저장
    FileUtil.writeNioOverwrite(DIR, NAME, str);
    //전체 글 갯수에서 1을 감소한후 저장.
    count--;
    FileUtil.writeNioOverwrite(DIR, IDX_NAME, count + "");
}
  • BbsController의 list
public String listBbs() {
    //전체글 리턴
    return FileUtil.readNioBbs(DIR, NAME);
}
  • FileUtil의 read
public static String readNioBbs(String dir, String filename) {
    //경로 저장
    Path path = Paths.get(dir, filename);
    String content = "";
    //파일이 있는지 확인
    //boolean pathExists = Files.exists(path,new LinkOption[]{ LinkOption.NOFOLLOW_LINKS});
    //http://tutorials.jenkov.com/java-nio/files.html
    if ( Files.exists(path,new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}) == true) {
        try {
            byte rawData[] = Files.readAllBytes(path);
            //Format을 맞춰서 byte배열을 String 객체로 생성
            content = new String(rawData, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            return content;
        }
    }
    else {    //파일이 없으면.
        return null;
    }
}
  • FileUtil의 write
public static void writeNioBbs(String dir, String filename, String content) {
    //경로저장
    Path path = Paths.get(dir, filename);
    try {
        //파일에 쓰기.
        Files.write(path, content.getBytes(StandardCharsets.UTF_8)    //파일 포맷
                , StandardOpenOption.CREATE, StandardOpenOption.APPEND );    //없으면 생성, 있으면 내용 붙이기.
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • FileUtil의 overwrite
public static void writeNioOverwrite(String dir, String filename, String content) {
    //경로
    Path path = Paths.get(dir, filename);
    try {
        //파일에 저장.
        Files.write(path, content.getBytes(StandardCharsets.UTF_8)    //파일 포맷
                , StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);    //파일이 없으면 생성, 파일이 있으면 무시하고 생성.
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • FileUtil의 getDate
public static String getDate() {
    String datetime = "";

    //날짜, 시간 정보를 생성하여 받아옴.
    Calendar cal = Calendar.getInstance();

    int[] iArr= new int[5];

    int yy = cal.get(Calendar.YEAR);
    int mm = cal.get(Calendar.MONTH) + 1;    //월 정보는 0~11이기 때문에 1을 더함.
    int dd = cal.get(Calendar.DATE);

    int ho = cal.get(Calendar.HOUR_OF_DAY);    //24시간으로 표시된 시간
    int mi = cal.get(Calendar.MINUTE);
    int se = cal.get(Calendar.SECOND);

    iArr[0] = mm;
    iArr[1] = dd;
    iArr[2] = ho;
    iArr[3] = mi;
    iArr[4] = se;        

    datetime = yy +"-";

    int idx = 0;
    for ( idx = 0; idx < 5; idx++) {

        if ( iArr[idx] < 10) {    //월, 일, 시, 분, 초가  2자리가 아니면 앞에 0을 더해줌. 
            datetime = datetime + 0;
        }

        switch(idx) {
        case 0 :    //month
            datetime = datetime + iArr[idx] + "-";
            break;
        case 1 :    //date
            datetime = datetime + iArr[idx] + " ";
            break;
        case 2 :    //hour
            datetime = datetime + iArr[idx] + ":";
            break;
        case 3 :    //minute
            datetime = datetime + iArr[idx] + ":";
            break;
        case 4 :    //second
            datetime = datetime + iArr[idx];
            break;
        }
    }
    return datetime;        
}

  1. 전체파일 다운로드 - https://github.com/Teddy-Hong/BBS_withNIO.git

  2. 개선해야할 점.

    • 현재 무조건 파일의 모든 정보를 가져오고 그걸 수정하여 쓰는데 이건 데이터가 커지면 문제 발생. line별로 가지고 올 수 있도록 해야함.
    • 기능 분리가 아직 제대로 안됨. 각 class에 맞는 함수 정리 필요.
    • 최초 작성일 : 2017.02.05. 19시 경.



반응형

댓글