TODAY TOTAL
[Spring] 댓글 구현

댓글은 View.jsp 게시판 상세보기를 클릭 시 게시판 상세보기가 나오고 그 밑에

댓글이 나오는건데 댓글은 JavaScript에 있는 fn_reply_list() 함수를 호출하고 댓글정보, 댓글 개수를 DB에서 가져온다.

 

 

그 뒤론 더보기, 삭제, 수정, 저장 함수를 호출하는 구조

 

ajax는 많이 쓰니 이해하기!

 

 

Controller

@RestController //@Controller + @ResponsBody
public class ReplyController {
	
	@Inject
	private IReplyService replyService;
	
		@RequestMapping(value="/reply/replyList", produces = "application/json;charset=UTF-8" )
		public Map<String, Object> replyList(ReplySearchVO searchVO) throws Exception {
		List<ReplyVO> list = replyService.getReplyListByParent(searchVO);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", true);
		map.put("data", list);
		map.put("count", list.size());
		return map;
		}
		// @PostMapping ("/reply/replyRegist")
		@RequestMapping(value="/reply/replyRegist", method = RequestMethod.POST)
		public Map<String, Object> replyRegist(ReplyVO reply, HttpServletRequest req, HttpSession session )
		throws Exception {
		reply.setReIp(req.getRemoteAddr());
		UserVO user = (UserVO)session.getAttribute("USER_INFO");
		reply.setReMemId(user.getUserId());
		replyService.registReply(reply);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("result", true);
		map.put("msg", "정상 등록 되었습니다.");
		return map;
		}

 

@RestController : @Controller와 @ResponseBody가 합친 어노테이션. 쓰면 좋은 점은 메소드에 매번 @ResponseBody를 붙여 주지 않아도 된다.

 

@RequestBody : 요청한 Body 내용을 자바 오브젝트로 변환시켜주는 역할이다. 즉, POST방식의 HTTP 바디 안에 JSON으로 넘어오는 값을 VO에 바인딩한다. 요청하는 곳으로 바로 감. ( Get 요청일 경우 RequestBody를 사용 못함)

 

@ResponseBody : VO 객체를 JSON으로 바꿔서 HTTP body에 담는 스프링 @

메소드의 리턴 값을 Response의 body에 담는 역할

 

 

		reply.setReIp(req.getRemoteAddr());
		UserVO user = (UserVO)session.getAttribute("USER_INFO");
		reply.setReMemId(user.getUserId());

 

:: 로그인 한 후 댓글을 쓸 수 있고, 댓글 쓴 사람은 자기 댓글만 수정,삭제 할 수 있게 하기 위해 User 정보를 가져온다.

 

 

@RequestMapping(value="/reply/replyModify")
		public Map<String, Object> replyModify(ReplyVO reply, HttpSession session ) throws Exception {
		UserVO user = (UserVO)session.getAttribute("USER_INFO");
		reply.setReMemId(user.getUserId());
		Map<String, Object> map = new HashMap<String, Object>();
		try {
		replyService.modifyReply(reply);
		map.put("result", true);
		map.put("msg", "수정 되었습니다.");
		return map;
		} catch (BizNotFoundException e) {
		map.put("result", false);
		map.put("msg", "글이 존재하지 않습니다.");
		return map;
		} catch (BizAccessFailException e) {
		map.put("result", false);
		map.put("msg", "접근에 실패했습니다.");
		return map;
		}
	}
		
		@RequestMapping(value="/reply/replyDelete")
		public Map<String, Object> replyDelete(ReplyVO reply, HttpSession session ) throws Exception {
			UserVO user = (UserVO)session.getAttribute("USER_INFO");
			reply.setReMemId(user.getUserId());
			Map<String, Object> map = new HashMap<String, Object>();
			try {
			replyService.removeReply(reply);
			map.put("result", true);
			map.put("msg", "삭제 되었습니다.");
			return map;
			
			} catch (BizNotFoundException e) {
			map.put("result", false);
			map.put("msg", "글이 존재하지 않습니다.");
			return map;
			
			} catch (BizAccessFailException e) {
			map.put("result", false);
			map.put("msg", "접근에 실패했습니다.");
			return map;
			}
		}
}

