From f251dbc92d50341fe65d253fe58f586d8b2dc6d1 Mon Sep 17 00:00:00 2001 From: fnzl54 Date: Tue, 17 Oct 2023 00:42:24 +0900 Subject: [PATCH 1/5] =?UTF-8?q?style:=20review=20pr=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EC=88=98=EC=A0=95=20=EC=82=AC=ED=95=AD=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../review/controller/ReviewController.java | 17 +++++++++-------- .../domain/review/service/ReviewService.java | 2 +- .../checkIt/global/result/ResultCode.java | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) 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", "리뷰 갱신 성공"), ; From cb43d5ceab0b9abd4e56cc7f354fe8f75651d7a0 Mon Sep 17 00:00:00 2001 From: fnzl54 Date: Tue, 17 Oct 2023 12:48:17 +0900 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20http=20method=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techeer/checkIt/domain/book/controller/BookController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..b62c2a1 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 @@ -56,7 +56,7 @@ public ResponseEntity getNewBooksList() { } @ApiOperation(value = "책 좋아요 API") - @GetMapping("/like/{bookId}") + @PostMapping("/like/{bookId}") public ResponseEntity updateLikeById( @AuthenticationPrincipal UserDetail userDetail, @PathVariable Long bookId From ca2d13f1afce8952ed38d450803ebd5e70687967 Mon Sep 17 00:00:00 2001 From: fnzl54 Date: Thu, 19 Oct 2023 23:44:42 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=EC=9D=B8=EA=B8=B0=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EC=B1=85=20=EC=A1=B0=ED=9A=8C=20API=20entity,=20ma?= =?UTF-8?q?pper=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/dto/Response/BookSearchLikeRes.java | 22 +++++++++++++++++++ .../checkIt/domain/book/entity/Book.java | 14 ++++++++++++ .../domain/book/mapper/BookMapper.java | 18 +++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/main/java/com/techeer/checkIt/domain/book/dto/Response/BookSearchLikeRes.java 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..d362706 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,6 +38,17 @@ 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) @@ -47,4 +59,10 @@ public Page toPageDtoList(Page books) { .map(this::toBookSearchDto) .collect(Collectors.toList())); } + + public Page toPageDtoList2(Page books) { + return new PageImpl<>(books.stream() + .map(this::toBookSearchLikeDto) + .collect(Collectors.toList())); + } } From 7c9ff3e535cd9f7e425b0b28a6d841061dbfe3da Mon Sep 17 00:00:00 2001 From: fnzl54 Date: Thu, 19 Oct 2023 23:45:02 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=EC=9D=B8=EA=B8=B0=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EC=B1=85=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/controller/BookController.java | 7 +++++++ .../domain/book/service/BookService.java | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) 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 b62c2a1..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; @@ -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/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); } } From f213d2802d999d0eafea6b67ab76691181dfb500 Mon Sep 17 00:00:00 2001 From: fnzl54 Date: Wed, 25 Oct 2023 15:55:34 +0900 Subject: [PATCH 5/5] =?UTF-8?q?style:=20=EC=A3=BC=EC=84=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=ED=95=A8=EC=88=98=20=EC=9D=B4=EB=A6=84=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=B6=94=EA=B0=80=20=EC=84=A4=EB=AA=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techeer/checkIt/domain/book/mapper/BookMapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 d362706..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 @@ -54,12 +54,13 @@ public List toSearchDtoList(List books){ .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)