Skip to content

Commit 67a80ca

Browse files
authored
Merge pull request #152 from Moongeul/feat/#134
[FEAT] 책 정보 자세히보기 API - 평가정보(평점(평균), Best5 태그, 리뷰 미리보기) 반환
2 parents 45951b9 + c0e2f5d commit 67a80ca

File tree

11 files changed

+127
-27
lines changed

11 files changed

+127
-27
lines changed

src/main/java/com/core/book/api/article/repository/ArticleRepository.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import org.springframework.stereotype.Repository;
77
import org.springframework.data.domain.Page;
88
import org.springframework.data.domain.Pageable;
9-
import org.springframework.data.jpa.repository.EntityGraph;
109

1110
import java.util.List;
1211

@@ -17,4 +16,6 @@ public interface ArticleRepository extends JpaRepository<Article, Long> {
1716

1817
Page<Article> findByTypeIn(Iterable<ArticleType> types, Pageable pageable);
1918

19+
// 특정 ISBN을 가진 최신 게시글 5개 가져오기
20+
List<Article> findByBookIsbnOrderByCreatedAtDesc(String isbn, Pageable pageable);
2021
}

src/main/java/com/core/book/api/article/service/ArticleCreateService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ public void updateRatingAverage(Book book, double new_rating){
8383

8484
// 해당 책의 평균 평점(rating_average) 새로 계산 및 rating_count(평점 개수) + 1
8585
// 계산 공식: new_rating_average = (rating_average * rating_count + rating) / rating_count + 1 )
86-
double new_rating_average = (book.getRatingAverage() * book.getRatingCount() + new_rating) / (book.getRatingCount() + 1);
87-
new_rating_average = Math.round(new_rating_average * 100) / 100.0;
86+
float new_rating_average = (float) ((book.getRatingAverage() * book.getRatingCount() + new_rating) / (book.getRatingCount() + 1));
87+
new_rating_average = (float) (Math.round(new_rating_average * 100) / 100.0);
8888

8989
Book updatedBook = book.toBuilder()
9090
.ratingAverage(new_rating_average)

src/main/java/com/core/book/api/article/service/ArticleModifyService.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ public void modifyReviewArticle(Long articleId, ReviewArticleCreateDTO reviewArt
8686
public void modifyRatingAverage(Book book, double new_rating, double old_rating){
8787

8888
// 새 점수들의 합 = (기존 점수들의 합) - (바뀌기 이전 평점) + (바뀐 평점)
89-
double new_rating_sum = (book.getRatingAverage() * book.getRatingCount()) - old_rating + new_rating;
90-
double new_rating_average = new_rating_sum / book.getRatingCount();
91-
new_rating_average = Math.round(new_rating_average * 100) / 100.0;
89+
float new_rating_sum = (float) ((book.getRatingAverage() * book.getRatingCount()) - old_rating + new_rating);
90+
float new_rating_average = new_rating_sum / book.getRatingCount();
91+
new_rating_average = (float) (Math.round(new_rating_average * 100) / 100.0);
9292

9393
Book updatedBook = book.toBuilder()
9494
.ratingAverage(new_rating_average)

src/main/java/com/core/book/api/book/controller/BookController.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.core.book.api.book.controller;
22

3-
import com.core.book.api.book.dto.BookInfoDTO;
3+
import com.core.book.api.book.dto.BookInfoDetailDTO;
44
import com.core.book.api.book.dto.BookResponseDTO;
55
import com.core.book.api.book.service.BookService;
66
import com.core.book.common.exception.BadRequestException;
@@ -62,15 +62,15 @@ public ResponseEntity<ApiResponse<BookResponseDTO>> book(
6262
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "해당 도서의 검색 결과가 없습니다.")
6363
})
6464
@GetMapping("/api/v1/book/info")
65-
public ResponseEntity<ApiResponse<BookInfoDTO>> bookInfo(
65+
public ResponseEntity<ApiResponse<BookInfoDetailDTO>> bookInfo(
6666
@RequestParam("isbn") String isbn){
6767

68-
BookInfoDTO bookInfo = bookService.bookInfo(isbn);
68+
BookInfoDetailDTO bookInfoDetail = bookService.bookInfo(isbn);
6969

70-
if(bookInfo == null){
70+
if(bookInfoDetail == null){
7171
throw new NotFoundException(ErrorStatus.BOOK_SEARCH_NOTFOUND_EXCEPTION.getMessage());
7272
}
7373

74-
return ApiResponse.success(SuccessStatus.BOOK_SEARCH_SUCCESS, bookInfo);
74+
return ApiResponse.success(SuccessStatus.BOOK_SEARCH_SUCCESS, bookInfoDetail);
7575
}
7676
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.core.book.api.book.dto;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
6+
import java.util.List;
7+
8+
@Builder
9+
@Getter
10+
public class BookInfoDetailDTO {
11+
/* 책 정보 자세히 보기 정보 */
12+
13+
private String isbn; // isbn
14+
private String image; // 책 이미지
15+
private String title; // 책 제목
16+
private String author; // 저자
17+
private String publisher; // 출판사
18+
private String pubdate; // 출판 날짜
19+
private String description; // 책 소개
20+
21+
private float ratingAverage; // 평점 (전체 평균)
22+
private List<String> tagList; // 태그 Best5
23+
List<ReviewPreviewDTO> reviewPreviewList; // 리뷰 (미리보기) - 5개
24+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.core.book.api.book.dto;
2+
3+
import com.core.book.api.article.entity.ArticleType;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
@Builder
8+
@Getter
9+
public class ReviewPreviewDTO {
10+
/* 책 정보 자세히보기 - 리뷰 미리보기 */
11+
12+
private String profileImage;
13+
private String nickname;
14+
private ArticleType articleType; // 게시글 타입 구분을 위한 필드
15+
private String content;
16+
}

src/main/java/com/core/book/api/book/entity/Book.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class Book {
2828
private String pubdate; // 출판연도
2929

3030
@Column(name = "rating_average")
31-
private double ratingAverage; // 평점 (전체 평균)
31+
private float ratingAverage; // 평점 (전체 평균)
3232

3333
@Column(name = "rating_count")
3434
private int ratingCount; // 평점 개수

src/main/java/com/core/book/api/book/repository/UserBookTagRepository.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import com.core.book.api.article.entity.ReviewArticle;
44
import com.core.book.api.book.entity.UserBookTag;
55
import com.core.book.api.bookshelf.entity.ReadBooks;
6+
import org.springframework.data.domain.Pageable;
67
import org.springframework.data.jpa.repository.JpaRepository;
8+
import org.springframework.data.jpa.repository.Query;
79
import org.springframework.stereotype.Repository;
810

911
import java.util.List;
@@ -16,4 +18,15 @@ public interface UserBookTagRepository extends JpaRepository<UserBookTag, Intege
1618

1719
// 'ReviewArticle(감상평 게시글)' ID에 해당하는 태그 리스트 가져오기
1820
List<UserBookTag> findByReviewArticle(ReviewArticle reviewArticle);
21+
22+
@Query("""
23+
SELECT u.tag
24+
FROM UserBookTag u
25+
WHERE u.book.isbn = :isbn
26+
GROUP BY u.tag
27+
ORDER BY COUNT(u.tag) DESC
28+
""")
29+
List<Integer> findTop5TagsByIsbn(String isbn, Pageable pageable);
30+
31+
1932
}

src/main/java/com/core/book/api/book/service/BookService.java

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
package com.core.book.api.book.service;
22

3+
import com.core.book.api.article.entity.Article;
4+
import com.core.book.api.article.repository.ArticleRepository;
5+
import com.core.book.api.book.constant.BookTag;
36
import com.core.book.api.book.dto.*;
47
import com.core.book.api.book.entity.Book;
58
import com.core.book.api.book.repository.BookRepository;
9+
import com.core.book.api.book.repository.UserBookTagRepository;
610
import com.core.book.common.exception.NotFoundException;
711
import com.core.book.common.response.ErrorStatus;
812
import com.fasterxml.jackson.core.JsonProcessingException;
913
import com.fasterxml.jackson.databind.JsonMappingException;
1014
import lombok.RequiredArgsConstructor;
1115
import lombok.extern.slf4j.Slf4j;
1216
import org.springframework.beans.factory.annotation.Value;
17+
import org.springframework.data.domain.PageRequest;
1318
import org.springframework.http.RequestEntity;
1419
import org.springframework.http.ResponseEntity;
1520
import org.springframework.stereotype.Service;
@@ -28,6 +33,8 @@
2833
public class BookService {
2934

3035
private final BookRepository bookRepository;
36+
private final UserBookTagRepository userBookTagRepository;
37+
private final ArticleRepository articleRepository;
3138

3239
@Value("${naver-client-id}")
3340
private String clientId;
@@ -56,7 +63,7 @@ public BookResponseDTO bookSearch(String text, int page, int size){
5663

5764
// bookList를 BookInfoDTO로 변환
5865
List<BookInfoDTO> BookInfoList = bookList.stream()
59-
.map(this::convertToBookInfoDTO)
66+
.map(this::convertFromBookDTOToBookInfoDTO)
6067
.collect(Collectors.toList());
6168

6269
// 마지막 페이지 여부 검사
@@ -73,24 +80,46 @@ public BookResponseDTO bookSearch(String text, int page, int size){
7380
.build();
7481
}
7582

76-
public BookInfoDTO bookInfo(String isbn){
83+
public BookInfoDetailDTO bookInfo(String isbn){
7784

7885
BookDTO bookDTO;
7986

87+
float ratingAverage = 0.0F;
88+
List<String> tagList = new ArrayList<>();
89+
List<ReviewPreviewDTO> reviewPreviewList = new ArrayList<>();
90+
8091
// BOOK DB에서 책 데이터 찾기
8192
if(bookRepository.existsByIsbn(isbn)){
82-
83-
log.info("도서 정보 DB 요청");
8493

8594
Book book = bookRepository.findById(isbn)
8695
.orElseThrow(() -> new NotFoundException(ErrorStatus.BOOK_NOTFOUND_EXCEPTION.getMessage()));
87-
bookDTO = convertToBookDTO(book);
96+
97+
bookDTO = convertFromBookToBookInfoDTO(book);
98+
99+
// 평균 평점
100+
ratingAverage = book.getRatingAverage();
101+
102+
// Best 5 태그
103+
List<Integer> tagIds = userBookTagRepository.findTop5TagsByIsbn(isbn, PageRequest.of(0, 5));
104+
for (Integer id : tagIds) {
105+
tagList.add(BookTag.fromId(id).getDescription());
106+
}
107+
108+
// 리뷰 (표시정보 : profile_image, nickname, article_type, content)
109+
List<Article> articleList = articleRepository.findByBookIsbnOrderByCreatedAtDesc(isbn, PageRequest.of(0, 5));
110+
for(Article article : articleList){
111+
ReviewPreviewDTO reviewPreview = ReviewPreviewDTO.builder()
112+
.profileImage(article.getMember().getImageUrl())
113+
.nickname(article.getMember().getNickname())
114+
.articleType(article.getType())
115+
.content(article.getContent())
116+
.build();
117+
reviewPreviewList.add(reviewPreview);
118+
}
88119

89120
}
90121
else{ // (DB에 없다면) 외부 도서 API에 데이터 요청
91122

92-
log.info("도서 정보 외부 API 요청");
93-
94123
// 외부 도서 API 요청
95124
URI uri = uriComponentBuild(null, isbn, 1, 10);
96125
ResultDTO resultDTO = fetchBookData(uri);
@@ -103,7 +132,7 @@ public BookInfoDTO bookInfo(String isbn){
103132
}
104133

105134
if(bookDTO != null){
106-
return convertToBookInfoDTO(bookDTO);
135+
return convertFromBookDTOToBookInfoDetailDTO(bookDTO, ratingAverage, tagList, reviewPreviewList);
107136
} else {
108137
return null;
109138
}
@@ -165,7 +194,7 @@ private ResultDTO fetchBookData(URI uri){
165194
}
166195

167196
// Book을 BookInfoDTO로 변환
168-
private BookDTO convertToBookDTO(Book book){
197+
private BookDTO convertFromBookToBookInfoDTO(Book book){
169198
return BookDTO.builder()
170199
.isbn(book.getIsbn())
171200
.image(book.getBookImage())
@@ -178,7 +207,7 @@ private BookDTO convertToBookDTO(Book book){
178207
}
179208

180209
// BookDTO를 BookInfoDTO로 변환
181-
private BookInfoDTO convertToBookInfoDTO(BookDTO bookDTO){
210+
private BookInfoDTO convertFromBookDTOToBookInfoDTO(BookDTO bookDTO){
182211
return BookInfoDTO.builder()
183212
.isbn(bookDTO.getIsbn())
184213
.image(bookDTO.getImage())
@@ -189,4 +218,20 @@ private BookInfoDTO convertToBookInfoDTO(BookDTO bookDTO){
189218
.description(bookDTO.getDescription())
190219
.build();
191220
}
221+
222+
// BookDTO를 BookInfoDetailDTO로 변환
223+
private BookInfoDetailDTO convertFromBookDTOToBookInfoDetailDTO(BookDTO bookDTO, float ratingAverage, List<String> tagList, List<ReviewPreviewDTO> reviewPreviewList){
224+
return BookInfoDetailDTO.builder()
225+
.isbn(bookDTO.getIsbn())
226+
.image(bookDTO.getImage())
227+
.title(bookDTO.getTitle())
228+
.author(bookDTO.getAuthor())
229+
.publisher(bookDTO.getPublisher())
230+
.pubdate(bookDTO.getPubdate())
231+
.description(bookDTO.getDescription())
232+
.ratingAverage(ratingAverage)
233+
.tagList(tagList)
234+
.reviewPreviewList(reviewPreviewList)
235+
.build();
236+
}
192237
}

src/main/java/com/core/book/api/book/service/UserBookTagService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
@Service
1818
@RequiredArgsConstructor
1919
public class UserBookTagService {
20+
2021
private final UserBookTagRepository userBookTagRepository;
2122

2223
// id로 태그 entity 가져오기

0 commit comments

Comments
 (0)