Skip to content

Commit

Permalink
Feat: 책의 좋아요가 가장 많은 베스트 한줄요약 조회 API 구현 (#174)
Browse files Browse the repository at this point in the history
* #167 - fix: 한줄요약 추천 API 중 잘못된 값 기입한 오류 수정

* #167 - refactor: 쓰지 않는 Entity인 ReadBook 클래스 삭제

* #167 - feat: 책의 좋아요가 가장 많은 베스트 한줄요약 조회 API 구현

* #167 - test: 책의 좋아요가 가장 많은 베스트 한줄요약 조회 API 테스트 구현

* #167 - comment: 게시글, 한줄요약 등록 로직에 대한 부가 설명과 베스트 한줄요약 예외 로직에 대한 부가 설명 주석 추가
  • Loading branch information
morenow98 authored Feb 20, 2024
1 parent f505706 commit 813a48b
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 26 deletions.
25 changes: 0 additions & 25 deletions src/main/java/cotato/bookitlist/mark/domain/ReadBook.java

This file was deleted.

3 changes: 3 additions & 0 deletions src/main/java/cotato/bookitlist/post/service/PostService.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class PostService {
public Long registerPost(PostRegisterRequest request, Long memberId) {
Member member = memberRepository.getReferenceById(memberId);

//게시글 등록 시 해당 책이 데이터베이스에 있으면 해당 책에 게시글을 작성한다.
//데이터베이스에 책이 없다면 알라딘 API 통신을 통해 책 정보를 가져와 저장 후 그 책에 게시글을 작성한다.
//단, 알라딘 API 통신을 하기 전 Redis 에 책 정보가 저장되어 있을 수 있으므로 있다면 그 정보로 책을 저장한다.
Book book = bookRepository.findByIsbn13(request.isbn13())
.orElseGet(() -> bookRepository.getReferenceById(
bookService.registerBook(request.isbn13())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import cotato.bookitlist.review.dto.response.ReviewCountResponse;
import cotato.bookitlist.review.dto.response.ReviewDetailResponse;
import cotato.bookitlist.review.dto.response.ReviewListResponse;
import cotato.bookitlist.review.dto.response.ReviewSimpleResponse;
import cotato.bookitlist.review.service.ReviewFacade;
import cotato.bookitlist.review.service.ReviewService;
import jakarta.servlet.http.Cookie;
Expand Down Expand Up @@ -146,7 +147,14 @@ public ResponseEntity<ReviewListResponse> getRecommendReviews(
if (details == null) {
return ResponseEntity.ok(reviewService.getRecommendReviews(type, start, DEFAULT_USER_ID));
}
return ResponseEntity.ok(reviewService.getRecommendReviews(type, start, DEFAULT_USER_ID));
return ResponseEntity.ok(reviewService.getRecommendReviews(type, start, details.getId()));
}

@GetMapping("/best")
public ResponseEntity<ReviewSimpleResponse> getBestReviewOfBook(
@RequestParam String isbn13
) {
return ResponseEntity.ok(reviewService.getBestReviewOfBook(isbn13));
}

private void handleReviewViewCount(HttpServletRequest request, HttpServletResponse response, Long reviewId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package cotato.bookitlist.review.dto.response;

public record ReviewSimpleResponse(
Long reviewId,
String content,
String name
) {
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cotato.bookitlist.review.repository.querydsl;

import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.review.dto.ReviewDetailDto;
import cotato.bookitlist.review.dto.ReviewDto;
import cotato.bookitlist.review.dto.response.ReviewSimpleResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

Expand All @@ -13,4 +15,6 @@ public interface ReviewRepositoryCustom {
Optional<ReviewDetailDto> findReviewDetailByReviewId(Long reviewId, Long memberId);

Page<ReviewDto> findLikeReviewByMemberId(Long memberId, Pageable pageable);

Optional<ReviewSimpleResponse> findBestReview(Book book);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.member.domain.ProfileStatus;
import cotato.bookitlist.review.domain.ReviewStatus;
import cotato.bookitlist.review.domain.entity.Review;
import cotato.bookitlist.review.dto.ReviewDetailDto;
import cotato.bookitlist.review.dto.ReviewDto;
import cotato.bookitlist.review.dto.response.ReviewSimpleResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -125,6 +128,26 @@ public Page<ReviewDto> findLikeReviewByMemberId(Long memberId, Pageable pageable
return PageableExecutionUtils.getPage(result, pageable, countQuery::fetchOne);
}

@Override
public Optional<ReviewSimpleResponse> findBestReview(Book book) {
return Optional.ofNullable(queryFactory
.select(
Projections.constructor(
ReviewSimpleResponse.class,
review.id,
review.content,
review.member.name
)
)
.from(review)
.where(review.book.eq(book))
.join(review.member, member)
.orderBy(review.likeCount.desc())
.limit(1)
.fetchOne()
);
}

private BooleanExpression isLikedByMember(Long memberId, NumberPath<Long> reviewId) {
return JPAExpressions.selectOne()
.from(reviewLike)
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/cotato/bookitlist/review/service/ReviewService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import cotato.bookitlist.review.dto.request.ReviewUpdateRequest;
import cotato.bookitlist.review.dto.response.ReviewCountResponse;
import cotato.bookitlist.review.dto.response.ReviewListResponse;
import cotato.bookitlist.review.dto.response.ReviewSimpleResponse;
import cotato.bookitlist.review.repository.ReviewRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -39,6 +40,9 @@ public class ReviewService {
public Long registerReview(ReviewRegisterRequest request, Long memberId) {
Member member = memberRepository.getReferenceById(memberId);

//한줄요약 등록 시 해당 책이 데이터베이스에 있으면 해당 책에 한줄요약을 작성한다.
//데이터베이스에 책이 없다면 알라딘 API 통신을 통해 책 정보를 가져와 저장 후 그 책에 한줄요약을 작성한다.
//단, 알라딘 API 통신을 하기 전 Redis 에 책 정보가 저장되어 있을 수 있으므로 있다면 그 정보로 책을 저장한다.
Book book = bookRepository.findByIsbn13(request.isbn13())
.orElseGet(() -> bookRepository.getReferenceById(
bookService.registerBook(request.isbn13())
Expand Down Expand Up @@ -125,4 +129,14 @@ public ReviewListResponse getNewReviews(int start, Long memberId) {

return ReviewListResponse.from(reviewPage, memberId);
}

public ReviewSimpleResponse getBestReviewOfBook(String isbn13) {
//책을 데이터베이스에서 찾지 못한 경우와 책이 데이터베이스에 있지만 한줄요약이 없는 경우가 서버 외부에선 같은 상황이므로
//두 경우 모두 한줄요약을 찾을 수 없다는 메시지를 보낸다.
Book book = bookRepository.findByIsbn13(isbn13)
.orElseThrow(() -> new EntityNotFoundException("한줄요약을 찾을 수 없습니다."));

return reviewRepository.findBestReview(book)
.orElseThrow(() -> new EntityNotFoundException("한줄요약을 찾을 수 없습니다."));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -507,4 +507,34 @@ void givenPageStartAndRecommendType_whenGettingNewReviews_thenReturnNewReviews()
.andExpect(jsonPath("$.reviewList[1].reviewId").value(2))
;
}

@Test
@DisplayName("isbn을 이용해 책의 가장 좋아요가 많은 한줄요약을 간략하게 반환한다.")
void givenIsbn13_whenGettingBestReviewOfBook_thenReturnBestReviewOfBook() throws Exception {
//given
String isbn13 = "9788931514810";

//when & then
mockMvc.perform(get("/reviews/best")
.param("isbn13", isbn13)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.reviewId").value(2))
;
}

@Test
@DisplayName("한줄요약이 없는 책에 isbn을 이용해 가장 좋아요가 많은 한줄요약을 조회하면 에러를 반환한다.")
void givenIsbn13NonReview_whenGettingBestReviewOfBook_thenReturnError() throws Exception {
//given
String isbn13 = "9791127278199";

//when & then
mockMvc.perform(get("/reviews/best")
.param("isbn13", isbn13)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.message").value("한줄요약을 찾을 수 없습니다."))
;
}
}

0 comments on commit 813a48b

Please sign in to comment.