개발 기록/도서관 관리 시스템

[Library Management System] 25.10.01 (57일) | (리팩토링) 공용 도서 전체 목록 조회, 도서 상세 조회, 도서 검색

dev.jelee 2025. 10. 1. 19:36

[ 작업한 내용 ]

< 공용: 도서 전체 목록 조회 >

# UserBookListResDTO

- 도서 전체 목록 조회 응답 DTO

- 도서 고유번호, 제목, 저자, 출판사, 출판일, 상태, 위치 (id, title, author, publisher, publishedDate, status, location)
** 변경사항 없음

@Getter
public class UserBookListResDTO {
  private Long id;
  private String title;
  private String author;
  private String publisher;
  private LocalDate publishedDate;
  private BookStatus status;
  private String location;

  public UserBookListResDTO(Book book) {
    this.id = book.getId();
    this.title = book.getTitle();
    this.author = book.getAuthor();
    this.publisher = book.getPublisher();
    this.publishedDate = book.getPublishedDate();
    this.status = book.getStatus();
    this.location = book.getLocation();
  }
}

# UserBookController

- GET /api/v1/books 로 요청.

- 파라미터로 page, size를 받음. 각 기본값이 0과 10.

- Service 계층으로 page, size를 전달함.

- 결과는 Page<UserBookListResDTO> 형태로 저장.

- 클라이언트 측으로 성공메시지와 결과를 ApiResponse.success()로 감싸서 응답.

** 변경사항 없음

@GetMapping()
public ResponseEntity<?> allListBooks(
  @RequestParam(value = "page", defaultValue = "0") int page,
  @RequestParam(value = "size", defaultValue = "10") int size) {
  
    // 서비스로직
    Page<UserBookListResDTO> responseDTO = userBookService.allListBooks(page, size);

    // 성공메시지
    String message = messageProvider.getMessage(BookSuccessCode.BOOK_LIST_FETCHED.getMessage());
    
    // 응답
    return ResponseEntity
              .status(BookSuccessCode.BOOK_LIST_FETCHED.getHttpStatus())
              .body(ApiResponse.success(
                BookSuccessCode.BOOK_LIST_FETCHED, 
                message, 
                responseDTO));
}

# UserBookService

- PageRequest.of(page, size)로 페이징을 정의하고 Pageable 형태로 저장.

- bookRepository.findAll(pageable)로 설정된 페이징으로 도서 전체 목록을 조회하여 Page<Book> 형태로 저장.

- Book을 <UserBookListResDTO>로 형변환 후 new PageResponse<>() 객체로 생성하여 Controller로 반환.

** List 형태로 형변환 했던 것을 삭제하고 Page<UserBookListResDTO>로 바로 형변환 하도록 수정.

public Page<UserBookListResDTO> allListBooks(int page, int size) {

  // 페이징 정의
  Pageable pageable = PageRequest.of(page, size);

  // Book 조회 후 UserBookListResDTO로 변환
  Page<Book> result = bookRepository.findAll(pageable);
  Page<UserBookListResDTO> pageDTO = result.map(UserBookListResDTO::new);

  // 반환
  return pageDTO;
}

< 공용: 도서 상세 조회 >

# UserBookDetailResDTO

- 도서 상세 조회 응답 DTO

- 도서 고유번호, 제목, 저자, 출판사, 출판일, 상태, 위치, 설명 (id, title, author, publisher, publishedDate, status, location, description)

** 변경사항 없음

@Getter
public class UserBookDetailResDTO {
  private Long id;
  private String title;
  private String isbn;
  private String author;
  private String publisher;
  private LocalDate publishedDate;
  private BookStatus status;
  private String location;
  private String description;

  public UserBookDetailResDTO(Book book) {
    this.id = book.getId();
    this.title = book.getTitle();
    this.isbn = book.getIsbn();
    this.author = book.getAuthor();
    this.publisher = book.getPublisher();
    this.publishedDate = book.getPublishedDate();
    this.status = book.getStatus();
    this.location = book.getLocation();
    this.description = book.getDescription();
  }
}

# UserBookController

- GET /api/v1/books/{bookId} 로 요청.

- 파라미터로 booId 전달받음.

- Service 계층으로 bookId를 전달함.

- 결과는 Page<UserBookDetailResDTO> 형태로 저장.

- 클라이언트 측으로 성공메시지와 결과를 ApiResponse.success()로 감싸서 응답.

** 변경사항 없음

@GetMapping("/{bookId}")
public ResponseEntity<?> detailBook(@PathVariable("bookId") Long bookId) {
  
  // 서비스 로직
  UserBookDetailResDTO responseDTO = userBookService.detailBook(bookId);

  // 성공 메시지
  String message = messageProvider.getMessage(BookSuccessCode.BOOK_FETCHED.getMessage());
  
  // 응답
  return ResponseEntity
            .status(BookSuccessCode.BOOK_FETCHED.getHttpStatus())
            .body(ApiResponse.success(
              BookSuccessCode.BOOK_FETCHED, 
              message, 
              responseDTO));
}

