위키에서는 인터넷에 오른 원문(하나의 게시물)에 대하여 짤막하게 답하여 올리는 글.

같은 말로는 '답글'이라고 정의한다.

댓글은 하나의 게시물에 대하여 작성한 글이기 때문에 글읽기 페이지에서 대부분의 기능이 이루어진다.

하나의 게시물 번호(BRDNO)에 대하여 다수의 댓글(RENO)을 가지는 형태로 구성된다.

댓글을 저장하는 테이블(TBL_BOARDREPLY )은

게시판과 유사한 테이블 구조로 다음 SQL문과 같이 구성되어 있다.

CREATE TABLE TBL_BOARDREPLY (
      BRDNO INT(11) NOT NULL,                       -- 게시물 번호
      RENO INT(11) NOT NULL,                         -- 댓글 번호
      REWRITER VARCHAR(10) NOT NULL,            -- 작성자
      REMEMO VARCHAR(500) DEFAULT NULL,       -- 댓글내용
      REDATE DATETIME DEFAULT NULL,              -- 작성일자
      REDELETEFLAG VARCHAR(1) NOT NULL,        -- 삭제여부
      PRIMARY KEY (RENO)
)


댓글 테이블 처리를 위해 다음과 같이 BoardReplyVO를 생성해야 한다.

public class BoardReplyVO {

    private String brdno;

    private String reno;

    private String rewriter;

    private String redeleteflag;

    private String rememo;

    private String redate;

   

    public String getBrdno() {

        return brdno;

    }

   

    public void setBrdno(String brdno) {

        this.brdno = brdno;

    }

    ~~ 생략 ~~

BoardReplyVO.java

하나의 게시물 번호(BRDNO)에 대하여 다수의 댓글(RENO)을 가지는 형태이기 때문에

키 구성은 게시물 번호(BRDNO)와 댓글번호(RENO)의 복합키로 구성하는 것이

데이터베이스 설계원칙에 맞지만 여기서는 댓글번호(RENO)만 키로 구성한다.

복합키를 사용하면 매 처리마다 키값들을 가지고 다니면서 처리해야 하기 때문에 프로그램이 복잡해 진다.

간편한 개발을 위해 댓글번호(RENO)만 기본키로 구성하였다.


글읽기 화면 하단에

댓글 작성을 위한 입력 화면이 있고, 그 아래에 기존에 작성된 댓글의 리스트가 출력된다.

댓글 리스트는 수정/삭제를 하기 위한 버튼이 필요하고

수정일 경우에는 댓글 수정을 위한 입력 화면이 있어야 한다.

글을 작성한 작성자만이 해당 댓글을 수정할 수 있게 하기 위해서는

현재 로그인한 사용자가 필요한데 여기서는 게시판만 만들기 때문에 이러한 기능이 없다.

따라서 작성자 이름과 내용을 입력하고 아무나 수정/삭제 할 수 있게 구성하였다.

비밀번호를 입력 받아서 처리하는 것도 좋은 방법인데

개념 파악을 위해 간단하게 구현하였고

이 소스를 실제 개발에 사용할 경우 작성자 이름(REWRITER)을 작성자 아이디(ID)로 바꿔서 사용할 수 있다는 걸 고려했다.


삭제는 댓글 번호(RENO)를 받아서 삭제 처리하면 간단하게 처리되지만

수정은 자바 스크립트와 관련된 조금의 기교가 필요하다.

예로, 열 개의 댓글이 있을 경우

열 개의 입력상자(Text, TextArea)를 만드는 경우가 대부분이다.

열 개의 입력상자를 숨겨놓고(display:none)

사용자가 수정 버튼을 누르면 해당 입력 상자를 보여주는(display:””) 방식으로 개발한다.

댓글 리스트는 페이징 처리를 하지 않는 경우가 많은데

100개의 댓글이 있으면 100개의 입력상자가 생성되기 때문에 선호하지 않는다.

개인적으로

하나의 입력상자를 이용하여 수정하고자 하는 해당 댓글 위치에 옮겨 넣는 방식을 선호한다.


마지막으로 게시판 리스트에서 해당 게시물의 댓글 수를 보여주면 된다.


'Java > 게시판 5: 댓글' 카테고리의 다른 글

2. 댓글 쓰기  (2) 2016.05.15
3. 댓글 리스트 / 삭제  (0) 2016.05.15
4. 댓글 수정  (1) 2016.05.15

기존 게시판 읽기(board5Read)의 기본 기능 뒤에

다음과 같이 댓글을 작성할 수 있는 화면 구성을 추가해 준다.

<a href="board5List">돌아가기</a>
<a href="board5Delete?brdno=<c:out value="${boardInfo.brdno}"/>">삭제</a>
<a href="board5Form?brdno=<c:out value="${boardInfo.brdno}"/>">수정</a>
<p>&nbsp;</p>
<div style="border: 1px solid; width: 600px; padding: 5px">
    <form name="form1" action="board5ReplySave" method="post">
        <input type="hidden" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
        작성자: <input type="text" name="rewriter" size="20" maxlength="20"> <br/>
        <textarea name="rememo" rows="3" cols="60" maxlength="500" placeholder="댓글을 달아주세요."></textarea>
        <a href="#" onclick="fn_formSubmit()">저장</a>
    </form>
</div>

BoardRead.jsp


숨겨진 값으로(hidden) 게시물 번호(BRDNO)가 있다. 

게시물 번호는 현재 읽고 있는 글 번호를 의미하며

사용자가 입력한 작성자명과 댓글 내용과 같이 서버로 전송(fn_formSubmit) 된다.

새로 작성되는 댓글은 댓글 번호(RENO)가 부여 되지 않았고

여기서는 수정 없이 새 글만 작성하기 때문에 댓글 번호(RENO)와 관련된 처리를 하지 않는다.


전송된 내용을 저장하기 위해 board5ReplySave 컨트롤을 작성한다.

전송 받은 내용을 서비스에 전달하고

데이터 베이스에 저장이 되면 다시 해당 글읽기 페이지로 이동한다.

해당 글을 가져오기 위해 게시 글 번호(brdno)를 파라메터로 넘겨줘야 한다.

