ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Camel][Spring] 게시판 만들기 #7-2. 댓글처리 구현 (댓글 등록, 수정, 삭제)
    Spring/게시판 만들기 2020. 6. 27. 19:19

    [Camel][Spring] 게시판 만들기 #7-2. 댓글처리 구현 (댓글 등록, 수정, 삭제)

     

    본 게시판 만들기 프로젝트는 더블에스 Devlog Spring-MVC 를 참조하여 작성했음을 알려드립니다. 또한 개인적인 학습을 목적으로한 포스팅이기 때문에 완벽하지 않을 수 있음을 알려드립니다. 문제점이나 궁금한점은 댓글로 남겨주시면 감사하겠습니다. 프로젝트 생성에 앞서 이번 게시판 만들기 프로젝트는 이클립스를 사용하여 구현하였습니다. 

     

    이번 포스팅에서는 이전 포스팅에서 구성했던 댓글 관련 계층들을 토대로 댓글처리가 정상적으로 작동하는지 테스트해 보겠습니다. 

     

    1. 댓글처리 테스트 

    1-1. 테스트 컨트롤러 작성

    댓글처리를 테스트하기 위해 테스트 페이지를 매핑하기위한 ReplyTestController를 생성해줍니다. 

    package com.cameldev.mypage.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/reply")
    public class ReplyTestController {
    
        @RequestMapping("/test")
        public String replyAjaxTest() {
            return "/reply/reply_test";
        }
    
    }

     

    1-2. 테스트 페이지 작성

    /WEB-INF/views/reply 디렉토리에 reply_test.jsp를 기존의 페이지들과 같이 생성하고, Main content 영역에 구현할 내용을 아래와 같이 작성해줍니다. 

    <div class="col-lg-12">
        <div class="card">
            <div class="card-header with-border">
                <h3 class="card-title">댓글 작성</h3>
            </div>
            <div class="card-body">
                <div class="row">
                <div class="form-group col-sm-8">
                <input class="form-control input-sm" id="newReplyText"
                type="text" placeholder="댓글 입력...">
                </div>
                <div class="form-group col-sm-2">
                <input class="form-control input-sm" id="newReplyWriter" type="text" placeholder="작성자">
    			</div>
    			<div class="form-group col-sm-2">
    			<button type="button" class="btn btn-primary btn-sm btn-block replyAddBtn">
    			<i class="fa fa-save"></i> 저장
    			</button>
    		</div>
    		</div>	
            </div>
            <div class="card-footer">
                <ul id="replies">
    
                </ul>
            </div>
            <div class="card-footer">
    		<nav aria-label="Contacts Page Navigation">
                    <ul class="pagination pagination-sm no-margin justify-content-center m-0">
    
                    </ul>
                </nav>
            </div>
        </div>
      </div>
    
      <div class="modal fade" id="modifyModal" role="dialog">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">댓글 수정창</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="reply_no">댓글 번호</label>
                        <input class="form-control" id="reply_no" name="reply_no" readonly>
                    </div>
                    <div class="form-group">
                        <label for="reply_text">댓글 내용</label>
                        <input class="form-control" id="reply_text" name="reply_text" placeholder="댓글 내용을 입력해주세요">
                    </div>
                    <div class="form-group">
                        <label for="reply_writer">댓글 작성자</label>
                        <input class="form-control" id="reply_writer" name="reply_writer" readonly>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default pull-left" data-dismiss="modal">닫기</button>
                    <button type="button" class="btn btn-success modalModBtn">수정</button>
                    <button type="button" class="btn btn-danger modalDelBtn">삭제</button>
                </div>
            </div>
        </div>
      </div>

     

    2. 댓글 목록 출력

    위에서 댓글 목록을 출력하기 위한 페이지를 만들었다면 이제 댓글 목록을 출력하기 위한 부분을 구현해야합니다. 그래서 댓글 목록을 출력하기 위한 함수를 정의하고, 그 내부에는 getJSON 메소드를 사용해서 댓글 목록 객체를 JSON형식으로 받아오겠습니다. 

     getJSON 메소드를 사용해 받아온 객체는 each() 메소드를 통해서 <li> 태그를 생성하고, <li> 태그는 댓글 내용과 댓글 작성자를 출력하도록 하였습니다. 

    그러면 이제 아래의 script를 reply_test.jsp에 추가해주겠습니다. 

    // 3번째 게시글
    var article_no = 3;
    
    // 댓글 목록 호출
    getReplies();
    
    // 댓글 목록 출력 함수
    function getReplies() {
    
        $.getJSON("${path}/replies/all/" + article_no, function (data) {
    
            console.log(data);
    
            var str = "";
    
            $(data).each(function () {
                str += "<li data-reply_no='" + this.reply_no + "' class='replyLi'>"
                    +   "<p class='reply_text'>" + this.reply_text + "</p>"
                    +   "<p class='reply_writer'>" + this.reply_writer + "</p>"
                    +   "<button type='button' class='btn btn-xs btn-success' data-toggle='modal' data-target='#modifyModal'>댓글 수정</button>"
                    + "</li>"
                    + "<hr/>";
    
            });
    
            $("#replies").html(str);
    
        });
    
    }

     

    이제 정상적으로 댓글이 출력되나 확인해보겠습니다. 

     

     

    3. 댓글 등록

    댓글 목록을 출력했다면 이번에는 댓글 등록을 구현해보겠습니다. 댓글 내용과 작성자를 입력하고 댓글 저장 버튼을 누를 경우 jQuery를 사용해 화면에 입력된 변수를 처리하고 ajax를 통해 서버를 호출합니다. 전송하는 데이터는 JSON으로 구성된 문자열입니다. 성공적으로 댓글 등록을 했다면 마지막에 댓글목록 출력함수를 호출함으로써 목록을 갱신시켜줍니다. 이를 구현하기위해 아래의 script를 이전에 작석했던 script하단에 붙여넣어 줍니다. 

    $(".replyAddBtn").on("click",function() {
    
        // 화면으로부터 입력 받은 변수값의 처리
        var reply_text = $("#newReplyText");
        var reply_writer = $("#newReplyWriter");
    
        var reply_textVal = reply_text.val();
        var reply_writerrVal = reply_writer.val();
    
        // AJAX 통신 : POST
        $.ajax({
            type : "post",
            url : "${path}/replies",
            headers : {
                "Content-type" : "application/json",
                "X-HTTP-Method-Override" : "POST"
            },
            dataType : "text",
            data : JSON.stringify({
                article_no : article_no,
                reply_text : reply_textVal,
                reply_writer : reply_writerrVal
            }),
            success : function (result) {
                // 성공적인 댓글 등록 처리 알림
                if (result == "regSuccess") {
                    alert("댓글 등록 완료!");
                }
                getReplies(); // 댓글 목록 출력 함수 호출
                reply_text.val(""); // 댓글 내용 초기화
                reply_writer.val(""); // 댓글 작성자 초기화
            }
        });
    });

     

    이제 댓글 등록 처리를 테스트 해보면 정상적으로 등록되고 목록에도 정상적으로 출력되는 것을 확인할 수 있습니다. 

    물론 DB에도 정상적으로 데이터가 입력된 것도 확인할 수 있습니다. 

     

     

    4. 댓글 조회 및 수정 (Modal 영역)

    댓글 목록 출력 함수 내부를 살펴보면 아래와 같은 <button> 태그가 있는 것을 확인할 수 있습니다. 

    <button type='button' class='btn btn-xs btn-success' data-toggle='modal' data-target='#modifyModal'>
      댓글 수정
    </button>

    또한 테스트 페이지를 작성하면서 미리 작성해둔 modal 영역은 댓글 수정과 삭제를 위한 영역입니다. 

    <div class="modal fade" id="modifyModal" role="dialog">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal">&times;</button>
                    <h4 class="modal-title">댓글 수정창</h4>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label for="reply_no">댓글 번호</label>
                        <input class="form-control" id="reply_no" name="reply_no" readonly>
                    </div>
                    <div class="form-group">
                        <label for="reply_text">댓글 내용</label>
                        <input class="form-control" id="reply_text" name="reply_text" placeholder="댓글 내용을 입력해주세요">
                    </div>
                    <div class="form-group">
                        <label for="reply_writer">댓글 작성자</label>
                        <input class="form-control" id="reply_writer" name="reply_writer" readonly>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-default pull-left" data-dismiss="modal">닫기</button>
                    <button type="button" class="btn btn-success modalModBtn">수정</button>
                    <button type="button" class="btn btn-danger modalDelBtn">삭제</button>
                </div>
            </div>
        </div>

     

    이제 본격적으로 조회 및 수정을 구현하기 위해 아래의 script를 기존 script에 추가해줍니다. 

    $("#replies").on("click", ".replyLi button", function () {
        var reply = $(this).parent();
    
        var reply_no = reply.attr("data-reply_no");
        var reply_text = reply.find(".reply_text").text();
        var reply_writer = reply.find(".reply_writer").text();
    
        $("#reply_no").val(reply_no);
        $("#reply_text").val(reply_text);
        $("#reply_writer").val(reply_writer);
    
    });

    위의 script를 추가한 뒤 댓글수정 버튼을 눌러보면 아래와 같은 Modal 창을 확인할 수 있습니다. Modal 창에는 해당 댓글의 번호, 댓글 내용, 댓글 작성자가 출력되는 것을 확인할 수 있습니다. 

     

     

    4. 댓글 삭제

    댓글 수정을 위해 띄워줬던 Modal 창을 확인하면 삭제 버튼이 있는 것을 확인할 수 있습니다. 삭제 버튼을 클릭하면 댓글의 삭제처리를 구현해 보도록하겠습니다. 

     

    우선 jQuery를 사용해 댓글번호를 처리한 후 ajax를 통해 서버를 호출합니다. 댓글이 정상적으로 삭제되었다면 삭제 완료를 알려주고 Modal 창을 닫으며 마지막으로 댓글 목록을 갱신시켜 주겠습니다. 

     

    댓글 삭제 처리을 위해 아래의 script를 기존 script에 추가합니다. 

    $(".modalDelBtn").on("click", function () {
    
        // 댓글 번호
        var reply_no = $(this).parent().parent().find("#reply_no").val();
    
        // AJAX통신 : DELETE
        $.ajax({
            type : "delete",
            url : "${path}/replies/" + reply_no,
            headers : {
                "Content-type" : "application/json",
                "X-HTTP-Method-Override" : "DELETE"
            },
            dataType : "text",
            success : function (result) {
                console.log("result : " + result);
                if (result == "delSuccess") {
                    alert("댓글 삭제 완료!");
                    $("#modifyModal").modal("hide"); // Modal 닫기
                    getReplies(); // 댓글 목록 갱신
                }
            }
        });
    
    });

     

     

    5. 댓글 수정

    댓글 수정 처리을 위해 아래의 script를 기존 script에 추가합니다. 

    $(".modalModBtn").on("click", function () {
    
        // 댓글 선택자
        var reply = $(this).parent().parent();
        // 댓글번호
        var reply_no = reply.find("#reply_no").val();
        // 수정한 댓글내용
        var reply_text = reply.find("#reply_text").val();
    
        // AJAX통신 : PUT
        $.ajax({
            type : "put",
            url : "${path}/replies/" + reply_no,
            headers : {
                "Content-type" : "application/json",
                "X-HTTP-Method-Override" : "PUT"
            },
            data : JSON.stringify(
                {reply_text : reply_text}
            ),
            dataType : "text",
            success : function (result) {
                console.log("result : " + result);
                if (result == "modSuccess") {
                    alert("댓글 수정 완료!");
                    $("#modifyModal").modal("hide"); // Modal 닫기
                    getReplies(); // 댓글 목록 갱신
                }
            }
        });
    
    });

    수정 처리 역시 jQuery를 사용해 댓글번호와 댓글 내용을 처리한 후 ajax를 통해 서버를 호출합니다. 댓글이 정상적으로 수정되었다면 수정완료를 알려주고 Modal 창을 닫으며 삭제처리와 마찬가지로 마지막으로 댓글 목록을 갱신시켜 주는 것을 확인할 수 있습니다. 

     

     

    6. 댓글 목록 페이징

     페이징 처리된 댓글 목록을 출력하기 위한 함수 getRepliesPaging()와 댓글 목록 페이지 번호를 출력하기 위한 함수 printPageNumbers()를 선언하고, 아래와 같이 작성해주겠습니다. 그리고 이전에 댓글 목록 출력을 위해 사용했던 함순인 getReplies()함수들을 getRepliesPaging()로 변경해주겠습니다. 댓글 처리 테스트 부분의 마지막이기에 reply_test.jsp 페이지의 전체 script 코드를 확인하시길 바랍니다. 

     

    $(document).ready(function () {
    
    	// 3번째 게시글
    	var article_no = 3;
    	
        // 목록페이지 번호 변수 선언, 1로 초기화(첫번째 페이지)
    	var replyPageNum = 1;
        
    	// 댓글 목록 호출
    	getRepliesPaging(replyPageNum);
    
    	// 댓글 목록 출력 함수
    	function getReplies() {
    
    	    $.getJSON("${path}/replies/all/" + article_no, function (data) {
    
    	        console.log(data);
    
    	        var str = "";
    
    	        $(data).each(function () {
    	            str += "<li data-reply_no='" + this.reply_no + "' class='replyLi'>"
    	                +   "<p class='reply_text'>" + this.reply_text + "</p>"
    	                +   "<p class='reply_writer'>" + this.reply_writer + "</p>"
    	                +   "<button type='button' class='btn btn-xs btn-success' data-toggle='modal' data-target='#modifyModal'>댓글 수정</button>"
    	                + "</li>"
    	                + "<hr/>";
    
    	        });
    
    	        $("#replies").html(str);
    
    	    });
    
    	}
    	
    	$(".replyAddBtn").on("click",function() {
    
    	    // 화면으로부터 입력 받은 변수값의 처리
    	    var reply_text = $("#newReplyText");
    	    var reply_writer = $("#newReplyWriter");
    
    	    var reply_textVal = reply_text.val();
    	    var reply_writerrVal = reply_writer.val();
    	    console.log("1212121212");
    	    // AJAX 통신 : POST
    	    $.ajax({
    	        type : "post",
    	        url : "${path}/replies",
    	        headers : {
    	            "Content-type" : "application/json",
    	            "X-HTTP-Method-Override" : "POST"
    	        },
    	        dataType : "text",
    	        data : JSON.stringify({
    	            article_no : article_no,
    	            reply_text : reply_textVal,
    	            reply_writer : reply_writerrVal
    	        }),
    	        success : function (result) {
    	            // 성공적인 댓글 등록 처리 알림
    	            if (result == "regSuccess") {
    	                alert("댓글 등록 완료!");
    	            }
    	            getRepliesPaging(replyPageNum); // 댓글 목록 출력 함수 호출
    	            reply_text.val(""); // 댓글 내용 초기화
    	            reply_writer.val(""); // 댓글 작성자 초기화
    	        }
    	    });
    	});
    	
    	$("#replies").on("click", ".replyLi button", function () {
    	    var reply = $(this).parent();
    
    	    var reply_no = reply.attr("data-reply_no");
    	    var reply_text = reply.find(".reply_text").text();
    	    var reply_writer = reply.find(".reply_writer").text();
    
    	    $("#reply_no").val(reply_no);
    	    $("#reply_text").val(reply_text);
    	    $("#reply_writer").val(reply_writer);
    
    	});
    	
    	$(".modalDelBtn").on("click", function () {
    
    	    // 댓글 번호
    	    var reply_no = $(this).parent().parent().find("#reply_no").val();
    
    	    // AJAX통신 : DELETE
    	    $.ajax({
    	        type : "delete",
    	        url : "${path}/replies/" + reply_no,
    	        headers : {
    	            "Content-type" : "application/json",
    	            "X-HTTP-Method-Override" : "DELETE"
    	        },
    	        dataType : "text",
    	        success : function (result) {
    	            console.log("result : " + result);
    	            if (result == "delSuccess") {
    	                alert("댓글 삭제 완료!");
    	                $("#modifyModal").modal("hide"); // Modal 닫기
    	                getRepliesPaging(replyPageNum); // 댓글 목록 갱신
    	            }
    	        }
    	    });
    
    	});
    	
    	$(".modalModBtn").on("click", function () {
    
    	    // 댓글 선택자
    	    var reply = $(this).parent().parent();
    	    // 댓글번호
    	    var reply_no = reply.find("#reply_no").val();
    	    // 수정한 댓글내용
    	    var reply_text = reply.find("#reply_text").val();
    
    	    // AJAX통신 : PUT
    	    $.ajax({
    	        type : "put",
    	        url : "${path}/replies/" + reply_no,
    	        headers : {
    	            "Content-type" : "application/json",
    	            "X-HTTP-Method-Override" : "PUT"
    	        },
    	        data : JSON.stringify(
    	            {reply_text : reply_text}
    	        ),
    	        dataType : "text",
    	        success : function (result) {
    	            console.log("result : " + result);
    	            if (result == "modSuccess") {
    	                alert("댓글 수정 완료!");
    	                $("#modifyModal").modal("hide"); // Modal 닫기
    	                getRepliesPaging(replyPageNum); // 댓글 목록 갱신
    	            }
    	        }
    	    });
    
    	});
    	
    	function getRepliesPaging(page) {
    
    	    $.getJSON("${path}/replies/" + article_no + "/" + page, function (data) {
    	        console.log(data);
    
    	        var str = "";
    
    	        $(data.replies).each(function () {
    	            str += "<li data-reply_no='" + this.reply_no + "' class='replyLi'>"
    	                +  "<p class='reply_text'>" + this.reply_text + "</p>"
    	                +  "<p class='reply_writer'>" + this.reply_writer + "</p>"
    	                +  "<button type='button' class='btn btn-xs btn-success' data-toggle='modal' data-target='#modifyModal'>댓글 수정</button>"
    	                +  "</li>"
    	                +  "<hr/>";
    	        });
    
    	        $("#replies").html(str);
    
    	        // 페이지 번호 출력 호출
    	        printPageNumbers(data.pageMaker);
    
    	    });
    
    	}
    
    	// 댓글 목록 페이지 번호 출력 함수
    	function printPageNumbers(pageMaker) {
    
    	    var str = "";
    
    	    // 이전 버튼 활성화
    	    if (pageMaker.prev) {
    	        str += "<li class=\"page-item\"><a class=\"page-link\" href='"+(pageMaker.startPage-1)+"'>이전</a></li>";
    	    }
    
    	    // 페이지 번호
    	    for (var i = pageMaker.startPage, len = pageMaker.endPage; i <= len; i++) {
    	        var strCalss = pageMaker.criteria.page == i ? 'class=active' : '';
    	        str += "<li class=\"page-item\" "+strCalss+"><a class=\"page-link\" href='"+i+"'>"+i+"</a></li>";
    	    }
    
    	    // 다음 버튼 활성화
    	    if (pageMaker.next) {
    	        str += "<li class=\"page-item\"><a class=\"page-link\" href='"+(pageMaker.endPage + 1)+"'>다음</a></li>";
    	    }
    
    	    $(".pagination-sm").html(str);
    	}
    	
    	
    
    	// 목록페이지 번호 클릭 이벤트
    	$(".pagination").on("click", "li a", function (event) {
    
    	    event.preventDefault();
    	    replyPageNum = $(this).attr("href"); // 목록 페이지 번호 추출
    	    getRepliesPaging(replyPageNum); // 목록 페이지 호출
    
    	});
    
    });

     

     

    6. 포스팅을 마치며 

    이번 포스팅에서는 댓글 등록, 수정, 삭제 처리 그리고 페이징 처리에 대해 테스트를 진행해 보았습니다. 다음 포스팅에서는 지금 까지 테스트해온 댓글처리를 게시물에 적용시켜보겠습니다. 

     

    다음 포스팅 

    2020/06/28 - [Spring/게시판 만들기] - [Camel][Spring] 게시판 만들기 #7-3. 댓글처리 구현 (게시물 적용)

     

    [Camel][Spring] 게시판 만들기 #7-3. 댓글처리 구현 (게시물 적용)

    [Camel][Spring] 게시판 만들기 #7-3. 댓글처리 구현 (게시물 적용) 본 게시판 만들기 프로젝트는 더블에스 Devlog Spring-MVC 를 참조하여 작성했음을 알려드립니다. 또한 개인적인 학습을 목적으로한 포

    cameldev.tistory.com

     

     

    글을 읽으시면서 잘못된 부분이나 궁금하신 사항은 댓글 달아주시면 빠른 시일내에 수정 및 답변하도록 하겠습니다. 

    댓글

Camel`s Tistory.