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

[Library Management System] 25.09.23 (52일) | (구현) 관리자 특정 도서 리뷰 목록, 특정 사용자 리뷰 목록

dev.jelee 2025. 9. 23. 22:29

[ 작업한 내용 ]

< 관리자: 특정 도서 리뷰 목록 >

# AdminReviewBookIdResDTO

- 특정 도서 리뷰 목록 응답 DTO

- 리뷰 고유번호, 사용자 고유번호, 사용자 아이디, 책 고유번호, 책 제목, 책 isbn, 리뷰 내용, 작성일, 수정일 (id, userId, username, bookId, bookTitle, bookIsbn, content, createdDate, updatedDate)

- Review 엔티티를 파라미터로 받는 생성자 함수 정의

@Getter
public class AdminReviewBookIdResDTO {
  private Long id;

  private Long userId;
  private String username;
  
  private Long bookId;
  private String bookTitle;
  private String bookIsbn;

  private String content;
  private LocalDateTime createdDate;
  private LocalDateTime updatedDate;

  public AdminReviewBookIdResDTO(Review review) {
    this.id = review.getId();
    this.userId = review.getUser().getId();
    this.username = review.getUser().getUsername();
    this.bookId = review.getBook().getId();
    this.bookTitle = review.getBook().getTitle();
    this.bookIsbn = review.getBook().getIsbn();
    this.content = review.getContent();
    this.createdDate = review.getCreatedDate();
    this.updatedDate = review.getUpdatedDate();
  }
}

# AdminReviewController

- GET /api/v1/admin/books/{bookId}/reviews 로 요청받습니다.

- RequestParam 형태로 page와 size를 파라미터로 받습니다. 각 기본값은 0과 10입니다.

- @AuthenticationPrincipal을 사용하여 사용자 인증 객체를 가져와 User 엔티티로 저장합니다.

- Service 계층으로 bookId, page, size, user.getId()를 전달하여 비즈니스 로직을 처리합니다.

- 결과는 Page<AdminReviewBookIdResDTO> 형태로 받습니다.

- 클라이언트 측으로 반환할 시 ApiResponse.success()로 성공메시지와 결과를 감싸서 반환합니다.

