재시작 후에도 대여 창구 상태 유지하기

JavaBeginner
지금 연습하기

소개

대여 창구는 애플리케이션을 닫은 뒤에도 누가 각 공구를 갖고 있는지 기억해야 합니다. 이 독립 환경은 정상적인 대여 규칙과, 기존 대여 및 정비 중인 공구를 포함하는 새 창구 파일을 제공합니다. 미완성 저장 코드는 현재 파일을 읽을 때 저장된 상태를 잃어버리고 변경 내용을 쓰지 않습니다.

UTF-8 파일 기록을 객체로 매핑하고 유효한 변경만 저장합니다. 이전 실습의 객체 규칙을 알고 있어야 하지만, 그 환경의 파일은 필요하지 않습니다. 이 프로그램은 단일 프로세스 학습용 애플리케이션으로, 데이터베이스가 아니며 정전 시 데이터 보존을 보장하지도 않습니다. 읽기와 연습 시간은 작성자 추정으로 45분입니다.

디스크에 실제로 저장된 상태 읽기

이 단계에서는 평범한 파일 기록 하나를 읽은 다음, 저장된 상태와 대여 회원의 관계를 Java 객체로 복원하는 방식을 수정합니다.

Terminal 탭을 엽니다. cd는 이 독립 실습의 폴더를 선택합니다. 아직 실행하지 않은 잘못된 셸 입력 줄은 Ctrl+U로 지울 수 있습니다. 파일 경로 오류가 나면 여기로 돌아와 올바른 명령을 다시 실행하세요.

cd /home/labex/project/tool-library

애플리케이션의 객체 규칙은 정상적으로 작동하지만 저장 기능은 미완성입니다. 먼저 작은 연습 파일로 기존 대여를 위험에 빠뜨리지 않고 다섯 필드 형식을 살펴봅니다. mkdir -p는 필요하면 연습 디렉터리를 만듭니다. printf는 지정한 형식으로 출력합니다. \t는 탭을 만들고 \n은 기록을 끝냅니다. >는 출력을 지정한 파일에 쓰며 이전 연습 사본이 있으면 덮어씁니다. 작은따옴표는 셸이 형식을 바꾸지 못하게 합니다. 애플리케이션은 창구 입력 옆에서 members.tsv를 찾으므로 cp로 회원 목록을 그 파일 옆에 복사합니다. 이 명령들은 실제 창구를 바꾸지 않습니다.

mkdir -p work
printf 'S01\tSpare drill\tAVAILABLE\t-\tPractice only\n' > work/sample.tsv
cp members.tsv work/members.tsv

현재 소스를 컴파일합니다. -encoding UTF-8은 텍스트 인코딩을, -d out은 컴파일 출력 위치를 선택하며, *.java는 이 폴더의 Java 파일을 선택합니다. 오류 없이 컴파일에 성공한 경우에만 계속하세요.

javac -encoding UTF-8 -d out *.java

-cp out은 Java에 클래스 위치를 알려 줍니다. -Dfile.encoding=UTF-8은 실행 시 텍스트 인코딩을 선택합니다. 연습 입력은 work/sample.tsv이며 --memory는 이번 시연의 저장을 막습니다.

java -Dfile.encoding=UTF-8 -cp out Desk work/sample.tsv --memory

프로그램 안에서 다음 줄을 입력하고 각 줄 뒤에 Enter를 누르세요.

list
borrow S01 M01
list
quit

S01은 대여 회원이 -인 AVAILABLE 상태로 시작하고 M01에게 대여하는 동작은 허용됩니다. 연습 행의 상태가 잘못된 코드의 가정과 이미 같으므로 미완성 로더에서도 이 일반적인 경우는 작동합니다. 기존 대여가 보존된다는 증거는 되지 못합니다. 이 프로세스를 닫으면 연습 중 변경 내용은 사라집니다.

실제 창구와 등록 회원을 읽으세요. cat은 파일을 편집하지 않고 표시합니다.

cat desk.tsv
cat members.tsv

ID, 이름, 열거형 상태, 대여 회원, 메모라는 다섯 개의 탭 구분 필드가 있습니다. 이 제한된 형식은 필드 안의 공백과 UTF-8 텍스트는 허용하지만 탭이나 줄바꿈은 허용하지 않습니다. T24는 이미 M03이 빌렸고, T25는 M02가 빌렸으며 Cafe workshop 메모가 있습니다. T23은 정비 중입니다. 이 사실들은 읽은 뒤에도 유지되어야 합니다. desk.tsv, members.tsv, reference 폴더를 직접 수정하지 마세요.

