댓글 작성 Mapper
<!--   	댓글 작성 -->
  	<insert id="reply_Insert" parameterType="replyVO">
  		INSERT INTO replytable(
		  			reply_idx
		  		   ,reply_content
		  		   ,id
		  		   ,reply_wdate
		  		   ,reply_ip
		  		   ,bidx
		  		   ,uidx
		  		   ,board_type
		  		   ,rparent
		  	)VALUES(
		  		   reply_idx_seq.nextval
		  		  ,#{reply_Content}
		  		  ,#{id}
		  		  ,SYSDATE
		  		  ,#{reply_Ip}
		  		  ,#{bidx}
		  		  ,#{uidx}
			  	  ,#{board_type}
			  	  ,reply_idx_seq.nextval
		  	)
		  			
  	</insert>

 

 

댓글 목록 Mapper
<!--   커뮤니티 댓글 목록 -->
  	<select id="reply_list" resultType="replyVO" parameterType="int">
  		SELECT reply_idx
			  ,reply_content
			  ,id
			  ,reply_wdate
			  ,bidx
			  ,uidx
			  ,rdepth
			  ,rparent
		  FROM replytable
		 WHERE bidx = #{bidx}
		   AND board_type = 0
		 ORDER BY rparent asc, reply_wdate asc
  	</select>

 

대댓글을 달은 댓글 밑에 대댓글 리스트를 작성 순서대로 출력하려면 부모댓글과 작성날짜를 정렬했어야했다.

 

댓글 삭제 Mapper
<!-- 댓글 삭제 -->
	<delete id="deleteByReply" parameterType="replyVO">
		DELETE replytable 
		 WHERE reply_idx = #{reply_Idx} 
	</delete>

 

댓글 수정 Mapper
<!-- 	댓글 수정 -->
	<update id="updateByReply" parameterType="replyVO">
		UPDATE replytable 
		   SET reply_content = #{reply_Content} 
		 WHERE reply_idx = #{reply_Idx}
	</update>
대댓글 작성 Mapper
<!-- 	대댓글 작성 -->
	<insert id="re_replyInsert" parameterType="replyVO">
		INSERT into replytable (
					 reply_idx
					,reply_content
					,id
					,reply_wdate
					,reply_ip
					,bidx
					,uidx
					,board_type
					,rdepth
					,rparent
					)
			VALUES (
					reply_idx_seq.nextval
					,#{reply_Content}
					,#{id}
					,SYSDATE
					,#{reply_Ip}
					,#{bidx}
					,#{uidx}
					,0
					,1
					,#{rparent}
					)
	</insert>

대댓글과 댓글의 구분을 위해 대댓글 입력시 rdepth를 1로 입력했다.

 

DAO
@Repository
public class ReplyDAO {

	@Autowired
	private SqlSession sqlSession;
	
	//댓글작성
	public int reply_Insert(ReplyVO replyVO) {
		return sqlSession.insert("project.healingcamp.mapper.replyMapper.reply_Insert", replyVO);
	}
	
	//커뮤니티 댓글 목록
	public List<ReplyVO> reply_list(int bidx){
		return sqlSession.selectList("project.healingcamp.mapper.replyMapper.reply_list",bidx);
	}
	
	//상담사 게시판 댓글 목록
	public List<ReplyVO> counseller_reply_list(int bidx){
		return sqlSession.selectList("project.healingcamp.mapper.replyMapper.counseller_reply_list",bidx);
	}
	
	//댓글 삭제
	public int deleteByReply(ReplyVO replyVO) {
		return sqlSession.delete("project.healingcamp.mapper.replyMapper.deleteByReply", replyVO);
	}
	
	//댓글 수정
	public int updateByReply(ReplyVO replyVO) {
		return sqlSession.update("project.healingcamp.mapper.replyMapper.updateByReply", replyVO);
	}
	
	//대댓글 작성
	public int re_replyInsert(ReplyVO replyVO) {
		return sqlSession.insert("project.healingcamp.mapper.replyMapper.re_replyInsert",replyVO);
	}
	
	
}

 

Service(interface)
public interface ReplyService {
	
    //댓글 작성
	int reply_Insert(ReplyVO replyVO);
    
    //댓글리스트
	List<ReplyVO> reply_list(int bidx);
    
