Spring Boot 대댓글 펼치기 기능 코드

Ada·2022년 11월 3일
0

항해TOL

목록 보기
38/63
post-custom-banner

댓글과 대댓글에 둘다 더보기 기능이 있을 때 두 부분 모두 페이징 처리를 해야했던 부분이 어려웠어서 저의 코드를 공유해보려고 합니다.

아직 미숙한 부분이 많아서 부끄럽지만 그동안 구글링의 도움을 많이 받은만큼 저도 누군가에게 도움이 되길 바라며 이 포스팅을 작성합니다.

Comment 엔티티

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Comment extends Timestamped {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String content;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="users_id", nullable = false)
    private Users users;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="post_id")
    private Post post;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "comment", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Likes> likes;

    @Column
    private String redHeart = "false";

    private Boolean isDeleted;

    @Column
    private Long rootId;

    @Column
    private String rootName;

    @Column
    private String parentName;
    
    public Comment(CommentRequestDto requestDto, Post post, Users users, String redHeart) {
        this.content = requestDto.getContents();
        this.rootId = requestDto.getRootId();
        this.rootName = requestDto.getRootName();
        this.post = post;
        this.users = users;
        this.redHeart = "false";
    }
    
    public void update(String content) {
        this.content = content;
    }
    //== 삭제 ==//
    public void delete() {
        this.isDeleted = true;
    }

    public boolean validateMember(Users users) {
        return !this.users.equals(users);
    }

    public void setRedHeart(Users users,  Long commentId){
        this.redHeart = "true";
    }

    public void cancelRedHeart(Users users, Long commentId){
        this.redHeart = "false";
    }

    public void setParentName(CommentResponseDto.CommentResponse comment){
        this.parentName = comment.getUserName();
    }


}
    

CommentRepository



