댓글창 구현해보기

꿈꾸는하늘·2024년 3월 24일

JSP

목록 보기
14/25

* Ajax란?

Ajax는 Asynchronous JavaScript and XML의 약자로, 말 그대로 JavaScript와 XML을 이용한 비동기적 정보 교환 기법이다. 다만 요즘은 XML보다는 JSON을 주로 사용한다고 한다.

브라우저의 XMLHttpRequest를 이용해 전체 페이지를 새로 가져오지 않고도 페이지 일부만을 변경할 수 있도록 javascript를 실행해 서버에 데이터만을 별도로 요청하는 기법이다.

HTTP 프로토콜을 이용한 비동기 통신이며 브라우저는 정적 HTML 파일과 CSS파일, 데이터를 어떻게 요청하면 되는지를 설명한 javascript를 통해 HTML,CSS를 이용해 골격을 먼저 형성하고 ajax 실행 부가 담긴 javascript 영역을 실행하여 데이터를 별도로 가져와 적절한 방법으로 데이터를 끼워 넣은 후 페이지를 로딩한다.

나는 jQuery를 이용한 Ajax 통신을 배웠기 때문에 코드도 jQuery를 이용하여 작성하였다.

기본적인 Ajax 코드는 아래와 같다.

$.ajax({
  type:'POST',       // 요청 메서드
  url: './comment?',  // 요청 URI
  data : { bno:bno , comment:comment } ,// 전달 데이터
  success : function(result){ // 요청이 성공일 때 실행되는 이벤트
      함수명
  },
  error: function(request, status, error){
	  alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error) } // 에러가 발생했을 때, 호출될 함수
  }); // $.ajax()

주석 달아놓은 것처럼 type에는 요청 메서드(GET, POST, PATCH, DELETE 중 1),
url에는 요청하고자하는 URI, 데이터에는 key:value 값을 작성해주면 되는데 get 방식이라면 url에 쿼리스트링으로 해당 값을 직접 입력해줘도 된다.
success/error에는 해당 요청이 성공/실패했을 때 실행하고자 하는 함수명을 작성해도 되고, 직접 코드를 작성해도 된다.

  • GET : 데이터를 읽거나 검색할 때 주로 사용되는 메서드
  • POST : 새로운 리소스를 생성할 때 주로 사용되는 메서드
  • PATCH : 리소스를 생성/업데이트 할 때 주로 사용되는 메서드
  • DELETE : 지정된 리소스를 삭제할 때 주로 사용되는 메서드
    여기서 PATCH와 DELETE의 경우에는 type 자체를 'PATCH', 'DELETE'로 줄 수 없으므로 get방식이라면 쿼리스트링에 mode를 작성해주거나 POST방식이라면 data에 mode의 key:value 값을 작성해주어야 메서드가 제대로 호출된다.(아래 코드 참고)

아래는 직접 작성해본 Comment.jsp 코드와 CommentController.java 코드이다.

  • Comment.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<style>
.clist {
	width: 800px;
}

#commentList {
	display: flex;
}

#sendBtn, .btn-default {
	width:70px;
	height: 35px;
	border:1px solid #d3d3d3;
	background-color:#fff;
	margin-left: 10px;
}

.commentAll {
	display: flex;
	flex-direction: column;
	width: 80%;
	margin-right: auto;
	margin-left: auto;
}

.send {
	display: flex;
	width:100%;
	margin:10px;
	align-items: center;
}

.commentAll input[type='text'], .form-control{
	height:30px;
	display:inline-block;
}
.mod {
	width: 800px;
	display: flex;
	justify-content: center;
	align-items: center;
}

#recomment {
	width: 700px;
}

#comment {
	width: 700px;
}

.clist li{
	height:30px;
	margin-top:10px;
	line-height:30px;
	font-size:15px;
	list-style-type:none;
}
.commentAll h2{
	margin:10px;
}