준비된 저장 코드를 읽으세요.

cat Store.java

Store는 영속성 경계입니다. load에서 기록이 객체가 되고 save에서 객체가 기록이 됩니다. Files.readAllLines는 UTF-8을 명시해 읽습니다. fields(line)은 형식을 확인하고 f[0]부터 f[4]까지의 필드를 반환합니다. new Tool(...) 호출을 찾으세요. 현재는 모든 행에서 Tool.State.AVAILABLE과 "-"를 대신 사용합니다. T24의 대여 회원과 T23의 정비 상태에 어떤 영향을 줄지 예상해 보세요. 루프, 리스트, 파싱 및 검증 도우미는 이미 준비되어 있으므로 유지하세요. 내부 HashSet 구현을 다시 작성할 필요는 없습니다.

편집 전에 소스만 백업합니다.

cp Store.java work/Store-before-load.java.txt
nano Store.java

첫 실습과 마찬가지로 Ctrl+W는 검색, Enter는 검색 확인, 화살표 키는 이동, Backspace는 문자 수정을 합니다. Tool tool = new Tool을 검색해 이 생성자 호출 하나를 찾으세요. 상태와 대여 회원 인수를 편집해 다음과 같이 만듭니다.

            Tool tool = new Tool(f[0], f[1], Tool.State.valueOf(f[2]), f[3], f[4]);

Tool.State.valueOf(f[2])는 저장된 열거형 이름을 열거형 값으로 바꾸고 f[3]은 저장된 대여 회원을 복원합니다. ID, 이름, 메모 인수와 주변 루프 및 모든 도우미는 유지하세요. 새 대여 가능 공구를 만들어 내는 것이 아니라 기존 정보를 매핑하는 작업입니다. Ctrl+O, Enter로 저장하고 Ctrl+X로 나갑니다. 저장하지 않은 실수는 Ctrl+X, N으로 버립니다. 컴파일 오류는 다시 열어 해당 호출을 검색하고 수정합니다. 이 편집을 의도적으로 처음부터 다시 해야 한다면 cp work/Store-before-load.java.txt Store.java로 이 소스 파일만 복원하고 매핑을 다시 수정하세요. 편집을 되돌리려고 setup을 다시 실행하지 마세요.

여기서 throws IOException은 파일 접근이 실패할 수 있음을 선언합니다. 입력이 없거나 형식이 잘못되면 명령 루프는 Cannot continue를 출력하고 멈춥니다. 이것은 파일 문제이며 대여 거부가 아닙니다. 표시된 경로나 소스 매핑을 수정하세요. 오류를 없애려고 원본 기록을 비우거나 다시 쓰지 마세요.

저장한 소스를 컴파일하고 실제 창구를 시작합니다. 시연과 달리 --memory는 생략합니다. 다음 단계에서 저장을 완성하면 실제 창구는 유효한 변경을 영속적으로 저장합니다. 문법 오류에는 파일과 줄이 표시됩니다. nano에서 고치고 컴파일에 성공한 뒤 실행하며 이전 클래스를 실행하지 마세요.

javac -encoding UTF-8 -d out *.java
java -Dfile.encoding=UTF-8 -cp out Desk desk.tsv

대여 창구 프로그램 안에서 다음 줄을 입력하세요.

list
members
quit

목록은 T24 → M03, T25 → M02, T23의 MAINTENANCE 상태와 모든 메모를 유지해야 합니다. members는 사용할 수 있는 등록 ID를 보여 주고 quit는 셸로 돌아갑니다. 목록 표시와 파일 열기는 파일을 다시 쓰면 안 됩니다. 다음 단계에서 실제 저장을 완성합니다. 성공 메시지만으로 영속성을 입증할 수는 없습니다.

유효한 변경을 저장하고 창구 다시 열기

이 단계에서는 새 대여 한 건과 유효한 반납 한 건이 실제 프로세스 종료 후에도 유지되게 합니다.

같은 Terminal 탭의 셸에서 시작합니다. 저장은 바뀌지 않은 대여와 정비 기록을 포함해 현재의 모든 객체를 직렬화합니다. row(tool)은 다섯 필드를 탭으로 연결합니다. 루프는 모든 행을 리스트에 추가하고 Files.write는 이들을 UTF-8로 씁니다. 명령 루프는 업무 규칙 메서드가 정상적으로 반환된 뒤에만 save를 호출합니다. 거부된 동작은 동일한 내용을 다시 쓰는 경우까지 포함해 데이터 파일에 쓰면 안 됩니다.