import com.example.pinterestclone.domain.Comment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface CommentRepository extends JpaRepository<Comment, Long> {
   @Query(" SELECT c FROM Comment c WHERE c.post.id = :postId and c.rootName = :rootName ")
   Page<Comment> findAllByPostIdAndRootName( @Param("postId") Long postId,@Param("rootName") String rootName, Pageable pageable);
   
   @Query(" SELECT c FROM Comment c WHERE c.post.id = :postId and c.rootName = :rootName ")
   List<Comment> findAllByPostIdAndRootNameAndOrderByCreatedAt( @Param("postId") Long postId,@Param("rootName") String rootName);
   
    @Query("SELECT c FROM Comment c WHERE c.post.id = :postId and c.rootName = :keyword ")
    Page<Comment> findAllReCommentByPostIdAndRootNameLikeComment(@Param("postId") Long postId, @Param("keyword") String keyword, Pageable pageable);
    
    int countByPostId(Long RootId);

    @Query("SELECT c FROM Comment c WHERE c.id = :id ")
    Comment findByCommentId(@Param("id") Long id);

서비스는 댓글을 불러오는 부분만 작성하겠습니다.

CommentService


@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
@Getter
public class CommentSerivce {

    private final PostRepository postRepository;
    private final CommentRepository commentRepository;
    private final LikesRepository likesRepository;
    private final PostService postService;
    private final TokenProvider tokenProvider;
    
    (create, update, delete 생략)
    
    
    //부모댓글만 가져오기
    public List<CommentResponseDto.CommentResponse> getParentComment (Long postId, String rootName, int size, int page){
        CommentResponseDto commentResponseDto = new CommentResponseDto();

        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").ascending());

        Page<Comment> parentCommentPage = commentRepository.findAllByPostIdAndRootName(postId, rootName, pageable);
        List<Comment> parentComment = parentCommentPage.getContent();
        int a = 0;
        for(int i = 0; i < parentComment.size(); i++){
            commentResponseDto.addComment(parentComment.get(i));
        }


        int totalCounts = commentRepository.countByPostId(postId);
        int totalPages = parentCommentPage.getTotalPages();
        int totalCountsInThisPage = parentCommentPage.getNumberOfElements();
        int currentPage = page;
        Boolean isLastPage =  parentCommentPage.isLast();
        Integer nextPage;

            if (isLastPage){
            nextPage = null;
        }else{
            nextPage = currentPage + 1;
    }

        commentResponseDto.addPagination(size, totalCountsInThisPage, totalPages, currentPage, nextPage, isLastPage);

        return commentResponseDto.getComments();
    }
    
    // 자식 댓글만 가져오기
    
     public List<ReCommentResponseDto.ReComment> getReCommentList (Long postId, int size, int page, Long commentId) {
        ReCommentResponseDto reCommentResponseDto = new ReCommentResponseDto();

        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").ascending());

        Page<Comment> reCommentList = commentRepository.findAllReCommentByPostIdAndRootNameLikeComment(postId, "comment", pageable);
        List<Comment> parentComment = commentRepository.findAllByPostIdAndRootNameAndOrderByCreatedAt(postId, "post");
        CommentResponseDto commentResponseDto = new CommentResponseDto();
        int a = 0;
        int b = size * (page + 1);
        for (Comment eachParent : parentComment) {
            commentResponseDto.addComment(eachParent);
        }
        List<CommentResponseDto.CommentResponse> parentComments = commentResponseDto.getComments();

        for (Comment eachComment : reCommentList) {
            Long itsParentId = eachComment.getRootId();
            if(itsParentId == commentId){

                for( CommentResponseDto.CommentResponse parents : parentComments){
                    if (parents.getCommentId().equals(itsParentId)) {
                        int index = commentResponseDto.getComments().indexOf(parents);
                        eachComment.setParentName(parents);
                        reCommentResponseDto.addComment(index, eachComment);
                    }
                } a +=1;
                if(a==b) break;
            }
        }
        return reCommentResponseDto.getComments();
    }

      // 자식댓글 가져올 때 부모댓글도 함께 가져오기
      
      public CommentResponseDto getReComment (Long postId, String rootName, int size, int page, Long commentId) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").ascending());
        List<Comment> reCommentList = commentRepository.findAllReCommentByPostIdAndRootNameLikeComment(postId, "comment");
        List<Comment> parentComment = commentRepository.findAllByPostIdAndRootNameAndOrderByCreatedAt(postId, "post");
        CommentResponseDto commentResponseDto = new CommentResponseDto();
        int a = 0;
        int b = size * (page + 1);
        //부모댓글 불러오기
        for (Comment eachParent : parentComment) {
            commentResponseDto.addComment(eachParent);
        }

        List<CommentResponseDto.CommentResponse> parentComments = commentResponseDto.getComments();

        // 대댓글이 현재 포스트에 있는 경우에만 반복문 실행
        for (Comment eachComment : reCommentList) {
                Long itsParentId = eachComment.getRootId();
                if(itsParentId == commentId){

                //부모댓글과 대댓글 매칭 시켜주기
                for( CommentResponseDto.CommentResponse parents : parentComments){
                    if (parents.getCommentId().equals(itsParentId)) {
                        int index = commentResponseDto.getComments().indexOf(parents);
                        commentResponseDto.addReCommentImpl(index, eachComment);
                    }
                } a +=1;
            if(a==b) break;
            }
        }
        return commentResponseDto;
    }

CommentResponseDto는 두개로 나누었습니다.

하나로 처리하려고 하니까 부모댓글과 자식댓글의 값이 다르게 들어가서 어쩔 수 없이 나누게 되었습니다.


package com.example.pinterestclone.controller.response;

import com.example.pinterestclone.domain.Comment;
import com.example.pinterestclone.domain.Timestamped;
import com.example.pinterestclone.domain.Users;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@Setter
@Getter
@NoArgsConstructor
public class CommentResponseDto extends Timestamped {

    private List<CommentResponse> comments = new ArrayList<>();

    public void addComment(Comment comment){
        this.comments.add(new CommentResponse(comment));
    }

    public void addReCommentImpl(int index, Comment comment){
        if(comment == null) {
            System.out.println("comment is null");
        }
        this.comments.get(index).addReComment(new ReComment(comment));
    }

    private Pagination pagination;

    public void addPagination(int size, int totalCounts, int totalPages,
                              int currentPage, Integer nextPage, Boolean isLastPage) {
        this.pagination = new Pagination(size, totalCounts, totalPages,
                currentPage, nextPage, isLastPage);
    }

    // 생성시간 순으로 오름차순 정렬
    
    public int compareTo(CommentResponseDto o) {
        return o.getCreatedAt().compareTo(o.getCreatedAt());
    }

    @Getter
    public class CommentResponse  implements Comparator<CommentResponse> {
        private Pagination pagination;
        private Long commentId;
        private Long postId;
        private Long userId;
        private String userName;
        private String uniqueName;
        private String profileImage;

        private String content;
        private String redHeart;
        private Integer likes;
        //   private Long nestedCommentsCount;
        
        // 대댓글 리스트에 넣어주기
        
        private List<ReComment> reComment = new ArrayList<>();

        private Long reCommentsCount = 0L;
        public LocalDateTime createdAt;
        public LocalDateTime modifiedAt;

        // comment와 user 정보 가져오기
        public CommentResponse(Comment comment) {
            this.commentId = comment.getId();
            this.postId = comment.getPost().getId();
            this.userId = comment.getUsers().getId();
            this.userName = comment.getUsers().getUserId();
            this.uniqueName = comment.getUsers().getUniqueName();
            this.profileImage = comment.getUsers().getProfileImage();
            // userOrigin.getIntroduce());
            this.likes = comment.getLikes().size();
            this.redHeart = comment.getRedHeart();
            this.content = comment.getContent();
            this.createdAt = comment.getCreatedAt();
            this.modifiedAt = comment.getModifiedAt();
            //this.isMine = isMine;
        }

        public void addReComment(ReComment reComment) {
            this.reComment.add(reComment);
            this.reCommentsCount += 1;
        }



        @Override
        public int compare(CommentResponse o1, CommentResponse o2) {
            Long first = Long.parseLong(String.valueOf(o1.createdAt));
            Long second = Long.parseLong(String.valueOf(o2.createdAt));

            if(first > second){
                return 1;
            }
            else if(first < second){
                return -1;
            }
            return 0;
        }
    }
    @Getter
    @Setter
    public class ReComment {
        private CommentResponseDto.Pagination pagination;
        private Long commentId;
        private Long parentId;
        private Long postId;
        private String parentName;
        @JsonIgnore
        private Users userOrigin;
        private Long userId;
        private String userName;
        private String uniqueName;
        private String content;
        private String profileImage;
        private Integer likes;
        private String redHeart = "false";
        private LocalDateTime createdAt;
        private LocalDateTime modifiedAt;
        private Boolean folded;



        public String checkNull(String redHeart, String replace) {
            replace = "false";
            return (redHeart == null || redHeart.equals("")) ? replace : redHeart;
        }



        public ReComment(Comment comment) {
            this.commentId = comment.getId();
            this.parentId = comment.getRootId();
            this.postId = comment.getPost().getId();
            this.parentName = comment.getParentName();
            this.userId = comment.getUsers().getId();
            this.userName = comment.getUsers().getUserId();
            this.uniqueName = comment.getUsers().getUniqueName();
            this.profileImage = comment.getUsers().getProfileImage();
            // userOrigin.getIntroduce());
            this.likes = comment.getLikes().size();
            this.redHeart = "false";
            this.content = comment.getContent();
            this.createdAt = comment.getCreatedAt();
            this.modifiedAt = comment.getModifiedAt();
            this.parentId = comment.getRootId();
            //this.isMine = isMine;
        }
    }

    @Getter
    @AllArgsConstructor
    public class Pagination {
        private int per;
        private int totalCounts;
        private int totalPages;
        private int currentPage;
        private Integer nextPage;
        private Boolean isLastPage;
    }
}

ReCommentResponseDto

@Setter
@Getter
@NoArgsConstructor
public class ReCommentResponseDto {


    private List<ReComment> comments = new ArrayList<>();

    public void addComment( int index, Comment comment){
        this.comments.add(new ReCommentResponseDto.ReComment(comment));
    }

    public void addPagination(int size, int totalCounts, int totalPages,
                              int currentPage, Integer nextPage, Boolean isLastPage) {
        this.pagination = new Pagination(size, totalCounts, totalPages,
                currentPage, nextPage, isLastPage);
    }
    private Pagination pagination;
    public int compareTo(CommentResponseDto o) {
        return o.getCreatedAt().compareTo(o.getCreatedAt());
    }

    @Getter
    @Setter
    public class ReComment  implements Comparator<ReComment> {

        private Long commentId;
        private Long parentId;
        private Long postId;
        private String parentName;
        private Long userId;
        private String userName;
        private String uniqueName;
        private String content;
        private String profileImage;
        private int likes;
        private String redHeart;
        private LocalDateTime createdAt;
        private LocalDateTime modifiedAt;

        private Pagination pagination;
        public ReComment(Comment comment) {
            this.commentId = comment.getId();
            this.parentId = comment.getRootId();
            this.postId = comment.getPost().getId();
            this.parentName = comment.getParentName();
            this.userId = comment.getUsers().getId();
            this.userName = comment.getUsers().getUserId();
            this.uniqueName = comment.getUsers().getUniqueName();
            this.profileImage = comment.getUsers().getProfileImage();
            // userOrigin.getIntroduce());
            this.likes = comment.getLikes().size();
            this.redHeart = comment.getRedHeart();
            this.content = comment.getContent();
            this.createdAt = comment.getCreatedAt();
            this.modifiedAt = comment.getModifiedAt();
            this.parentId = comment.getRootId();
            //this.isMine = isMine;
        }

        @Override
        public int compare(ReComment o1, ReComment o2) {
            Long first = Long.parseLong(String.valueOf(o1.createdAt));
            Long second = Long.parseLong(String.valueOf(o2.createdAt));

            if(first > second){
                return 1;
            }
            else if(first < second){
                return -1;
            }
            return 0;
        }
    }
    @Getter
    @AllArgsConstructor
    public class Pagination {
        private int per;
        private int totalCounts;
        private int totalPages;
        private int currentPage;
        private Integer nextPage;
        private Boolean isLastPage;
    }
}

CommentRequestDto


@Getter
@NoArgsConstructor
@AllArgsConstructor
public class CommentRequestDto {

        private String contents;
        //댓글이면 postId, 대댓글이면 댓글id
        private Long rootId;
        private String rootName; //comment/post
}

CommentController


@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api")
@RestController
public class CommentController {

    private final CommentSerivce commentSerivce;
    
     @GetMapping(value = "/comments/{rootId}")
    // @Pagable을 통해 보여줄 페이지 위치(0이 시작), 한 페이지에 댓글 개수 2, 정렬 기준(createdAt), 정렬 기준의 순서(오름차순)을 정의
    public ResponseDto<?> getAllComments(@PathVariable Long rootId, String keyword,
                                       int size, int page, Long commentId) {

        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").ascending());
        if (keyword == null) {
            return ResponseDto.success(commentSerivce.getParentComment(rootId, "post", size, page));

        }else {
                List<ReCommentResponseDto.ReComment> result = commentSerivce.getReCommentList(rootId,  size, page, commentId);

                    return ResponseDto.success(result);
                }
    }

    @GetMapping(value = "/comments/find/{commentId}")
    public ResponseDto<?> getOneComment(@PathVariable Long commentId) {
        return ResponseDto.success(commentSerivce.getOneComment(commentId));
    }
    
    
 	 // 좋아요 처리
 	@DeleteMapping("/comments/likes/{commentId}")
    public ResponseDto<?> cancelLike(@LoginUsers Users loginUsers,
                                            @PathVariable Long commentId) {
        if (loginUsers != null) {
            commentSerivce.cancelLike(loginUsers, commentId);
        }
        return ResponseDto.success(true);
    }



	@PostMapping("/comments/likes/{commentId}")
    public ResponseDto<?> addLike(@LoginUsers Users loginUsers,
                                          @PathVariable Long commentId) {
        boolean result = false;

        if (Objects.nonNull(loginUsers))
            result = commentSerivce.addLike(loginUsers, commentId);

        return result ?
                ResponseDto.success(true) : ResponseDto.fail("false", "좋아요를 이미 하셨습니다.");
    }
}

다른분 코드도 많이 참고했지만 제가 작성한 부분도 많아서 미흡한 부분이 있을거라고 생각합니다.

지적해주시면 감사드리겠습니다.

profile
백엔드 프로그래머
post-custom-banner

0개의 댓글