[ 작업한 내용 ]
< 관리자: 리뷰 상세 >
# AdminReviewDetailResDTO
- 관리자 리뷰 상세 응답 DTO 정의
- 리뷰 고유번호, 사용자 고유번호, 사용자 아이디, 책 고유번호, 책 제목, 책 isbn, 리뷰 내용, 작성일, 수정일 (id, userId, username, bookId, bookTitle, bookIsbn, content, createdDate, updatedDate)
- Review 엔티티를 파라미터로 받는 생성자 함수 정의
@Getter
public class AdminReviewDetailResDTO {
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 AdminReviewDetailResDTO(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/reviews/{reviewId}로 요청합니다
- 파라미터는 reviewId와 user이며, @AuthenticationPrincipal로 가져온 사용자 정보를 User 엔티티로 저장합니다.
- Service 계층으로 reviewId, user.getId()를 전달합니다.
- 결과는 AdminReviewDetailResDTO 형태로 저장합니다.
- 클라이언트 측으로 응답할 때에는 ApiResponse.success()로 성공 메시지와 결과를 감싸서 반환합니다.
@GetMapping("/reviews/{reviewId}")
public ResponseEntity<?> detailReview(
@PathVariable(name = "reviewId") Long reviewId,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminReviewDetailResDTO responseDTO = adminReviewService.detailReview(reviewId, user.getId());
// 성공메시지
String message = messageProvider.getMessage(ReviewSuccessCode.REVIEW_FETCHED.getMessage());
// 응답
return ResponseEntity
.status(ReviewSuccessCode.REVIEW_FETCHED.getHttpStatus())
.body(ApiResponse.success(
ReviewSuccessCode.REVIEW_FETCHED,
message,
responseDTO));
}
# AdminReviewService
- userRepository.findById(userId)을 사용하여 유효한 사용자인지 확인을 한 후 User 객체로 저장합니다. 만약에 사용자가 없다면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.
- user의 권한이 ROLE_ADMIN이 아닌 경우 AuthErrorCode.AUTH_FORBIDDEN 예외를 던집니다.
- reviewRepository.findById(reviewId)를 사용하여 유효한 리뷰인지 확인을 한 후 Review 객체로 저장합니다. 만약에 없는 리뷰라면 ReviewErrorCode.REVIEW_NOT_FOUND 예외를 던집니다.
- Controller로 Review 엔티티를 AdminReviewDetailResDTO 객체로 생성하여 보냅니다.
public AdminReviewDetailResDTO detailReview(Long reviewId, 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);
}
// 리뷰 조회
Review result = reviewRepository.findById(reviewId).orElseThrow(()-> new BaseException(ReviewErrorCode.REVIEW_NOT_FOUND));
// 반환
return new AdminReviewDetailResDTO(result);
}
< 관리자: 리뷰 삭제 >
# AdminReviewDeleteResDTO
- 관리자 리뷰 삭제 응답 DTO 정의
- 리뷰 고유번호 (id)
- Review 엔티티를 파라미터로 받는 생성자 함수 정의
@Getter
public class AdminReviewDeleteResDTO {
private Long id;
public AdminReviewDeleteResDTO(Review review) {
this.id = review.getId();
}
}
# AdminReviewController
- DELETE /api/v1/admin/reviews/{reviewId}로 요청합니다
- 파라미터는 reviewId와 user이며, @AuthenticationPrincipal로 가져온 사용자 정보를 User 엔티티로 저장합니다.
- Service 계층으로 reviewId, user.getId()를 전달합니다.
- 결과는 AdminReviewDeleteResDTO 형태로 저장합니다.
- 클라이언트 측으로 응답할 때에는 ApiResponse.success()로 성공 메시지와 결과를 감싸서 반환합니다.
@DeleteMapping("/reviews/{reviewId}")
public ResponseEntity<?> deleteReview(
@PathVariable(name = "reviewId") Long reviewId,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminReviewDeleteResDTO responseDTO = adminReviewService.deleteReview(reviewId, user.getId());
// 성공메시지
String message = messageProvider.getMessage(ReviewSuccessCode.REVIEW_DELETED.getMessage());
// 응답
return ResponseEntity
.status(ReviewSuccessCode.REVIEW_DELETED.getHttpStatus())
.body(ApiResponse.success(
ReviewSuccessCode.REVIEW_DELETED,
message,
responseDTO));
}
# AdminReviewService
- userRepository.findById(userId)을 사용하여 유효한 사용자인지 확인을 한 후 User 객체로 저장합니다. 만약에 사용자가 없
다면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.
- user의 권한이 ROLE_ADMIN이 아닌 경우 AuthErrorCode.AUTH_FORBIDDEN 예외를 던집니다.
- reviewRepository.findById(reviewId)를 사용하여 유효한 리뷰인지 확인을 한 후 Review 객체로 저장합니다. 만약에 없는 리뷰라면 ReviewErrorCode.REVIEW_NOT_FOUND 예외를 던집니다.
- 응답 DTO를 위해 조회한 리뷰를 Review tempRivew에 저장합니다.
- reviewRepository.delete(delReview)를 사용하여 조회한 리뷰를 삭제합니다.
- Controller로 tempReview를 AdminReviewDeleteResDTO 객체로 생성하여 보냅니다.
@Transactional
public AdminReviewDeleteResDTO deleteReview(Long reviewId, Long usreId) {
// 관리자 조회 및 권한 확인
User user = userRepository.findById(usreId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (user.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// 리뷰 조회
Review delReview = reviewRepository.findById(reviewId)
.orElseThrow(() -> new BaseException(ReviewErrorCode.REVIEW_NOT_FOUND));
Review tempReview = delReview;
// 리뷰 삭제
reviewRepository.delete(delReview);
// 반환
return new AdminReviewDeleteResDTO(tempReview);
}
< 공용: 특정 책 리뷰 전체 목록 >
# AllReviewListResDTO
- 공용 특정 책 리뷰 전체 목록 조회 응답 DTO 정의
- 리뷰 고유번호, 책 제목, 사용자 아이디, 리뷰 내용, 작성일, 수정일 (id, bookTitle, username, content, createdDate, updatedDate)
- Review 엔티티를 파라미터로 받는 생성자 함수 정의
@Getter
public class AllReviewListResDTO {
private long id;
private String bookTitle;
private String username;
private String content;
private LocalDateTime createdDate;
private LocalDateTime updatedDate;
public AllReviewListResDTO(Review review) {
this.id = review.getId();
this.bookTitle = review.getBook().getTitle();
this.username = review.getUser().getUsername();
this.content = review.getContent();
this.createdDate = review.getCreatedDate();
this.updatedDate = review.getUpdatedDate();
}
}
# AllReviewController
- GET /api/v1/books/{bookId}/reviews로 요청합니다
- 파라미터는 bookId와 page, size 있으며, page와 size는 각 기본값이 0과 10입니다. 그리고 @AuthenticationPrincipal로 가져온 사용자 정보를 User 엔티티로 저장합니다.
- Service 계층으로 bookId, page, size, user.getId()를 전달합니다.
- 결과는 AllReviewListResDTO 형태로 저장합니다.
- 클라이언트 측으로 응답할 때에는 ApiResponse.success()로 성공 메시지와 결과를 감싸서 반환합니다.
@GetMapping("/books/{bookId}/reviews")
public ResponseEntity<?> allListReviews(
@PathVariable(name = "bookId") Long bookId,
@RequestParam(name = "page", defaultValue = "0") int page,
@RequestParam(name = "size", defaultValue = "10") int size,
@AuthenticationPrincipal User user) {
// 서비스로직
Page<AllReviewListResDTO> responseDTO = allReviewService.allListReviews(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));
}
# AllReviewService
- userRepository.findById(userId)을 사용하여 유효한 사용자인지 확인하고 만약에 사용자가 없다면 UserErrorCode.USER_NOT_FOUND 예외를 던집니다.
- bookRepository.findById(bookId)를 사용하여 유효한 도서인지 확인하고 만약에 없는 도서라면 BookErrorCode.BOOK_NOT_FOUND 예외를 던집니다.
- PageRequest.of(page, size)를 사용하여 페이징 정의를 하고 Pageable 형태로 저장합니다.
- reviewRepository.findByBook_Id(bookId, pageable)를 사용하여 bookId에 작성된 리뷰를 찾아 페이징 형태로 조회하여 Page<Review> 형태로 저장합니다.
- Page형태의 DTO를 List<AllReviewListResDTO> 형태로 형변환 한 후, Controller로 반환시 PageImpl<>을 사용하여 listDTO를 Pageable로 랩핑하여 반환합니다.
public Page<AllReviewListResDTO> allListReviews(Long bookId, int page, int size, Long userId) {
// 사용자 확인
userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
// 도서 확인
bookRepository.findById(bookId)
.orElseThrow(() -> new BaseException(BookErrorCode.BOOK_NOT_FOUND));
// 페이징 정의
Pageable pageable = PageRequest.of(page, size);
// bookId 페이징 조회
Page<Review> result = reviewRepository.findByBook_Id(bookId, pageable);
// List로 형변환
List<AllReviewListResDTO> listDTO = result.getContent()
.stream()
.map(AllReviewListResDTO::new)
.toList();
// PageImpl을 사용하여 pageable 형태로 랩핑하여 반환
return new PageImpl<>(listDTO, result.getPageable(), result.getTotalElements());
}