@GetMapping("/books/{bookId}/reviews")
public ResponseEntity<?> bookIdListReview(
  @PathVariable("bookId") Long bookId, 
  @RequestParam(name = "page", defaultValue = "0") int page,
  @RequestParam(name = "size", defaultValue = "10") int size,
  @AuthenticationPrincipal User user) {

    // 서비스로직
    Page<AdminReviewBookIdResDTO> responseDTO = adminReviewService.bookIdListReview(bookId, page, size, user.getId());

    // 성공메시지
    String message = messageProvider.getMessage(ReviewSuccessCode.REVIEW_LIST_FETCHED.getMessage());

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

# AdminReviewService

- userRepository.findById(userId)로 사용자 조회를 하여 User 엔티티 형태로 저장합니다. 만약에 없는 사용자라면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.

- 조회한 사용자의 권한이 ROLE_ADMIN이 아니면 AuthErrorCode.AUTH_FORBIDDEN 예외를 던집니다.

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

- reviewRepository.findByBook_Id(bookId, pageable)을 호출하여 특정 책 고유번호의 리뷰를 조회하는데 페이징 형태로 조회합니다. 결과는 Page<Review> 형태로 저장합니다.

- Page 형태로 저장된 DTO는 List형태로 변환후 클라이언트 측으로 반환할 때에는 PageImpl<>을 사용하여 List형태의 DTO를 pageable로 랩핑하여 변환합니다.

public Page<AdminReviewBookIdResDTO> bookIdListReview(Long bookId, int page, int size, Long userId) {

  // 관리자 조회 및 권한 확인
  User user = userRepository.findById(userId)
      .orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
  
  if (user.getRole() != Role.ROLE_ADMIN) {
    throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
  }

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

  // Page형태로 결과 가져오기
  Page<Review> result = reviewRepository.findByBook_Id(bookId, pageable);

  // PageDTO를 List 형태로 변환
  List<AdminReviewBookIdResDTO> listDTO = result.getContent()
      .stream()
      .map(AdminReviewBookIdResDTO::new)
      .toList();

  // PageImpl을 사용하여 ListDTO를 pageable로 랩핑하여 반환
  return new PageImpl<>(listDTO, result.getPageable(), result.getTotalElements());
}

 


# ReviewRepository

- bookId로 조회하여 페이징으로 결과를 가져오기 위한 메서드 정의

Page<Review> findByBook_Id(Long bookId, Pageable pageable);

 


< 관리자: 특정 사용자 리뷰 목록 >

# AdminReviewUserIdResDTO

- 특정 사용자 리뷰 목록 응답 DTO

- 리뷰 고유번호, 사용자 고유번호, 사용자 아이디, 책 고유번호, 책 제목, 책 isbn, 리뷰 내용, 작성일, 수정일 (id, userId, username, bookId, bookTitle, bookIsbn, content, createdDate, updatedDate)

- Review 엔티티를 파라미터로 받는 생성자 함수 정의

@Getter
public class AdminReviewUserIdResDTO {
  private Long id;

  private Long userId;
  private String username;
  
  private Long bookId;
  private String bookTitle;
  private String bookIsbn;

  private String content;
  private LocalDateTime createdDate;
  private LocalDateTime updatedDate;

  public AdminReviewUserIdResDTO(Review review) {
    this.id = review.getId();
    this.userId = review.getUser().getId();
    this.username = review.getUser().getUsername();
    this.bookId = review.getBook().getId();
    this.bookTitle = review.getBook().getTitle();
    this.bookIsbn = review.getBook().getIsbn();
    this.content = review.getContent();
    this.createdDate = review.getCreatedDate();
    this.updatedDate = review.getUpdatedDate();
  }
}

# AdminReviewController

- GET /api/v1/admin/users/{userId}/reviews 로 요청받습니다.

- RequestParam 형태로 page와 size를 파라미터로 받습니다. 각 기본값은 0과 10입니다.

- @AuthenticationPrincipal을 사용하여 사용자 인증 객체를 가져와 User 엔티티로 저장합니다.

- Service 계층으로 userId, page, size, user.getId()를 전달하여 비즈니스 로직을 처리합니다.

- 결과는 Page<AdminReviewUserIdResDTO> 형태로 받습니다.

- 클라이언트 측으로 반환할 시 ApiResponse.success()로 성공메시지와 결과를 감싸서 반환합니다.

@GetMapping("/users/{userId}/reviews")
public ResponseEntity<?> userIdListReview(
  @PathVariable("userId") Long userId, 
  @RequestParam(name = "page", defaultValue = "0") int page,
  @RequestParam(name = "size", defaultValue = "10") int size,
  @AuthenticationPrincipal User user) {

    // 서비스로직
    Page<AdminReviewUserIdResDTO> responseDTO = adminReviewService.userIdListReview(userId, page, size, user.getId());

    // 성공메시지
    String message = messageProvider.getMessage(ReviewSuccessCode.REVIEW_LIST_FETCHED.getMessage());

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

# AdminReviewService

- userRepository.findById(userGetId)로 사용자 조회를 하여 User 엔티티 형태로 저장합니다. 만약에 없는 사용자라면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.

- 조회한 사용자의 권한이 ROLE_ADMIN이 아니면 AuthErrorCode.AUTH_FORBIDDEN 예외를 던집니다.

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

- reviewRepository.findByUser_Id(userId, pageable)을 호출하여 특정 책 고유번호의 리뷰를 조회하는데 페이징 형태로 조회합니다. 결과는 Page<Review> 형태로 저장합니다.

- Page 형태로 저장된 DTO는 List형태로 변환후 클라이언트 측으로 반환할 때에는 PageImpl<>을 사용하여 List형태의 DTO를 pageable로 랩핑하여 변환합니다.

public Page<AdminReviewUserIdResDTO> userIdListReview(Long userId, int page, int size, Long userGetId) {

  // 관리자 조회 및 권한 확인
  User user = userRepository.findById(userGetId)
      .orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
  
  if (user.getRole() != Role.ROLE_ADMIN) {
    throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
  }

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

  // Page형태로 결과 가져오기
  Page<Review> result = reviewRepository.findByUser_Id(userId, pageable);

  // PageDTO를 List 형태로 변환
  List<AdminReviewUserIdResDTO> listDTO = result.getContent()
      .stream()
      .map(AdminReviewUserIdResDTO::new)
      .toList();

  // PageImpl을 사용하여 ListDTO를 pageable로 랩핑하여 반환
  return new PageImpl<>(listDTO, result.getPageable(), result.getTotalElements());
}

commit
특정 도서 리뷰 목록 조회(좌), 특정 사용자 리뷰 목록 조회(우)