본문 바로가기

Springboot

[JPA] 댓글, 대댓글 계층형 구조 구현

1.  요구 사항

댓글1

     대댓글1

     대댓글2

     대댓글3

 

댓글2

    대댓글1

 

댓글뿐만 아니라 댓글에 대댓글을 달 수 있는 계층형 구조로 구현하고 싶었다.

댓글을 삭제 한다면 대댓글까지 모두 삭제하여야 한다.

 

2. domain

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Builder
public class Comment extends BaseTimeEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id; // 기본키

    @Column(columnDefinition = "TEXT", nullable = false)
    private String comment; // 댓글 내용

    @ManyToOne
    private Member commentWriter; // 댓글 쓴 회원

    @ManyToOne
    private Post post; //댓글 단 게시물

    @ManyToOne(fetch = FetchType.LAZY)
    private Comment parentComment; //부모 댓글 (그냥 댓글)

    @OneToMany(mappedBy = "parentComment", orphanRemoval = true)
    private List<Comment> children = new ArrayList<>(); //자식 댓글(대댓글)

    public void update(String comment){
        this.comment = comment;
    }

 

 

여기서 우리가 봐야 할 부분은

@ManyToOne(fetch = FetchType.LAZY)
private Comment parentComment;

@OneToMany(mappedBy = "parentComment", orphanRemoval = true)
private List<Comment> children = new ArrayList<>();

이 부분이다.

같은 domain class에  다대 일 관계를 만들어준다.

이렇게  한 댓글(parentComment)에 여러개의 대댓글(children)을 달 수 있게 매핑해준다.

 

 - @ManyToOne(fetch = FetchType.Lazy) 

   : 부모 댓글이다. 즉, 그냥 댓글이다.

   : fetch type을 lazy로 하여 필요한 시점에만 데이터를 불러 온다.

 

 - @OneToMany(mappedBy = "parentComment", orphanRemoval = true)

   : 자식 댓글이다. 즉, 대댓글이다.

   : parentComment 을 매핑한다.

   : orphanRemoval = true -> 부모 댓글을 삭제 하면 자식댓글까지 저절로 삭제 된다.

 

3. 댓글, 대댓글 생성

public Long saveComment(CommentDto commentDto, Long id, Member member) {

    Post post = postRepository.findById(id).orElseThrow(); // 댓글 을 단 게시물 

    if (commentDto.getParentComment() != -1) { //부모 댓글이 존재 한다 = 자식 댓글 = 대댓글
        Comment commentParent = commentRepository.findById(commentDto.getParentComment()).orElseThrow();
        // CommentDto에서 가져온 부모 댓글 아이디로 부모 댓글을 가져 온다.
        
        commentRepository.save(Comment.builder()
                .comment(commentDto.getComment()) 
                .commentWriter(member)
                .post(post)
                .parentComment(commentParent)
                .build());
                // 댓글내용, 댓글 쓴 회원, 게시물, 부모 댓글 을 저장한다.
    } else { // 부모 댓글이 존재 하지 않는다 = 부모 댓글 = 댓글
        commentRepository.save(Comment.builder()
                .comment(commentDto.getComment())
                .commentWriter(member)
                .post(post)
                .build());
                 // 댓글내용, 댓글 쓴 회원, 게시물을 저장한다.
    }


    return id;
}
  •  프론트 쪽에서 현재 로그인한 회원, 게시물 번호, Comment Dto로 댓글 내용, 부모 댓글 기본키 id(parentComment)를 가지고 왔다.
  • 저장 할때에는 부모 댓글이냐 자식댓글이냐에 따라 repository에 저장하는 방식이 다르다.
  • parentComment == -1 즉 자신이 부모 댓글이면 parentComment 를 저장하지 않는다 -> null
  • parentComment != -1 이면 부모댓글의 기본키 값이 존재 하기 때문이기 때문에 그 댓글의 대댓글이다. 이럴때는 repository에 parentComment 값을 저장 해준다.

 

4. DB Test

- 댓글, 대댓글 을 단 화면

   

- 댓글, 대댓글 DB 

  : 부모 댓글 일땐 parent_comment_id(댓글) 가 null 처리 되어 있고

  : 자식 댓글 일땐 parent_comment_id(대댓글)가 부모 댓글 id로 저장되어 있다.

- 부모 댓글 테스트 1 삭제 후

: 부모 댓글1 테스트 뿐만 아니라 자식 댓글인 1-1, 1-2도 자동으로 삭제 되었다.