쌍용교육(JAVA)/MVC

쌍용교육 -JSP수업 65일차 - ch06_mvcPageMVC(10)

구 승 2024. 5. 23. 14:08

댓글 수정

BoardDAO (내용 추가) 맨아래에 내용 추가

//댓글 상세(댓글 수정, 삭제시 작성자 회원번호 체크 용도로 사용)
		public BoardReplyVO getReplyBoard(int re_num) throws Exception{
			Connection conn = null;
			PreparedStatement pstmt = null;
			String sql =null;
			ResultSet rs = null;
			BoardReplyVO reply = null;
			try {
				//커넥션풀로부터 커넥션 할당
				conn = DBUtil.getConnection();
				
				//SQL문 작성
				sql="SELECT * FROM zboard_reply WHERE re_num=?";
				
				//PreparedStatment 객체 생성
				pstmt = conn.prepareStatement(sql);
				//?에 데이터 바인딩
				pstmt.setInt(1, re_num);
				rs = pstmt.executeQuery();
				if(rs.next()) {
					reply = new BoardReplyVO();
					reply.setRe_num(rs.getInt("re_num"));
					reply.setMem_num(rs.getInt("mem_num"));
				}
			}catch(Exception e) {
				throw new Exception(e);
			}finally {
				DBUtil.executeClose(rs, pstmt, conn);
			}
			
			return reply;
		}
		//댓글 수정
		public void updateReplyBoard(BoardReplyVO reply) throws Exception{
			Connection conn = null;
			PreparedStatement pstmt = null;
			String sql =null;
			try {
				//커넥션풀로부터 커넥션 할당
				conn = DBUtil.getConnection();
				
				//SQL문 작성
				sql="UPDATE zboard_reply SET re_content=?,re_modifydate=SYSDATE,re_ip=? WHERE re_num=?";
				
				//PreparedStatment 객체 생성
				pstmt = conn.prepareStatement(sql);
				//?에 데이터 바인딩
				pstmt.setString(1, reply.getRe_content());
				pstmt.setString(2, reply.getRe_ip());
				pstmt.setInt(3, reply.getRe_num());
				//SQL문 실행
				pstmt.executeUpdate();
				
			}catch(Exception e) {
				throw new Exception(e);
			}finally {
				DBUtil.executeClose(null, pstmt, conn);
			}
		}

UpdateReplyAction

package kr.board.action;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.codehaus.jackson.map.ObjectMapper;

import kr.board.dao.BoardDAO;
import kr.board.vo.BoardReplyVO;
import kr.controller.Action;

public class UpdateReplyAction implements Action{

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		request.setCharacterEncoding("utf-8");
		
		//댓글 번호 반환
		int re_num = Integer.parseInt(request.getParameter("re_num"));
		
		BoardDAO dao = BoardDAO.getInstance();
		BoardReplyVO db_reply = dao.getReplyBoard(re_num);
		
		HttpSession session = request.getSession();
		Integer user_num = (Integer)session.getAttribute("user_num");
		
		Map<String,String> mapAjax = new HashMap<String,String>();
		
		if(user_num==null) {//로그인이 되지 않는 경우
			mapAjax.put("result", "logout");
		}else if (user_num!=null && user_num == db_reply.getMem_num()) {
			//로그인한 회원번호와 작성자 회원번호 일치
			BoardReplyVO reply = new BoardReplyVO();
			reply.setRe_num(re_num);
			reply.setRe_content(request.getParameter("re_content"));
			reply.setRe_ip(request.getRemoteAddr());
			
			dao.updateReplyBoard(reply);
			
			mapAjax.put("result", "success");
			
		}else {
			//로그인한 회원번호와 작성자 회원번호 불일치
			mapAjax.put("result", "wrongAccess");
		}
		
		//JSON 데이터 변환
		ObjectMapper mapper = new ObjectMapper();
		String ajaxData = mapper.writeValueAsString(mapAjax);
		
		request.setAttribute("ajaxData", ajaxData);
		return "/WEB-INF/views/common/ajax.view.jsp";
	}

}

 