    //댓글 삭제
	int deleteByReply(ReplyVO replyVO);
    
    //댓글 수정
	int updateByReply(ReplyVO replyVO);
    
    //대댓글 작성
	int re_replyInsert(ReplyVO replyVO);
}

 

Service
@Service
public class ReplyServiceImpl implements ReplyService {
	
	@Autowired
	private ReplyDAO replyDAO;
	
	@Autowired
	private Community_BoardDAO cboardDAO;

	//댓글 작성
	//Community_BoardDAO 사용을 위한 트랜잭션
	@Transactional
	@Override
	public int reply_Insert(ReplyVO replyVO) {
		cboardDAO.addReplyCnt(replyVO.getBidx()); // 댓글 작성시 댓글 카운트 +1
		return replyDAO.reply_Insert(replyVO);
	}

	//댓글 리스트
	@Override
	public List<ReplyVO> reply_list(int bidx) {
		List<ReplyVO> reply_list = replyDAO.reply_list(bidx);
		return reply_list;
	}

	//댓글 삭제
	@Transactional
	@Override
	public int deleteByReply(ReplyVO replyVO) {
		cboardDAO.removeReplyCnt(replyVO.getBidx()); //댓글 삭제 댓글카운트 -1
		return replyDAO.deleteByReply(replyVO);
	}

	//댓글 수정
	@Override
	public int updateByReply(ReplyVO replyVO) {
		return replyDAO.updateByReply(replyVO);
	}

	//대댓글 작성
	@Transactional
	@Override
	public int re_replyInsert(ReplyVO replyVO) {
		cboardDAO.addReplyCnt(replyVO.getBidx()); // 대댓글 작성시 카운트+1
		return replyDAO.re_replyInsert(replyVO);
	}

 

VO
public class ReplyVO {
	
	private int reply_Idx; //댓글 번호
	private String reply_Content; //댓글 내용
	private String id; //댓글 작성한 아이디
	private String reply_Wdate; //댓글 작성 날짜
	private String reply_Ip; //댓글 작성 ip
	private int bidx; //댓글 작성한 게시글 번호
	private int uidx; //댓글 작성한 회원의 uidx
	private int board_type; //게시판 유형
	private int rdepth; //댓글 - rdepth:0 , 대댓글 - rdepth:1
	private int rparent; //부모 댓글

getter / setter 생성

 

Controller
	//댓글 작성
	@RequestMapping(value="/community_write.do",method=RequestMethod.POST)
	public String community_write(Community_BoardVO cboardVO,HttpSession session,HttpServletRequest request) {
		
		UserVo login = (UserVo)session.getAttribute("login");
		
		cboardVO.setId(login.getId());			
		cboardVO.setUidx(login.getUidx());
		cboardVO.setIp(request.getRemoteAddr());
		
		//게시글 작성
		cboardService.insert(cboardVO);
		//최근작성한 게시글의 bidx
		int bidx = cboardService.maxBidx();
		
		return "redirect:community_view.do?bidx="+bidx;
	}
    
    //댓글 리스트
	@RequestMapping(value="/community_replyList.do",method=RequestMethod.GET)
	@ResponseBody
	public List<ReplyVO> community_view(int bidx) {
		
		//댓글 리스트
		List<ReplyVO> reply_list = replyService.reply_list(bidx);
		
		return reply_list;
	}
    
   //댓글 삭제
	@RequestMapping(value="/community_reply_delete.do",method=RequestMethod.POST)
	@ResponseBody
	public String community_reply_delete(ReplyVO replyVO) {
		replyService.deleteByReply(replyVO);
		
		return "1";
	}
	
	//댓글 수정
	@RequestMapping(value="/community_reply_update.do",method=RequestMethod.POST)
	@ResponseBody
	public String community_reply_update(@RequestBody ReplyVO replyVO) {
		replyService.updateByReply(replyVO);
		
		return "1";
	}
	
