📌 프로젝트 개요
16일차까지 배운 Java 기초 문법을 활용하여 만든 도서관 도서 관리 시스템 (CLI 기반)
- 프로젝트 명: Library Book Manager (CLI)
- 개발 기간: 25.07.02 ~ 25.07.03
- 목적:
- Java 기초 문법 복습
- 실무처럼 디렉토리 및 클래스 구조 설계 연습
- 단순 기능 구현 이상의 설계 감각을 기르기 위한 실습
- 사용 기술: Java 17, VS Code IDE, Git & GitHub
🧩 구현 기능
기능 | 설명 |
책 등록 | 제목, 저자, 출판 연도 입력 후 리스트에 저장 |
전체 목록 조회 | 등록된 도서들을 연도순으로 정렬하여 출력 |
책 검색 | 제목 또는 저자 키워드로 부분 검색 |
책 삭제 | 제목을 기준으로 도서 삭제 |
종료 | 프로그램 종료 |
예외 처리 | 연도 음수 입력, 사용자 입력 오류에 대한 처리 |
💜 GitHub 저장소 & 데모
📁 디렉토리 구조
📂 src/com/example/librarybookmanager
├── LibraryBookManagerApplication.java // 프로그램 실행 진입점
├── domain/
│ └── Book.java // 도서 정보 클래스
├── service/
│ ├── LibraryService.java // 서비스 인터페이스
│ └── LibraryServiceImpl.java // 비즈니스 로직 구현체
├── constants/
│ └── Messages.java // 메시지 상수 모음
├── exception/
│ └── InvalidYearException.java // 사용자 정의 예외
├── comparator/
│ ├── BookTitleComparator.java // 제목 정렬
│ ├── BookAuthorComparator.java // 저자 정렬
│ └── BookYearComparator.java // 연도 정렬
└── README.md
🧱 클래스/설계 구조 설명
- Book:
- private으로 title, author, year 멤버 필드를 생성했다.
- 도서 등록을 위해 Book(String title, String author, int year) 사용자 함수를 생성했다.
- 책 제목 또는 저자, 출판연도로 도서를 검색할 수 있도록 getter를 생성했다.
- Object를 기본으로 상속 받기 때문에 toString() 메서드를 오버라이드하여 제목 (저자, 출판연도) 이렇게 출력되도록 작성했다.
- LibraryService:
- 등록은 registerBook()
- 조회는 printBook()
- 검색은 searchBook()
- 삭제는 deleteBook()으로 정의한 인터페이스 파일이다.
- LibraryServiceImpl:
- LibraryService의 구현 클래스이다.
- List<Book> 기반으로 로직 구성하였다. List<Book> books
- Scanner로 입력을 받는 형태이다.
- 책 등록은
- try-catch문을 사용했다.
- try 블럭에는 책 제목, 저자, 출판 연도 순서로 값을 입력받아서 books 리스트에 저장하는데, 출판연도가 0보다 작은. 음수의 값이면 예외처리를 해준다.
- catch 블럭에는 연도를 음수로 입력하였을 경우 커스텀으로 생성한 InvalidYearExcepion으로 예외처리한다.
- 두번째 catch 블럭에는 Message클래스에서 정의한 ERROR_INPUT을 불러와 입력 형식이 올바르지 않다는 메시지를 출력해준다.
- 책 전체 목록은
- books가 비어 있다면 Message클래스에서 정의한 NO_BOOKS를 불러와 책이 없다는 메시지를 출력해준다.
- 책이 있다면 기본 연도별로 정렬을 한 다음에 for-each문을 사용해 books에 담긴 책을 출력한다.
- 책 검색은
- 사용자로부터 입력받은 값을 keyword 변수에 저장하는데 알파벳의 경우를 대비해 소문자로 변환하여 저장한다.
- for-each문을 사용하여 books 리스트에 각각의 요소를 꺼내어 해당 keyword가 있는지 .contains()를 사용해 체크한 다음 있으면 해당 책을 출력해준다.
- 만약에 없으면 Message클래스에서 정의한 BOOK_NOT_FOUND를 불러와 책을 찾을 수 없다는 메시지를 출력한다.
- 책 삭제는
- 사용자로부터 삭제할 책 제목을 입력 받아 title 변수에 저장한다.
- .removeIf()를 사용하여 books 리스트(컬렉션)에 해당 title이 있으면 제거한다.
- 제거에 성공했으면 Message 클래스에서 정의한 SUCCESS_DELETE를 불러와 삭제 성공했다는 메시지를 출력.
- 해당 책 제목이 없어서 제거하지 못하면 Message 클래스에서 정의한 BOOK_NOT_FOUND를 불러와 책이 없다는 메시지를 출력한다.
- Comparator 3종: 연도/제목/저자
- BookAuthorComparator, BookTitleComparator, BookYearComparator 각각 연도, 제목, 저자 기준으로 오름차순 정렬을 생성해준다.
- 여기서 나는 BookYearComparator만 사용했다.
- Messages:
- UI 메시지 텍스트를 상수로 관리
- TITLE, MENU, ERROR_INVALID_YEAR, ERROR_INPUT, SUCCESS_ADD, SUCCESS_DELETE, BOOK_NOT_FOUND, NO_BOOKS 이렇게 정의했다.
- InvalidYearException:
- Exception을 상속받는다.
- 출판 연도 음수 입력 시 사용자 정의 예외 발생을 위한 클래스다.
🔢 개발 순서
순서 | 내용 | 상세 설명 |
1 | Book 객체 설계 | 제목, 저자, 출판연도를 멤버 변수로 가짐 |
2 | 예외 처리 | 출판 연도를 음수로 입력 시 InvalidYearException 발생 |
3 | 고정 메시지 설계 | - Message.java에 고정으로 사용되는 메시지 작성 - 메시지는 public static final 키워드를 사용하여 작성 |
4 | 정렬 관련 파일 설계 | - 책 제목, 저자, 출판연도 각각의 comparator 파일을 생성 - BookTitleComparaotr.java, BookAuthorComparator.java, BookYearComparator.java |
5 | LibraryService 인터페이스와 구현체 설계 |
- LibraryService 인터페이스에 책 등록/전체 목록/검색/삭제 메서드 작성 - LibraryServiceImpl을 구현체로 생성하여 비즈니스 로직을 설계 |
6 | 프로그램 실행 main 작성 | - while문을 사용하여 메뉴 무한 반복 실행. - try-catch문을 사용하고, try 블럭에는 사용자가 메뉴를 입력하면 swtich-case문으로 각 case별로 메서드 실행 |
🐞 문제 해결 & 트러블슈팅
✅ 이슈 1 - 정렬 시 에러 (Comparator 관련)
- 문제: .compareToIgnoreCase() 에서 에러 발생
- 원인: 정수 비교에 문자열 비교 함수 사용
- 해결:
// 숫자 정렬
Integer.compare(b1.getYear(), b2.getYear());
// 문자열 정렬
b1.getTitle().compareToIgnoreCase(b2.getTitle());
✅ 이슈 2 - 책 전체 목록 출력 안됨
- 문제: 책을 등록하고 목록을 조회하면 출력이 되지 않음
- 원인: 정렬만 하고 출력 메서드 누락
- 해결: 정렬 후 리스트 출력 코드 추가
✅ 이슈 3 - 도서 검색 시 입력이 되지 않음
- 문제: 검색 메뉴 선택 후 keyword 입력이 안 되고 전체 목록이 바로 출력됨
- 원인: Scanner의 nextInt() 이후 nextLine() 사용 -> 버퍼 문제
- 해결:
int input = Integer.parseInt(sc.nextLine());
✅ 이슈 4 - Scanner 경고 발생
- 문제: Scanner 인스턴스에 노란 밑줄이 생김 (자원 누수 경고)
- 해결: try-with-resources 구문 사용
try (Scanner sc = new Scanner(System.in)) {
// 코드
}
✍ 느낀 점 / 회고
- 클래스 설계를 하다 보니 처음에 어려웠지만 모르는 것은 찾아가며 나의 속도대로 나아가니 이해를 하게 되었다.
- 인터페이스와 구현체를 나누는 것을 글로만 봤을 때에는 '그렇구나' 정도로 이해를 했지만, 이번에 직접 만들어보니 나중에 코드를 수정하거나 유지보수면에서도 관리하기 좋다는 걸 느꼈다.
- Scanner 버퍼 문제, Comparator에 대해서 한 걸음 더 다가가게 되었다.
- 이번 토이 프로젝트를 진행하면서 구조를 어떻게 나누어야 하는지, 각 구조마다 어떤 역할을 하는지 알게 되었다.
'개발 기록 > 개발 요약' 카테고리의 다른 글
[mini-project] To-do List (React) (0) | 2025.07.07 |
---|---|
[mini-project] Country Flag Guessing Game (JS) (0) | 2025.07.05 |
[toy-project] JWT 기반 인증/인가 구현 (Spring Boot) (0) | 2025.07.04 |
[team-project] Hotel PMS (0) | 2025.04.29 |
JavaScript를 사용하여 목록을 추가하는 간단한 예제 (0) | 2024.08.24 |