js/board.reply.js(내용 추가)

/*====================================
	*댓글 수정
	* ====================================*/
	$(document).on('click','modify-btn',function(){
		//댓글 번호
		let re_num = $(this).attr('data-renum');
		//댓글 내용 		컨텐트의 바로위에부모 div중 p태그를 찾아서 br 태그를 \n으로 바꾼다(?)										//g:지정문자열 모두,i:대소문자 무시
		let content = $(this).parent().find('p').html().replace(/<br>/gi,'\n'); //<br>을 전부 검색 하는 법 //gi 안에 내용넣기. 콤마 다음은 바꿀내용. 즉 <br>을 \n으로 바꾼다.
		
		//댓글 수정폼 UI
		let modifyUI = '<form id="mre_form">';
		modifyUI +='<input type="hidden" name="re_num" id="mre_num" value="'+re_num+'">';
		modifyUI +='<textarea rows="3" cols="50" name="re_content" id="mre_content" class="rep-content">'+content+'</textarea>';
		modifyUI +='<div id="mre_first"><span class="letter-count">300/300</span></div>';
		modifyUI += '<div id="mre_second" class="align-right">';
		modifyUI += '<input type="submit" value="수정">';
		modifyUI += '<input type="button" value="취소" class="re-reset">';
		modifyUI += '</div>';
		modifyUI += '<hr size="1" noshade width="96%">';
		modifyUI += '</form>';
		
		//수정폼을 수정하고자 하는 데이터가 있는 div에 노출
			//parent는 바로위에 부모, parents는 여러개 부모중 검색가능. 여기선 item을 찾아서 추가
		$(this).parents('.item').append(modifyUI);
		
		//입력한 글자수 셋팅
		let inputLength = $('#mre_content').val().length;
		let remain = 300 - inputLength;
		remain += '/300';
		
		//문서 객체에 반영
		$('#mre_first .letter-content').text(remain);

수정을 계속 누르면 수정창이 계속 뜨는 문제가 생기는 부분을 해결해야됨

145라인 modifyUI += '</form>'

으로 끝나는 부분 아래에 명시

//수정버튼을 감싸고 있는 div
		//this는 수정버튼. 수정버튼의 바로위에있는 div를 숨긴다.
		$(this).parent().hide();

하나의 댓글에는 더이상 문제가없음
그러나 빨간 동그라미 부분을 ID로 명시해뒀기 때문에 하나의 아이디가 여러개의 댓글을 달았을 경우 수정폼의 문제가 생김. (수정폼을 누른 것 빼고 나머지는 전부 가리도록 하면 문제 해결)

//이전에 이미 수정하는 댓글이 있을경우 수정 버튼을 클릭하면 sub-item 클래스로 지정된 div를 환원시키고 수정폼을 제거함
		initModifyForm();

 

//댓글 수정폼 초기화
	function initModifyForm(){
		$('.sub-item').show();
		$('#mre_form').remove();
	}

 

이 두 코드를 위 아래로 넣는다.

//수정버튼을 감싸고 있는 div 

여기 위에

//문서 객체에 반영

$('#mre_first .letter-content').text(remain);

});

여기아래 입력

 

 취소버튼 작동 (//댓글 수정폼 초기화) 밑에 명시

//수정폼에서 취소버튼 클릭시 수정폼 초기화 (취소버튼 누르면 수정폼이 사라짐)
	$(document).on('click','.re-reset',function(){
		initModifyForm();
	});
	//댓글 수정
	$(document).on('submit','#mre_form',function(event){
		if($('#mre_content').val().trim()==''){
			alert('내용을 입력하세요');
			$('#mre_content').val('').focus();
			return false;
		}
		
		//폼에 입력한 데이터 반환
		let form_data = $(this).serialize();
		
		//서버와 통신
		$.ajax({
			url:'updateReply.do',   
			type:'post',
			data:form_data,
			dataType:'json',
			success:function(param){
				if(param.result == 'logout'){
					alert('로그인해야 수정할 수 있습니다.');
				}else if(param.result == 'success'){
					//수정된 댓글 내용을 화면에 반영하는 역할
					//mre_form 의 부모 div의 하위 p태그의 접근 후 html 괄호안에 수정된 내용을 넣어준다.
					$('#mre_form').parent().find('p').html($('#mre_content').val().replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g,'<br>'));
					$('#mre_form').parent().find('.modify-date').text('최근 수정일 : 5초 미만');
					
					//수정폼 삭제 및 초기화
					initModifyForm();
				}else if(param.result == 'wrongAccess'){
					alert('타인의 글을 수정할 수 없습니다.');
				}else{
					alert('댓글 수정 오류 발생');
				}
			},
			error:function(){
				alert('네트워크 오류 발생');   
			}
		});
		
		//기본 이벤트 제거
		event.preventDefault();
	});

 

 