::Key값을 string으로 value 값을 Object형으로 put 메소드를 통해 입력 할 수 있다.

 

 

 

view.jsp

 

<!-- START : 댓글 관련 영역 -->
	<div class="container">
		<!-- START : 댓글 입력 영역 -->
		<div class="panel panel-default">
			<div class="panel-body form-horizontal">
				<form name="frm_reply" action="<c:url value='/reply/replyRegist' />"
					method="post" onclick="return false;">
					<input type="hidden" name="reParentNo" value="${board.boNo}">
					<input type="hidden" name="reCategory" value="FREE">
					<div class="form-group">
						<label class="col-sm-2 control-label">댓글</label>
						<div class="col-sm-8">
							<textarea rows="2" name="reContent" class="form-control" ></textarea>
						</div>
						<div class="col-sm-2">
							<button id="btn_reply_regist" type="button" class="btn btn-sm btn-info">등록</button>
						</div>
					</div>
				</form>
			</div>
		</div>
		<!-- END : 댓글 입력 영역 -->
<!-- START : 댓글 목록 영역-->
		<div id="id_reply_list_area"></div>
		<!-- END : 댓글 목록 영역-->

		<!-- START : 더보기 버튼 영역-->
		<div class="row text-center" id="id_reply_list_more">
			<button id="btn_reply_list_more">
				<span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span>
				더보기
			</button>
		</div>
		<!-- END : 더보기 버튼 영역-->

 

<!-- START : 댓글 수정용 Modal-->
		<div class="modal fade" id="id_reply_edit_modal" role="dialog">
			<div class="modal-dialog">
				<!-- Modal content-->
				<div class="modal-content">
					<form name="frm_reply_edit"
						action="<c:url value='/reply/replyModify' />" method="post"
						onclick="return false;">
						<div class="modal-header">
							<button type="button" class="close" data-dismiss="modal">×</button>
							<h4 class="modal-title">댓글수정</h4>
						</div>
						
						<div class="modal-body">
							<input type="text" name="reNo" value="">
							<textarea rows="3" name="reContent" class="form-control"></textarea>
						</div>
						<div class="modal-footer">
							<button id="btn_reply_modify" type="button"
								class="btn btn-sm btn-info">저장</button>
							<button type="button" class="btn btn-default btn-sm"
								data-dismiss="modal">닫기</button>
						</div>
					</form>
				</div>
			</div>
		</div>
		<!-- END : 댓글 수정용 Modal-->
	</div> <!-- END : 댓글 container-->

 

:: 더보기, 수정, 삭제, 등록만 해도 이정도다;;; ㄷㄷ

 

 

그리고 자바스크립트 부분 (ajax 이해하기)

 

<!-- START : 댓글 목록 영역-->
<div id="id_reply_list_area"></div>
<!-- END : 댓글 목록 영역-->

 

 

<script type="text/javascript">
		
		<!-- START : 댓글 처리 스크립트 -->
        <!--페이지마다 댓글 보여줘야한다 -->
		var curPage = 1;
		var rowSizePerPage = 10 ;
		var parentNo = ${board.boNo};
		var sendParam = {"curPage" :  curPage
							, "rowSizePerPage" : rowSizePerPage
							, "reCategory" : "FREE"
							,  "reParentNo": ${board.boNo} };
        <!--댓글목록영역 -->
		var $reply_list_area = $('#id_reply_list_area');

 