    /**
     * 댓글 저장.
     */
    @RequestMapping(value = "/board5ReplySave")
    public String board5ReplySave(HttpServletRequest request, BoardReplyVO boardReplyInfo) {
       
        boardSvc.insertBoardReply(boardReplyInfo);

        return "redirect:/board5Read?brdno=" + boardReplyInfo.getBrdno();
    }

Board5Ctr.java

서비스(insertBoardReply)에서는

댓글 번호(reno)가 없으면 SQL의 Insert문을, 있으면 Update문을 실행하도록 처리해준다.

    public void insertBoardReply(BoardReplyVO param) {
        if (param.getReno()==null || "".equals(param.getReno())) {
            sqlSession.insert("insertBoard5Reply", param);
        } else {
            sqlSession.insert("updateBoard5Reply", param);
        }
    }

Board5Svc.java

댓글 번호(reno)는 게시판과 동일하게 저장된 댓글 번호 중 최대값(+1)을 계산하여 저장한다.

수정일 때는 댓글 내용(rememo)만 수정해 주면 된다.

<insert id="insertBoard5Reply" parameterType="gu.board5.BoardReplyVO" >
    <selectKey resultType="String" keyProperty="reno" order="BEFORE">
        SELECT IFNULL(MAX(RENO),0)+1 FROM TBL_BOARDREPLY
    </selectKey>
       