	//댓글 신고 팝업창
	@RequestMapping(value="/reply_popup.do",method=RequestMethod.GET)
	public String reply_popup() {
		return "community/reply_popup";
	}
	
	
	//대댓글 작성
	@RequestMapping(value="community_re_reply.do",method=RequestMethod.POST)
	@ResponseBody
	public String re_replyInsert(@RequestBody ReplyVO replyVO, HttpSession session, HttpServletRequest request,Community_BoardVO cboardVO) {
		
		//로그인 정보
		UserVo login = (UserVo)session.getAttribute("login");
		
		replyVO.setId(login.getId()); //대댓글 작성자 아이디
		replyVO.setUidx(login.getUidx()); //대댓글 작성자 uidx
		replyVO.setReply_Ip(request.getRemoteAddr()); //ip
		
		replyService.re_replyInsert(replyVO);
		
		return "1";
		
	}

 

 

 

JavaScript
댓글 작성
//로그인 정보
var login = "${login}";
   		
//현재 로그인한아이디
var id = '<%=session.getAttribute("id")%>'; 

// 댓글 작성 버튼 클릭
$(document).on("click","#reply_btn",function(){
    //댓글 입력값
    var reply = $("textarea[name=reply_Content]").val();
    //로그인 여부
    if(login == ""){
        alert("로그인 후 이용해주세요");
        return false;
    }
    //댓글 작성여부
    else if(reply == ""){
        alert("댓글을 입력해주세요.");
        return false;
    }
    
    //댓글작성
   			$.ajax({
	    		type:"post",
	    		url:"community_reply_insert.do",
	    		data:$("#commentForm").serialize(),
	    		dataType:"text",
	    		success:function(data){
	    			if(data == "success"){
		    			$("#reply").val("");
	    				getCommentList(); //댓글 작성 완료시 댓글 목록함수 호출
	    			}
	    		},error:function(){
	    			alert("error");
	    		}
	    	});
   		});
   		
