공부/프로그래밍

무한 대댓글 구현

미친사람 2023. 12. 21. 12:35
반응형

- Mysql 5.6 버전대로 만든 버전

- 회사 신입이라 무한 대댓글 구현해보라고 해서 구현을 해봄

- 익명 게시판을 기반으로 구현

 

댓글 테이블 생성

# 댓글 생성
create table MS_COMMENT (
	id int unsigned not null primary key,
	msbId int unsigned not null,
	parentNo int unsigned not null,
	groupNo int unsigned not null,
	depthNo int unsigned not null,
	orderNo int unsigned not null,
	comment text not null,
	writer varchar(40) not null,
	writerPw varchar(100) not null,
	regDate datetime not null,
	updateDate datetime not null,
	isDel char(1) not null default "N"
);
테이블 구성

댓글 아이디
게시글 아이디
부모댓글 번호
댓글 그룹 
댓글 깊이
댓글 순서
댓글 내용
작성자
작성자 비번
작성일
수정일
삭제 여부

 

 

자바 작성

@RequestMapping(value="/write.do")
public String commentWrite(HttpServletRequest req
        , @RequestParam HashMap<String, Object> param
        , ModelMap model) throws Exception {

    // 널이면 댓글, 널이 아니면 대댓글 작성
    if(param.get("id") == null) {
        commentService.insertComment(req, param);
    } else {
        // 대댓글에 작성하는 경우 부모 댓글 정보 가져오기
        Map<String,Object> Comment = commentService.selectComment(param);

        // 부모 댓글의 깊이, 순서 값을 넣는다.
        int depthNo = Integer.parseInt(String.valueOf(Comment.get("depthNo")));
        int orderNo = Integer.parseInt(String.valueOf(Comment.get("orderNo")));

        // 이 조건에 맞는 경우는 모두 부모 댓글에 적는 경우, 대댓글이 아니니까 순서를 맨아래로 해두면 된다.
        if(depthNo == 0 && orderNo == 0) {
            param.put("depthNo", depthNo + 1);
            param.put("orderNo", commentService.selectMaxOrderNo(param));
        } else {
            // 부모 댓글의 자손 수 계산
            int childCount = commentService.selectCntChild(param);

            // 부모 댓글의 자손 수가 0이 아니라면
            if(childCount != 0) {
                // 부모 댓글의 순서 값 + 자손 수 초과하는 순서 값을 + 1
                param.put("orderNo", orderNo + childCount);
                commentService.updateRemainComment(param);

                // 그 사이에 들어가는 대댓글의 순서 및 깊이 값
                param.put("orderNo", orderNo + childCount + 1);
                param.put("depthNo", depthNo + 1);

            } else {
                // 부모댓글 이후의 대댓글의 순서 값 + 1
                param.put("orderNo", orderNo);
                commentService.updateRemainComment(param);

                // 그 사이에 들어가는 대댓글의 순서 및 깊이 값
                param.put("depthNo", depthNo + 1);
                param.put("orderNo", orderNo + 1);
            }
        }

        // 댓글 작성
        commentService.insertReplyComment(req, param);
    }

    model.addAttribute("url", "/board/view.do?id=" + param.get("msbId"));

    return "모델에 값을 넣고 해당 값을 자바스크립트로 판별 후 링크를 이동시켜줌";
}

 

SQL 쿼리문 ( ibatis 를 이용했다 )

<!-- 댓글 작성 -->
    INSERT INTO MS_COMMENT (
        id,
        msbId,
        parentNo,
        groupNo,
        depthNo,
        orderNo,
        comment,
        writer,
        writerPw,
        regDate,
        updateDate
    ) VALUES (
        (SELECT IFNULL(MAX(m.id), 0) + 1 FROM MS_COMMENT as m),
        #msbId#,
        0,
        (SELECT IFNULL(MAX(m.id), 0) + 1 FROM MS_COMMENT as m),
        0,
        0,
        #comment#,
        #writer#,
        #writerPw#,
        NOW(),
        NOW()
    )

