diff --git a/src/main/java/capstone/bookitty/domain/controller/BookStateController.java b/src/main/java/capstone/bookitty/domain/controller/BookStateController.java index 04adbf6..7bcb11b 100644 --- a/src/main/java/capstone/bookitty/domain/controller/BookStateController.java +++ b/src/main/java/capstone/bookitty/domain/controller/BookStateController.java @@ -8,6 +8,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -33,14 +36,16 @@ public ResponseEntity saveBookState( bookStateService.saveState(request))); } - @Operation(summary = "isbn으로 책 상태 리스트 가져오기") + @Operation(summary = "isbn으로 책 상태 리스트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") @GetMapping(path = "/isbn/{isbn}") public ResponseEntity getStateByISBN( - @PathVariable("isbn") String isbn + @PathVariable("isbn") String isbn, + @PageableDefault(sort = "id", size=10) Pageable pageable ){ return ResponseEntity.ok() - .body(new ResponseCounter>( - bookStateService.findStateByISBN(isbn))); + .body(new ResponseCounter>( + bookStateService.findStateByISBN(isbn, pageable))); } @Operation(summary = "stateId로 책 상태 가져오기") @@ -53,14 +58,16 @@ public ResponseEntity getStateById( bookStateService.findStateByStateId(stateId))); } - @Operation(summary = "memberId로 책 상태 리스트 가져오기") + @Operation(summary = "memberId로 책 상태 리스트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") @GetMapping(path = "/member/{member-id}") public ResponseEntity getStateByMemberId( - @PathVariable("member-id") Long memberId + @PathVariable("member-id") Long memberId, + @PageableDefault(sort = "id", size=10) Pageable pageable ){ return ResponseEntity.ok() - .body(new ResponseCounter>( - bookStateService.findStateByMemberId(memberId))); + .body(new ResponseCounter>( + bookStateService.findStateByMemberId(memberId,pageable))); } @Operation(summary = "state 정보 수정") diff --git a/src/main/java/capstone/bookitty/domain/controller/CommentController.java b/src/main/java/capstone/bookitty/domain/controller/CommentController.java new file mode 100644 index 0000000..548d779 --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/controller/CommentController.java @@ -0,0 +1,126 @@ +package capstone.bookitty.domain.controller; + +import capstone.bookitty.domain.dto.ResponseType.BasicResponse; +import capstone.bookitty.domain.dto.ResponseType.ResponseCounter; +import capstone.bookitty.domain.dto.ResponseType.ResponseString; +import capstone.bookitty.domain.service.CommentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import static capstone.bookitty.domain.dto.CommentDTO.*; + +@Tag(name="코멘트", description = "코멘트 관리 api 입니다.") +@RestController +@RequiredArgsConstructor +@RequestMapping("/comment") +public class CommentController { + + private final CommentService commentService; + + @Operation(summary = "코멘트 생성") + @PostMapping(path = "/new") + public ResponseEntity saveComment( + @RequestBody @Valid SaveRequest request + ){ + return ResponseEntity.ok() + .body(new ResponseCounter( + commentService.saveComment(request))); + } + + @Operation(summary = "commentId로 코멘트 가져오기") + @GetMapping(path="/{comment-id}") + public ResponseEntity getCommentById( + @PathVariable("comment-id") Long commentId + ){ + return ResponseEntity.ok() + .body(new ResponseCounter( + commentService.findCommentByCommentId(commentId))); + } + + @Operation(summary = "전체 코멘트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") + @GetMapping(path = "/all") + public ResponseEntity getAll( + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ){ + return ResponseEntity.ok() + .body(new ResponseCounter>( + commentService.findAllComment(pageable))); + } + + @Operation(summary = "isbn으로 코멘트 리스트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") + @GetMapping(path = "/isbn/{isbn}") + public ResponseEntity getCommentByISBN( + @PathVariable("isbn") String isbn, + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ){ + return ResponseEntity.ok() + .body(new ResponseCounter>( + commentService.findCommentByIsbn(isbn, pageable))); + } + + @Operation(summary = "memberId로 코멘트 리스트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") + @GetMapping(path = "/member/{member-id}") + public ResponseEntity getCommentByMemberId( + @PathVariable("member-id") Long memberId, + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ){ + return ResponseEntity.ok() + .body(new ResponseCounter>( + commentService.findCommentByMemberId(memberId, pageable))); + } + + @Operation(summary = "코멘트 수정") + @PatchMapping(path = "/{comment-id}") + public ResponseEntity updateComment( + @PathVariable("comment-id") Long commentId, + @RequestBody @Valid UpdateRequest request + ){ + commentService.updateComment(commentId, request); + return ResponseEntity.ok() + .body(new ResponseString("update Comment!")); + } + + @Operation(summary = "코멘트 삭제") + @DeleteMapping(path = "/{comment-id}") + public ResponseEntity deleteComment( + @PathVariable("comment-id") Long commentId + ){ + commentService.deleteComment(commentId); + return ResponseEntity.ok() + .body(new ResponseString("delete Comment!")); + } + + @Operation(summary = "코멘트 좋아요 등록") + @PostMapping(path = "/{comment-id}/member/{member-id}/like/increase") + public ResponseEntity increaseLike( + @PathVariable("comment-id") Long commentId, + @PathVariable("member-id") Long memberId + ){ + commentService.increaseLike(commentId,memberId); + return ResponseEntity.ok() + .body(new ResponseString("increase Like!")); + } + + @Operation(summary = "코멘트 좋아요 삭제") + @PostMapping(path = "/{comment-id}/member/{member-id}/like/decrease") + public ResponseEntity decreaseLike( + @PathVariable("comment-id") Long commentId, + @PathVariable("member-id") Long memberId + ){ + commentService.decreaseLike(commentId,memberId); + return ResponseEntity.ok() + .body(new ResponseString("decrease Like!")); + } + +} diff --git a/src/main/java/capstone/bookitty/domain/controller/MemberController.java b/src/main/java/capstone/bookitty/domain/controller/MemberController.java index 97fdfee..fbe79e6 100644 --- a/src/main/java/capstone/bookitty/domain/controller/MemberController.java +++ b/src/main/java/capstone/bookitty/domain/controller/MemberController.java @@ -8,11 +8,12 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - import static capstone.bookitty.domain.dto.MemberDTO.*; @Tag(name = "회원", description = "회원 관련 api 입니다.") @@ -68,12 +69,15 @@ public ResponseEntity findOneMember( memberService.getMemberInfoWithId(memberId))); } - @Operation(summary = "전체 회원 조회") + @Operation(summary = "전체 회원 조회 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") @GetMapping(path = "/all") - public ResponseEntity findAllMembers(){ + public ResponseEntity findAllMembers( + @PageableDefault(sort="id",size = 10) Pageable pageable + ){ return ResponseEntity.ok( - new ResponseCounter>( - memberService.getAllMemberInfo())); + new ResponseCounter>( + memberService.getAllMemberInfo(pageable))); } /* TODO : S3 diff --git a/src/main/java/capstone/bookitty/domain/controller/OpenApiBookController.java b/src/main/java/capstone/bookitty/domain/controller/OpenApiBookController.java index 0da0be4..2e28dbd 100644 --- a/src/main/java/capstone/bookitty/domain/controller/OpenApiBookController.java +++ b/src/main/java/capstone/bookitty/domain/controller/OpenApiBookController.java @@ -44,8 +44,8 @@ public Mono getBestSeller(){ } - @Operation(summary = "카테고리별 베스트셀러 Top 10\n CategoryId: " + - "(170 : 경제경영 / 987 : 과학 / 1 : 문학 / 656 : 인문 / 336 : 자기계발") + @Operation(summary = "카테고리별 베스트셀러 Top 10\n / CategoryId: " + + "(170 : 경제경영 / 987 : 과학 / 1 : 문학 / 656 : 인문 / 336 : 자기계발)") @GetMapping(path = "/bestseller/category/{category-id}") public Mono getBestSellerByGenre( @PathVariable("category-id") int cid diff --git a/src/main/java/capstone/bookitty/domain/controller/StarController.java b/src/main/java/capstone/bookitty/domain/controller/StarController.java index 4ac0ab6..008314c 100644 --- a/src/main/java/capstone/bookitty/domain/controller/StarController.java +++ b/src/main/java/capstone/bookitty/domain/controller/StarController.java @@ -8,11 +8,13 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - import static capstone.bookitty.domain.dto.StarDTO.*; @Tag(name="평점", description = "평점 관리 api 입니다.") @@ -43,26 +45,40 @@ public ResponseEntity getStarById( starService.findStarByStarId(starId))); } - //TODO: PAGING - @Operation(summary = "isbn으로 평점 리스트 가져오기") + + @Operation(summary = "전체 평점 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") + @GetMapping(path = "/all") + public ResponseEntity getAllStar( + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable + ){ + return ResponseEntity.ok() + .body(new ResponseCounter>( + starService.findAllStar(pageable))); + } + + @Operation(summary = "isbn으로 평점 리스트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") @GetMapping(path = "/isbn/{isbn}") public ResponseEntity getStarByISBN( - @PathVariable("isbn") String isbn + @PathVariable("isbn") String isbn, + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable ){ return ResponseEntity.ok() - .body(new ResponseCounter>( - starService.findStarByISBN(isbn))); + .body(new ResponseCounter>( + starService.findStarByISBN(isbn,pageable))); } - //TODO: PAGING - @Operation(summary = "member id로 평점 리스트 가져오기") + @Operation(summary = "member id로 평점 리스트 가져오기 / page는 requestParam으로 요청할 수 있습니다. / "+ + "size(한 페이지 당 element 수, default = 10), page(요청하는 페이지, 0부터 시작)") @GetMapping(path = "/member/{member-id}") public ResponseEntity getStarByMemberId( - @PathVariable("member-id") Long memberId + @PathVariable("member-id") Long memberId, + @PageableDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable ){ return ResponseEntity.ok() - .body(new ResponseCounter>( - starService.findStarByMemberId(memberId))); + .body(new ResponseCounter>( + starService.findStarByMemberId(memberId,pageable))); } @Operation(summary = "평점 수정") diff --git a/src/main/java/capstone/bookitty/domain/dto/BookStateDTO.java b/src/main/java/capstone/bookitty/domain/dto/BookStateDTO.java index c6cc43b..032b215 100644 --- a/src/main/java/capstone/bookitty/domain/dto/BookStateDTO.java +++ b/src/main/java/capstone/bookitty/domain/dto/BookStateDTO.java @@ -4,7 +4,6 @@ import capstone.bookitty.domain.entity.BookState; import capstone.bookitty.domain.entity.State; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/capstone/bookitty/domain/dto/CommentDTO.java b/src/main/java/capstone/bookitty/domain/dto/CommentDTO.java new file mode 100644 index 0000000..78c839e --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/dto/CommentDTO.java @@ -0,0 +1,67 @@ +package capstone.bookitty.domain.dto; + +import capstone.bookitty.domain.entity.Comment; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +public class CommentDTO { + + @Data + public static class SaveRequest{ + @NotBlank(message = "Isbn is a required entry value.") + private String isbn; + @NotNull(message = "memberId is a required entry value.") + private Long memberId; + @NotEmpty(message = "content is a required entry value.") + @Size(min = 1, max = 100, message = "Name must be between 1 and 100 characters") + private String content; + } + + @Data + public static class UpdateRequest{ + @NotEmpty(message = "content is a required entry value.") + @Size(min = 1, max = 100, message = "Name must be between 1 and 100 characters") + private String content; + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class IdResponse{ + private Long id; + public static IdResponse of(Comment comment){ + return new IdResponse(comment.getId()); + } + } + + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class InfoResponse{ + private Long id; + private Long memberId; + private String isbn; + private String content; + private int like_count; + @DateTimeFormat(pattern = "yyyy-mm-dd'T'HH:mm:ss") + private LocalDateTime createdAt; + @DateTimeFormat(pattern = "yyyy-mm-dd'T'HH:mm:ss") + private LocalDateTime modifiedAt; + + public static InfoResponse of(Comment comment, int like_count){ + return new InfoResponse(comment.getId(), comment.getMember().getId(),comment.getIsbn(), + comment.getContent(), like_count ,comment.getCreatedAt(), + comment.getModifiedAt()); + } + + } +} diff --git a/src/main/java/capstone/bookitty/domain/dto/ResponseType/ResponseCounter.java b/src/main/java/capstone/bookitty/domain/dto/ResponseType/ResponseCounter.java index 688bd44..8757c5f 100644 --- a/src/main/java/capstone/bookitty/domain/dto/ResponseType/ResponseCounter.java +++ b/src/main/java/capstone/bookitty/domain/dto/ResponseType/ResponseCounter.java @@ -1,5 +1,7 @@ package capstone.bookitty.domain.dto.ResponseType; +import org.springframework.data.domain.Page; + import lombok.Getter; import lombok.Setter; @@ -13,7 +15,10 @@ public class ResponseCounter extends BasicResponse { public ResponseCounter(T data) { this.data = data; - if (data instanceof List) { + if (data instanceof Page) { + this.count = (int) ((Page) data).getTotalElements(); + } + else if (data instanceof List) { this.count = ((List) data).size(); } else { this.count = 1; diff --git a/src/main/java/capstone/bookitty/domain/dto/StarDTO.java b/src/main/java/capstone/bookitty/domain/dto/StarDTO.java index ca48fe2..46af677 100644 --- a/src/main/java/capstone/bookitty/domain/dto/StarDTO.java +++ b/src/main/java/capstone/bookitty/domain/dto/StarDTO.java @@ -2,7 +2,7 @@ import capstone.bookitty.domain.annotation.ValidScore; import capstone.bookitty.domain.entity.Star; -import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Data; @@ -15,9 +15,9 @@ public class StarDTO { @Data public static class SaveRequest{ - @NotEmpty + @NotBlank(message = "Isbn is a required entry value.") private String isbn; - @NotNull + @NotNull(message = "memberId is a required entry value.") private Long memberId; @ValidScore private double score; @@ -25,7 +25,7 @@ public static class SaveRequest{ @Data public static class UpdateRequest{ - @NotNull + @NotNull(message = "score is a required entry value.") @ValidScore private double score; } diff --git a/src/main/java/capstone/bookitty/domain/entity/BookState.java b/src/main/java/capstone/bookitty/domain/entity/BookState.java index f35e631..2bfc1d1 100644 --- a/src/main/java/capstone/bookitty/domain/entity/BookState.java +++ b/src/main/java/capstone/bookitty/domain/entity/BookState.java @@ -5,6 +5,8 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -20,6 +22,7 @@ public class BookState { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") + @OnDelete(action = OnDeleteAction.CASCADE) private Member member; private String isbn; diff --git a/src/main/java/capstone/bookitty/domain/entity/Comment.java b/src/main/java/capstone/bookitty/domain/entity/Comment.java new file mode 100644 index 0000000..33ab4bc --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/entity/Comment.java @@ -0,0 +1,49 @@ +package capstone.bookitty.domain.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +@Entity @Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name="comment") +public class Comment { + + @Id @Column(name = "comment_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + @OnDelete(action = OnDeleteAction.CASCADE) + private Member member; + + private String isbn; + private String content; + + @DateTimeFormat(pattern = "yyyy-mm-dd'T'HH:mm:ss") + private LocalDateTime createdAt; + @DateTimeFormat(pattern = "yyyy-mm-dd'T'HH:mm:ss") + private LocalDateTime modifiedAt; + + @Builder + public Comment(Member member, String isbn, String content) { + this.member = member; + this.isbn = isbn; + this.content = content; + this.createdAt = LocalDateTime.now(); + } + + public void updateContent(String content){ + this.content = content; + this.modifiedAt = LocalDateTime.now(); + } + +} diff --git a/src/main/java/capstone/bookitty/domain/entity/Like.java b/src/main/java/capstone/bookitty/domain/entity/Like.java new file mode 100644 index 0000000..79d13b0 --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/entity/Like.java @@ -0,0 +1,42 @@ +package capstone.bookitty.domain.entity; + +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +@Entity @Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "like_count") +public class Like { + + @Id @Column(name="like_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + @OnDelete(action = OnDeleteAction.CASCADE) + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "comment_id") + @OnDelete(action = OnDeleteAction.CASCADE) + private Comment comment; + + @DateTimeFormat(pattern = "yyyy-mm-dd'T'HH:mm:ss") + private LocalDateTime createdAt; + + @Builder + public Like(Member member, Comment comment){ + this.member = member; + this.comment = comment; + this.createdAt = LocalDateTime.now(); + } +} diff --git a/src/main/java/capstone/bookitty/domain/entity/Star.java b/src/main/java/capstone/bookitty/domain/entity/Star.java index 500ef19..b71d52b 100644 --- a/src/main/java/capstone/bookitty/domain/entity/Star.java +++ b/src/main/java/capstone/bookitty/domain/entity/Star.java @@ -5,6 +5,8 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -20,6 +22,7 @@ public class Star { @ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name = "member_id") + @OnDelete(action = OnDeleteAction.CASCADE) private Member member; private String isbn; diff --git a/src/main/java/capstone/bookitty/domain/repository/BookStateRepository.java b/src/main/java/capstone/bookitty/domain/repository/BookStateRepository.java index d48e07c..959febb 100644 --- a/src/main/java/capstone/bookitty/domain/repository/BookStateRepository.java +++ b/src/main/java/capstone/bookitty/domain/repository/BookStateRepository.java @@ -1,6 +1,8 @@ package capstone.bookitty.domain.repository; import capstone.bookitty.domain.entity.BookState; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -8,8 +10,8 @@ @Repository public interface BookStateRepository extends JpaRepository { - List findByIsbn(String isbn); - List findByMemberId(Long memberId); + Page findByIsbn(String isbn, Pageable pageable); + Page findByMemberId(Long memberId,Pageable pageable); boolean existsByMemberIdAndIsbn(Long memberId, String isbn); } \ No newline at end of file diff --git a/src/main/java/capstone/bookitty/domain/repository/CommentRepository.java b/src/main/java/capstone/bookitty/domain/repository/CommentRepository.java new file mode 100644 index 0000000..90edbc8 --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/repository/CommentRepository.java @@ -0,0 +1,14 @@ +package capstone.bookitty.domain.repository; + +import capstone.bookitty.domain.entity.Comment; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CommentRepository extends JpaRepository { + boolean existsByMemberIdAndIsbn(Long memberId, String isbn); + Page findByMemberId(Long memberId, Pageable pageable); + Page findByIsbn(String isbn, Pageable pageable); +} diff --git a/src/main/java/capstone/bookitty/domain/repository/LikeRepository.java b/src/main/java/capstone/bookitty/domain/repository/LikeRepository.java new file mode 100644 index 0000000..1f40ab7 --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/repository/LikeRepository.java @@ -0,0 +1,17 @@ +package capstone.bookitty.domain.repository; + +import capstone.bookitty.domain.entity.Like; +import capstone.bookitty.domain.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface LikeRepository extends JpaRepository { + List findByCommentId(Long commentId); + List findByMemberId(Long memberId); + Optional findByMemberIdAndCommentId(Long memberId, Long commentId); + boolean existsByMemberIdAndCommentId(Long memberId,Long CommentId); +} diff --git a/src/main/java/capstone/bookitty/domain/repository/StarRepository.java b/src/main/java/capstone/bookitty/domain/repository/StarRepository.java index d6ffc97..a88734e 100644 --- a/src/main/java/capstone/bookitty/domain/repository/StarRepository.java +++ b/src/main/java/capstone/bookitty/domain/repository/StarRepository.java @@ -1,12 +1,14 @@ package capstone.bookitty.domain.repository; import capstone.bookitty.domain.entity.Star; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface StarRepository extends JpaRepository { boolean existsByMemberIdAndIsbn(Long memberId, String isbn); - List findByIsbn(String isbn); - List findByMemberId(Long memberId); + Page findByIsbn(String isbn, Pageable pageable); + Page findByMemberId(Long memberId, Pageable pageable); } diff --git a/src/main/java/capstone/bookitty/domain/service/BookStateService.java b/src/main/java/capstone/bookitty/domain/service/BookStateService.java index 9f65718..bc9ea98 100644 --- a/src/main/java/capstone/bookitty/domain/service/BookStateService.java +++ b/src/main/java/capstone/bookitty/domain/service/BookStateService.java @@ -7,6 +7,8 @@ import capstone.bookitty.domain.repository.MemberRepository; import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -50,10 +52,9 @@ public IdResponse saveState(SaveRequest request) { return new IdResponse(bookState.getId()); } - public List findStateByISBN(String isbn) { - return stateRepository.findByIsbn(isbn).stream() - .map(InfoResponse::of) - .collect(Collectors.toList()); + public Page findStateByISBN(String isbn, Pageable pageable) { + return stateRepository.findByIsbn(isbn, pageable) + .map(InfoResponse::of); } public InfoResponse findStateByStateId(Long stateId) { @@ -62,10 +63,13 @@ public InfoResponse findStateByStateId(Long stateId) { .orElseThrow(() -> new EntityNotFoundException("BookState with ID " + stateId + " not found.")); } - public List findStateByMemberId(Long memberId) { - return stateRepository.findByMemberId(memberId).stream() - .map(InfoResponse::of) - .collect(Collectors.toList()); + public Page findStateByMemberId(Long memberId, Pageable pageable) { + Member member = memberRepository.findById(memberId) + .orElseThrow(()->new EntityNotFoundException( + "Member with ID: "+memberId+" not found.")); + + return stateRepository.findByMemberId(memberId,pageable) + .map(InfoResponse::of); } @Transactional diff --git a/src/main/java/capstone/bookitty/domain/service/CommentService.java b/src/main/java/capstone/bookitty/domain/service/CommentService.java new file mode 100644 index 0000000..159c42b --- /dev/null +++ b/src/main/java/capstone/bookitty/domain/service/CommentService.java @@ -0,0 +1,117 @@ +package capstone.bookitty.domain.service; + +import capstone.bookitty.domain.entity.Comment; +import capstone.bookitty.domain.entity.Like; +import capstone.bookitty.domain.entity.Member; +import capstone.bookitty.domain.repository.CommentRepository; +import capstone.bookitty.domain.repository.LikeRepository; +import capstone.bookitty.domain.repository.MemberRepository; +import jakarta.persistence.EntityNotFoundException; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import static capstone.bookitty.domain.dto.CommentDTO.*; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class CommentService { + + private final CommentRepository commentRepository; + private final LikeRepository likeRepository; + private final MemberRepository memberRepository; + + @Transactional + public IdResponse saveComment(SaveRequest request) { + Member member = memberRepository.findById(request.getMemberId()) + .orElseThrow(()->new EntityNotFoundException( + "Member with ID "+request.getMemberId()+" not found.")); + if(commentRepository.existsByMemberIdAndIsbn(request.getMemberId(),request.getIsbn())) + throw new IllegalArgumentException("comment already exists."); + + Comment comment = Comment.builder() + .member(member) + .isbn(request.getIsbn()) + .content(request.getContent()) + .build(); + commentRepository.save(comment); + + return new IdResponse(comment.getId()); + } + + public InfoResponse findCommentByCommentId(Long commentId) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment with ID " + commentId + " not found.")); + int like_count = likeRepository.findByCommentId(commentId).size(); + return InfoResponse.of(comment, like_count); + } + + public Page findAllComment(Pageable pageable) { + return commentRepository.findAll(pageable) + .map(comment -> { + int like_count = likeRepository.findByCommentId(comment.getId()).size(); + return InfoResponse.of(comment,like_count); + }); + } + + public Page findCommentByIsbn(String isbn, Pageable pageable) { + return commentRepository.findByIsbn(isbn,pageable) + .map(comment -> { + int like_count = likeRepository.findByCommentId(comment.getId()).size(); + return InfoResponse.of(comment,like_count); + }); + } + + public Page findCommentByMemberId(Long memberId, Pageable pageable) { + Member member = memberRepository.findById(memberId) + .orElseThrow(()->new EntityNotFoundException("Member with ID "+memberId+" not found.")); + return commentRepository.findByMemberId(memberId,pageable) + .map(comment -> { + int like_count = likeRepository.findByCommentId(comment.getId()).size(); + return InfoResponse.of(comment,like_count); + }); + } + + @Transactional + public void updateComment(Long commentId, UpdateRequest request) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment with ID " + commentId + " not found.")); + comment.updateContent(request.getContent()); + } + + @Transactional + public void deleteComment(Long commentId) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment with ID " + commentId + " not found.")); + commentRepository.delete(comment); + } + + @Transactional + public void increaseLike(Long commentId, Long memberId) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment with ID " + commentId + " not found.")); + Member member = memberRepository.findById(memberId) + .orElseThrow(()->new EntityNotFoundException("Member with ID "+memberId+" not found.")); + if(likeRepository.existsByMemberIdAndCommentId(memberId,commentId)) + throw new IllegalArgumentException("Like already exists"); + Like like = Like.builder() + .comment(comment) + .member(member) + .build(); + likeRepository.save(like); + } + + @Transactional + public void decreaseLike(Long commentId, Long memberId) { + Comment comment = commentRepository.findById(commentId) + .orElseThrow(() -> new EntityNotFoundException("Comment with ID " + commentId + " not found.")); + Member member = memberRepository.findById(memberId) + .orElseThrow(()->new EntityNotFoundException("Member with ID " + memberId + " not found.")); + Like like = likeRepository.findByMemberIdAndCommentId(memberId,commentId) + .orElseThrow(()->new EntityNotFoundException("Like with commentId "+commentId+" not found.")); + likeRepository.delete(like); + } +} diff --git a/src/main/java/capstone/bookitty/domain/service/MemberService.java b/src/main/java/capstone/bookitty/domain/service/MemberService.java index 37d3b83..b8ef70f 100644 --- a/src/main/java/capstone/bookitty/domain/service/MemberService.java +++ b/src/main/java/capstone/bookitty/domain/service/MemberService.java @@ -4,6 +4,8 @@ import capstone.bookitty.domain.repository.MemberRepository; import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -53,10 +55,9 @@ public InfoResponse getMemberInfoWithId(Long memberId) { .orElseThrow(()-> new EntityNotFoundException("Member not found.")); } - public List getAllMemberInfo() { - return memberRepository.findAll().stream() - .map(InfoResponse::of) - .collect(Collectors.toList()); + public Page getAllMemberInfo(Pageable pageable) { + return memberRepository.findAll(pageable) + .map(InfoResponse::of); } /*TODO: S3 관련 처리 diff --git a/src/main/java/capstone/bookitty/domain/service/StarService.java b/src/main/java/capstone/bookitty/domain/service/StarService.java index c5d2d49..2713428 100644 --- a/src/main/java/capstone/bookitty/domain/service/StarService.java +++ b/src/main/java/capstone/bookitty/domain/service/StarService.java @@ -6,12 +6,13 @@ import capstone.bookitty.domain.repository.StarRepository; import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; -import java.util.List; -import java.util.stream.Collectors; + import static capstone.bookitty.domain.dto.StarDTO.*; @@ -49,16 +50,16 @@ public InfoResponse findStarByStarId(Long starId) { .orElseThrow(()->new EntityNotFoundException("Star with ID "+starId+" not found.")); } - public List findStarByISBN(String isbn) { - return starRepository.findByIsbn(isbn).stream() - .map(InfoResponse::of) - .collect(Collectors.toList()); + public Page findStarByISBN(String isbn, Pageable pageable) { + return starRepository.findByIsbn(isbn,pageable) + .map(InfoResponse::of); } - public List findStarByMemberId(Long memberId) { - return starRepository.findByMemberId(memberId).stream() - .map(InfoResponse::of) - .collect(Collectors.toList()); + public Page findStarByMemberId(Long memberId, Pageable pageable) { + Member member = memberRepository.findById(memberId) + .orElseThrow(()-> new EntityNotFoundException("Member with ID "+ memberId+" not found.")); + return starRepository.findByMemberId(memberId,pageable) + .map(InfoResponse::of); } @Transactional @@ -74,4 +75,9 @@ public void deleteStar(Long starId) { .orElseThrow(()-> new EntityNotFoundException("Star with ID "+starId+" not found.")); starRepository.delete(star); } + + public Page findAllStar(Pageable pageable) { + return starRepository.findAll(pageable) + .map(InfoResponse::of); + } }