   		//초기페이지 로딩시 댓글 불러오기
   		$(function(){
   			getCommentList();
});

 

댓글 목록
//댓글목록
   		function getCommentList(){
   			
   			//작성하려는 댓글의 게시물 번호
   			var bidx = $("input[name=bidx]").val();
   			
   			$.ajax({
   				type:"get",
   				url:"community_replyList.do",
				data:"bidx="+bidx,
   				success : function(result){
   					var html="";
   					if(result.length > 0){
   						for(i = 0; i < result.length; i++){
   						
	   					var reply_Idx = result[i].reply_Idx; //댓글번호
	   					var bidx = result[i].bidx; // 댓글이 달린  게시글 번호
	   					var reply_Content = result[i].reply_Content; //댓글 내용
	   					var writer = result[i].id //댓글 작성자
	   					var rdepth = result[i].rdepth //댓글깊이 
	   					var rparent = result[i].rparent; 
	   					console.log(rparent);
	   					
	   						html += "<div class='reply_area"+rparent+"'>";
	   						if(reply_Content == ""){ //삭제된 댓글일때
	   							html += "<dlv>";
	   							html += "<div>삭제된 댓글입니다.</div>"
	   							html += "</dlv>";
	   						}else{
		   						if(rdepth == 0){//댓글일때
		   						    html += "<div class='reply_box'>";
		   						    html += 	"<div class='reply_box_wrapper"+reply_Idx+"'>"; //댓글 수정 버튼 클릭시 수정 창으로 바뀌는 부분(수정하려는 댓글의 idx)
		   						    html += 		"<div class='reply_info_wrapper'>";
		   						    html += 			"<ul class='reply_info'>";
		   						    html += 				"<li class='id'>"+result[i].id+"</li>";
		   						    html += 				"<li class='wdate'>"+result[i].reply_Wdate+"</li>";
		   						    
		   						    if(id == result[i].id){ //현재 로그인된 아이디일시 댓글수정가능 
		   						        html += 			"<li class='commentModify' onclick='commentModify("+reply_Idx+",\""+reply_Content+"\",\""+writer+"\");'>댓글수정</li>";
		   						    }else{
		   						        html += 			"<li class='re_reply' onclick='re_reply("+reply_Idx+","+bidx+")'>답글쓰기</li>";
		   						    }
		   						    
		   						    if(id == result[i].id){//현재 로그인된 아이디일시 댓글삭제가능 
		   						        html += 			"<li class='delete' onclick='deleteReply("+reply_Idx+","+bidx+");'>삭제</li>";
		   						    }else{
		   						        html += 			"<li class='report' onclick='reportReply()'>신고</li>";
		   						    }
		   						    
		   						    html += 			"</ul>"; //.reply_info
		   						    html += 		"</div>"; //.reply_info_wrapper
		   						    html += 		"<div class='reply_view_wrapper'>";
		   						    html += 			"<div class='reply_view'>"+result[i].reply_Content+"</div>";
		   						    html += 		"</div>"; //.reply_view_wrapper
		   						    html += 	"</div>"; //.reply_box_wrapper
		   						    html += "</div>"; //.reply_box
		   						    html += "<div class='re_reply_area"+reply_Idx+"'></div>"; //답글작성이 들어갈 칸
		   						    
		   						}else{//대댓글일때
			   						html += "<div class='re_reply_box'>";
			   					 	html += 	"<div class='reply_box_wrapper"+reply_Idx+"'>"; //답글 수정 버튼 클릭시 수정 창으로 바뀌는 부분(수정하려는 답글의 idx)
		   		   					html += 	"<span class='reply_ico'>└</span>";
		   		   					html += 	"<div class='reply_info_wrapper' >";
		   		   					html += 		"<ul class='reply_info'>";
		   		   					html += 			"<li class='id'>"+result[i].id+"</li>";
			   		   				html += 			"<li class='wdate'>"+result[i].reply_Wdate+"</li>";
		   							
		   							if(id == result[i].id){
			   							html += 		"<li class='commentModify' onclick='commentModify("+reply_Idx+",\""+reply_Content+"\",\""+writer+"\");'>댓글수정</li>";
		   							}else{
		   								html += 		"<li class='re_reply' onclick='re_reply("+reply_Idx+","+bidx+")'>답글쓰기</li>";
		   							}
		   							
		   							if(id == result[i].id){
		   								html += 		"<li class='delete' onclick='deleteReply("+reply_Idx+","+bidx+");'>삭제</li>";
		   							}else{
			   							html += 		"<li class='report' onclick='reportReply()'>신고</li>";
		   							}
		   							html += 		"</ul>"; //.reply_info
		   							html += 	"</div>"; //.reply_info_wrapper
		   		   					html += 	"<div class='reply_view_wrapper'>";
		   		   					html += 		"<div class='reply_view'>"+result[i].reply_Content+"</div>";
		   		   					html += 	"</div>"; //.reply_view_wrapper
		   		   					html += 	"</div>"; //.reply_box_wrapper
		   		   					html += "</div>"; //.re_reply_box
			   					}
	   						}
		   					html += "</div>"; //.reply_area
   						}
   					}else{
   						html += "<div>등록된 댓글이 없습니다.</div>";
   					}
   					
   					$("#reply_wrapper").html(html);
   					
   				},error:function(){
   					alert("error");
   				}
   			});
   		}

 

댓글 삭제
//댓글 삭제
   		function deleteReply(reply_Idx,bidx){
   			var ans = confirm("선택하신 댓글을 삭제하시겠습니까?");
   			if(!ans){return false;}
   			
   			$.ajax({
   				type:"post",
   				url:"community_reply_delete.do",
   				data:{"reply_Idx":reply_Idx,"bidx":bidx},
   				success:function(data){
   					if(data == 1){
   						alert("삭제가 완료되었습니다.");
   						location.reload();
   					}
   				},error:function(){
   					alert("댓글 삭제 실패");
   				}
   			});
   		}

 

댓글 수정
		//댓글 수정창띄우기
		function commentModify(reply_Idx,reply_Content,writer){
			
			var comment = ""
				comment +="<div class='reply_info_wrapper' >";
				comment +=	"<ul class='reply_info'>";
				comment +=		"<li class='id'>"+writer+"</li>";
				comment +=		"<li class='commentModify' onclick='updateBtn("+reply_Idx+",\""+reply_Content+"\");'>댓글수정</li>";
				comment +=		"<li class='cancel' onclick='getCommentList();'>취소</li>";
				comment +=	"</ul>";
				comment +="</div>"; //취소버튼 클릭시 댓글 목록리스트 함수 실행
				comment +="<div class='reply_view_wrapper'>";
				comment +=	"<textarea id='reply_Edit_Content' name='reply_Content' style='width:100%;'>"+reply_Content+"</textarea>";
				comment +="</div>";
			
			$(".reply_box_wrapper"+reply_Idx).replaceWith(comment);
		}
   		
