코딩과 결혼합니다

230826 - 댓글 + 대댓글 좋아요 기능 구현 본문

코딩과 매일매일♥/Seoulvival

230826 - 댓글 + 대댓글 좋아요 기능 구현

코딩러버 2023. 8. 26. 23:46
728x90

✔️문제 

댓글 테이블과 대댓글 테이블을 따로 만들게 되면서 로직이 굉장히 복잡하고 관리가 어려워졌다. 대댓글 작성, 수정, 삭제, 좋아요 까지는 만들었으나 post를 조회할 때 comment와 연관관계인 recomment까지 조회로 불러와서 사용자가 대댓글에 좋아요를 눌렀는지 안 눌렀는지를 나타내는 과정이 너무도 어려웠다.

 

✔️해결 

프런트에서 post조회와 comment조회를 따로 만들어 달라던게 생각나서 따로 분리해 주었다. 조회를 따로 분리하니 댓글 조회할 때 대댓글에 대한 사용자의 좋아요 여부를 넣어주면 되어 좀 더 편해졌다.

 

✔️별도의 테이블로 관리하는 경우 장 · 단점

  1. 성능: 대규모 애플리케이션에서는 댓글과 대댓글을 별도의 테이블로 분리하여 쿼리 성능을 최적화할 수 있다. 댓글만 필요한 경우 대댓글 테이블을 조인하지 않아도 된다.
  2. 유지보수: 코드와 데이터베이스 스키마를 관리하기 쉽다. 댓글과 대댓글에 대한 변경이 각각의 테이블에 영향을 미치지 않는다.
  3. 단점: 두 개의 테이블을 유지해야 하므로 스키마가 조금 더 복잡할 수 있다.

Comment Controller

    //comment 상세 조회
    @GetMapping("/get/{postId}")
    public CommentListResponse getOneComment(@PathVariable Long postId,
                                             @AuthenticationPrincipal UserDetailsImpl userDetails,
                                             int size,
                                             int page) {
        User user = userDetails != null ? userDetails.getUser() : null;
        return commentService.getCommentByPostId(page-1, size, postId, user);
    }

* 조회를 할 때 비회원과 회원을 구분해 준다. 회원정보가 존재하면 그 회원이 해당 댓글에 좋아요를 눌렀는지 누르지 않았는지 확인할 수 있다. (commentHasLiked/ ReCommentHasLiked) 프런트는 comment의 id를 알 수 없다고 하니 post Id를 통해서 comment를 가져온다.

 

Comment Service

 //comment 조회
    public CommentListResponse getCommentByPostId(int page, int size, Long postId, User user) {
        // postId 유효성 확인
        if (!postRepository.existsById(postId)) {
            throw new IllegalArgumentException("해당 게시물이 존재하지 않습니다.");
        }
        
        Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"));
        Page<Comment> commentPages = commentRepository.findAllByPostId(postId, pageable);
        List<CommentResponseDto> commentResponseDtos = new ArrayList<>();

        for (Comment comment : commentPages) {
            List<ReCommentResponseDto> reComments = comment.getReCommentList().stream()
                    .map(reComment -> getOneReComment(reComment.getId(), user))
                    .collect(Collectors.toList());

            boolean hasLikeComment = user != null && commentLikeRepository.existsLikeByCommentAndUser(comment, user);
            commentResponseDtos.add(new CommentResponseDto(comment, hasLikeComment, reComments));
        }

        return new CommentListResponse(commentResponseDtos,commentPages.getTotalPages(), commentPages.getTotalElements(), size);
    }

comment 부분이 길어질 수 있으니 페이징 처리를 해주었다.

다음 commentPages에 내가 불러오고 싶은 post에 달린 댓글들을 모두 가져와서 저장한다.

 

postId를 통해 찾은 post가 있는지 확인하고 없으면 에러처리, 다음으로 comment와 그리고 recomment 각각 사용자 정보가 있는지 없는지에 따라서 좋아요에 대한 여부를 확인하는 로직을 구현하였다.


Comment Entity

@Entity
@Getter
@Setter
@Table(name = "comments")
@NoArgsConstructor
public class Comment extends Auditing {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "comment_id")
    private Long id;

    @Column
    private String nickname;

    @Column(nullable = false, length = 500)
    private  String comment;

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

    @JsonManagedReference
    @OneToMany(mappedBy = "comment", cascade = {CascadeType.REMOVE})
    private List<ReComment> reCommentList = new ArrayList<>();

    @JsonManagedReference
    @OneToMany(mappedBy = "comment", cascade = {CascadeType.REMOVE})
    private List<Commentlike> commentLike = new ArrayList<>();

    private String userImg;

    @Transient
    private boolean commentHasLiked;


    public Comment(CommentRequestDto requestDto, String nickname, Post post) {
        this.nickname = nickname;
        this.comment = requestDto.getComment();
        this.post = post;
    }

    public void update(CommentRequestDto requestDto) {
        this.comment = requestDto.getComment();
    }
}
ReComment Entity

@Entity
@Getter
@Setter
@Table(name = "re_comments")
@NoArgsConstructor
public class ReComment extends Auditing {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "re_comment_id")
    private Long id;

    @Column
    private String nickname;

    @Column(nullable = false, length = 500)
    private  String reComment;

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "comment_id")
    private Comment comment;

    private String userImg;

    @Transient
    private boolean reCommentHasLiked;

    @OneToMany(mappedBy = "reComment", cascade = {CascadeType.REMOVE})
    private List<ReCommentLike> reCommentLikes = new ArrayList<>();

    public ReComment(ReCommentRequestDto requestDto, String nickname, Comment comment) {
        this.nickname = nickname;
        this.reComment = requestDto.getReComment();
        this.comment = comment;
    }

    public void update(ReCommentRequestDto requestDto) {
        this.reComment = requestDto.getReComment();
    }
}

결과


비회원일 때에는 HasLiked가 모두 false로, 회원일 때는 본인이 좋아요를 누른 post나 댓글에 true가 뜬다.

 

 


다음은 comment를 지웠을 때 연관된 것들도 지우며 걸리는 시간

잉 생각보다 얼마 안 걸리네?