.clist button  {
	width:40px;
	height: 35px;
	border:1px solid #d3d3d3;
	background-color:#fff;
	margin-left: 10px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>

<body>
	<div class="commentAll">
		<h2>댓글</h2>
		<div class="send">
			<input class="form-control" type="text" name="comment" id="comment">
			<button class="btn btn-default" id="sendBtn" type="button">등록</button>
		</div>
		<div class="mod"></div>
		<h2>서버로부터 온 데이터</h2>
		<div id="commentList"></div>
	</div>

	<script>
	let bno= "${param.num}";
	//let bno=${param.num}으로 큰따옴표("")없이 감싸줄 경우 값이 없을때는 let bno=;로 되기때문에 오류가 남. 그러므로 반드시 문자열처럼 감싸줘야함
	
	let mode = false;
	
	let showList= function(bno){
		console.log(bno);
		let comment = $('input[name=comment]').val("");
		
        $.ajax({
            type:'GET',       // 요청 메서드
            url: './comment?bno='+bno,  // 요청 URI
            success : function(result){
				$("#commentList").html(toHtml(result));
            },
            error: function(request, status, error){ alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error) } // 에러가 발생했을 때, 호출될 함수
        }); // $.ajax()
        
	}
	
	// 문서가 로드가 되었을 때 실행되는 함수 - main함수와 동일한 역할로 생각
	$(document).ready(function(){
			showList(bno);
		    $("#sendBtn").click(function(){
		    	let comment = $('input[name=comment]').val();
		    	if(comment.trim()==''){
		    		alert("입력해주세요");
		    		return;
		    	}
		        $.ajax({
		            type:'POST',       // 요청 메서드
		            url: './comment?',  // 요청 URI
		            data : { bno:bno , comment:comment } ,// 전달 데이터
		            success : function(result){ // 요청이 성공일 때 실행되는 이벤트
		            	showList(bno);
		            	$("#cmt").text(" / 댓글 수 : "+result.res) //조회수 1 증가하지 않음
		            	//(위와 동일하나 윈도우를 새로고침하기 때문에 조회수도 1 증가함)$("#cmtTxt").load(window.location.href+' #cmtTxt');
		            },
		            error: function(request, status, error){ alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error) } // 에러가 발생했을 때, 호출될 함수
		        }); // $.ajax()
	    	});
	    
			// 각 댓글의 수정 버튼이 눌렀을 경우 
			$("#commentList").on("click", ".modBtnb" , (function(){
		    	let cno = $(this).parent().attr('data-cno');
		    	let bno = $(this).parent().attr('data-bno');
				// 요소 추가 (수정버튼, input)
				$(".mod").append('<input class="form-control" type="text" name="recomment" id="recomment">');
				$(".mod").append('<button class="btn btn-default" id="modBtn" type="button">수정</button>');
				//텍스트 가져오기 (해당 수정글에))	
				$('input[name=recomment]').val($('span.comment', $(this).parent()).text());
				//수정 댓글 번호를 저장하기
			    $("#modBtn").attr('data-cno', cno);
				console.log($('span.comment', $(this).parent()).text());
			}));
			
		   // 등록 아래 수정 버튼을 눌렀을 경우
			$(".mod").on("click", "#modBtn" , (function(){
				let comment = $('input[name=recomment]').val();
		    	if(comment.trim()==''){
		    		alert("입력해주세요");
		    		return;
		    	}
		    	let cno = $("#modBtn").attr('data-cno');
		    	// 수정, input 메서드 보이지 않게 요소 숨김
		    	//제이쿼리 데이터나 이벤트는 삭제되지 않고, 계속 유지 append로 복구 가능
		    	let del = $("#recomment").detach();
		    	let btn = $("#modBtn").detach();
		    	$.ajax({
		            type:'POST',       // 요청 메서드
		            url: './comment',  // 요청 URI
		            data : {cno:cno, comment:comment, mode:"mody"},
		            success :function(result){
		        		showList(bno);
		            },
		            error: function(request, status, error){ alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error) } // 에러가 발생했을 때, 호출될 함수
		             // 에러가 발생했을 때, 호출될 함수
		        }); // $.ajax()
			}));// function()
		
		     
			//삭제 버튼은 동적으로 생성되는 버튼이므로 이벤트를 추가하기에 적합하지 않음
			//$(".delBtn").click(function(){
			//	showList(bno);
			//});
			$("#commentList").on("click", ".delBtn" , (function(){
			    	let cno = $(this).parent().attr('data-cno');	    	
			        $.ajax({
			            type:'GET',       // 요청 메서드
			            url: './comment?cno='+cno+'&bno='+bno+"&mode=delete",  // 요청 URI
			            success : function(result){
			            	showList(bno);
			            	$("#cmt").text(" / 댓글 수 : "+result.res)
			            },
			            error: function(request, status, error){ alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error) } // 에러가 발생했을 때, 호출될 함수
			        }); // $.ajax()
			       // alert("the request is sent")
			}));	
		}); //ready
	
		let toHtml =function(comments){
			console.log(comments)
			let tmp ="<ul class=clist>"
			comments.forEach(function(comment){
				tmp +='<li data-cno='+comment.cno
				tmp +=' data-bno='+comment.bno+'>'
				tmp +='commenter= <span class="commenter"> '+comment.commenter+'</span>'
				tmp +='   comment= <span class="comment"> '+comment.comment+'</span>'
				if(comment.commenter=="${sessionScope.id}"){
					tmp +='<button type = "button" class="delBtn">삭제</button>'
					tmp +='<button type = "button"  class="modBtnb">수정</button>'
				}
				tmp +='</li>'
			})
			return tmp +'</ul>';
		}
	
	</script>
	</body>