<!-- 대댓글 작성 -->
    INSERT INTO MS_COMMENT (
        id,
        msbId,
        parentNo,
        groupNo,
        depthNo,
        orderNo,
        comment,
        writer,
        writerPw,
        regDate,
        updateDate
    ) VALUES (
        (SELECT IFNULL(MAX(m.id), 0) + 1 FROM MS_COMMENT as m),
        #msbId#,
        #parentNo#,
        #groupNo#,
        #depthNo#,
        #orderNo#,
        #comment#,
        #writer#,
        #writerPw#,
        NOW(),
        NOW()
    )
    
<!-- 댓글 순서 업데이트 -->
    UPDATE ms_comment
    SET
        orderNo = orderNo + 1
    WHERE
        msbId = #msbId#
    AND
        groupNo = #groupNo#
    AND
        orderNo > #orderNo#

<!-- 댓글 순서 최대값 조회 -->
    SELECT
        IFNULL(MAX(orderNo), 0) + 1
    FROM
        MS_COMMENT
    WHERE
        msbId = #msbId#
    AND
        groupNo = #groupNo#

<!-- 해당 부모의 자손 개수 -->
    SELECT count(*)
    FROM (
        SELECT *
        FROM ms_comment
        ) cList,
        (SELECT @pv := #id#) initial
    WHERE find_in_set(parentNo, @pv)
    AND   length(@pv := concat(@pv, ',', id));

<!-- 댓글 목록 조회 -->
    SELECT
        id,
        msbId,
        groupNo,
        depthNo,
        orderNo,
        comment,
        writer,
        regDate,
        updateDate,
        isDel
    FROM
        MS_COMMENT
    WHERE
        msbId = #msbId#
    ORDER BY groupNo, orderNo;

 

 

이런식의 코드를 작성 후, 여러개의 댓글을 작성

 

 

무한 댓글 구현 완료다..!

 

대충 글로 설명이라도 적어보자 ( 그림 그리기 귀찮다, 힘들다 )

 

댓글 작성 부분에서 id 파라미터가 건너오지 못한다면

그 댓글은 무조건 최상위 부모 댓글로 작성된다.

 

그 외의 경우 id 파라미터가 건너온다면 해당 댓글은 부모댓글이 있으며 대댓글이라는 의미

그럼 이제 그 ID 값을 가지고 부모의 정보를 가져온다.

 

부모의 정보를 토대로

깊이값, 순서값을 변수에 저장해준다.

 

깊이값, 순서값이 0 이라면

해당 댓글은 최상위 부모 댓글에 달리는 댓글이기 때문에

부모가 가진 깊이 값 + 1, 부모 그룹의 최대 순서 값을 가진다.

1 번 댓글 [id 1]
ㄴ 1-1 댓글 [id 2]
   ㄴ 1-1-1 댓글 [id 3]
ㄴ 1-2 댓글  [id 4]

 

id 4번 댓글이 위에 설명한 형태로 들어간 것

 

최상위 부모 댓글에 달리는 댓글은 처리했다, 그렇다면 나머지 자식의 댓글들.. 여기서 엄청 해맸다.. 쿼리를 잘 알았더라면..

 

일단 부모 댓글의 자손 수를 계산한다, 여기서 작동하는 쿼리는 구글링을 열심히 한 결과.. 찾은 것..

해당 쿼리문의 결과는

 

해당 하는 아이디가 가진 자손의 전체 갯수다.

 

이제 이 자손의 개수로 댓글 순서가 정해진다.

 

부모 댓글의 자손 수가 0이 아니라면

 

댓글 순서 > (부모 댓글의 순서 값 + 자손 수) 조건에 해당하는 댓글 순서 값을 + 1 해준다.

 

그리고 나서 그 사이에 들어가는 대댓글의 값을 넣어준다.

 

자손수가 0인 경우는 별 거 없다.

해당 부모 댓글 이후의 순서 값 + 1 업데이트 해주고

그 사이에 들어가는 대댓글의 값도 부모의 깊이, 순서 값 + 1 넣어주면 끝

 

 

 

 

반응형