// 댓글목록을 구하는 함수
		function fn_reply_list(){
			$.ajax({
				url : "<c:url value = '/reply/replyList' />",
				// 요청 페이지 URL정보
				dataType : 'json', // 서버로부터 전달받을 데이터 유형 (html, xml, json, script)
				data : sendParam, // 서버에 전송할 파라미터 정보
				success : function(data) {
					console.log('data.result', data.result);
					console.log('data.count', data.count);
					console.log('data.data', data.data);
					
					$.each(data.data,function(i,el){
						console.log(i,el);
						var str = '<div class="row" >'; 
							str += '<div class="col-sm-2 text-right" >'+el.reMemName+'</div>'; 
							str += '<div class="col-sm-6"><pre>'+el.reContent+'</pre></div>';
						   str += '<div class="col-sm-2" >'+el.reRegDate+'</div>';
						   str += '<div class="col-sm-2">';
						   //로그인 사용자 + 댓글 등록자
						   if('${sessionScope.USER_INFO.userId}' == el.reMemId){
						   str  += '<button name="btn_reply_edit" type="button" 
                           		class=" btn btn-sm btn-info" data-re-no="'+el.reNo+'">수정</button>';
						   str +='<button name="btn_reply_delete" type="button" 
                           		class="btn btn-sm btn-danger" data-re-no="'+el.reNo+'">삭제</button>';
						   }
						   str +='</div>';
			    			str +='</div>';
			    			$('#id_reply_list_area').append(str); //append
					}); //.each
					if(data.count < sendParam.rowSizePerPage){
					$('#id_reply_list_more').hide();
					}
				}, // 요청에 성공한 경우 호출되는 함수 (data, status, xhr )
				error : function(xhr,status,error) {
					console.log('xhr',xhr);
					console.log('status',status);
					console.log('error',error);
				}
				// 요청에 실패한 경우 호출되는 함수 (xhr, status, error)
				}); // ajax
			
		} // fn_reply_list

데이터 유형은 json , 서버에 전송할 파라미터 정보는 sendParam

성공 할 시 function(data) 함수를 실행하고

 

$.each는 JQuery를 사용해 배열을 관리하고자 할 때 each() 메서드를 사용 할 수 있다.

매개 변수로 받은 것을 사용해 for in 반복문과 같이 배열이나 객체의 요소를 검사 할 수 있는 메서드.

 

 