kr.util/DurationFromNow.java(자바 파일을 다운 후 넣기)

1분전,1시간전,하루전 등등 댓글의 시간을 명시하는 법을 추가하려고한다.

DurationFromNow.java
0.00MB

 

 

 

BoardDAO (내용 변경) 

//댓글 목록
		public List<BoardReplyVO> getListReplyBoard(int start, int end, int board_num) throws Exception{
			Connection conn = null;
			PreparedStatement pstmt = null;
			String sql =null;
			ResultSet rs = null;
			List<BoardReplyVO> list = null;
			try {
				//커넥션풀로부터 커넥션 할당
				conn = DBUtil.getConnection();
				//SQL문 작성
				sql="SELECT * FROM (SELECT a.*, rownum rnum FROM "
						+ "(SELECT * FROM zboard_reply JOIN zmember USING(mem_num) "
						+ "WHERE board_num=? ORDER BY re_num DESC)a) "
						+ "WHERE rnum >=? AND rnum <=?";
				//PreparedStatment 객체 생성
				pstmt = conn.prepareStatement(sql);
				//?에 데이터 바인딩
				pstmt.setInt(1, board_num);
				pstmt.setInt(2, start);
				pstmt.setInt(3, end);
				//SQL문 실행
				rs = pstmt.executeQuery();
				list = new ArrayList<BoardReplyVO>();
				while(rs.next()) {
					BoardReplyVO reply = new BoardReplyVO();
					reply.setRe_num(rs.getInt("re_num"));
					//날짜 -> 1분전,1시간전,1일전 형식의 문자열로 변환
					reply.setRe_date(DurationFromNow.getTimeDiffLabel(rs.getString("re_date")));
					//수정일이 없으면 에러가 나기 때문에 수정일이 있을 경우에만 변경되도록 조건문을 명시해둔다.
					if(rs.getString("re_modifydate")!=null) {
						reply.setRe_modifydate(DurationFromNow.getTimeDiffLabel(rs.getString("re_modifydate")));
					}
					reply.setRe_content(StringUtil.useBrNoHTML(rs.getString("re_content")));
					reply.setBoard_num(rs.getInt("board_num"));
					reply.setMem_num(rs.getInt("mem_num"));//작성자 회원번호
					reply.setId(rs.getString("id"));//작성자 아이디 (조인했기 때문에 가져올 수 있음)
					
					list.add(reply);
				}
			}catch(Exception e) {
				throw new Exception(e);
			}finally {
				DBUtil.executeClose(rs, pstmt, conn);
			}
			return list;
		}

최근 등록일이 바뀐모습

BoardDAO (추가명시) 맨아래에 명시 

//댓글 삭제
		public void deleteReplyBoard(int re_num)throws Exception{
			Connection conn = null;
			PreparedStatement pstmt = null;
			String sql =null;
			try {
				//커넥션풀로부터 커넥션 할당
				conn = DBUtil.getConnection();
				
				//SQL문 작성
				sql="DELETE FROM zboard_reply WHERE re_num=?";
				
				//PreparedStatment 객체 생성
				pstmt = conn.prepareStatement(sql);
				pstmt.setInt(1, re_num);
				
				pstmt.executeUpdate();
			}catch(Exception e) {
				throw new Exception(e);
			}finally {
				DBUtil.executeClose(null, pstmt, conn);
			}
		}