# UserBookService

- bookRepository.findById(bookId)로 도서 조회를 하여 도서가 있으면 Book 형태로 저장하고, 없다면 BookErrorCode.BOOK_NOT_FOUND 예외를 발생 시킴.

- Book 기반으로 UserBookDetailResDTO 객체를 생성하여 Controller로 반환.

** 변경사항 없음

public UserBookDetailResDTO detailBook(Long bookId) {

  // bookId 조회 및 예외 처리
  Book book = bookRepository.findById(bookId)
      .orElseThrow(() -> new BaseException(BookErrorCode.BOOK_NOT_FOUND));
  
  // 반환
  return new UserBookDetailResDTO(book);
}

< 공용: 도서 검색 >

# UserBookSearchResDTO

- 도서 검색 응답 DTO

- 도서 고유번호, 제목, isbn, 저자, 출판사, 출판일, 상태, 위치 (id, title, isbn, author, publisher, publishedDate, status, location)

** 변경사항 없음

@Getter
public class UserBookSearchResDTO {
  private Long id;
  private String title;
  private String isbn;
  private String author;
  private String publisher;
  private LocalDate publishedDate;
  private BookStatus status;
  private String location;

  public UserBookSearchResDTO(Book book) {
    this.id = book.getId();
    this.title = book.getTitle();
    this.isbn = book.getIsbn();
    this.author = book.getAuthor();
    this.publisher = book.getPublisher();
    this.publishedDate = book.getPublishedDate();
    this.status = book.getStatus();
    this.location = book.getLocation();
  }
}

# UserBookController

- GET /api/v1/books/search 로 요청.

- 파라미터로 type, keyword, page, size 전달받음.

- Service 계층으로 type, keyword, page, size를 전달함.

- 결과는 PageResponse<UserBookSearchResDTO> 형태로 저장.

- 클라이언트 측으로 성공메시지와 결과를 ApiResponse.success()로 감싸서 응답.

** PageResponse 형태로 결과 받음

@GetMapping("/search")
public ResponseEntity<?> searchBooks(
  @RequestParam("type") BookSearchType type,
  @RequestParam("keyword") String keyword,
  @RequestParam(value = "page", defaultValue = "0") int page,
  @RequestParam(value = "size", defaultValue = "10") int size) {

    // 서비스 로직
    PageResponse<UserBookSearchResDTO> responseDTO = userBookService.searchBooks(type, keyword, page, size);

    // 성공 메시지
    String message = messageProvider.getMessage(BookSuccessCode.BOOK_LIST_FETCHED.getMessage());

    // 반환
    return ResponseEntity
              .status(BookSuccessCode.BOOK_LIST_FETCHED.getHttpStatus())
              .body(ApiResponse.success(
                BookSuccessCode.BOOK_LIST_FETCHED, 
                message, 
                responseDTO));
}

# UserBookService

- PageRequest.of(page,size)를 사용하여 페이징을 정의하여 Pageable 형태로 저장.

- Page<Book>타입의 변수 생성.

- switch문을 사용하여 type(ALL, TITLE, AUTHOR)별 Repository.메서드 실행

- Book 형태로 받은 결과를 UserBookSearchResDTO로 맵핑한 다음 Controller로 반환할 때  PageResponse<> 객체로 생성하여 반환한다.

** PageResponse 활용

public PageResponse<UserBookSearchResDTO> searchBooks(BookSearchType type, String keyword, int page, int size) {

  // 페이징 정의
  Pageable pageable = PageRequest.of(page, size);

  // Page<Book> 타입의 변수 생성
  Page<Book> result;

  // 타입 switch문으로 case 실행
  switch(type) {
    case ALL:
      result = bookRepository.findByTitleContainingIgnoreCaseOrAuthorContainingIgnoreCase(keyword, keyword, pageable);
      break;
    case TITLE:
      result = bookRepository.findByTitleContainingIgnoreCase(keyword, pageable);
      break;
    case AUTHOR:
      result = bookRepository.findByAuthorContainingIgnoreCase(keyword, pageable);
      break;
    default:
      throw new IllegalArgumentException("Unexpected search type: " + type);
  }

  // Book -> UserBookSearchResDTO로 형변환
  Page<UserBookSearchResDTO> pageDTO = result.map(UserBookSearchResDTO::new);

  // 반환
  return new PageResponse<>(pageDTO);
}

commit
도서 전체 목록 조회(좌), 도서 상세 조회(가운데), 도서 검색(우)