diff --git a/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java b/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java index d9c424a..4b2e048 100644 --- a/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java +++ b/src/main/java/meltingpot/server/comment/dto/CommentsListResponse.java @@ -41,7 +41,7 @@ public static CommentDetail from(Comment comment) { .content(comment.getContent()) .name(comment.getAccount().getName()) .isAnonymous(comment.getIsAnonymous()) - .imageUrl(comment.getCommentImage() != null ? comment.getCommentImage().getImageKey() : null) + .imageUrl(comment.getCommentImage() != null ? comment.getCommentImage().getImageUrl() : null) .updatedAt(comment.getUpdatedAt()) .build(); } diff --git a/src/main/java/meltingpot/server/comment/service/CommentService.java b/src/main/java/meltingpot/server/comment/service/CommentService.java index 91e5a82..4b2b359 100644 --- a/src/main/java/meltingpot/server/comment/service/CommentService.java +++ b/src/main/java/meltingpot/server/comment/service/CommentService.java @@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -34,93 +35,103 @@ public class CommentService { private FileService fileService; - + /* 댓글 작성 */ public ResponseCode createComment(CommentCreateRequest commentCreateRequest , Account account, Long postId) { Post post = findPostById(postId); - String commentImgUrl = null; - if (commentCreateRequest.getImageKey() != null){ - commentImgUrl = getCdnUrl(commentCreateRequest.getImageKey()); - } Comment comment = commentCreateRequest.toEntity(post, account, null); - if (commentCreateRequest.getImageKey() == null || commentCreateRequest.getImageKey().isEmpty()) { - return null; - } - if (commentImgUrl != null) { - CommentImage commentImage = CommentImage.builder() - .imageUrl(commentImgUrl) - .comment(comment) - .account(account) - .build(); - comment.setCommentImage(commentImage); + if (commentCreateRequest.getImageKey() != null && !commentCreateRequest.getImageKey().isEmpty()) { + String commentImgUrl = getCdnUrl(commentCreateRequest.getImageKey()); + createCommentImage(comment, account, commentImgUrl); } + commentRepository.save(comment); return ResponseCode.CREATE_COMMENT_SUCCESS; } - - public ResponseCode createChildComment(CommentCreateRequest commentCreateRequest, Account account, Long commentId) { - Comment parentComment = findCommentById(commentId); - Post post = findPostById(parentComment.getPost().getId()); - String commentImgUrl = null; - if (commentCreateRequest.getImageKey() != null) { - commentImgUrl = getCdnUrl(commentCreateRequest.getImageKey()); - } + /* 대댓글 작성 */ + public ResponseCode createChildComment(CommentCreateRequest commentCreateRequest, Account account, Long parentCommentId) { + Comment parentComment = findCommentById(parentCommentId); + Post post = parentComment.getPost(); Comment childComment = commentCreateRequest.toEntity(post, account, parentComment); - if (commentImgUrl != null) { - CommentImage commentImage = CommentImage.builder() - .imageUrl(commentImgUrl) - .comment(childComment) - .account(account) - .build(); - childComment.setCommentImage(commentImage); + if (commentCreateRequest.getImageKey() != null && !commentCreateRequest.getImageKey().isEmpty()) { + String commentImgUrl = getCdnUrl(commentCreateRequest.getImageKey()); + createCommentImage(childComment, account, commentImgUrl); } commentRepository.save(childComment); return ResponseCode.CREATE_CHILD_COMMENT_SUCCESS; } - + /* 댓글 수정 */ public ResponseCode updateComment(CommentCreateRequest updateCommentDTO, Account account, Long commentId) { - // 댓글을 ID로 찾기 Comment comment = findCommentById(commentId); - - // 댓글 내용 업데이트 comment.setContent(updateCommentDTO.getContent()); - // 새로운 이미지 키와 기존 댓글 이미지 가져오기 String newImageKey = updateCommentDTO.getImageKey(); - CommentImage oldCommentImage = comment.getCommentImage(); + updateCommentImage(comment, account, newImageKey); - if (newImageKey == null || newImageKey.isEmpty()) { - // 새로운 이미지 키가 없을 경우 기존 이미지 삭제 - if (oldCommentImage != null) { - commentImageRepository.delete(oldCommentImage); - comment.setCommentImage(null); - } - } else { - // 새로운 이미지 키가 있을 경우 이미지 업데이트 또는 생성 - String newImageUrl = getCdnUrl(newImageKey); - if (oldCommentImage != null) { - oldCommentImage.setImageUrl(newImageKey); - commentImageRepository.save(oldCommentImage); - } else { - CommentImage newCommentImage = CommentImage.builder() - .imageUrl(newImageUrl) - .comment(comment) - .account(account) - .build(); - comment.setCommentImage(newCommentImage); - commentImageRepository.save(newCommentImage); - } - } - // 댓글 저장 commentRepository.save(comment); return ResponseCode.UPDATE_COMMENT_SUCCESS; } - @Transactional(readOnly = true) + + + /* 댓글 목록 불러오기 */ +// @Transactional(readOnly = true) +// public CommentsListResponse getCommentsList(Account account, Long postId, Long cursor, int pageSize) { +// List commentDetailDTOs = new ArrayList<>(); +// int count = 0; +// Long parentCursor = null; +// +// // Cursor가 자식 댓글에 해당하는 경우 처리 +// if (cursor != null) { +// // Cursor가 부모 댓글이 아닌 자식 댓글을 나타내는 경우 +// Comment childComment = commentRepository.findById(cursor).orElse(null); +// if (childComment != null && childComment.getParent() != null) { +// Comment parentComment = childComment.getParent(); +// List remainingChildren = commentRepository.findChildrenCommentsByParentId(parentComment.getId(), cursor); +// for (Comment child : remainingChildren) { +// if (count >= pageSize) break; +// commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(child)); +// count++; +// } +// parentCursor = parentComment.getId(); +// +// // 만약 자식 댓글을 모두 가져왔고, 페이지가 꽉 차지 않았다면 다음 부모 댓글로 넘어감 +// if (count < pageSize && remainingChildren.size() < pageSize) { +// parentCursor = parentComment.getId(); +// } +// } else { +// parentCursor = cursor; // cursor가 부모 댓글인 경우 +// } +// } +// +// // 부모 댓글과 자식 댓글을 가져오는 처리 +// if (count < pageSize) { +// Pageable pageable = PageRequest.of(0, pageSize - count); +// List parentComments = commentRepository.findParentCommentsByPostId(postId, parentCursor, pageable); +// for (Comment parent : parentComments) { +// if (count >= pageSize) break; +// commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(parent)); +// count++; +// +// List children = commentRepository.findChildrenCommentsByParentId(parent.getId(), null); +// for (Comment child : children) { +// if (count >= pageSize) break; +// commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(child)); +// count++; +// } +// } +// } +// +// Long nextCursor = (count < pageSize) ? null : commentDetailDTOs.get(commentDetailDTOs.size() - 1).getCommentId(); +// boolean isLast = (count < pageSize); +// +// return CommentsListResponse.from(commentDetailDTOs,nextCursor,isLast); +// } + public CommentsListResponse getCommentsList(Account account, Long postId, Long cursor, int pageSize) { List commentDetailDTOs = new ArrayList<>(); int count = 0; @@ -128,10 +139,17 @@ public CommentsListResponse getCommentsList(Account account, Long postId, Long c // Cursor가 자식 댓글에 해당하는 경우 처리 if (cursor != null) { - // Cursor가 부모 댓글이 아닌 자식 댓글을 나타내는 경우 - Comment childComment = commentRepository.findById(cursor).orElse(null); - if (childComment != null && childComment.getParent() != null) { - Comment parentComment = childComment.getParent(); + Comment cursorComment = commentRepository.findById(cursor).orElse(null); + if (cursorComment != null) { + Comment parentComment; + if (cursorComment.getParent() != null) { + // Cursor가 자식 댓글을 나타내는 경우 + parentComment = cursorComment.getParent(); + } else { + // Cursor가 부모 댓글을 나타내는 경우 + parentComment = cursorComment; + } + List remainingChildren = commentRepository.findChildrenCommentsByParentId(parentComment.getId(), cursor); for (Comment child : remainingChildren) { if (count >= pageSize) break; @@ -170,16 +188,11 @@ public CommentsListResponse getCommentsList(Account account, Long postId, Long c Long nextCursor = (count < pageSize) ? null : commentDetailDTOs.get(commentDetailDTOs.size() - 1).getCommentId(); boolean isLast = (count < pageSize); - return CommentsListResponse.from(commentDetailDTOs,nextCursor,isLast); + return CommentsListResponse.from(commentDetailDTOs, nextCursor, isLast); } - private String getCdnUrl(String imageKey) { - String prefix = "comment"; // 적절한 prefix 값을 설정 - return fileService.getCdnUrl(prefix, imageKey); - } - private Comment findCommentById(Long commentId) { return commentRepository.findById(commentId) @@ -197,6 +210,38 @@ private Post findPostById(Long postId) { .orElseThrow(() -> new RuntimeException("게시물을 찾을 수 없습니다.")); } + private String getCdnUrl(String imageKey) { + String prefix = "comment"; // 적절한 prefix 값을 설정 + return fileService.getCdnUrl(prefix, imageKey); + } + + private void createCommentImage(Comment comment, Account account, String imageUrl) { + CommentImage commentImage = CommentImage.builder() + .imageUrl(imageUrl) + .comment(comment) + .account(account) + .build(); + comment.setCommentImage(commentImage); + } + + private void updateCommentImage(Comment comment, Account account, String newImageKey) { + CommentImage oldCommentImage = comment.getCommentImage(); + if (newImageKey == null || newImageKey.isEmpty()) { + if (oldCommentImage != null) { + commentImageRepository.delete(oldCommentImage); + comment.setCommentImage(null); + } + } else { + String newImageUrl = getCdnUrl(newImageKey); + if (oldCommentImage != null) { + oldCommentImage.setImageUrl(newImageUrl); + commentImageRepository.save(oldCommentImage); + } else { + createCommentImage(comment, account, newImageUrl); + } + } + } + } diff --git a/src/main/java/meltingpot/server/domain/repository/CommentRepository.java b/src/main/java/meltingpot/server/domain/repository/CommentRepository.java index 13a5b34..b0e78e6 100644 --- a/src/main/java/meltingpot/server/domain/repository/CommentRepository.java +++ b/src/main/java/meltingpot/server/domain/repository/CommentRepository.java @@ -22,8 +22,8 @@ public interface CommentRepository extends JpaRepository { - @Query("SELECT c FROM Comment c WHERE c.post.id = :postId AND c.parent IS NULL AND (:cursor IS NULL OR c.id > :cursor) ORDER BY c.id ASC") - List findParentCommentsByPostId(@Param("postId") Long postId, @Param("cursor") Long cursor, Pageable pageable); + @Query("SELECT c FROM Comment c WHERE c.post.id = :postId AND c.parent IS NULL AND (:parentCursor IS NULL OR c.id > :parentCursor) ORDER BY c.id ASC") + List findParentCommentsByPostId(@Param("postId") Long postId, @Param("parentCursor") Long parentCursor, Pageable pageable); @Query("SELECT c FROM Comment c WHERE c.parent.id = :parentId AND (:cursor IS NULL OR c.id > :cursor) ORDER BY c.id ASC") List findChildrenCommentsByParentId(@Param("parentId") Long parentId, @Param("cursor") Long cursor); @@ -31,4 +31,6 @@ public interface CommentRepository extends JpaRepository { Slice findAllByAccountAndDeletedAtIsNullOrderByIdDesc(Account account, Pageable pageable); + + } diff --git a/src/main/java/meltingpot/server/post/service/PostService.java b/src/main/java/meltingpot/server/post/service/PostService.java index 667c9c9..787faa8 100644 --- a/src/main/java/meltingpot/server/post/service/PostService.java +++ b/src/main/java/meltingpot/server/post/service/PostService.java @@ -45,16 +45,7 @@ public class PostService { public ResponseCode createPost(PostCreateRequest createPostDTO,Account account){ Post post = createPostDTO.toEntity(account); List postImgUrls = Collections.emptyList(); - if (createPostDTO.getImageKeys() != null && !createPostDTO.getImageKeys().isEmpty()) { - postImgUrls = getCdnUrls(createPostDTO.getImageKeys()); - } - List postImages = postImgUrls.stream() - .map(imageUrl->PostImage.builder() - .imageUrl(imageUrl) - .post(post) - .account(account) - .build()) - .collect(Collectors.toList()); + List postImages = createPostImages(createPostDTO.getImageKeys(), post, account); post.setPostImages(postImages); postRepository.save(post); return ResponseCode.POST_CREATE_SUCCESS; @@ -65,8 +56,6 @@ public ResponseCode createPost(PostCreateRequest createPostDTO,Account account){ @Transactional(readOnly = true) public PostDetailResponse getPostDetail(Long postId, Long cursor, int pageSize){ Post post = findPostById(postId); - - // 댓글 목록 가져오기 CommentsListResponse commentsList = fetchCommentsList(postId, cursor, pageSize); return PostDetailResponse.of(post,commentsList); } @@ -75,17 +64,9 @@ public PostDetailResponse getPostDetail(Long postId, Long cursor, int pageSize){ @Transactional(readOnly = true) public PostsListResponse getPostsList(Account account, PostType postType, Long cursor, int pageSize){ Pageable pageable = PageRequest.of(0, pageSize); - Long nextCursor = null; - boolean isLast = false; List posts = postRepository.findByPostTypeAndCursor(postType, cursor, pageable); - - if (posts.size() > 0) { - nextCursor = posts.get(posts.size() - 1).getId(); - isLast = posts.size() < pageSize; - } else { - isLast = true; - } - + Long nextCursor = posts.isEmpty() ? null : posts.get(posts.size() - 1).getId(); + boolean isLast = posts.size() < pageSize; return PostsListResponse.from(posts, nextCursor, isLast); } @@ -110,55 +91,74 @@ private List getCdnUrls(List imageKeys) { .collect(Collectors.toList()); } + private List createPostImages(List imageKeys, Post post, Account account) { + List postImgUrls = getCdnUrls(imageKeys); + return postImgUrls.stream() + .map(imageUrl -> PostImage.builder() + .imageUrl(imageUrl) + .post(post) + .account(account) + .build()) + .collect(Collectors.toList()); + } + private CommentsListResponse fetchCommentsList(Long postId, Long cursor, int pageSize) { - List commentDetails = new ArrayList<>(); + List commentDetailDTOs = new ArrayList<>(); int count = 0; Long parentCursor = null; - // Handle case where cursor points to a child comment + // Cursor가 자식 댓글에 해당하는 경우 처리 if (cursor != null) { - Comment childComment = commentRepository.findById(cursor).orElse(null); - if (childComment != null && childComment.getParent() != null) { - Comment parentComment = childComment.getParent(); + Comment cursorComment = commentRepository.findById(cursor).orElse(null); + if (cursorComment != null) { + Comment parentComment; + if (cursorComment.getParent() != null) { + // Cursor가 자식 댓글을 나타내는 경우 + parentComment = cursorComment.getParent(); + } else { + // Cursor가 부모 댓글을 나타내는 경우 + parentComment = cursorComment; + } + List remainingChildren = commentRepository.findChildrenCommentsByParentId(parentComment.getId(), cursor); for (Comment child : remainingChildren) { if (count >= pageSize) break; - commentDetails.add(CommentsListResponse.CommentDetail.from(child)); + commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(child)); count++; } parentCursor = parentComment.getId(); - // If there are more parent comments to fetch after children + // 만약 자식 댓글을 모두 가져왔고, 페이지가 꽉 차지 않았다면 다음 부모 댓글로 넘어감 if (count < pageSize && remainingChildren.size() < pageSize) { parentCursor = parentComment.getId(); } } else { - parentCursor = cursor; // cursor points to a parent comment + parentCursor = cursor; // cursor가 부모 댓글인 경우 } } - // Fetch parent comments and their children + // 부모 댓글과 자식 댓글을 가져오는 처리 if (count < pageSize) { Pageable pageable = PageRequest.of(0, pageSize - count); List parentComments = commentRepository.findParentCommentsByPostId(postId, parentCursor, pageable); for (Comment parent : parentComments) { if (count >= pageSize) break; - commentDetails.add(CommentsListResponse.CommentDetail.from(parent)); + commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(parent)); count++; List children = commentRepository.findChildrenCommentsByParentId(parent.getId(), null); for (Comment child : children) { if (count >= pageSize) break; - commentDetails.add(CommentsListResponse.CommentDetail.from(child)); + commentDetailDTOs.add(CommentsListResponse.CommentDetail.from(child)); count++; } } } - Long nextCursor = (count < pageSize) ? null : commentDetails.get(commentDetails.size() - 1).getCommentId(); + Long nextCursor = (count < pageSize) ? null : commentDetailDTOs.get(commentDetailDTOs.size() - 1).getCommentId(); boolean isLast = (count < pageSize); - return CommentsListResponse.from(commentDetails, nextCursor, isLast); + return CommentsListResponse.from(commentDetailDTOs, nextCursor, isLast); }