Jave & Kotlin

Java - 간단한 게시판 구현을 통한 직렬화(Serialization) 이해하기(2) - 게시판 구현 및 직렬화 역직렬화 테스트

devLog by Ronnie's 2021. 12. 24. 20:04

들어가며


이번 시간에는 게시판 구현을 통해 직렬화와 역직렬화 테스트를 진행한다.

 

(1)글 링크

https://sjparkk-dev1og.tistory.com/124

 

Java - 간단한 게시판 구현을 통한 직렬화(Serialization) 이해하기(1) - 클래스 생성과 serialVersionUID 개

들어가며 직렬화에 대한 개념을 정리해보았으니 이번에는 코드 구현을 통해 직렬화에 대해서 좀 더 이해력을 높이고자 한다. 간단한 게시판을 구현해본다. 더불어 개념 설명시 빠져있던 serialVer

sjparkk-dev1og.tistory.com

 

게시판 만들기


해당 예제의 순서는 List<Article> 타입의 직렬화된 데이터가 있다면 역직렬화를 통해서 읽어오고 없다면 새로운 입력을 받아 직렬화를 통해 데이터를 저장하고 저장된 데이터를 읽어와 보여주는 방식으로 진행한다. 

 

 

구현 전체 코드


package com.company;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Board {

    static List<Article> list = new ArrayList<>();

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        try {
            // 직렬화된 파일을 읽어와 보여줌
            readFromFile();
        } catch(FileNotFoundException e) {
            // 없다면 e 발생
            e.printStackTrace();
        }

        //입력을 받음
        Scanner s = new Scanner(System.in);
        while(true) {
            prompt(s);
        }
    }

    private static void prompt(Scanner s) throws FileNotFoundException, IOException {

        displayBoard();

        System.out.println(">> 입력을 원하면 w, 종료를 원하면 x를 입력해주세요.");
        String command = s.nextLine();
        if(command.equalsIgnoreCase("w")) {
            write(s);
        } else if (command.equalsIgnoreCase("x")) {
            System.exit(0);
        }

    }

    private static void write(Scanner s) throws FileNotFoundException, IOException {
        System.out.print("작성자 이름을 입력해주세요.");
        String writer = s.nextLine();

        System.out.print("글 내용을 입력해주세요.");
        String message = s.nextLine();

        int seq = 0;
        if(list.size() != 0) {
            seq = list.get(list.size() - 1).seq + 1;
        }

        list.add(new Article(seq, writer, message));
        System.out.println();

        // 직렬화 출력하기: 글이 작성되었으면 메모리의 객체를 직렬화한 뒤
        // 물리적인 파일로 하드디스크에 저장한다.
        saveToFile();

    }

    private static void displayBoard() {
        System.out.println("순서\t글쓴이\t메시지");
        System.out.println("-----------------------");

        if(list.size() == 0) {
            System.out.println("[아직 글이 없습니다.]");
        }

        list.forEach(System.out::println);
    }

    private static void saveToFile() throws FileNotFoundException, IOException {

        // 파일 출력 스트림 객체를 만든 후, 이름을 "board.txt"라고 지정하고
        // fos를 바탕으로 오브젝트 출력 스트림을 생성한 뒤 writeObject 한다.
        try(FileOutputStream fos = new FileOutputStream("board.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos);) {
            oos.writeObject(list);
        }
    }

    @SuppressWarnings("unchecked")
    private static void readFromFile() throws FileNotFoundException, IOException, ClassNotFoundException {
        // FileInputStream을 통해 파일 입력 스트림 객체를 만든 후 "board.txt" 파일로부터 읽어온다.
        // fis를 바탕으로 오브젝트 입력 스트림을 생성한 뒤 readObject 한다.
        // 오브젝트 형태로 읽으면 안에 있는 내용이 무슨 타입인지 정확히 알기 어려우므로 타입 캐스팅 해준다.
        try(FileInputStream fis = new FileInputStream("board.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);) {
            list = (List<Article>) ois.readObject();
        }
    }
}

 

동작 순서 설명


먼저 가장 처음 돌렸을때는 직렬화된 파일(board.txt)이 없기 때문에 FileNotFoundException에 걸려 에러를 발생한다.

그 후 displayBoard 메서드를 통해서 List에 내용이 있는지 없는지 판단 후 Scanner를 통해 입력을 할지 종료를 할지 입력 받고 입력을 선택하면 작성자의 이름과 글의 내용을 입력 받아 list에 저장 후 saveToFile 메서드를 통해서 파일 출력 스트림 객체를 만들어 파일 이름을 정하고 오브젝트 출력 스트림을 이용하여 list에 내용을 저장한다.  이 과정이 직렬화 과정이다.

try(FileOutputStream fos = new FileOutputStream("board.txt");
    ObjectOutputStream oos = new ObjectOutputStream(fos);) {
    oos.writeObject(list);
}

 

한번 입력을 마쳤다면 종료 후에 다시 시작을 해보면 내용이 있기 때문에 e 발생시키지 않고 리스트를 읽어오는 것을 확인할 수 있다. 이때 역직렬화 과정을 통해 읽어온다.

try(FileInputStream fis = new FileInputStream("board.txt");
    ObjectInputStream ois = new ObjectInputStream(fis);) {
    list = (List<Article>) ois.readObject();
}

그리고 옆에 프로젝트를 확인해보면 board.txt가 생성된 것을 확인할 수 있다.

눌러 보면 다음과 같이 직렬화된 데이터 값이 들어있다.

 

transient


마지막으로 transient에 대해서 알아보자. transient는 직렬화하려는 클래스에 필드에 붙여서 직렬화시 transient가 붙은 대상을 제외하고 직렬화한다. transient 필드는 역직렬화 시 null 또는 타입의 기본값으로 반환된다.

 

만약 다음과 같이 message를 transient 처리하게 되면 출력 시 직렬화 대상에서 제외되어 null로 처리 되는 것을 확인 할 수 있다.

 

깃 링크


더 디테일한 구현과정이 궁금하시다면 아래 깃헙에 올려준 commit 내역을 참고하길 바란다.

https://github.com/sjparkk/board-serialization

 

GitHub - sjparkk/board-serialization

Contribute to sjparkk/board-serialization development by creating an account on GitHub.

github.com

 

 

마치며


이렇게 코드로 직접 구현까지 해보니 처음에 이론적이 부분만 봤을때 보다는 이해력이 올라간 것을 느낀다.