   		//댓글 수정
   		function updateBtn(reply_Idx,reply_Content){
   			var reply_Content = $("textarea[name='reply_Content']").val(); //수정된 댓글 내용
   			
   			if(reply_Content == ""){
   				alert("내용을 입력해주세요.");
   			}else{
	   			$.ajax({
	   				url:"community_reply_update.do",
	   				type:"post",
	   				data:JSON.stringify({ "reply_Idx":reply_Idx ,"reply_Content":reply_Content}),
	   				dataType:"json",
	   				contentType : "application/json;charset=UTF-8",
	   				success:function(result){
	   					if(result == 1){
		   					alert("댓글 수정이 완료되었습니다.");
		   					getCommentList();//댓글 수정완료시 댓글 목록리스트 함수 실행
	   					}
	   				},error:function(){
	   					alert("error");
	   				}
	   			});
   			}
   		}

 

대댓글
//대댓글창 띄우기
   		function re_reply(reply_Idx,bidx){
   			if(login == ""){
   				alert("로그인 후 이용해주세요.");
   			}else{
   				var reply = "";
   					reply += "<div class='re_reply_box'>";
   					reply += 	"<span class='reply_ico'>└</span>";
   					reply += 	"<div class='reply_info_wrapper' >";
   					reply += 		"<ul class='reply_info'>";
   					reply += 			"<li class='id'>"+id+"</li>";
   					reply += 			"<li class='re_reply_btn' onclick='re_reply_btn("+reply_Idx+","+bidx+");'>댓글등록</li>";
   					reply += 			"<li class='cancel' onclick='getCommentList();'>취소</li>";//취소버튼 클릭시 댓글 목록리스트 함수 실행
   					reply +=		"</ul>";
   					reply += 	"</div>"; 
   					reply += 	"<div class='reply_view_wrapper'>";
   					reply += 		"<textarea id='reply_Edit_Content' name='reply_Content' style='width:100%;'></textarea>";
   					reply += 		"<input type='hidden' name='rparent' value="+reply_Idx+">";
   					reply += 	"</div>";
   					reply += "</div>";
	   				$(".re_reply_area"+reply_Idx).html(reply);
   			}
   			
   			//display 여부에 따라 show,hide
    			if($(".re_reply_area"+reply_Idx).css("display") == "none"){
    				$(".re_reply_area"+reply_Idx).show();
    			}else{
    				$(".re_reply_area"+reply_Idx).hide();
   			}
   		}

 

대댓글 등록
//대댓글 등록
   		function re_reply_btn(reply_Idx,bidx){
   			var reply_Content = $("textarea[name='reply_Content']").val();
   			var rparent = $("input[name=rparent]").val();
   			
   			if(reply_Content == ""){
   				alert("내용을 입력해주세요.");
   			}else{
	   			$.ajax({
	   				url:"community_re_reply.do",
	   				type:"post",
	   				data:JSON.stringify({"reply_Content":reply_Content, "bidx":bidx,"rparent":rparent}), //rparent:대댓글 다는 댓글의 idx
	   				dataType:"json",
	   				contentType:"application/json; charset=UTF-8",
	   				success:function(result){
	   					getCommentList(); //대댓글 입력시 댓글목록함수 호출
	   					
	   				},error:function(){
	   					alert("error");
	   				}
	   			});
   			}
   		}

 

 


로그인을 하지 않고 답글쓰기 클릭시 로그인 후 이용하라는 경고창이 뜬다.

 

답글쓰기 클릭시 답글 밑에 답글 입력창이 나타남

 

답글등록 완료 후 답글을 등록한 댓글 밑에 작성한 순서대로 답글이 출력된다.

 

 

드디어 완성 해서 넘뿌듯뿌듯~~!

이번에 댓글 기능을 만들면서 느낀것은

ajax로 html을 뿌려줄때 태그의 열림닫힘 표시를 잘 해두자...............헷갈려죽는 줄 

 

https://gimmesome.tistory.com/176

 

Spring MVC 로 댓글(답글) 구현하기

사진자랑 게시판(게시판명: picture)의 '댓글' 기능을 예로 들었다. picture 게시판에선 카드리스트에서 카드를 클릭하면 나오는 모달창에서 댓글 아이콘을 클릭해야 댓글들을 볼 수 있고, 댓글과 대

gimmesome.tistory.com

댓글 기능 구현시 참고했던 포스팅!!

+ Recent posts