</html>
  • CommentController.java
package controller;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import com.mysql.cj.xdevapi.JsonArray;

import dao.BoardDao;
import dao.CommentDao;
import dto.Comment;
@WebServlet ("/comment")
public class CommentController extends HttpServlet{

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String method = req.getParameter("mode");
		if("delete".equals(method)) {
			doDelete(req,resp);
		}else if("mody".equals(method)) {
			doPatch(req,resp);
		}else {
			super.service(req, resp);
		}
	}

	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String bno = req.getParameter("bno");
		CommentDao dao = new CommentDao(req.getServletContext());
		ArrayList<Comment> dtos = dao.selectAll(bno);
		
		JSONArray jArray = new JSONArray();
		for(Comment dto : dtos) {
			JSONObject sobject = new JSONObject();
			sobject.put("cno", dto.getCno());
			sobject.put("bno", dto.getBno());
			sobject.put("comment", dto.getComment());
			sobject.put("commenter", dto.getCommenter());
			sobject.put("regDate", dto.getRegDate()+"");
			
			jArray.add(sobject);
			
		}
		resp.setContentType("application/json; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		out.println(jArray.toJSONString());
		System.out.println(jArray.toJSONString());
		dao.close();
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String bno = req.getParameter("bno");
		String comment = req.getParameter("comment");
		String id = req.getSession().getAttribute("id")+"";
		/* String id = "asdf"; */
		System.out.println("bno: "+bno+" / comment: "+comment+" / id: "+id);
		
		Comment dto = new Comment(bno, comment, id);
		CommentDao dao = new CommentDao(req.getServletContext());
		BoardDao bdao = new BoardDao(req.getServletContext());
		
		int res = dao.insert(dto);
		if(res ==1 ) {
			res = bdao.updateCommentCnt(bno, 1);
		}
		int cnt = dao.count(bno);
		dao.close();
		bdao.close();
		
		resp.setContentType("application/json; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		JSONObject object = new JSONObject();
		if(res==1) {
			object.put("res", cnt+"");
		}else {
			object.put("res", cnt+"");
		}
		out.println(object.toJSONString());
	}

	//삭제
	protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String cno= req.getParameter("cno");
		String bno= req.getParameter("bno");
		String id = req.getSession().getAttribute("id")+"";
		/* String id = "asdf"; */
		
		CommentDao dao = new CommentDao(req.getServletContext());
		BoardDao bdao = new BoardDao(req.getServletContext());
		
		Map<String, String> param = new HashMap<String, String>();
		param.put("cno", cno);
		param.put("commenter", id);
		
		int res = dao.delete(param);
		if(res==1) {
			res = bdao.updateCommentCnt(bno, -1);
			
		}
		int cnt = dao.count(bno); //댓글이 삭제됐을때의 댓글수(-1)를 새로 보여주기위함
		
		resp.setContentType("application/json; charset=UTF-8");
		PrintWriter out = resp.getWriter();
		
		JSONObject object = new JSONObject();
		if(res==1) {
			object.put("res", cnt+""); //삭제됐으면 댓글수가 바뀌고(-1),
		}else {
			object.put("res", cnt+""); //삭제가 안됐으면 댓글수가 안바뀜
		}
		out.println(object.toJSONString());
		
		dao.close();
		bdao.close();
	}
	
	//수정
	protected void doPatch(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String cno = req.getParameter("cno");
		String bno = req.getParameter("bno");
		String comment = req.getParameter("comment");
		String commenter = req.getSession().getAttribute("id")+"";
		/* String commenter = "asdf"; */
		
		Comment dto = new Comment(cno, bno, comment, commenter);
		
		CommentDao dao = new CommentDao(req.getServletContext());
		int res = dao.update(dto);
		
		PrintWriter out = resp.getWriter();
		JSONObject object = new JSONObject();
		if(res==1) {
			object.put("res", "ok");
		}else {
			object.put("res", "no");
		}
		out.println(object.toJSONString());
		
		dao.close();
	}

}

doGet과 doPost는 이미 존재하는 메서드이기 때문에 바로 Override할 수 있으나 doPatch와 doDelete의 경우에는 직접 작성해주어야 하므로 컨트롤러 제일 상단에 service 메서드를 재정의하여 요청방식이 PATCH인 경우 doPatch 메소드를, DELETE인 경우 doDelete 메서드를 호출할 수 있도록 해주어야한다.

@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String method = req.getParameter("mode");
		if("delete".equals(method)) {
			doDelete(req,resp);
		}else if("mody".equals(method)) {
			doPatch(req,resp);
		}else {
			super.service(req, resp);
		}
	}

0개의 댓글