$.each(data.data,function(i,el)

 

컨트롤러단을 보면 data는 list다. list와 익명 i,el

 

회원이름 + 글 내용 + 작성일

 

 

	if('${sessionScope.USER_INFO.userId}' == el.reMemId){
		str  += '<button name="btn_reply_edit" 
        	type="button" class=" btn btn-sm btn-info" data-re-no="'+el.reNo+'">수정</button>';
		str +='<button name="btn_reply_delete" 
        	type="button" class="btn btn-sm btn-danger" data-re-no="'+el.reNo+'">삭제</button>';
	}

if 문은 접속한 아이디와 일치시 수정,삭제가 나타나게 함. (자기 댓글만 수정,삭제 가능)

 

수정

$(document).ready(function() {
			
		// 수정버튼 클릭
		$('#id_reply_list_area').on('click','button[name=btn_reply_edit]',function(e){
			/* $('#id_reply_edit_modal').modal('show') */
			$btn = $(this);
			$('form[name=frm_reply_edit] ').find('input[name=reNo]').val($btn.data('re-no') );
			$('form[name=frm_reply_edit] ').find('textarea[name=reContent]').val($btn.closest('div.row').find('pre').text() );
			$('#id_reply_edit_modal').modal('show');
		}); // btn_reply_edit.click
		
	
		// 모달창의 (수정)저장버튼 btn_reply_modify 클릭
		$("#btn_reply_modify").click(function(e) {
			var params = $('form[name =frm_reply_edit]').serialize();
			 // #btn_reply_regist.click
			 
			$.ajax({
				type :"POST", // 전송 방식 설정 (Defaut : GET)
				url : "<c:url value = '/reply/replyModify' />",
				dataType : 'json', // 서버로부터 전달받을 데이터 유형 (html, xml, json, script)
				data : params, // 서버에 전송할 파라미터 정보
				success : function(data) {
					if(data.result) {
						// 성공
						reNo = $('form[name=frm_reply_edit]').find('input[name=reNo]').val();
						reContent = $('form[name=frm_reply_edit] ').find('textarea[name=reContent]').val();
						$('button[data-re-no=' + reNo + ']').closest('div.row').find('pre').text(reContent);
					}else{
						alert(data.msg);
					}
					
					$('#id_reply_edit_modal').modal('hide');
					
				}, // 요청에 성공한 경우 호출되는 함수 (data, status, xhr )
				error : function(xhr,status,error) {
					console.log('xhr',xhr);
					console.log('status',status);
					console.log('error',error);
				}
				// 요청에 실패한 경우 호출되는 함수 (xhr, status, error)
				}); // ajax
			
			}); //("#btn_reply_regist").click

url : "<c:url value = '/reply/replyModify' />",

 

<c:url : URL에 자동으로 Context Path를 붙여줍니다. 편리한게 Context를 변경을 하더라도 URL을 수정 할 필요 X

 

if(data.result) {
		// 성공
		reNo = $('form[name=frm_reply_edit]').find('input[name=reNo]').val();
        
        //reply_edit 중 input name이 reNo인 것을 찾아 값 넣기
		reContent = $('form[name=frm_reply_edit] ').find('textarea[name=reContent]').val();
        //reply_edit 중 input name이 reContent인 것을 찾아 값 넣기
        
		$('button[data-re-no=' + reNo + ']').closest('div.row').find('pre').text(reContent);
			}else{
				alert(data.msg);
			}

.closest('div.row') : 선택한 요소를 포함하면서 가장 가까운 상위 요소를 선택

 

삭제

 

// 삭제버튼 클릭
		$('#id_reply_list_area').on('click','button[name=btn_reply_delete]',function(e){
			$btn = $(this);
			var params = {"reNo" : $btn.data('re-no')};
			res = confirm("정말로 삭제하시겠습니까?");
			if(res) {
				 
				 $.ajax({
					 type : "POST",
					 url : "<c:url value = '/reply/replyDelete' />",
					 dataType : "json",
					 data : params,
					 success : function(data) {
						 if(data.result){
							 reContent = $('form[name=frm_reply_edit] ').find('textarea[name=reContent]').val();
							 $('button[data-re-no=' + del + ']').closest('div.row').find('pre').text(reContent);
						 }
						 $("")
				 }
				 });
			}
			
		}); // btn_reply_delete.click

 

더보기

 

// 더보기 버튼 클릭
		$('#btn_reply_list_more').click(function(e) {
		sendParam.curPage =sendParam.curPage + 1;
		fn_reply_list();
		}); // #btn_reply_list_more.click

 

등록

 

// 등록버튼 클릭(아작스)
		$("#btn_reply_regist").click(function(e) {
			var params = $('form[name =frm_reply]').serialize();
		 // #btn_reply_regist.click
		$.ajax({
			type :"POST", // 전송 방식 설정 (Defaut : GET)
			url : "<c:url value = '/reply/replyRegist' />",
			// 요청 페이지 URL정보
			dataType : 'json', // 서버로부터 전달받을 데이터 유형 (html, xml, json, script)
			data : params, // 서버에 전송할 파라미터 정보
			success : function(data) {
				alert(data);
			}, // 요청에 성공한 경우 호출되는 함수 (data, status, xhr )
			error : function() {
				
			}
			// 요청에 실패한 경우 호출되는 함수 (xhr, status, error)
			}); // ajax
		
		}); //("#btn_reply_regist").click
		
		// 4. 초기화 함수 호출
		fn_reply_list();
		}); // ready
		
		</script>

'Back-End > Spring' 카테고리의 다른 글

[Spring] AOP  (0) 2021.09.03
[Spring] 댓글 구현 2  (0) 2021.08.29
[Spring] 검색 화면 처리  (0) 2021.08.11
[Spring] 검색 처리  (0) 2021.08.11
[Spring] 페이징 처리 및 번호 출력  (0) 2021.08.06
  Comments,     Trackbacks