Skip to content

Commit

Permalink
feat : comment
Browse files Browse the repository at this point in the history
  • Loading branch information
moonyaeyoon committed Jul 24, 2024
1 parent 44dbebe commit b70bf3b
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@ public ResponseEntity<ResponseData<CommentResponseDTO.CreateCommentResultDTO>> u
}
}

@Operation(summary = "λŒ“κΈ€ λͺ©λ‘ κ°€μ Έμ˜€κΈ°")
@GetMapping("/list/{postId}")
public ResponseEntity<ResponseData<CommentResponseDTO.CommentsListDTO>> getCommentsList ( @CurrentUser Account account, @PathVariable Long postId,
@RequestParam(required = false) Long cursor,
@RequestParam(defaultValue = "10") int pageSize){
try{
return ResponseData.toResponseEntity(ResponseCode.READ_COMMENTS_LIST_SUCCESS, commentService.getCommentsList(account,postId,cursor,pageSize));
}catch (NoSuchElementException e) {
return ResponseData.toResponseEntity(ResponseCode.COMMENT_UPDATE_FAIL, null);
}
}


}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import meltingpot.server.domain.entity.post.Post;

import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
public class CommentConverter {
Expand Down Expand Up @@ -38,22 +39,25 @@ public static CommentResponseDTO.CreateCommentResultDTO toCreateCommentResult(St
public static CommentResponseDTO.CommentDetailDTO toCommentDetailDTO(Comment comment){
return CommentResponseDTO.CommentDetailDTO.builder()
.commentId(comment.getId())
.parentId(comment.getParent() != null ? comment.getParent().getId() : null)
.userId(comment.getAccount().getId())
.content(comment.getContent())
.name(comment.getAccount().getName())
.isAnonymous(comment.getIsAnonymous())
.updatedAt(comment.getUpdatedAt())
.children(comment.getChildren() != null ? toCommentDetailDTOList(comment.getChildren()) : null)
.build();
}

public static CommentResponseDTO.ParentCommentDTO toParentCommentDTO(Comment parentComment,List<CommentResponseDTO.CommentDetailDTO>childrenComments){
return CommentResponseDTO.ParentCommentDTO.builder()
.parentComment(toCommentDetailDTO(parentComment))
.childrenComments(childrenComments)
.build();
public static List<CommentResponseDTO.CommentDetailDTO> toCommentDetailDTOList(List<Comment> comments) {
return comments.stream()
.map(CommentConverter::toCommentDetailDTO)
.collect(Collectors.toList());
}

public static CommentResponseDTO.CommentsListDTO toCommentsListDTO(List<CommentResponseDTO.ParentCommentDTO> parentComments, Long nextCursor, Boolean isLast){
public static CommentResponseDTO.CommentsListDTO toCommentsListDTO(List<CommentResponseDTO.CommentDetailDTO> comments, Long nextCursor, Boolean isLast){
return CommentResponseDTO.CommentsListDTO.builder()
.parentComments(parentComments)
.comments(comments)
.nextCursor(nextCursor)
.isLast(isLast)
.build();
Expand Down
25 changes: 15 additions & 10 deletions src/main/java/meltingpot/server/comment/dto/CommentResponseDTO.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package meltingpot.server.comment.dto;

import lombok.*;
import meltingpot.server.domain.entity.comment.Comment;

import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -25,32 +26,36 @@ public static class CreateCommentResultDTO{
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class CommentDetailDTO {
private Long commentId;
private Long parentId;
private Long userId;
private String content;
private String name;
private Boolean isAnonymous;
private String imageUrl;
private LocalDateTime updatedAt;
private List<CommentDetailDTO> children;
}


@Builder
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class ParentCommentDTO{
private CommentDetailDTO parentComment;
private List<CommentDetailDTO> childrenComments;
}

@Builder
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public static class CommentsListDTO{
private List<ParentCommentDTO> parentComments;
private List<CommentDetailDTO> comments;
private Long nextCursor;
private Boolean isLast;
}

public class CommentQueueItem {
public Comment parent;
public List<Comment> children;

public CommentQueueItem(Comment parent, List<Comment> children) {
this.parent = parent;
this.children = children;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ public interface CommentService {
CommentResponseDTO.CreateCommentResultDTO createChildComment (CommentRequestDTO.CreateCommentDTO createCommentDTO, Account account, Long commentId);

CommentResponseDTO.CreateCommentResultDTO updateComment (CommentRequestDTO.CreateCommentDTO updateCommentDTO,Account account, Long commentId);

CommentResponseDTO.CommentsListDTO getCommentsList(Account account, Long postId, Long cursor, int pageSize);
}
154 changes: 100 additions & 54 deletions src/main/java/meltingpot/server/comment/service/CommentServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
import meltingpot.server.domain.repository.CommentRepository;
import meltingpot.server.domain.repository.PostRepository;
import meltingpot.server.util.r2.FileService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Collections;
import java.util.*;
import java.util.stream.Collectors;

import static meltingpot.server.comment.converter.CommentConverter.toComment;
import static meltingpot.server.comment.converter.CommentConverter.toCreateCommentResult;
import static meltingpot.server.comment.converter.CommentConverter.*;
import static meltingpot.server.comment.converter.CommentImageConverter.toCommentImage;

@Service
Expand All @@ -38,8 +38,7 @@ public class CommentServiceImpl implements CommentService {


@Override
//
public CommentResponseDTO.CreateCommentResultDTO createComment (CommentRequestDTO.CreateCommentDTO createCommentDTO, Account account, Long postId) {
public CommentResponseDTO.CreateCommentResultDTO createComment(CommentRequestDTO.CreateCommentDTO createCommentDTO, Account account, Long postId) {
Post post = findPostById(postId);
Comment comment = toComment(createCommentDTO, account, post);
return processCommentCreation(createCommentDTO, account, comment);
Expand All @@ -52,58 +51,92 @@ public CommentResponseDTO.CreateCommentResultDTO createChildComment(CommentReque
return processCommentCreation(createCommentDTO, account, childComment);
}

// @Override
// public CommentResponseDTO.CreateCommentResultDTO updateComment (CommentRequestDTO.CreateCommentDTO updateCommentDTO, Account account,Long commentId){
// Comment comment = findCommentById(commentId);
// Post post = comment.getPost();
// String newImageKey = updateCommentDTO.getImageKey();
// CommentImage oldCommentImage = comment.getCommentImage();
// if (newImageKey == null || newImageKey.isEmpty()) {
// if (oldCommentImage != null) {
// commentImageRepository.delete(oldCommentImage);
// comment.setCommentImage(null);
// }
// } else {
// comment = toComment(updateCommentDTO,account,post);
// }
// return processCommentCreation(updateCommentDTO, account, comment);
// }
@Override
public CommentResponseDTO.CreateCommentResultDTO updateComment(CommentRequestDTO.CreateCommentDTO updateCommentDTO, Account account, Long commentId) {
// λŒ“κΈ€μ„ ID둜 μ°ΎκΈ°
Comment comment = findCommentById(commentId);

// λŒ“κΈ€ λ‚΄μš© μ—…λ°μ΄νŠΈ
comment.setContent(updateCommentDTO.getContent());

// μƒˆλ‘œμš΄ 이미지 킀와 κΈ°μ‘΄ λŒ“κΈ€ 이미지 κ°€μ Έμ˜€κΈ°
String newImageKey = updateCommentDTO.getImageKey();
CommentImage oldCommentImage = comment.getCommentImage();

if (newImageKey == null || newImageKey.isEmpty()) {
// μƒˆλ‘œμš΄ 이미지 ν‚€κ°€ 없을 경우 κΈ°μ‘΄ 이미지 μ‚­μ œ
if (oldCommentImage != null) {
commentImageRepository.delete(oldCommentImage);
comment.setCommentImage(null);
}
} else {
// μƒˆλ‘œμš΄ 이미지 ν‚€κ°€ μžˆμ„ 경우 이미지 μ—…λ°μ΄νŠΈ λ˜λŠ” 생성
if (oldCommentImage != null) {
oldCommentImage.setImageKey(newImageKey);
commentImageRepository.save(oldCommentImage);
@Override
public CommentResponseDTO.CreateCommentResultDTO updateComment(CommentRequestDTO.CreateCommentDTO updateCommentDTO, Account account, Long commentId) {
// λŒ“κΈ€μ„ ID둜 μ°ΎκΈ°
Comment comment = findCommentById(commentId);

// λŒ“κΈ€ λ‚΄μš© μ—…λ°μ΄νŠΈ
comment.setContent(updateCommentDTO.getContent());

// μƒˆλ‘œμš΄ 이미지 킀와 κΈ°μ‘΄ λŒ“κΈ€ 이미지 κ°€μ Έμ˜€κΈ°
String newImageKey = updateCommentDTO.getImageKey();
CommentImage oldCommentImage = comment.getCommentImage();

if (newImageKey == null || newImageKey.isEmpty()) {
// μƒˆλ‘œμš΄ 이미지 ν‚€κ°€ 없을 경우 κΈ°μ‘΄ 이미지 μ‚­μ œ
if (oldCommentImage != null) {
commentImageRepository.delete(oldCommentImage);
comment.setCommentImage(null);
}
} else {
CommentImage newCommentImage = toCommentImage(updateCommentDTO, account, comment);
comment.setCommentImage(newCommentImage);
// μƒˆλ‘œμš΄ 이미지 ν‚€κ°€ μžˆμ„ 경우 이미지 μ—…λ°μ΄νŠΈ λ˜λŠ” 생성
if (oldCommentImage != null) {
oldCommentImage.setImageKey(newImageKey);
commentImageRepository.save(oldCommentImage);
} else {
CommentImage newCommentImage = toCommentImage(updateCommentDTO, account, comment);
comment.setCommentImage(newCommentImage);
}
}


// λŒ“κΈ€ μ €μž₯
commentRepository.save(comment);

// κ²°κ³Ό DTO 생성 및 λ°˜ν™˜
String commentImgUrl = newImageKey != null && !newImageKey.isEmpty() ? fileService.getCdnUrl("comment", newImageKey) : null;
return toCreateCommentResult(commentImgUrl, comment);
}

// λŒ“κΈ€ μ €μž₯
commentRepository.save(comment);

// κ²°κ³Ό DTO 생성 및 λ°˜ν™˜
String commentImgUrl = newImageKey != null && !newImageKey.isEmpty() ? fileService.getCdnUrl("comment", newImageKey) : null;
return toCreateCommentResult(commentImgUrl, comment);
}
public CommentResponseDTO.CommentsListDTO getCommentsList(Account account, Long postId, Long cursor, int pageSize) {
// Retrieve the parent comment based on cursor
Comment parentComment = getParentComment(cursor, postId);

// If no parent comment found, throw an exception or handle accordingly
if (parentComment == null) {
throw new NoSuchElementException("No parent comment found for the given cursor.");
}

// Retrieve child comments for the parent comment
List<Comment> childComments = getChildComments(parentComment, pageSize - 1); // -1 for the parent comment

// Determine the next cursor and if it's the last page
Long nextCursor = determineNextCursor(parentComment, childComments, pageSize);
boolean isLast = nextCursor == null;

// Convert parent comment to DTO
CommentResponseDTO.CommentDetailDTO parentCommentDTO = CommentConverter.toCommentDetailDTO(parentComment);

// Convert child comments to DTOs
List<CommentResponseDTO.CommentDetailDTO> childCommentDTOs = CommentConverter.toCommentDetailDTOList(childComments);

// Add the parent comment DTO at the beginning of the list
childCommentDTOs.add(0, parentCommentDTO);

// Return the final DTO list with next cursor and isLast flag
return CommentResponseDTO.CommentsListDTO.builder()
.comments(childCommentDTOs)
.nextCursor(nextCursor)
.isLast(isLast)
.build();
}


private Comment getParentComment(Long cursor, Long postId) {
if (cursor == null) {
// Fetch the first parent comment if no cursor is provided
return commentRepository.findFirstByPostIdAndParentIsNull(postId).orElse(null);
} else {
// Fetch the parent comment based on the cursor
return commentRepository.findById(cursor).orElse(null);
}
}

private List<Comment> getChildComments(Comment parentComment, int pageSize) {
return commentRepository.findByParent(parentComment, PageRequest.of(0, pageSize));
}

private CommentResponseDTO.CreateCommentResultDTO processCommentCreation(CommentRequestDTO.CreateCommentDTO createCommentDTO, Account account, Comment comment) {
String commentImgUrl = null;
Expand All @@ -120,7 +153,7 @@ private CommentResponseDTO.CreateCommentResultDTO processCommentCreation(Comment

private Comment findCommentById(Long commentId) {
return commentRepository.findById(commentId)
.orElseThrow(() -> new RuntimeException("λŒ“κΈ€μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."));
.orElseThrow(() -> new RuntimeException("λŒ“κΈ€μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."));
}


Expand All @@ -134,4 +167,17 @@ private Post findPostById(Long postId) {
.orElseThrow(() -> new RuntimeException("κ²Œμ‹œλ¬Όμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€."));
}

private Long determineNextCursor(Comment parentComment, List<Comment> childComments, int pageSize) {
if (childComments.size() < pageSize - 1) {
// μžμ‹ λŒ“κΈ€μ˜ μˆ˜κ°€ νŽ˜μ΄μ§€ 크기보닀 적으면, λ‹€μŒ λΆ€λͺ¨ λŒ“κΈ€μ„ κ°€μ Έμ˜¨λ‹€.
Optional<Comment> nextParentComment = commentRepository.findNextParentComment(parentComment.getId(), parentComment.getPost().getId());
return nextParentComment.map(Comment::getId).orElse(null);
} else {
// λ§ˆμ§€λ§‰μœΌλ‘œ κ°€μ Έμ˜¨ μžμ‹ λŒ“κΈ€μ˜ IDλ₯Ό λ‹€μŒ μ»€μ„œλ‘œ μ„€μ •ν•œλ‹€.
return childComments.get(childComments.size() - 1).getId();
}
}
}



Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.persistence.*;
import lombok.*;
import meltingpot.server.comment.dto.CommentResponseDTO;
import meltingpot.server.domain.entity.Account;
import meltingpot.server.domain.entity.post.Post;
import meltingpot.server.domain.entity.common.BaseEntity;
Expand Down Expand Up @@ -77,4 +78,11 @@ public CommentImage getCommentImage() {
public void setContent(String content) {
this.content = content;
}

public Comment getParent() { return parent;}


public List<Comment> getChildren() {
return children;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,22 @@ public interface CommentRepository extends JpaRepository<Comment, Long> {

Optional<Comment> findById(Long id);

@Query("SELECT c FROM Comment c WHERE c.post.id = :postId AND c.parent IS NULL AND c.id < :cursor ORDER BY c.id DESC")
List<Comment> findParentCommentsByPostIdAndCursor(@Param("postId") Long postId, @Param("cursor") Long cursor, Pageable pageable);
@Query("SELECT c FROM Comment c WHERE c.post.id = :postId AND c.id < :cursor ORDER BY c.id DESC")
List<Comment> findParentComments(Long postId, Long cursor, Pageable pageable);

@Query("SELECT c FROM Comment c WHERE c.parent.id = :parentId ORDER BY c.id ASC")
List<Comment> findChildCommentsByParentId(@Param("parentId") Long parentId, Pageable pageable);
// μžμ‹ λŒ“κΈ€μ„ μ‘°νšŒν•˜λŠ” λ©”μ„œλ“œ
@Query("SELECT c FROM Comment c WHERE c.parent.id = :parentId")
List<Comment> findChildrenComments(Long parentId);

// λΆ€λͺ¨κ°€ μ—†λŠ” 첫 번째 λŒ“κΈ€μ„ μ°ΎκΈ° μœ„ν•œ λ©”μ„œλ“œ (κ°€μž₯ μƒμœ„ λŒ“κΈ€)
Optional<Comment> findFirstByPostIdAndParentIsNull(Long postId);

// νŠΉμ • λΆ€λͺ¨ λŒ“κΈ€μ˜ μžμ‹ λŒ“κΈ€μ„ νŽ˜μ΄μ§€λ‘œ κ°€μ Έμ˜€λŠ” λ©”μ„œλ“œ
List<Comment> findByParent(Comment parent, Pageable pageable);

// λ‹€μŒ λΆ€λͺ¨ λŒ“κΈ€μ„ μ°ΎκΈ° μœ„ν•œ λ©”μ„œλ“œ
@Query("SELECT c FROM Comment c WHERE c.post.id = :postId AND c.parent IS NULL AND c.id > :parentId ORDER BY c.id ASC")
Optional<Comment> findNextParentComment(Long parentId, Long postId);

Slice<Comment> findAllByAccountAndDeletedAtIsNullOrderByIdDesc(Account account, Pageable pageable);
}
Loading

0 comments on commit b70bf3b

Please sign in to comment.