    INSERT INTO TBL_BOARDREPLY(BRDNO, RENO, REWRITER, REDELETEFLAG, REMEMO, REDATE)
    VALUES (#{brdno}, #{reno}, #{rewriter}, 'N', #{rememo}, NOW())
</insert>

<update id="updateBoard5Reply" parameterType="gu.board5.BoardReplyVO">
    UPDATE TBL_BOARDREPLY
       SET REMEMO=#{rememo}
     WHERE RENO=#{reno}
</update>

board5.xml

실행해서 댓글을 달아보고

데이터 베이스에 잘 저장되었는지 확인하면 된다.

수정은 제법 복잡한 화면 처리를 필요로 해서 지금 처리하지 않는다.


'Java > 게시판 5: 댓글' 카테고리의 다른 글

1. 댓글 시작하기  (1) 2016.05.15
3. 댓글 리스트 / 삭제  (0) 2016.05.15
4. 댓글 수정  (1) 2016.05.15

댓글 리스트는 해당 게시물에 맞는 댓글을 읽어서 게시판 리스트처럼 뿌려주면 된다.

다음 그림처럼 댓글 입력 화면 뒤에 리스트를 나열 하였다.


먼저 댓글 리스트는 해당 게시물을 가져올 때(board5Read 컨트롤 처리시) 같이 가져와야 한다.

다음 코드처럼 글 읽기 컨트롤(board5Read)에

댓글 리스트를 가져오는 서비스(selectBoard5ReplyList)를 추가해 주고

반환 받은 리스트(replylist)를 JSP로 전달해(modelMap) 준다.

public String board5Read(HttpServletRequest request, ModelMap modelMap) {
   
    String brdno = request.getParameter("brdno");
   
    boardSvc.updateBoard5Read(brdno);
    BoardVO boardInfo = boardSvc.selectBoardOne(brdno);
    List<?> listview = boardSvc.selectBoard5FileList(brdno);
    List<?> replylist = boardSvc.selectBoard5ReplyList(brdno);
   
    modelMap.addAttribute("boardInfo", boardInfo);
    modelMap.addAttribute("listview", listview);
    modelMap.addAttribute("replylist", replylist);
   
    return "board5/BoardRead";
}

Board5Ctr.java

public List<?> selectBoard5ReplyList(String param) {

        return sqlSession.selectList("selectBoard5ReplyList", param);

}

Board5Svc.java

JSP 파일에서 다음과 같이 앞서 추가했던 댓글 입력 코드 뒤에

댓글 리스트를 출력하는 코드를 작성한다.

<div style="border: 1px solid; width: 600px; padding: 5px">
    <form name="form1" action="board5ReplySave" method="post">
        <input type="hidden" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
        <input type="hidden" name="reno">
        작성자: <input type="text" name="rewriter" size="20" maxlength="20"> <br/>
        <textarea name="rememo" rows="3" cols="60" maxlength="500" placeholder="댓글을 달아주세요."></textarea>
        <a href="#" onclick="fn_formSubmit()">저장</a>
    </form>
</div>

<c:forEach var="replylist" items="${replylist}" varStatus="status">
    <div style="border: 1px solid gray; width: 600px; padding: 5px; margin-top: 5px;">   
        <c:out value="${replylist.rewriter}"/> <c:out value="${replylist.redate}"/>
        <a href="#" onclick="fn_replyDelete('<c:out value="${replylist.reno}"/>')">삭제</a>
        <a href="#" onclick="fn_replyUpdate('<c:out value="${replylist.reno}"/>')">수정</a>
        <br/>
        <div id="reply<c:out value="${replylist.reno}"/>"><c:out value="${replylist.rememo}"/></div>
    </div>
</c:forEach>

<div id="replyDiv" style="width: 99%; display:none">
    <form name="form2" action="board5ReplySave" method="post">
        <input type="hidden" name="brdno" value="<c:out value="${boardInfo.brdno}"/>">
        <input type="hidden" name="reno">
        <textarea name="rememo" rows="3" cols="60" maxlength="500"></textarea>
        <a href="#" onclick="fn_replyUpdateSave()">저장</a>
        <a href="#" onclick="fn_replyUpdateCancel()">취소</a>
    </form>
</div>

BoardRead.jsp

리스트(replylist)의 개수만큼 반복해서(forEach) 개별 댓글들을 출력해 준다.

게시판 리스트에서는 Table 테그를 이용했지만

여기서는 DIV를 사용했다.

예전에는 많은 개발자들이 리스트를 Table 테그로 생성했지만 근래에는 DIV를 많이 사용한다.


replyDiv는 수정을 위한 입력 폼으로 삭제시 댓글번호를 전달하기 위해 사용한다.

자세한 내용은 댓글 수정 부분에서 설명할 것이다.


삭제는 fn_replyDelete, 수정은 fn_replyUpdate 함수를 호출하고 파라메터로 댓글 번호(reno)를 넘겨준다.

삭제는 다음과 같이 댓글 번호(reno)를 숨겨진 필드에 넣어서

삭제 컨트롤(board5ReplyDelete)를 호출(submit)하면 된다.

function fn_replyDelete(reno){
    if (!confirm("삭제하시겠습니까?")) {
        return;
    }
    var form = document.form2;

    form.action="board5ReplyDelete";
    form.reno.value=reno;
    form.submit();   
}

BoardRead.jsp


컨트롤에서는 전송 받은 내용을 서비스에 전달하여

해당 댓글을 삭제 한 뒤 다시 해당 글읽기 페이지로 이동한다.

해당 글을 가져오기 위해 게시 글 번호(brdno)를 파라메터로 넘겨준다.

    @RequestMapping(value = "/board5ReplyDelete")
    public String board5ReplyDelete(HttpServletRequest request, BoardReplyVO boardReplyInfo) {
       
        boardSvc.deleteBoard5Reply(boardReplyInfo.getReno());

        return "redirect:/board5Read?brdno=" + boardReplyInfo.getBrdno();
    }

Board5Ctr.java

'Java > 게시판 5: 댓글' 카테고리의 다른 글

1. 댓글 시작하기  (1) 2016.05.15
2. 댓글 쓰기  (2) 2016.05.15
4. 댓글 수정  (1) 2016.05.15

수정과 관련된 입력 폼은 앞서 삭제에서 같이 만들었다.

삭제에서는 댓글 번호를 넣어 전달했고

수정에서는 댓글 번호와 댓글 내용을 넣어서 전달한다.

다만, 댓글 쓰기에서 같은 형태의 입력처리를 했기 때문에 충돌을 막기 위해

댓글 쓰기에서는 form1으로 폼 태그의 이름을 부여했고

댓글 수정에서는 form2으로 폼 태그의 이름을 부여했다.

즉, 게시물에 대하여 작성하는 댓글의 댓글내용(rememo)와

수정시 사용하는 댓글내용(rememo)의 컨트롤(HTML Tag) 이름이 동일해도 문제가 생기지 않는 것은

컨트롤들이 속한 폼 이름이 달라서 그런 것이다.

폼 이름이 다르면 각 폼 안의 컨트롤은 이름이 같아도 구별되어 사용된다.

댓글 내용인 rememo은 form1.rememo와 form2.rememo로 다르게 처리한다.


수정 SQL(UPDATE)문은 댓글 쓰기 처리시 같이 작성했다 (updateBoard5Reply). 


따라서 남아 있는 것이 화면 처리이고,

이 화면 처리는 자바 스크립트를 이용하여 다소 복잡하게 구현해야 한다.

사용된 자바 스크립트 함수는 3가지로

수정 버튼을 누르면 수정 폼을 화면에 보여주는 함수(fn_replyUpdate),

수정 후 저장 버튼을 누르면 서버로 전송하는 함수(fn_replyUpdateSave),

수정하나 취소 버튼을 눌러서 입력 폼을 감추는 함수(fn_replyUpdateCancel) 로 구성되어 있다.

var updateReno = updateRememo = null;
function fn_replyUpdate(reno){
    var form = document.form2;
    var reply = document.getElementById("reply"+reno);
    var replyDiv = document.getElementById("replyDiv");
    replyDiv.style.display = "";
   
    if (updateReno) {
        document.body.appendChild(replyDiv);
        var oldReno = document.getElementById("reply"+updateReno);
        oldReno.innerText = updateRememo;
    }
   
    form.reno.value=reno;
    form.rememo.value = reply.innerText;
    reply.innerText ="";
    reply.appendChild(replyDiv);
    updateReno   = reno;
    updateRememo = form.rememo.value;
    form.rememo.focus();
}

function fn_replyUpdateSave(){
    var form = document.form2;
    if (form.rememo.value=="") {
        alert("글 내용을 입력해주세요.");
        form.rememo.focus();
        return;
    }
   
    form.action="board5ReplySave";
    form.submit();   
}

function fn_replyUpdateCancel(){
    var form = document.form2;
    var replyDiv = document.getElementById("replyDiv");
    document.body.appendChild(replyDiv);
    replyDiv.style.display = "none";
   
    var oldReno = document.getElementById("reply"+updateReno);
    oldReno.innerText = updateRememo;
    updateReno = updateRememo = null;
}

BoardRead.jsp


저장 버튼 처리는 댓글 입력 여부만 확인하는 단순한 코드로 작성했다.

수정 폼을 화면에 보여주는 기능과 숨기는 기능은 제법 복잡한 처리를 해야 한다.

자바 스크립트의 document.body, document.form2, document.getElementById,.appendChild 등은 찾아보길 바라고 여기서는 간단하게 넘어간다.


수정 폼을 화면에 보여주는 함수(fn_replyUpdate)는

숨겨져 있는 댓글 입력창(id=replyDiv)을 사용자에게 보여주는 것이 핵심 기능이다.

댓글 입력창을 보여주며 입력박스(rememo)에 기존에 입력한 댓글 내용을 넣어줘야 한다.

댓글 번호를 이용해서 Ajax로 서버에서 댓글 내용을 가져올 수 있지만

여기서는 화면에 출력된 리스트에서 선택한 댓글의 내용을 가져와 넣어준다.

리스트에서 선택한 댓글의 내용을 가져오기 위해

리스트를 생성할 때 각 댓글을 DIV 테그로 생성하고, 댓글번호를 이용하여 이 DIV 테그의 ID("reply"+reno)를 부여하였다.

즉, document.getElementById("reply"+reno)로 사용자가 수정하고자 하는 댓글의 내용을 가져와

입력창의 입력박스에 넣어주는 것이다 (form.rememo.value = reply.innerText;).

댓글 수정 상태에서 취소나 저장을 하지 않고 다른 글을 수정하려고 할 때,

현재 입력하던 내용을 취소하기 위해, 현재 입력하는 댓글 번호를 저장해서 가지고 있어야 한다.

updateReno는 현재 입력하는 댓글 번호로

현재 입력하던 내용을 취소하고 이전 내용을 화면에 출력하는 데 이용한다 (oldReno.innerText = updateRememo).

입력 창을 감추는 함수(fn_replyUpdateCancel)는

수정하던 댓글 내용(updateReno)를 취소하고 입력창(replyDiv)을 화면에서 보이지 않게 처리한다 (display="none”).

그리고 부모를 document.body로 바꾸어 준다.

현재 있는 위치에는 기존 댓글의 내용이 출력되어야 하기 때문에 다른 곳으로 옮겨 주는 것이다.


수정 후 저장 버튼을 누르면 입력한 내용을 서버로 전송(submit)하고,

서버에서는 내용을 데이터베이스에 저장한 후

다시 게시판 글 읽기로 돌아가("redirect:/board5Read?brdno=") 수정된 댓글이 보이게 된다.


이상의 내용에서 자바 스트립트가 조금 복잡해 보일 수 있는데

기본 개념은 입력창을 적절한 위치에 보여주고 숨기는 것이니 잘 익혀두길 바라고

여기서는 자바 스트립트로만 구성했지만

실제로는 JQuery를 이용하는 것이 조금 더 깔끔하고 쉬울 수 있다.

직접 JQuery로 변환해 보는 것도 좋을 것이고 차후에 변환할 예정이다.


'Java > 게시판 5: 댓글' 카테고리의 다른 글

1. 댓글 시작하기  (1) 2016.05.15
2. 댓글 쓰기  (2) 2016.05.15
3. 댓글 리스트 / 삭제  (0) 2016.05.15

+ Recent posts