diff --git a/src/main/java/com/techeer/checkIt/domain/book/controller/BookController.java b/src/main/java/com/techeer/checkIt/domain/book/controller/BookController.java index 7a4f69d..257e41e 100644 --- a/src/main/java/com/techeer/checkIt/domain/book/controller/BookController.java +++ b/src/main/java/com/techeer/checkIt/domain/book/controller/BookController.java @@ -1,6 +1,7 @@ package com.techeer.checkIt.domain.book.controller; import com.techeer.checkIt.domain.book.dto.Response.BookRes; +import com.techeer.checkIt.domain.book.dto.Response.BookSearchLikeRes; import com.techeer.checkIt.domain.book.dto.Response.BookSearchRes; import com.techeer.checkIt.domain.book.service.BookService; import com.techeer.checkIt.domain.user.entity.User; @@ -56,7 +57,7 @@ public ResponseEntity getNewBooksList() { } @ApiOperation(value = "책 좋아요 API") - @GetMapping("/like/{bookId}") + @PostMapping("/like/{bookId}") public ResponseEntity updateLikeById( @AuthenticationPrincipal UserDetail userDetail, @PathVariable Long bookId @@ -67,4 +68,10 @@ public ResponseEntity updateLikeById( return ResponseEntity.ok(ResultResponse.of(UPDATE_BOOK_LIKE_SUCCESS ,bookResponse)); } + @ApiOperation(value = "인기 있는 책 조회 API") + @GetMapping("/like") + public ResponseEntity getLikeBooksList() { + Page books = bookService.sortedBooksByLike(); + return ResponseEntity.ok(ResultResponse.of(GET_NEW_BOOK_SUCCESS, books)); + } } diff --git a/src/main/java/com/techeer/checkIt/domain/book/dto/Response/BookSearchLikeRes.java b/src/main/java/com/techeer/checkIt/domain/book/dto/Response/BookSearchLikeRes.java new file mode 100644 index 0000000..81d82f9 --- /dev/null +++ b/src/main/java/com/techeer/checkIt/domain/book/dto/Response/BookSearchLikeRes.java @@ -0,0 +1,22 @@ +package com.techeer.checkIt.domain.book.dto.Response; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +public class BookSearchLikeRes { + private String title; + private String author; + private String publisher; + private String coverImageUrl; + private int pages; + private String category; + private int like; +} diff --git a/src/main/java/com/techeer/checkIt/domain/book/entity/Book.java b/src/main/java/com/techeer/checkIt/domain/book/entity/Book.java index 6abc1bc..becef39 100644 --- a/src/main/java/com/techeer/checkIt/domain/book/entity/Book.java +++ b/src/main/java/com/techeer/checkIt/domain/book/entity/Book.java @@ -37,6 +37,8 @@ public class Book extends BaseEntity { private String category; @OneToMany(mappedBy = "book") private List readingList = new ArrayList<>(); + @Column(name = "like_count") + private Integer likeCount = 0; @Builder public Book(String title, String author, String publisher, String coverImageUrl, int pages, int height, int width, int thickness, String category) { this.title = title; @@ -49,4 +51,16 @@ public Book(String title, String author, String publisher, String coverImageUrl, this.thickness = thickness; this.category = category; } + + @PostLoad + @PrePersist + private void initializeDefaults() { + if (likeCount == null) { + likeCount = 0; // 기본값을 0으로 설정 + } + } + public void updateLike(int like) { + this.likeCount = like; + } + public void setLikeCount(Integer likeCount) { this.likeCount = likeCount; } } diff --git a/src/main/java/com/techeer/checkIt/domain/book/mapper/BookMapper.java b/src/main/java/com/techeer/checkIt/domain/book/mapper/BookMapper.java index 331c9e3..fd776a1 100644 --- a/src/main/java/com/techeer/checkIt/domain/book/mapper/BookMapper.java +++ b/src/main/java/com/techeer/checkIt/domain/book/mapper/BookMapper.java @@ -1,6 +1,7 @@ package com.techeer.checkIt.domain.book.mapper; import com.techeer.checkIt.domain.book.dto.Response.BookRes; +import com.techeer.checkIt.domain.book.dto.Response.BookSearchLikeRes; import com.techeer.checkIt.domain.book.dto.Response.BookSearchRes; import com.techeer.checkIt.domain.book.entity.Book; import com.techeer.checkIt.domain.book.entity.BookDocument; @@ -37,14 +38,32 @@ public BookSearchRes toBookSearchDto(BookDocument book) { .category(book.getCategory()) .build(); } + public BookSearchLikeRes toBookSearchLikeDto(Book book) { + return BookSearchLikeRes.builder() + .title(book.getTitle()) + .author(book.getAuthor()) + .publisher(book.getPublisher()) + .coverImageUrl(book.getCoverImageUrl()) + .pages(book.getPages()) + .category(book.getCategory()) + .like(book.getLikeCount()) + .build(); + } public List toSearchDtoList(List books){ return books.stream() .map(this::toBookSearchDto) .collect(Collectors.toList()); } + // toPageDtoList = toBookSearchResDtoPage public Page toPageDtoList(Page books) { return new PageImpl<>(books.stream() .map(this::toBookSearchDto) .collect(Collectors.toList())); } + // toPageDtoList2 = BookSearchLikeResDtoPage + public Page toPageDtoList2(Page books) { + return new PageImpl<>(books.stream() + .map(this::toBookSearchLikeDto) + .collect(Collectors.toList())); + } } diff --git a/src/main/java/com/techeer/checkIt/domain/book/service/BookService.java b/src/main/java/com/techeer/checkIt/domain/book/service/BookService.java index b4a483d..b4ae563 100644 --- a/src/main/java/com/techeer/checkIt/domain/book/service/BookService.java +++ b/src/main/java/com/techeer/checkIt/domain/book/service/BookService.java @@ -2,6 +2,7 @@ import com.techeer.checkIt.domain.book.dao.RedisDao; import com.techeer.checkIt.domain.book.dto.Response.BookRes; +import com.techeer.checkIt.domain.book.dto.Response.BookSearchLikeRes; import com.techeer.checkIt.domain.book.dto.Response.BookSearchRes; import com.techeer.checkIt.domain.book.entity.Book; import com.techeer.checkIt.domain.book.entity.BookDocument; @@ -9,6 +10,7 @@ import com.techeer.checkIt.domain.book.mapper.BookMapper; import com.techeer.checkIt.domain.book.repository.BookJpaRepository; import com.techeer.checkIt.domain.book.repository.BookSearchRepository; +import javax.transaction.Transactional; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -39,6 +41,12 @@ public Page sortedBooksByTime() { return bookMapper.toPageDtoList(newBooks); } + public Page sortedBooksByLike() { + PageRequest pageRequest = PageRequest.of(0, 10, Sort.by(Sort.Order.desc("likeCount"))); + Page newBooks = bookJpaRepository.findAll(pageRequest); + return bookMapper.toPageDtoList2(newBooks); + } + // id별 조회할 때 public BookRes findBookById(Long userId, Long bookId) { Book book = bookJpaRepository.findByBookId(bookId).orElseThrow(BookNotFoundException::new); @@ -53,22 +61,31 @@ public BookRes findBookById(Long userId, Long bookId) { public Book findById(Long id) { return bookJpaRepository.findById(id).orElseThrow(BookNotFoundException::new); } + @Transactional public void updateLike(Long userId, Long bookId) { + Book book = bookJpaRepository.findByBookId(bookId).orElseThrow(BookNotFoundException::new); String redisKey = "B" + bookId.toString(); // 게시글 key String redisUserKey = "U" + userId.toString(); // 유저 key // redis에 없는 게시글 id가 들어올 경우 : 새롭게 데이터를 만들어주고 좋아요수를 0으로 초기화, 있는 경우 : 현제 좋아요수 반환 String values = (redisDao.getValues(redisKey) == null) ? redisDao.setValues(redisKey,"0") : redisDao.getValues(redisKey); - int likes = Integer.parseInt(values); + int likes = Integer.parseInt(values), bookLikes = 0; + // 유저를 key로 조회한 게시글 ID List안에 해당 게시글 ID가 포함되어있지 않는다면, if (!redisDao.getValuesList(redisUserKey).contains(redisKey.substring(1))) { redisDao.setValuesList(redisUserKey, redisKey.substring(1)); // 유저 key로 해당 글 ID를 List 형태로 저장 likes = Integer.parseInt(values) + 1; // 좋아요 증가 redisDao.setValues(redisKey, String.valueOf(likes)); // 글ID key로 좋아요 저장 + bookLikes = book.getLikeCount(); + book.updateLike(bookLikes+1); } else { redisDao.deleteValueList(redisUserKey, redisKey.substring(1)); // 유저 key로 해당 글 ID를 List 형태에서 제거 likes = Integer.parseInt(values) - 1; // 좋아요 감소 redisDao.setValues(redisKey, String.valueOf(likes)); // 글ID key로 좋아요 저장 + bookLikes = book.getLikeCount(); + book.updateLike(bookLikes-1); } + + bookJpaRepository.save(book); } } diff --git a/src/main/java/com/techeer/checkIt/domain/review/controller/ReviewController.java b/src/main/java/com/techeer/checkIt/domain/review/controller/ReviewController.java index c65c894..b7b0989 100644 --- a/src/main/java/com/techeer/checkIt/domain/review/controller/ReviewController.java +++ b/src/main/java/com/techeer/checkIt/domain/review/controller/ReviewController.java @@ -12,6 +12,7 @@ import com.techeer.checkIt.global.result.ResultResponse; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import javax.validation.Valid; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -35,15 +36,15 @@ public class ReviewController { private final BookService bookService; @ApiOperation(value = "리뷰 생성 API") - @PostMapping() + @PostMapping public ResponseEntity createReview( @AuthenticationPrincipal UserDetail userDetail, - @RequestBody CreateReviewReq createReviewReq + @RequestBody @Valid CreateReviewReq createReviewReq ){ User user = userService.findUserByUsername(userDetail.getUsername()); Book book = bookService.findById(createReviewReq.getBookId()); reviewService.createReview(user, book, createReviewReq); - ReviewRes reviewRes = reviewService.findReviewByNameIdBookId(user, createReviewReq.getBookId()); + ReviewRes reviewRes = reviewService.findReviewByUserNameIdBookId(user, createReviewReq.getBookId()); return ResponseEntity.ok(ResultResponse.of(ResultCode.REVIEW_CREATE_SUCCESS, reviewRes)); } @@ -54,13 +55,13 @@ public ResponseEntity getReviewByUserNameBookId( @PathVariable Long bookId ){ User user = userService.findUserByUsername(userDetail.getUsername()); - ReviewRes reviewRes = reviewService.findReviewByNameIdBookId(user, bookId); + ReviewRes reviewRes = reviewService.findReviewByUserNameIdBookId(user, bookId); return ResponseEntity.ok(ResultResponse.of(ResultCode.REVIEW_CREATE_SUCCESS, reviewRes)); } @ApiOperation(value = "리뷰 삭제 API") @DeleteMapping ("{bookId}") - public ResponseEntity deleteReviewUserNameBookId( + public ResponseEntity deleteReviewByUserNameBookId( @AuthenticationPrincipal UserDetail userDetail, @PathVariable Long bookId ){ @@ -70,14 +71,14 @@ public ResponseEntity deleteReviewUserNameBookId( } @ApiOperation(value = "리뷰 내용 변경 API") - @PutMapping() + @PutMapping public ResponseEntity updateReview( @AuthenticationPrincipal UserDetail userDetail, - @RequestBody CreateReviewReq createReviewReq + @RequestBody @Valid CreateReviewReq createReviewReq ) { User user = userService.findUserByUsername(userDetail.getUsername()); reviewService.updateReview(user, createReviewReq); - ReviewRes reviewRes = reviewService.findReviewByNameIdBookId(user, createReviewReq.getBookId()); + ReviewRes reviewRes = reviewService.findReviewByUserNameIdBookId(user, createReviewReq.getBookId()); return ResponseEntity.ok(ResultResponse.of(ResultCode.REVIEW_DELETE_SUCCESS, reviewRes)); } diff --git a/src/main/java/com/techeer/checkIt/domain/review/service/ReviewService.java b/src/main/java/com/techeer/checkIt/domain/review/service/ReviewService.java index bc24f96..b2eec09 100644 --- a/src/main/java/com/techeer/checkIt/domain/review/service/ReviewService.java +++ b/src/main/java/com/techeer/checkIt/domain/review/service/ReviewService.java @@ -25,7 +25,7 @@ public void createReview (User user, Book book, CreateReviewReq createReviewReq) reviewRepository.save(review); } - public ReviewRes findReviewByNameIdBookId (User user, Long bookId) { + public ReviewRes findReviewByUserNameIdBookId (User user, Long bookId) { Review review = reviewRepository.findByUserNameBookId(user.getNickname(), bookId).orElseThrow(ReviewNotFoundException::new); return reviewMapper.toDto(review); } diff --git a/src/main/java/com/techeer/checkIt/global/result/ResultCode.java b/src/main/java/com/techeer/checkIt/global/result/ResultCode.java index af4fbe8..432f5a6 100644 --- a/src/main/java/com/techeer/checkIt/global/result/ResultCode.java +++ b/src/main/java/com/techeer/checkIt/global/result/ResultCode.java @@ -36,7 +36,7 @@ public enum ResultCode { // Review REVIEW_CREATE_SUCCESS("RE001", "리뷰 등록 성공"), - GET_REVIEW_SUCCESS("RE0012", "리뷰 조회 성공"), + GET_REVIEW_SUCCESS("RE002", "리뷰 조회 성공"), REVIEW_DELETE_SUCCESS("RE003", "리뷰 삭제 성공"), REVIEW_UPDATE_SUCCESS("RE004", "리뷰 갱신 성공"), ;