명령 처리 틀을 읽고 이 규칙이 저장 경계와 어떻게 연결되는지 확인하세요.

cat Desk.java

found.borrow(c[2]), found.giveBack(c[2])와 그 뒤의 Store.save(path, tools)를 찾으세요. 업무 규칙 예외가 발생하면 저장 호출을 건너뛰고 정상적인 거부로 처리합니다. 준비된 순서를 유지하세요. 거부 처리기에 쓰기를 추가하면 계약을 위반합니다.

수정한 로더를 유지하는 소스 전용 백업을 만듭니다.

cp Store.java work/Store-before-save.java.txt
nano Store.java

Ctrl+W를 누르고 TODO: write all rows를 검색한 다음 Enter를 누르세요. 바로 위의 루프를 읽으세요. 변경하지 않은 대여도 포함하여 각 공구의 직렬화된 행 하나씩을 모읍니다. 화살표 키로 그 주석의 끝에 가서 Backspace로 주석 문자를 지웁니다. 같은 들여쓰기로 쓰기 코드를 입력하세요. 루프 뒤이면서 메서드의 닫는 중괄호 앞에서 TODO 주석만 아래의 실제 쓰기로 교체합니다.

        Files.write(path, rows, StandardCharsets.UTF_8);

path는 선택한 창구 파일이며, rows는 마지막으로 바꾼 객체만이 아니라 직렬화된 전체 목록입니다. 문자셋을 명시하면 모든 필드의 텍스트 인코딩이 유지됩니다. 수정한 load 메서드, 행 루프, 모든 도우미는 유지하세요. Ctrl+O, Enter, Ctrl+X로 저장하고 나갑니다. 저장하지 않은 오류는 Ctrl+X, N으로 버립니다. 저장된 소스 실수는 다시 열어 고치세요. 선택적으로 cp work/Store-before-save.java.txt Store.java로 소스만 되돌리면 로더는 유지됩니다. 그 뒤 쓰기를 다시 작성하세요. 창구 파일을 초기화하거나 setup을 다시 실행하지 마세요.

저장한 소스를 다시 컴파일합니다.

javac -encoding UTF-8 -d out *.java
java -Dfile.encoding=UTF-8 -cp out Desk desk.tsv

창구 안에서 다음 내용을 입력하세요.

borrow T21 M01
borrow T21 M02
return T24 M01
borrow T23 M01
borrow TYPO M01
return T24 M03
list
quit

T21은 M01에게 대여됩니다. 중복 대여, 잘못된 반납자, 정비 중 공구의 대여, 잘못 입력한 ID는 의도대로 거부됩니다. M03의 T24 반납만 성공합니다. T22는 대여 가능 상태, T23은 정비 중 상태를 유지하며, T25는 원래 메모를 가진 채 M02에게 대여된 상태입니다. 알 수 없는 ID가 거부되어도 명령 루프는 계속 쓸 수 있습니다. 재시작하거나 초기화하지 말고 ID를 수정하세요.

이제 같은 파일로 새 Java 프로세스를 시작합니다.

java -Dfile.encoding=UTF-8 -cp out Desk desk.tsv
list
quit

T21은 여전히 M01에게 BORROWED 상태여야 하고, T24는 대여 회원이 -인 AVAILABLE 상태여야 합니다. 그렇지 않다면 현재 Store.java를 컴파일했고 --memory 없이 실행했는지 확인하세요. 저장된 대여를 흉내 내려 최종 기록을 수정하면 안 됩니다. 허용된 동작이 이미 저장됐다면 이제 거부된다는 이유만으로 반복하지 마세요. list는 현재의 사실을 보여 줍니다.

셸로 돌아와 실제 저장 결과를 읽습니다.

cat desk.tsv

기록의 관계는 새 프로세스의 목록과 같아야 합니다. 모든 ID, 이름, 회원, 정비 상태, 관련 없는 대여와 메모를 유지하세요. 바뀌는 것은 T21의 상태·대여 회원과 T24의 상태·대여 회원뿐입니다. 이 작은 쓰기 기능은 저장 성공 시 파일을 교체합니다. 동시 접근, 비정상 종료 후 복구, 원자적 트랜잭션을 제공하지는 않습니다. 쓰기가 실패하면 멈추고 오류를 살핀 다음 진행하세요.

요약

UTF-8 기록을 Java 객체로 매핑하고, 유효한 전이 후 현재의 전체 기록을 저장한 다음 새 프로세스에서 창구를 다시 열었습니다. 기존 대여, 정비, 메모는 그대로 유지됐고 거부된 동작은 저장소에 쓰지 않았습니다.