DeleteReplyAction

package kr.board.action;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.codehaus.jackson.map.ObjectMapper;

import kr.board.dao.BoardDAO;
import kr.board.vo.BoardReplyVO;
import kr.controller.Action;

public class DeleteReplyAction implements Action{

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//전송된 데이터 인코딩 타입 지정
		request.setCharacterEncoding("utf-8");
		
		//댓글번호
		int re_num = Integer.parseInt(request.getParameter("re_num"));
		
		Map<String,String> mapAjax = new HashMap<String,String>();
		BoardDAO dao = BoardDAO.getInstance();
		BoardReplyVO db_reply = dao.getReplyBoard(re_num);
		
		HttpSession session = request.getSession();
		Integer user_num = (Integer)session.getAttribute("user_num");
		
		if(user_num == null) {//로그인이 되지 않은 경우
			mapAjax.put("result", "logout");
		}else if(user_num !=null && user_num == db_reply.getMem_num()) {
			//로그인한 회원번호와 작성자 회원번호 일치
			dao.deleteReplyBoard(re_num);
			
			mapAjax.put("result","success");
		}else {
			//로그인한 회원번호와 작성자 회원번호 불일치
			mapAjax.put("result", "wrongAccess");
		}
		//JSON 데이터로 변환
		ObjectMapper mapper = new ObjectMapper();
		String ajaxData = mapper.writeValueAsString(mapAjax);
		
		request.setAttribute("ajaxData",ajaxData);
		return "/WEB-INF/views/common/ajax_view.jsp";
	}

}

js/board.reply.js(내용 추가)

/*====================================
	*댓글 삭제
	* ====================================*/
	$(document).on('click','.delete-btn',function(){
		//댓글번호
		let re_num = $(this).attr('data-renum');
		//서버와 통신
		$.ajax({
			url:'deleteReply.do',
			type:'post',
			data:{re_num:re_num},
			dataType:'json',
			success:function(param){
				if(param.result=='logout'){
					alert('로그인해야 삭제할 수 있습니다.');
				}else if(param.result=='success'){
					alert('삭제 완료!');
					selectList(1); //삭제를 완료하면 다시 첫페이지를 호출
				}else if(param.result=="wrongAccess"){
					alert('타인의 글을 삭제할 수 없습니다.');
				}else{
					alert('댓글 삭제 오류 발생');
				}
			},
			error:function(){
				alert('네트워크 오류 발생');
			}
		});
	});

 

BoardDAO (내용 변경)  게시물 삭제

//글 삭제
		public void deleteBoard(int board_num)throws Exception{
			Connection conn = null;
			PreparedStatement pstmt = null;
			PreparedStatement pstmt2 = null;
			PreparedStatement pstmt3 = null;
			String sql = null;
			try {
				conn = DBUtil.getConnection();
				//오토커밋 해제
				conn.setAutoCommit(false);
				//좋아요 삭제
				sql = "DELETE FROM zboard_fav WHERE board_num=?";
				pstmt = conn.prepareStatement(sql);
				pstmt.setInt(1, board_num);
				pstmt.executeUpdate();
				//댓글 삭제
				sql ="DELETE FROM zboard_reply where board_num=?";
				pstmt2 = conn.prepareStatement(sql);
				pstmt2.setInt(1, board_num);
				pstmt2.executeUpdate();
				//좋아요와 댓글은 순서가 바뀌어도 되지만 부모글은 반드시 마지막에 삭제되어야된다.
				//부모글 삭제
				sql = "DELETE FROM zboard WHERE board_num=?";
				pstmt3 = conn.prepareStatement(sql);
				pstmt3.setInt(1, board_num);
				pstmt3.executeUpdate();
				//예외 발생 없이 정상적으로 SQL문 실행
				conn.commit();
			}catch(Exception e) {
				//예외 발생
				conn.rollback();
				throw new Exception(e);
			}finally {
				DBUtil.executeClose(null, pstmt3, null);
				DBUtil.executeClose(null, pstmt2, null);
				DBUtil.executeClose(null, pstmt, conn);
			}
		}