본문 바로가기
개발입문/SPRING 게시판 만들기

[SPRING] 댓글 화면 처리 및 CRUD

by 양히◡̈ 2022. 10. 13.

이제 웹페이지에서도 댓글이 동작하도록 JavaScript를 이용할 것이다.

​댓글의 스크립트 처리는 따로 js 파일을 만들어 관리하도록 한다.

 

src > main > webapp > resources > js > new JavaScript file 생성 > name: reply.js

 

reply.js는 Reply가 잘 동작하는지를 간단하게 확인하는 용도이다.

다음과 같이 입력한다.

/**
 * 
 */
 
 console.log("Reply module......");
 
 var replyService ={};

reply.js 파일은 게시물 글 읽기 페이지에서 사용하기 위한 것이므로,

WEB-INF > views > board > get.jsp 파일에 추가해야 한다.

<script type="text/javascript" src="/resources/js/reply.js"></script>

 

js파일이 잘 연결되었는지 확인하기 위해 문서가 준비되자마자 콘솔에 찍히도록 로그 코드를 입력한다.

(위치는 $(document).ready(function() 안에!)

console.log(replyService);

 

서버를 구동한 후 리플이 존재하는 게시물로 들어가 본다.

 

아까 475번 게시글에 리플이 있는 것을 확인했으므로, 475번 게시물의 조회 페이지를 들어가볼 것이다.

주소창에 http://localhost:9091/board/get?bno=475 라고 입력한다.

게시물 조회 화면에 들어왔으면 F12를 눌러 개발자모드로 들어간 후 console창을 확인해보자.

방금 전에 reply.js에서 만든 내용이 콘솔에 나타나고 있는 것을 볼 수 있다.

 

 

 

JavaScript 모듈화 하기

댓글처리를 페이지에서 하기 위해서 앞으로 Ajax, jQuery 등 여러가지 처리를 섞어 하다보면 유지보수하기 힘들기 때문에, 이런 경우를 대비해 좀 더 JavaScript를 하나의 모듈처럼 구성하는 방식으로 하는 것이 좋다.

JavaScript에서 가장 많이 사용하는 패턴 중 하나는 모듈패턴이며, 관련있는 함수들을 하나의 모듈처럼 묶음으로 구성하는 것을 의미한다.

JavaScrpit의 클로저를 이용하는 대표적인 방법이다.

 

모듈을 구성하려면 JAVA의 클래스처럼 JavaScript를 이용해 메소드를 가지는 객체를 구성한다.

모듈 패턴은 JavaScript의 즉시 실행 함수{ } 를 이용해서 객체를 구성하는 것이다.

//즉시실행함수: 명시하는 것과 동시에 메모리에 등록한다

 

reply.js 를 열어 이제 replyService 부분을 수정해볼 것이다.

 

/**
 * 
 */
 
 console.log("Reply module......");
 
 var replyService = (function() {
 	function add(reply, callback, error) {
 		console.log("add reply......");
 	
 		$.ajax({
 			type: 'post',
 			url: '/replies/new',
 			data: JSON.stringify(reply), //전달받은 객체를 json으로 변환
 			contentType: "application/json; charset=utf-8",
 			success: function(result,status,xhr) {
 				if (callback) {
 					callback(status);
 				}
 			},
 			error: function(xhr,status,er) {
 				if (error) {
 					error(er);
 				}
 			}
 		});
 	}
 	return {
	 	add: add //변수명.호출명 (ex_replyService.add)
 	};
 })();

reply: 댓글 객체

callback: 댓글 등록 후 수행할 메소드

$.ajax는 비동기처리한다는 의미

 

Reference ▼

jQuery.ajax() | jQuery API Documentation

jQuery ajax() Method (w3schools.com)

function add는 주문과 동시에 처리할 내용도 전달한다. 페이지 이동 없이 새로운 내용을 갱신한다.

여기서 즉시실행함수는 'replyService'라는 객체 함수이다.

add( )에서 주의 깊게 봐야 하는 부분은 데이터 전송 타입이 'application/json; charset=utf-8' 방식으로 전송한다는 점과 파라미터로 callbackerror를 함수로 받을 것이라는 점이다.

만일 Ajax 호출이 성공하고, callback 값으로 적절한 함수가 존재한다면 해당 함수를 호출해서 결과를 반영하는 방식이다.

JavaScript는 특이하게도 함수의 파라미터 개수를 일치시킬 필요가 없기 때문에 callback이나 error와 같은 파라미터는 필요에 따라서 작성할 수 있다.

 

get.jsp 에서 방금 작성한 console.log를 지우고 바로 아래에 새로 작성한다.

 

var bnoValue = '<c:out value="${board.bno}"/>';

replyService.add({
    reply: "js test",
    replyer: "tester",
    bno: bnoValue
}, function(result) {
    alert("result: " + result);
}); //게시글을 읽을 때 자동으로 댓글 1개 등록

 

이 댓글 추가 스크립트는 document.ready 함수 안에 구성했으므로, 페이지를 새로고침 할 때마다 추가된다.

replyService는 함수를 담고 있는 변수이다.

reply.js의 replyService 변수 안에 있는 add()가 호출될 것이다.

//함수를 담고있는 변수 replyService의 add함수 호출하면서 replyVO객체(reply,replyer,bno)와 callback함수(fuction(result))를 전달한다.

작성했으면 서버를 구동한 후 새로고침하면 다음과 같이 alert 가 화면에 뜨고 sql developer에서도 댓글이 추가된 것을 확인할 수 있다.

새로고침을 2회 하였기 때문에 같은 댓글이 두 번 추가된 상황

 

 

 

 

 

글읽기 페이지에 댓글창 만들기

이제 댓글을 글읽기 페이지에서 화면에 보이도록 만들 것이다.

 

get.jsp 의 마지막 <div>태그 맨 아래에 코드를 추가한다.

 

<!-- 댓글 목록 시작 -->
<br />
<div class="row">
	<div class="col-lg-12">
		<div class="panel panel-default">
			<div class="panel-heading">
				<i class="fa fa-comments fa-fw"></i>댓글
				<button id="addReplyBtn" class="btn btn-primary btn-xs float-right">새 댓글</button>
			</div>
			<br />
			<div class="panel-body">
				<ul class="chat">
					<li>댓글 예시</li>
				</ul>
			</div>
			<div class="panel-footer"></div>
		</div>
	</div>
</div>
<!-- 댓글 목록 끝 -->

 

글 읽기 페이지에 댓글 부분이 추가되었다.

 

 

 

 

댓글 입력 모달창 만들기

새로운 댓글을 쓸 수 있도록 모달을 이용해 댓글 입력 창을 만들 것이다.
방금 작성한 코드 바로 아래에 이어서 입력한다.

 

<!-- 댓글 입력 모달창 시작 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
	aria-labelledby="exampleModalLabel" aria-hidden="true">
	<div class="modal-dialog">
		<div class="modal-content">
			<div class="modal-header">
				&times;
				<h4 class="modal-title" id="myModalLabel">댓글 창</h4>
			</div>
			<div class="modal-body">
				<div class="form-group">
					<label>댓글</label> <input class="form-control" name="reply"
						value="새 댓글">
				</div>
				<div class="form-group">
					<label>작성자</label> <input class="form-control" name="replyer"
						value="replyer">
				</div>
				<div class="form-group">
					<label>댓글 작성일</label> <input class="form-control" name="replyDate"
						value="">
				</div>
			</div>
			<div class="modal-footer">
				<button id="modalModBtn" type="button" class="btn btnwarning">수정</button>
				<button id="modalRemoveBtn" type="button" class="btn btndanger">삭제</button>
				<button id="modalRegisterBtn" type="button" class="btn btnprimary">등록</button>
				<button id="modalCloseBtn" type="button" class="btn btndefault">닫기</button>
			</div>
		</div>
	</div>
</div>
<!-- 댓글 입력 모달창 끝 -->

기존에는 테스트를 위해 새로고침을 할 때마다 게시글을 읽을 때 자동으로 댓글 1개를 등록하는 스크립트를 만들었지만,

이제는 화면에서 댓글 등록 창을 통해 입력하고, 등록 완료한 댓글이 삽입되어야 하므로 기존 replyService.add 부분은 지우고 새로 코드를 추가한다.

var modal = $("#myModal"); //댓글용 모달
var modalInputReplyDate = modal.find("input[name='replyDate']"); //댓글 작성일
var modalRegisterBtn = $("#modalRegisterBtn"); //모달에서 표시되는 댓글쓰기 버튼
var modalInputReply = modal.find("input[name='reply']"); //댓글 내용
var modalInputReplyer = modal.find("input[name='replyer']"); //댓글 작성자

//새 댓글 입력 모달 표시하기
$("#addReplyBtn").on("click", function(e) {
    modal.find("input").val(""); //모달의 모든 입력창을 초기화
    modalInputReplyDate.closest("div").hide(); //closest: 선택요소와 가장 가까운 요소를 지정해서 숨김(=날짜창)
    modal.find("button[id != 'modalCloseBtn']").hide(); //모달창 버튼 중 닫기 버튼을 제외하고 숨김
    modalRegisterBtn.show(); //등록 버튼 보이기
    $("#myModal").modal("show"); //모달 표시
});

 

더보기

*** 여기서 서버 구동이 잘 되지 않는 오류가 발생했다. footer.jsp에 들어있는 스크립트가 header.jsp에서 읽을 수 없는 문제이다.

 

모달창이 동작하지 않는 오류 메세지

 

footer.jsp 아래에 있는 스크립트 부분을 header.jsp의 스크립트에 옮긴다.

 

이렇게 하면 오류가 해결된다.

 

서버를 재구동하고 아무 게시글에 들어가 [새 댓글]버튼을 누르면, 위와 같이 모달창이 뜨는 것을 볼 수 있다.

 

 

 

 

댓글 등록 처리

이제 댓글 모달창에서 등록버튼과 닫기버튼에 이벤트처리를 할 것이다.

get.jsp에 스크립트를 추가한다.

//모달창 닫기
$("#modalCloseBtn").on("click", function(e) {
    modal.modal("hide");
});
//댓글 쓰기
modalRegisterBtn.on("click", function(e) {
    var reply = {
            reply : modalInputReply.val(),
            replyer : modalInputReplyer.val(),
            bno : bnoValue
    };
    replyService.add(reply, function(result) {
        alert(result);	//ajax처리 후 결과 리턴
        modal.find("input").val(""); //모달창 초기화
        modal.modal("hide");
    });
});

* .val() 함수 : jQuery / Method / .val() – 양식(form)의 값을 가져오거나 값을 설정하는 메소드 – CODING FACTORY

새로고침 후 새댓글 버튼을 눌러 댓글을 작성해보면 success 모달창이 뜨고 sql developer에서 추가된 것을 볼 수 있다.

 

 
 
 
 

콘솔에 댓글 목록 띄우기

댓글이 등록은 되었지만 댓글 목록에 표시가 되지 않고 있다. 이 부분을 처리해볼 것이다.
방금 작성한 댓글 쓰기 script 아래에 추가한다.

//댓글 목록 콘솔에 보이기
replyService.getList({
    bno : bnoValue,
    page : 1
}, function(list) {
    for (var i=0, len = list.length || 0; i < len; i++) {
        console.log(list[i]);
    }	
});

 

reply.js의 return 위에 함수를 추가로 만든다.

//댓글 목록 가져오기
function getList(param, callback, error) {
    console.log("getList......");
    var bno = param.bno;
    var page = param.page || 1; //페이지번호가 있으면 페이지번호, 없으면 1을 전달 	
    $.getJSON("/replies/pages/" + bno + "/" + page,
        function(data) {
            if (callback) {
                callback(data);
            }
        }).fail(function(xhr, status, err) {
            //xhr: xml http request의 약자. 현재는 사용되지 않고, 형식만 맞춰줌
            if (error) {
                error(er);
            }
    });
}

 

그리고 return { } 안에도 getList를 추가한다.

return {
    add: add, //변수명.호출명 (ex_replyService.add)
    getList: getList
};

 

이제 console 창에서 리플을 확인할 수 있게 되었다.

 

 

 

 

댓글 목록 화면 처리

콘솔에서 확인되는 댓글 목록을 이제 화면에서도 보여지도록 구현해볼 것이다.

get.jsp의 기존에 콘솔에 댓글목록을 보이게 만들었던 스크립트를 주석 처리한 후 아래에 작성한다.

 

/* 		//댓글 목록 콘솔에 보이기
 replyService.getList({
    bno: bnoValue,
    page: 1
}, function(list){
    for (var i=0, len = list.length || 0; i < len; i++) {
        console.log(list[i]);
    }		
}); */

var replyUL = $(".chat");
function showList(page) {
    replyService.getList({
        bno: bnoValue,
        page: page || 1
    },
    function (list) {
        var str="";
        if (list == null || list.length == 0) {
            replyUL.html("");
            return;					
        }
        for (var i=0, len=list.length||0; i<len; i++) {
            str+= "<li class='left ";
            str+= "clearfix' data-rno='";
            str+= list[i].rno+"'>";
            str+= "<div><div class='header' ";
            str+= "><strong class='";
            str+= "primary-font'>";
            str+= list[i].replyer + "</strong>";
            str+= "<small class='float-sm-right '>";
            str+= list[i].replyDate + "</small></div>";
            str+= "<p>" + list[i].reply;
            str+= "</p></div></li>";
        }
        replyUL.html(str);
    });
}
showList(1);

 

 

페이지 하단에 댓글 목록이 나온다.

 

 

 

 

댓글목록 시간 표시 변경

사진처럼 댓글 목록에 시간이 순수한 숫자로 표현이 되고 있다. (JSON이나 XML 처리시 발생하는 현상)

화면에서는 날짜 포맷을 변경하여 표시되도록 수정해야 한다.

 

24시간 이내에 작성된 댓글은 '시:분:초'로 표시하고, 24시간이 초과한 댓글은 '연/월/일'로 표시되도록 구현할 것이다.

 

reply.js 에 펑션을 추가한다.

//댓글 시간 표시
function displayTime(timeValue) {
    var today = new Date();
    var gap = today.getTime() - timeValue;
    var dateObj = new Date(timeValue);
    var str = "";

    if (gap < (1000*60*60*24)) {
    //시간의 차이가 24시간 미만이라면
        var hh = dateObj.getHours();
        var mi = dateObj.getMinutes();
        var ss = dateObj.getSeconds();

        return [ (hh>9?'':'0')+hh, ':', (mi>9?'':'0')+mi, ':', (ss>9?'':'0')+ss ].join('');
        //배열 요소를 문자열로 변환. 시간에 포맷을 맞추기 위해서 0~9까지는 앞에 0을 추가로 표시
    }
    else {
        var yy = dateObj.getFullYear();
        var mm = dateObj.getMonth() + 1;
        var dd = dateObj.getDate();

        return [ yy, '/', (mm>9?'':'0')+mm, '/', (dd>9?'':'0')+dd ].join('');
    }
}
 

 

return { } 안에도 displayTime을 추가한다.

return {
    add: add,
    getList: getList,
    displayTime: displayTime
};

 

displayTime( )은 Ajax에서 데이터를 가져와서 HTML을 만들어 주는 부분에 'replyService.displayTime(list[i].replyDate)'의 형태로 적용하도록 한다.

get.jsp 에서 시간을 표시하는 부분을 수정한다.

str += replyService.displayTime(list[i].replyDate) + "</small></div>";

 

 

댓글의 시간 표시가 바뀌었다.

24시간이 넘은 댓글은 날짜로, 넘어가지 않은 댓글은 시간으로 표시된다.

 

 

 

 

 

 

 

 

특정 댓글 클릭 이벤트(댓글 읽기)

특정 댓글을 클릭했을 때 해당 댓글의 상세페이지를 모달로 띄울 것이다.

 

DOM에서 이벤트 리스너를 등록하는 것은 반드시 해당 DOM 요소가 존재해야 한다.

위와 같이 동적으로 Ajax를 통해서 태그들이 만들어지면 이후에 이벤트를 등록해야 하기 때문에,

일반적인 방식이 아니라 '이벤트 위임(delegation)'의 형태로 작성해야 한다.

 

'이벤트 위임'은 이벤트를 동적으로 생성되는 요소가 아닌

이미 존재하는 요소에 이벤트를 걸어주고, 나중에 이벤트의 대상을 변경해 주는 방식이다.

jQuery는 on()을 이용해서 쉽게 처리할 수 있다.

 

 

reply.js 에 펑션을 추가한다.

 

//댓글 읽기 처리
function get(rno, callback, error) {
    $.get("/replies/" + rno, function(result) {
            if (callback) {
                callback(result);
            }
        }).fail(function(xhr, status, err) {
            if (error) {
                error(er);
            }
    });
}

 

마찬가지로 return { } 에도 추가한다.

return {
    add: add,
    getList: getList,
    displayTime: displayTime,
    get: get
};

 

 

 

이제 get 메소드를 호출할 것이다.

get.jsp를 열어 <script>에 추가한다.

var modalModBtn = $("#modalModBtn");
var modalRemoveBtn = $("#modalRemoveBtn");

//특정 댓글 이벤트 처리
$(".chat").on("click", "li", function(e) {
    //클래스 chat을 클릭하는데 하위요소가 li라면
    var rno = $(this).data("rno");
    console.log(rno);

    replyService.get(rno, function(reply) {
        modalInputReply.val(reply.reply);
        modalInputReplyer.val(reply.replyer);
        modalInputReplyDate.val(replyService.displayTime(reply.replyDate))
        .attr("readonly","readonly");
        //댓글 목록 값들을 모달창에 할당
        modal.data("rno", reply.rno);
        modal.find("button[id != 'modalCloseBtn']").hide();
        modalModBtn.show();
        modalRemoveBtn.show();
        $("#myModal").modal("show");
    });
});

 

 

 

댓글 목록에서 댓글을 클릭하면 위와 같은 댓글창이 모달로 띄워진다.

 

 

 

 

 

새 댓글 바로 반영하기

현재는 댓글 작성 후에 목록이 새로고침을 해야만 새 댓글이 목록에 보여지고 있기 때문에 이 부분을 수정할 것이다.

get.jsp 에서 //댓글 쓰기 부분을 찾아 다음과 같이 수정한다.

showList(1); //댓글 실시간 반영하기

 

 

 

 

 

 

댓글 수정 버튼 이벤트

댓글 확인 창에서 수정 버튼에 이벤트처리를 할 것이다.

reply.js 에 추가한다.

 

//댓글 수정처리
function update(reply, callback, error) {
    console.log("rno: " + reply.rno);
    $.ajax({
        type : 'put',
        url : '/replies/' + reply.rno,
        data : JSON.stringify(reply),
        contentType : "application/json;charset=utf-8",
        success : function(result, status, xhr) {
            if (callback) {
                callback(result);
            }
        },
        error : function(xhr, status, er) {
            if (error) {
                error(er);
            }
        }
    });
}

 

마찬가지로 return { } 에 update를 추가한다.

return {
    ...
    update: update
};

 

 

get.jsp 에 스크립트를 추가한다.

//댓글 수정 처리
modalModBtn.on("click", function(e) {
    var reply = {
            rno: modal.data("rno"),
            reply: modalInputReply.val()
    };
    replyService.update(reply, function(result) {
        alert(result);
        modal.modal("hide");
        showList(-1);
    });
});

 

 

댓글을 수정하면 완료메세지와 함께 수정이 반영된다.

 

 

 

 

댓글 삭제 버튼 이벤트

같은 절차로 삭제도 구현할 것이다.

reply.js 에 추가한다.

 

//댓글 삭제처리
function remove(rno, callback, error) {
    $.ajax({
        type : 'delete',
        url : '/replies/' + rno,
        success : function(deleteResult, status, xhr) {
            if (callback) {
                callback(deleteResult);
            }
        },
        error : function(xhr, status, er) {
            if (error) {
                error(er);
            }	
        }
    });
}

 

마찬가지로 return { } 에 update를 추가한다.

return {
    ...
    remove: remove
};

 

get.jsp 스크립트에 추가한다.

//댓글 삭제 처리
modalRemoveBtn.on("click", function(e) {
    var rno = modal.data("rno");
    replyService.remove(rno, function(result) {
        alert(result);
        modal.modal("hide");
        showList(-1);
    });
});

 

댓글을 클릭한 후 확인 창에서 삭제 버튼을 누르면, success 메세지와 함께 정상적으로 삭제된 것을 볼 수 있다.

 

 

댓글