분홍색 하이라이트 = 생소한 내용

하늘색 하이라이트 = 대비

 

Spring MVC 검색 기능 게시판 프로그램 (이어서)

상세 페이지

- 목록 페이지 list.jsp 에서 제목을 클릭하면 "view.do" 로 요청하면서, 글 번호, 페이지 번호를 전달함

<a href="view.do?num=${board.num}&pageNum=${pp.currentPage}" class="btn btn-default"> 
	<c:if test="${board.re_level >0 }">
	<img alt="" src="images/level.gif" height="2" width="${board.re_level *5 }">
	<img alt="" src="images/re.gif">
	</c:if> ${board.subject} 
	<c:if test="${board.readcount > 30 }">
	<img alt="" src="images/hot.gif">
	</c:if></a>

 

- Controller 클래스에서 "view.do" 요청 부분만

	@RequestMapping("view.do")	// 상세 페이지
	public String view(int num, String pageNum, Model model) {
		bs.selectUpdate(num);	// 조회수 1 증가
		Board board = bs.select(num); // 상세 정보 구하기
		model.addAttribute("board", board);
		model.addAttribute("pageNum", pageNum);
		
		return "view";
	}

상세 페이지로 갈때 수행할 DB작업 2가지

1. selectUpdate() 메소드 : 조회수 증가

2. select() 메소드 : 상세 정보 구하기

<돌아온 후>

- 상세 정보를 저장한 객체 board 와 페이지 번호 pageNum 을 Mdoel 객체에 저장해서 view.jsp 로 전달

 

- 관련 내용을 많이 했으므로, Service, DAO 제외하고 Mapper 파일만 보자

- Mapper 파일 Board.xml 에서 id 가 "selectUpdate" 인 SQL문 부분만

	<update id="selectUpdate" parameterType="int">
		update board set readcount = readcount+1 where num=#{num}
	</update>

- Mapper 파일 Board.xml 에서 id 가 "select" 인 SQL문 부분만

	<select id="select" parameterType="int" resultType="board">
		select * from board where num=#{num}
	</select>

 

- View 페이지 view.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	$(function() {
		$('#list').load('list.do?pageNum=${pageNum}');
	});
</script>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">게시글 상세정보</h2>
		<table class="table table-bordered">
			<tr>
				<td>제목</td>
				<td>${board.subject}</td>
			</tr>
			<tr>
				<td>작성자</td>
				<td>${board.writer}</td>
			</tr>
			<tr>
				<td>조회수</td>
				<td>${board.readcount}</td>
			</tr>
			<tr>
				<td>아이피</td>
				<td>${board.ip}</td>
			</tr>
			<tr>
				<td>이메일</td>
				<td>${board.email}</td>
			</tr>
			<tr>
				<td>내용</td>
				<td><pre>${board.content}</pre></td>
			</tr>
		</table>
		
		<a href="list.do?pageNum=${pageNum}" class="btn btn-info">목록</a> 
		<a href="updateForm.do?num=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">수정</a> 
		<a href="deleteForm.do?num=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">삭제</a> 
		<a href="insertForm.do?nm=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">답변</a>
		<div id="list"></div>
	</div>
</body>
</html>

- Controller 에서 View 로 올때 Model 에 페이지 번호 pageNum 을 가져왔다

- 목록이 출력될 위치에 div 태그가 있고, ajax 의 load() 함수를 사용해서 "list.do" 요청하고 페이지 번호를 전달하면서 아래쪽에 리스트를 불러옴

 

 

버튼 처리

- '목록' 버튼을 누르면 페이지 번호를 전달하고 원래의 목록 페이지로 돌아감

- '답변' 버튼을 누르면 "insertForm.do" 로 요청하면서 부모글이 될 현재 글의 글 번호와 페이지 번호를 전달함

 

댓글 작성 요청 vs 원문 작성 요청

		<a href="insertForm.do?nm=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">답변</a>

- 댓글 작성을 할떄는 "insertForm.do" 로 요청하면서 nm (부모가될 글 글번호) 과 pageNum (페이지 번호) 를 가져감

			<a href="insertForm.do" class="btn btn-info">글 입력</a>

- 원문 글 작성을 할때는 아무런 값을 가져가지 않음


댓글 작성 폼

		<a href="insertForm.do?nm=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">답변</a>

- view.jsp 에서 "답변" 버튼을 누르면 "insertForm.do" 로 요청하면서 nm (부모가될 글 글번호) 과 pageNum (페이지 번호) 를 가져감

- 댓글 작성 폼으로 이동한다

 

- Controller 클래스에서 "insertForm.do" 요청 부분만

	@RequestMapping("insertForm.do")	// 글작성 폼 (원문, 답변글)
	public String insertForm(String nm, String pageNum, Model model) {
		int num = 0, ref = 0, re_level = 0, re_step = 0; // 원문
		if (nm != null) {	// 답변글
			num = Integer.parseInt(nm);
			Board board = bs.select(num);	// 부모글 정보 구해오기
			ref = board.getRef();
			re_level = board.getRe_level();
			re_step = board.getRe_step();
		}
		model.addAttribute("num", num);
		model.addAttribute("ref", ref);
		model.addAttribute("re_level", re_level);
		model.addAttribute("re_step", re_step);
		model.addAttribute("pageNum", pageNum);
		
		return "insertForm";
	}

- 답변 글인 경우 nm 이 null 이 아니므로 if 문 안의 내용을 수행함

- 부모글 번호로 부모글의 상세 정보를 구해오고, 부모글의 ref, re_level, re_step 값을 구해서 insertForm.jsp 로 이동함

- 답변글을 쓰기 전에 항상 부모글에 대한 정보를 구해와야한다, 부모글의 ref, lev, step 값을 알아야 댓글 작성 가능

- insertForm.jsp 로 갈때 Model 객체에 부모글의 글 번호 num, 부모글의 정보 ref, re_level, re_step 과 페이지 번호 pageNum 을 가져간다

+ 원문은 가져가는 num, ref, re_level, re_step 이 모두 0 으로 초기화되서 전달됨

 

- select() 메소드는 상세 정보를 구해오는 메소드, 많이 했으므로 설명 생략

 

- View 페이지 insertForm.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">게시판 글쓰기</h2>
		<form action="insert.do" method="post">
			<input type="hidden" name="num" value="${num}"> 
			<input type="hidden" name="ref" value="${ref}"> 
			<input type="hidden" name="re_step" value="${re_step}"> 
			<input type="hidden" name="re_level" value="${re_level}"> 
			<input type="hidden" name="pageNum" value="${pageNum}">
			<table class="table table-striped">
				<tr>
					<td>제목</td>
					<td><input type="text" name="subject" required="required"></td>
				</tr>
				<tr>
					<td>작성자</td>
					<td><input type="text" name="writer" required="required"></td>
				</tr>
				<tr>
					<td>이메일</td>
					<td><input type="email" name="email" required="required"></td>
				</tr>
				<tr>
					<td>암호</td>
					<td><input type="password" name="passwd" required="required"></td>
				</tr>
				<tr>
					<td>내용</td>
					<td><textarea rows="5" cols="30" name="content"
							required="required"></textarea></td>
				</tr>
				<tr>
					<td colspan="2" align="center"><input type="submit" value="확인"></td>
				</tr>
			</table>
		</form>
	</div>
</body>
</html>

- Controller 클래스에서 넘어온 값이 부모글에 대한 5가지 정보를 hidden 으로 "insert.do" 로 재전달한다

- 댓글 작성 시에는 부모글의 num, ref, re_level, re_step, pageNum 이 넘어온다

+ 원문은 가져가는 num, ref, re_level, re_step 이 모두 0 으로 초기화되서 전달됨

 

- 댓글 작성 후 "확인" 버튼을 누르면 "insert.do" 로 요청


댓글 작성

- 댓글 작성폼에서 댓글 작성 후 "확인" 버튼을 누르면 "insert.do" 로 요청

- Controller 클래스에서 "insert.do" 요청 부분만

	@RequestMapping("insert.do")	// 글 작성
	public String insert(Board board, Model model, HttpServletRequest request) {
		int num = board.getNum();
		int number = bs.getMaxNum();
		if (num != 0) {		// 답변글
			bs.updateRe(board);
			board.setRe_level(board.getRe_level() + 1);
			board.setRe_step(board.getRe_step() + 1);
		} else				// 원문	
			board.setRef(number); // else 문 끝
            
			board.setNum(number);
			String ip = request.getRemoteAddr();
			board.setIp(ip);
			int result = bs.insert(board);
			model.addAttribute("result", result);
			
		return "insert";
	}

- 여기서 원문 작성도 하고 댓글 작성도 한다, ref, re_level, re_step 값을 다르게 설정해서 insert 하면 각각 원문, 댓글이 됨

- 댓글이므로 부모글의 num, ref, re_level, re_step, pageNum 가 hidden 으로 넘어온다

+ 원문은 num, ref, re_level, re_step 이 모두 0이고 pageNum 이 null 이다

- 이걸 @ModelAttribute (생략) 로 DTO Board 객체 board 로 바로 받음

 

흐름 설명

1. 넘어온 num 값을 가져옴, 그 num 값은 부모의 num 값이다

2. 작성할 댓글의 num 컬럼을 입력해야하므로, Service 클래스의 getMaxNum() 메소드를 사용해서 최대 num 값 + 1 된 값을 구해서 변수 number 에 저장 *아래에서 설명

3. 댓글 작성이므로 num != 0 이다

4. Service 의 updateRe() 메소드를 사용해서 부모글과 ref 가 같으면서 부모글보다 step 값이 큰 글들의 step 을 1 증가

* 아래에서 설명

5. 현재 board 의 ref, re_lvel, re_step 은 부모의 값이므로, ref 는 그대로, re_level 은 1 증가, re_step 은 1 증가시켜서 board 에 대시 세팅

6. if-else 문 뒤의 코드들을 실행, 변수 number 를 board 의 프로퍼티 num 으로 세팅한다

7. 글 작성한 사람의 ip 주소를 request.getRemoteAddr() 메소드로 구해와서 객체 board 의 프로퍼티 ip에 세팅

8. 객체 board 를 매개변수로 insert() 를 호출해서 댓글을 작성함

* 아래에서 설명

- 이때 board 의 num 은 새로 작성할 글번호, ref 는 부모와 같음, re_level, re_step 은 부모글보다 1 보다 증가된 값

<돌아온 후>

- insert() 의 결과를 변수 result 에 받아서 Model 객체에 저장해서 insert.jsp 로 이동

 

댓글 작성시 필요한 DB작업 2가지

1. getMaxNum() 메소드 : DB에서 최대 num 값 + 1을 가져옴, 컬럼 num 값을 넣기 위해 필요

2. updateRe() 메소드 : 부모글과 ref 가 같으면서 부모글보다 step 값이 큰 글들의 step 값을 1 증가

3. insert() 메소드 : 댓글 등록 (insert)


- Service, DAO 생략하고 Mapper 파일만 보기

- Mapper 파일 Board.xml 에서 id 가 "getMaxNum" 인 SQL문 부분만

	<!-- num 번호중 최대값 구하기 : 첫번째 글은 1번으로  설정 -->
	<select id="getMaxNum" resultType="int">
		select nvl(max(num),0) + 1 from board
	</select>

- DB에 아무 글도 없을때만 max(num) 이 null 이므로 nvl() 함수는 글을 처음으로 작성할때만 사용된다

- 여기서 이미 1 을 더한 뒤 돌아오므로, 이 돌아온 값이 새로 작성할 글의 num 이 될 것


- Mapper 파일 Board.xml 에서 id 가 "updateRe" 인 SQL문 부분만

	<update id="updateRe" parameterType="board">
		update board set re_step = re_step + 1
		 where ref=#{ref} and re_step > #{re_step}
	</update>

- 모글과 ref 가 같으면서 부모글보다 step 값이 큰 글들의 step 을 1 증가시킴


- Mapper 파일 Board.xml 에서 id 가 "insert" 인 SQL문 부분만

	<insert id="insert" parameterType="board">
	<!--<selectKey keyProperty="num" 
			order="BEFORE" resultType="int">
			select nvl(max(num),0) + 1 from board
		</selectKey> -->
		insert into board values (#{num},#{writer},#{subject},
			#{content},#{email},0,#{passwd},#{ref},
			#{re_step},#{re_level},#{ip},sysdate,'n')
	</insert>

 

- View 페이지 insert.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<c:if test="${result > 0 }">
		<script type="text/javascript">
			alert("입력 성공");
			location.href = "list.do";
		</script>
	</c:if>
	<c:if test="${result <= 0 }">
		<script type="text/javascript">
			alert("입력 실패");
			history.go(-1);
		</script>
	</c:if>
</body>
</html>


글 수정 폼

		<a href="updateForm.do?num=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">수정</a>

- view.jsp 에서 '수정' 버튼을 누르면 "updateForm.do" 로 요청하면서 글 번호와 페이지 번호를 전달함

 

- Controller 클래스에서 "updateForm.do" 요청 부분만

	@RequestMapping("updateForm.do")	// 수정 폼
	public String updateForm(int num, String pageNum, Model model) {
		Board board = bs.select(num); // 상세 정보 구하기
		model.addAttribute("board", board);
		model.addAttribute("pageNum", pageNum);
		
		return "updateForm";
	}

- 전달받은 글 번호 num 과 페이지 번호 pageNum 을 바로 저장한다

- select() 메소드는 상세 정보를 가져오는 메소드, 많이 했으므로 설명 생략

- 가져온 상세정보 객체 board 와 페이지 번호 pageNum 을 가져간다

- 수정을 위해서는 글 번호, 페이지 번호, 비밀번호가 필요함

+ 글 번호, 비밀번호는 객체 board 안에 있다

+ 수정 위해 글 번호 필요, 수정 후 원래 페이지로 돌아가기 위해서 페이지 번호 필요

- 이전과 다르게 이번엔 수정폼에서 비번 비교를 할 것이므로 비밀번호를 가져가기

 

- View 페이지 updateForm.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	function chk() {
		if(frm.passwd.value != frm.passwd2.value) {
			alert("암호가 다르면 수정할 수 없습니다");
			frm.passwd2.focus();
			frm.passwd2.value = "";
			return false;
		}
	}
</script>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">게시글 글수정</h2>
		<form action="update.do" method="post" name="frm"
			  onsubmit="return chk()">
			<input type="hidden" name="num" value="${board.num}"> 
			<input type="hidden" name="pageNum" value="${pageNum}"> 
			<input type="hidden" name="passwd" value="${board.passwd}">
			<table class="table table-striped">
				<tr>
					<td>번호</td>
					<td>${board.num}</td>
				</tr>
				<tr>
					<td>제목</td>
					<td><input type="text" name="subject" required="required"
								value="${board.subject}"></td>
				</tr>
				<tr>
					<td>작성자</td>
					<td><input type="text" name="writer" required="required"
								value="${board.writer}"></td>
				</tr>
				<tr>
					<td>이메일</td>
					<td><input type="email" name="email" required="required"
								value="${board.email}"></td>
				</tr>
				<tr>
					<td>암호</td>
					<td><input type="password" name="passwd2" required="required"></td>
				</tr>
				<tr>
					<td>내용</td>
					<td>
						<textarea rows="5" cols="30" name="content" required="required">${board.content}
						</textarea>
					</td>
				</tr>
				<tr>
					<td colspan="2" align="center"><input type="submit" value="확인"></td>
				</tr>
			</table>
		</form>
	</div>
</body>
</html>

- 넘어온 상세 정보 객체 board 에서 글 번호를 가져와서 hidden 객체로 "update.do" 로 전달

+ 글 번호는 출력만 하고 있으므로 hidden 으로 전달해야함

- 넘어온 페이지번호도 다시 hidden 객체로 "update.do" 로 전달

- DB와 사용자가 입력한 비번 비교를 DB 에서 하는 대신 여기서 Javascript 로 하고 있다 

 

<넘어가는 값>

- 글 번호 페이지 번호 뿐 아니라 비밀번호도 전달하고 있다

- 넘어온 상세 정보 객체 board 에서 비밀번호를 가져와서 name 값 "passwd" 변수로 저장해서 전달

비번 비교

- DB와 사용자가 입력한 비번 비교를 DB 에서 하는 대신 여기서 Javascript 로 하고 있다 

- 앞에서 넘어온 객체 board 에서 비밀번호를 가져올 수 있으므로 여기서 비번 비교를 할 수 있다

- 즉, DB의 비번은 passwd 변수에 저장되고, 사용자가 입력한 비번은 passwd2 라는 변수에 저장된다

- Controller 클래스에서 비번 비교하는 대신 이렇게 하는 방법도 있다

 

<script type="text/javascript">
	function chk() {
		if(frm.passwd.value != frm.passwd2.value) {
			alert("암호가 다르면 수정할 수 없습니다");
			frm.passwd2.focus();
			frm.passwd2.value = "";
			return false;
		}
	}
</script>

- form 태그의 name 값이 frm 이므로 frm.passwd.value 와 frm.passwd2.value 를 비교

- frm.passwd.value 는 넘어온 DB의 비밀번호, frm.passwd2.value 는 사용자가 수정 폼에 입력한 비밀번호

+ hidden 으로 넘어가는 값도 입력양식과 마찬가지로 name 값으로 값을 구할 수 있음

+ form 객체 하위객체는 name 값이다, name 값을 .(점) 으로 연결한다

 


글 수정

- 수정 폼에서 입력하고 "확인" 버튼 클릭시 "update.do" 로 요청

 

- Controller 클래스에서 "update.do" 요청 부분만

	@RequestMapping("update.do")	// 수정
	public String update(Board board, String pageNum, Model model) {
		int result = bs.update(board);
		model.addAttribute("result", result);
		model.addAttribute("pageNum", pageNum);
		
		return "update";
	}

- 비번 일치한 경우에만 여기로 넘어온다

- 수정폼에선 hidden 으로 넘어온 글 번호, 글 비밀번호, 사용자가 수정폼에서 입력한 값들을 Board 객체 board 로 받음

+ DTO 프로퍼티명과 일치한 num 이 passwd 인 DB에 저장된 비밀번호가 넘어오게 되지만, DB의 비번과 사용자가 입력한 비번이 일치한 경우만 여기로 넘어오므로 괜찮다

- 수정폼에서 hidden 으로 넘어온 페이지 번호 pageNum 은 DTO Board 프로퍼티에 없으므로 따로 받아줌

- update() 메소드를 호출하면서 매개변수로 board 를 전달한다, 그렇게 수정을 완료

- 수정 결과 result 와 페이지 번호 pageNum 을 Model 객체에 저장해서 전달

- update.jsp 에서 수정 성공 / 실패 처리를 한 후 목록 페이지로 이동할때 페이지 번호가 필요하므로 여기서 페이지 번호를 전달

 

- Service, DAO 생략

- Mapper 파일 Board.xml 에서 id 가 "update" 인 SQL문 부분만

	<update id="update" parameterType="board">
		update board set writer=#{writer},subject=#{subject},
			content=#{content},email=#{email} where num=#{num}
	</update>

- 넘어온 객체 board 에서 수정할 데이터와 글 번호를 가져와서 수정을 한다

 

- View 페이지 update.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<c:if test="${result > 0 }">
		<script type="text/javascript">
			alert("수정 성공 ");
			location.href = "list.do?pageNum=${pageNum}";
		</script>
	</c:if>
	<c:if test="${result <= 0 }">
		<script type="text/javascript">
			alert("수정 실패");
			history.go(-1);
		</script>
	</c:if>
</body>
</html>

- 원래 페이지로 돌아가기 위해 페이지 번호를 받아왔다, "list.do" 로 요청하면서 받은 페이지 번호를 전달


글 삭제 폼

		<a href="deleteForm.do?num=${board.num}&pageNum=${pageNum}"
		   class="btn btn-info">삭제</a>

- view.jsp 에서 '삭제' 버튼을 누르면 "deleteForm.do" 로 요청하면서 글 번호와 페이지 번호를 전달함

 

- Controller 클래스에서 "deleteForm.do" 요청 부분만

	@RequestMapping("deleteForm.do")
	public String deleteForm(int num, String pageNum, Model model) {
		Board board = bs.select(num);
		model.addAttribute("board", board);
		model.addAttribute("pageNum", pageNum);
		
		return "deleteForm";
	}

 

- 전달받은 글 번호 num 과 페이지 번호 pageNum 을 바로 저장한다

- select() 메소드는 상세 정보를 가져오는 메소드, 많이 했으므로 설명 생략

- 가져온 상세정보 객체 board 와 페이지 번호 pageNum 을 가져간다

 

- 삭제를 위해서는 글 번호, 페이지 번호, 비밀번호가 필요함

+ 글 번호, 비밀번호는 객체 board 안에 있다

- 원래는 수정폼에 비밀번호는 가져갈 필요 없지만, 지금은 수정폼에서 비번 비교를 할 것이므로 가져감

+ 삭제 위해 글 번호 필요, 삭제 후 원래 페이지로 돌아가기 위해서 페이지 번호 필요

 

- View 페이지 deleteForm.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	function chk() {
		if (frm.passwd.value != frm.passwd2.value) {
			alert("암호가 다릅니다. 수정후 작업하세요");
			frm.passwd2.focus();
			frm.passwd2.value = "";
			return false;
		}
	}
</script>
</head>
<body>
	<div class="container">
		<h2 class="text-primary">게시글 삭제</h2>
		<form action="delete.do" name="frm" onsubmit="return chk()"	method="post">
			<input type="hidden" name="pageNum" value="${pageNum}"> 
			<input	type="hidden" name="passwd" value="${board.passwd}"> 
			<input type="hidden" name="num" value="${board.num}">
			<table class="table">
				<tr>
					<td>암호</td>
					<td><input type="password" name="passwd2" required="required"></td>
				</tr>
				<tr>
					<td colspan="2"><input type="submit" value="확인"></td>
				</tr>
			</table>
		</form>
	</div>
</body>
</html>

- 넘어온 상세 정보 객체 board 에서 글 번호를 가져와서 hidden 객체로 "delete.do" 로 전달

- 넘어온 상세 정보 객체 board 에서 비밀번호를 가져와서 hidden 객체로 변수 "passwd" 에 저장 후 전달

- 넘어온 페이지번호도 다시 hidden 객체로 "update.do" 로 전달

- DB와 사용자가 입력한 비번 비교를 DB 에서 하는 대신 여기서 Javascript 로 하고 있다 

 

<넘어가는 값>

- 글 번호 페이지 번호 뿐 아니라 비밀번호도 전달하고 있다

- 넘어온 상세 정보 객체 board 에서 비밀번호를 가져와서 name 값 "passwd" 변수로 저장해서 전달

- 이때 비밀번호는 넘겨줄 필요 없지만 비번 비교용으로 hidden 객체를 생성해서 변수 "passwd" 에 값을 저장하기 위해 hidden 객체를 사용했다

비번 비교

- DB와 사용자가 입력한 비번 비교를 DB 에서 하는 대신 여기서 Javascript 로 하고 있다 

- 앞에서 넘어온 객체 board 에서 비밀번호를 가져올 수 있으므로 여기서 비번 비교를 할 수 있다

- 즉, DB의 비번은 passwd 변수에 저장되고, 사용자가 입력한 비번은 passwd2 라는 변수에 저장된다

- Controller 클래스에서 비번 비교하는 대신 이렇게 하는 방법도 있다

 

<script type="text/javascript">
	function chk() {
		if (frm.passwd.value != frm.passwd2.value) {
			alert("암호가 다릅니다. 수정후 작업하세요");
			frm.passwd2.focus();
			return false;
		}
	}
</script>

- form 태그의 name 값이 frm 이므로 frm.passwd.value 와 frm.passwd2.value 를 비교

- frm.passwd.value 는 넘어온 DB의 비밀번호, frm.passwd2.value 는 사용자가 수정 폼에 입력한 비밀번호

+ hidden 으로 넘어가는 값도 입력양식과 마찬가지로 name 값으로 값을 구할 수 있음

+ form 객체 하위객체는 name 값이다, name 값을 .(점) 으로 연결한다

 

 


글 삭제

- 글 삭제 폼에서 비밀번호를 입력하고 비밀번호가 일치할때 "확인" 클릭시 "delete.do" 로 요청한다

- 요청하면서 글 번호, 페이지 번호, 비밀번호 넘어옴

+ 넘어온 값 중, 비밀번호는 필요 없다

 

- Controller 클래스에서 "delete.do" 요청 부분만

	@RequestMapping("delete.do")
	public String delete(int num, String pageNum, Model model) {
		int result = bs.delete(num);
		model.addAttribute("result", result);
		model.addAttribute("pageNum", pageNum);
		
		return "delete";
	}

- 넘어온 글 번호와 페이지 번호를 받고 Service 의 delete() 메소드 호출

<돌아온 후>

- 삭제 결과값 result 와 페이지 번호 pageNum 을 가져간다

- delete.jsp 에서 삭제 성공 / 실패 처리를 하면서 성공시 목록 페이지로 넘어갈 것, 그래서 페이지 번호를 delete.jsp 로 가져가야한다

 

- Service 는 생략

- DAO 에서 delete() 메소드 부분만

	public int delete(int num) {
		return sst.update("boardns.delete",num);
	}

- 실제 삭제 (delete) 가 아닌 del 값을 "y" 로 수정할 것이므로 SqlSession 객체 제공 메소드 중 update 메소드를 사용해야함

 

- Mapper 파일 Board.xml 에서 id 가 "delete" 인 SQL문 값만

	<update id="delete" parameterType="int">
		update board set del='y' where num=#{num}
	</update>

- 해당 글의 del 컬럼의 값을 "y" 로 설정하면 삭제된 글이 됨

- 실제로 삭제를 하진 않았다

 


Spring MVC ajax 비동기 댓글 게시판 프로그램 

- 댓글 처리시에도 페이지를 바꾸지 않고 비동기식으로 처리하는 경우가 많다

- 댓글 기능을 ajax 기능을 써서 페이지 바꾸지 않고 댓글 달기 / 수정 / 삭제를 해보자

 

실습 준비

- 클라우드의 sboard 프로젝트를 다운, 압축 해제, import

- 이 sboard 프로젝트는 부모 테이블 뿐 아니라 댓글을 위한 자식 테이블이 들어가있다, 총 테이블 2개

 

파일들 살펴보기 : web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	<!-- 한글 입력 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

- url-pattern 이 / 이므로 모든 요청이 Dispatcher Servlet 으로 간다

- 한글값 인코딩 처리가 되어있음

 

파일들 살펴보기 : servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />
	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />
	<resources mapping="/css/**" location="/WEB-INF/css/" />
	<resources mapping="/js/**" location="/WEB-INF/js/" />
	<resources mapping="/fonts/**" location="/WEB-INF/fonts/" />
	<resources mapping="/images/**" location="/WEB-INF/images/" />
	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>	
	<context:component-scan base-package="board1" />	
</beans:beans>

+ resources mapping 으로 View 파일들이 저장된 곳의 위치를 지정

- 매핑 잡는 방법 : 위의 코드처럼 폴더명을 쓰고 /** 를 쓴다 ex) "/resources/**"

- base-package 자바파일이 저장될 최상위 디렉토리는 board1 이다

- 테이블이 2개이므로 부모 테이블에 대한 클래스 1개, 자식 테이블에 대한 클래스 1개로 클래스도 2개이다

- DAO, DTO, Service 도 테이블마다 따로 있다

+ PagingPgm 클래스는 board1 프로젝트와 같은 내용

 

테이블 2개

1. 부모 테이블은 board1 으로서 이전 프로젝트 board1 에서 이미 만들었던 테이블 board을 그대로 활용

- 새로 만들 필요 없다

2. 자식 테이블은 replyBoard 이다, 댓글을 저장하는 테이블이다

 

파일들 살펴보기 : root-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
	
	<context:property-placeholder location="classpath:jdbc.properties" />
		
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="driverClass" value="${jdbc.driverClassName}" />
		<property name="jdbcUrl" value="${jdbc.url}" />
		<property name="user" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
	</bean>		
	
	<!-- 스프링 jdbc 즉 스프링으로 oracle 디비 연결 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:configuration.xml" />
		<property name="mapperLocations" value="classpath:sql/*.xml" />
	</bean>
	
	<bean id="session" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg index="0" ref="sqlSessionFactory" />
	</bean>
	
</beans>

- jdbc.properties 파일을 불러와서 DB 접속 정보 설정

- jdbc.properties

jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:xe
jdbc.username=spring
jdbc.password=spring123
jdbc.maxPoolSize=20

 

파일들 살펴보기 : configuration.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<typeAliases>
		<typeAlias alias="board" type="board1.model.Board" />
		<typeAlias alias="rb" type="board1.model.ReplyBoard" />
	</typeAliases>
	<!-- 
	<mappers>
		<mapper resource="Board.xml" />
		<mapper resource="ReplyBoard.xml" />
	</mappers> 
	-->
</configuration>

- alias 가 두개 잡혀 있다

- 부모 테이블에 관련된 DTO 인 Board DTO 에 대한 alias 가 "board"

- 자식 테이블에 관련된 DTO 인 ReplyBoard DTO 에 대한 alais 가 "rb"

 

- 테이블 개수가 늘어나면 DAO, DTO, Service, Controller, Alias 모두 늘어난다

 


테이블 생성

- SQL파일이 2개 있다

- board1.sql 에서 board 테이블 생성 코드 있다, 이전 프로젝트에서 생성 했으므로 생성할 필요 없음

- sboard.sql 에서 replyBoard 테이블을 생성하자

 

테이블 2개

1. 부모 테이블은 board1 으로서 이전 프로젝트 board1 에서 이미 만들었던 테이블 board을 그대로 활용

- 새로 만들 필요 없다

2. 자식 테이블은 replyBoard 이다, 댓글을 저장하는 테이블이다

- 부모 테이블 안의 글 마다 댓글을 따로 달 것이므로 자식 테이블이 필요함

 

- sboard.sql

select * from tab;
select * from board;
select * from REPLYBOARD;

-- 댓글 게시판
drop table replyBoard;
create table replyBoard (
	rno number primary key, -- 댓글 번호
	bno number not null references board(num), -- 부모키 번호
	-- on delete cascade,
	replytext varchar2(500) not null, -- 댓글 내용
	replyer varchar2(50) not null, -- 댓글 작성자
	regdate date not null, -- 댓글 작성일
	updatedate date not null -- 댓글 수정일
);
select * from REPLYBOARD;
select * from board order by num desc;
insert into REPLYBOARD values(10,262,'11','나',sysdate,sysdate);

- 테이블 replyBoard 를 생성하자

- 이 테이블 관련 DTO는 이 컬럼명과 같은 이름의 프로퍼티를 만들어아햔다

+ 테이블 board 는 생성하지 않고 이전 프로젝트의 테이블 그대로 쓰기

 

테이블 replyBoard 컬럼 설명

- rno : 댓글 번호, primary key

- 여기서도 sequence 를 쓰지 않고 있으므로 최대 댓글 번호 rno 를 구해서 1 증가시킨 값을 새 글의 rno 로 넣을것

- bno : 부모 글의 번호, foreign key 제약 조건이 설정되어있다

- replytext : 댓글 내용

- replyer : 댓글 단 사람 이름

- regdate : 댓글 작성된 날짜

- updatedate : 댓글 수정된 날짜

 

 

bno 컬럼 설명

- 부모 글의 번호, foreign key 제약 조건이 설정되어있다

- 부모 글이 같은 댓글 끼리는 bno 값이 같다

- 컬럼 bno 는 참조하는 부모 테이블 board 에서 num 컬럼을 부모키로 설정

+ 부모 키의 조건은 primary 또는 unique, board 의 num 은 primary key 이므로 부모키가 될 수 있다

+ bno 에 on delete cascade 옵션을 붙이면 부모 글을 삭제할때 달린 댓글(참조하는 자식)들도 모두 삭제됨

	bno number not null references board(num) on delete cascade, -- 부모키 번호

- bno에 on delete cascade 옵션이 없으면, 참조하는 자식이 있는 경우 부모 글이 삭제되지 않음!

+ 단 여기서는 on delete cascade 가 필요 없다, 실제 부모글을 삭제하는 코드는 없기때문에, update 로 상태값만 바꿔줌

 


흐름 설명

- 프로젝트 실행

- 이전에 달았던 댓글(실제론 글) 이 아니라 한 부모글에 대한 실제 댓글을 달 수 있다!

- 부모글마다 댓글이 따로 달릴 수 있다

- bno 값이 같은 댓글들만 출력되는 것이다

 

이전에 했던 댓글 vs 지금 하는 댓글

- 이전에 했던 댓글은 1개의 테이블에 입력됐던 사실상 글

- 지금 하는 댓글은 실제 부모글에 달리는 댓글

 


코드 설명

- index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<script type="text/javascript">
		location.href = "list";
	</script>
</body>
</html>

- url-pattern 이 / 로 설정되어 있으므로 어떤 걸로 요청해도 Dispatcher Servlet 으로 이동한다

- "list" 로 요청했다

 

- Controller 클래스 BoardController.java 에서 "list" 요청 부분만

	@RequestMapping("/list/pageNum/{pageNum}")
	public String list(@PathVariable String pageNum, Board board, Model model) {
		final int rowPerPage = 10;
		if (pageNum == null || pageNum.equals("")) {
			pageNum = "1";
		}
		int currentPage = Integer.parseInt(pageNum);
		// int total = bs.getTotal();
		int total = bs.getTotal(board); // 검색
		int startRow = (currentPage - 1) * rowPerPage + 1;
		int endRow = startRow + rowPerPage - 1;
		PagingPgm pp = new PagingPgm(total, rowPerPage, currentPage);
		board.setStartRow(startRow);
		board.setEndRow(endRow);
		// List<Board> list = bs.list(startRow, endRow);
		int no = total - startRow + 1;
		List<Board> list = bs.list(board);
		model.addAttribute("list", list);
		model.addAttribute("no", no);
		model.addAttribute("pp", pp);
		// 검색
		model.addAttribute("search", board.getSearch());
		model.addAttribute("keyword", board.getKeyword());
		return "list";
	}

- 요청했을때 값을 전달하는 방식이 달라짐

바뀐 방식

1. @RequestMapping 로 요청이름값 "list" 를 받고, / 변수명 pageNum/ pageNum 변수에 전달될 값을 쓴다

2. 위처럼 썼을때는 매개변수쪽에 @PathVariable 어노테이션을 쓰고 pageNum 변수에 전달되는 값을 오른쪽의 변수 pageNum 이 받음

+ 지금은 index.jsp 에서 넘어왔으므로 아무 것도 가지고 오지 않았다, pageNum 값이 없음

 

기존방식 vs 바뀐 방식

기존 방식
list?pageNum=1
바뀐 방식
/list/pageNum/{pageNum}

 

- View 페이지 list.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">게시판 목록</h2>
		<table class="table table-striped">
			<tr>
				<td>번호</td>
				<td>제목</td>
				<td>작성자</td>
				<td>작성일</td>
				<td>조회수</td>
			</tr>
			<c:if test="${empty list}">
				<tr>
					<td colspan="5">데이터가 없습니다</td>
				</tr>
			</c:if>
			<c:if test="${not empty list}">
				<c:set var="no1" value="${no }"></c:set>
				<c:forEach var="board" items="${list }">
					<tr>
						<td>${no1}</td>
						<c:if test="${board.del =='y' }">
							<td colspan="4">삭제된 데이터 입니다</td>
						</c:if>
						<c:if test="${board.del !='y' }">
							<td><a href="${path }/view/num/${board.num}/pageNum/${pp.currentPage}"
									class="btn btn-default"> 
									<c:if test="${board.re_level >0 }">
										<img alt="" src="${path }/images/level.gif" height="2" width="${board.re_level *5 }">
										<img alt="" src="${path }/images/re.gif">
									</c:if> 
									${board.subject} 
									<c:if test="${board.readcount > 30 }">
										<img alt="" src="${path }/images/hot.gif">
									</c:if></a></td>
							<td>${board.writer}</td>
							<td>${board.reg_date}</td>
							<td>${board.readcount}</td>
						</c:if>
					</tr>
					<c:set var="no1" value="${no1 - 1}"></c:set>
				</c:forEach>
			</c:if>
		</table>
		<form action="${path}/list/pageNum/1">
			<select name="search">
				<option value="subject"
					<c:if test="${search=='subject'}">selected="selected" </c:if>>제목</option>
				<option value="content"
					<c:if test="${search=='content'}">selected="selected" </c:if>>내용</option>
				<option value="writer"
					<c:if test="${search=='writer'}">selected="selected" </c:if>>작성자</option>
				<option value="subcon"
					<c:if test="${search=='subcon'}">selected="selected" </c:if>>제목+내용</option>
			</select> 
			<input type="text" name="keyword"> 
			<input type="submit" value="확인">
		</form>
		<ul class="pagination">
			<c:if test="${not empty keyword}">
				<c:if test="${pp.startPage > pp.pagePerBlk }">
					<li><a href="${path }/list/pageNum/${pp.startPage - 1}?search=${search}&keyword=${keyword}">이전</a></li>
				</c:if>
				<c:forEach var="i" begin="${pp.startPage}" end="${pp.endPage}">
					<li <c:if test="${pp.currentPage==i}">class="active"</c:if>><a
						href="${path }/list/pageNum/${i}?search=${search}&keyword=${keyword}">${i}</a></li>
				</c:forEach>
				<c:if test="${pp.endPage < pp.totalPage}">
					<li><a href="${path }/list/pageNum/${pp.endPage + 1}?search=${search}&keyword=${keyword}">다음</a></li>
				</c:if>
			</c:if>
			<c:if test="${empty keyword}">
				<c:if test="${pp.startPage > pp.pagePerBlk }">
					<li><a href="${path }/list/pageNum/${pp.startPage - 1}">이전</a></li>
				</c:if>
				<c:forEach var="i" begin="${pp.startPage}" end="${pp.endPage}">
					<li <c:if test="${pp.currentPage==i}">class="active"</c:if>><a
						href="${path }/list/pageNum/${i}">${i}</a></li>
				</c:forEach>
				<c:if test="${pp.endPage < pp.totalPage}">
					<li><a href="${path }/list/pageNum/${pp.endPage + 1}">다음</a></li>
				</c:if>
		  </c:if>
		</ul>
		<div align="center">
			<a href="${path}/insertForm" class="btn btn-info">글 입력</a>
		</div>
	</div>
</body>
</html>

 

요청하면서 값 전달하는 방법 1 (list.jsp 부분)

 

<form action="${path}/list/pageNum/1">
			<select name="search">
				<option value="subject"
					<c:if test="${search=='subject'}">selected="selected" </c:if>>제목</option>
				<option value="content"
					<c:if test="${search=='content'}">selected="selected" </c:if>>내용</option>
				<option value="writer"
					<c:if test="${search=='writer'}">selected="selected" </c:if>>작성자</option>
				<option value="subcon"
					<c:if test="${search=='subcon'}">selected="selected" </c:if>>제목+내용</option>
			</select> 
			<input type="text" name="keyword"> 
			<input type="submit" value="확인">
		</form>

- ${path} : 현재 프로젝트 명을 의미, header.jsp 안에 있다

- list : "list" 란 이름으로 요청

- pageNum : 변수명

- 1 : pageNum 에 넣을 값

- 즉, "list" 로 요청하면서 pageNum 에 1 을 저장해 전달하라는 의미

 

- 여기서 선택시 다시 "list" 로 요청한다, 이때 "list" 로 갔을때는 pageNum 에 1 이라는 값이 전달됨

 

- header.jsp 부분

<c:set var="path" value="${pageContext.request.contextPath }" />

- 현재 프로젝트명 sboard 가 변수 path 에 저장되어있다

- JSTL set 태그로 변수 선언했다, 해당 내용은 EL 태그로 출력 가능

 

요청하면서 값 전달하는 방법 2 (list.jsp 부분)

- 마찬가지로 페이지 메뉴에 있는 페이지 또는 이전, 다음을 클릭시 "list" 로 요청하면서 해당 페이지 번호르 전달한다

- 이전에는 list?pageNum=${pp.startPage-1} 형식으로 전달했지만, 현재 list/pageNum/${pp.startPage-1} 형식으로 전달

 

제목 클릭시 상세 페이지로 이동 (list.jsp 부분)

<a href="${path }/view/num/${board.num}/pageNum/${pp.currentPage}" class="btn btn-default"> 
		<c:if test="${board.re_level >0 }">
		<img alt="" src="${path }/images/level.gif" height="2" width="${board.re_level *5 }">
		<img alt="" src="${path }/images/re.gif">
		</c:if> 
		${board.subject} 
		<c:if test="${board.readcount > 30 }">
		<img alt="" src="${path }/images/hot.gif">
		</c:if></a>

- 상세 페이지로 이동하기 위해 "view" 로 요청하면서 num, pageNum 변수에 값들을 저장해서 전달

- num 변수에 ${board.num} 값이 저장되어 전달, pageNum 변수에 ${pp.currentPage} 값이 저장되어 전달

 

- Controller 클래스 BoardController.java 에서 "view" 요청 부분만

	@RequestMapping("/view/num/{num}/pageNum/{pageNum}")
	public String view(@PathVariable int num, @PathVariable String pageNum, Model model) {
		bs.selectUpdate(num);
		Board board = bs.select(num);
		model.addAttribute("board", board);
		model.addAttribute("pageNum", pageNum);
		return "view";
	}

- /view/num/{num}/pageNum/{pageNum} 으로 요청과 값을 받음

- 전달된 값을 받을때는 "요청이름값/변수/{값}/변수/{값}" 형태로 받는다

- 조회수 1 증가 + 상세 정보 구하기 작업을 한 후 view.jsp 파일로 이동, 상세 정보 board 와 페이지 번호 pageNum 전달

 

- view.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	/* 	window.onload=function() {
	
	 } */
	$(function() {
		$('#slist').load('${path}/slist/num/${board.num}')
//		$('#list').load('${path}/list/pageNum/${pageNum}');
		$('#repInsert').click(function() {
			if (!frm.replytext.value) {
				alert('댓글 입력후에 클릭하시오');
				frm.replytext.focus();
				return false;
			}
			var frmData = $('form').serialize();
			// var frmData = 'replyer='+frm.replyer.value+'&bno='+
			//				  frm.bno.value+'&replytext='+frm.replytext.value;				  
			$.post('${path}/sInsert', frmData, function(data) {
				$('#slist').html(data);
				frm.replytext.value = '';
			});
		});
	});
</script>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">게시글 상세정보</h2>
		<table class="table table-bordered">
			<tr>
				<td>제목</td>
				<td>${board.subject}</td>
			</tr>
			<tr>
				<td>작성자</td>
				<td>${board.writer}</td>
			</tr>
			<tr>
				<td>조회수</td>
				<td>${board.readcount}</td>
			</tr>
			<tr>
				<td>아이피</td>
				<td>${board.ip}</td>
			</tr>
			<tr>
				<td>이메일</td>
				<td>${board.email}</td>
			</tr>
			<tr>
				<td>내용</td>
				<td><pre>${board.content}</pre></td>
			</tr>
		</table>
		<a href="${path}/list/pageNum/${pageNum}" class="btn btn-info">목록</a>
		<a href="${path}/updateForm/num/${board.num}/pageNum/${pageNum}"
			class="btn btn-info">수정</a> <a
			href="${path}/deleteForm/num/${board.num}/pageNum/${pageNum}"
			class="btn btn-info">삭제</a> <a
			href="${path}/insertForm/nm/${board.num}/pageNum/${pageNum}"
			class="btn btn-info">답변</a>
		<p>
		<form name="frm" id="frm">
			<input type="hidden" name="replyer" value="${board.writer}">
			<input type="hidden" name="bno" value="${board.num}"> 댓글 :
			<textarea rows="3" cols="50" name="replytext"></textarea>
			<input type="button" value="확인" id="repInsert">
		</form>
		<div id="slist"></div>
		<!-- <div id="list"></div> -->
	</div>
</body>
</html>

 

버튼 처리 (view.jsp 부분)

		<a href="${path}/list/pageNum/${pageNum}" class="btn btn-info">목록</a>
		<a href="${path}/updateForm/num/${board.num}/pageNum/${pageNum}"
			class="btn btn-info">수정</a> <a
			href="${path}/deleteForm/num/${board.num}/pageNum/${pageNum}"
			class="btn btn-info">삭제</a> <a
			href="${path}/insertForm/nm/${board.num}/pageNum/${pageNum}"
			class="btn btn-info">답변</a>

- 잘못찾아 갈땐 앞에 프로젝트 명 sboard, 즉 ${path} 를 넣어줌

- 목록으로 가기 위해 "list" 요청시에는 페이지 번호를 전달해야함

- 수정폼, 삭제폼, 답변폼 으로 가기 위한 요청에서는 글 번호, 페이지 번호 를 가져가야함


댓글

- 댓글은 댓글 입력 부분, 댓글 처리 부분이 나뉨

- 댓글 처리시에는 댓글 목록 처리, 댓글 작성 처리가 있다

 

댓글 입력 부분 (view.jsp 부분)

		<form name="frm" id="frm">
			<input type="hidden" name="replyer" value="${board.writer}">
			<input type="hidden" name="bno" value="${board.num}"> 댓글 :
			<textarea rows="3" cols="50" name="replytext"></textarea>
			<input type="button" value="확인" id="repInsert">
		</form>
		<div id="slist"></div>

- 댓글을 입력하고 " 확인을 누르면 댓글이 달린다

- 비동기적으로 처리할 것이므로 action 값이 없다

+ 동기적으로 처리할떄는 form 의 action 값으로 값을 전달함, action 값이 있어야함

- 아래의 id 가 "slist" 인 div 태그는 댓글 목록이 출력될 자리

- 처리한 댓글 목록을 콜백함수로 받아서 아래의 div 태그에 뿌릴 것

- textarea 에 내용을 입력하고 "확인" 버튼 클릭시 onClick 이벤트 발생, 그걸 jQuery 에서 처리 * 아래에서 설명

- hidden 객체로 부모글 작성자명(원래는 댓글 작성자명을 써야함) ${board.writer} 값을 변수 "replyer" 에 저장

- hidden 객체로 부모글 번호 ${board.num} 값을 변수 "bno" 에 저장

- 사용자가 입력한 댓글 내용은 변수 "replytex" 에 저장

 

- 댓글을 달면 replyBoard 테이블에 저장된다

create table replyBoard (
	rno number primary key, -- 댓글 번호
	bno number not null references board(num), 
	-- on delete cascade, -- 부모키 번호
	replytext varchar2(500) not null, -- 댓글 내용
	replyer varchar2(50) not null, -- 댓글 작성자
	regdate date not null, -- 댓글 작성일
	updatedate date not null -- 댓글 수정일
);

- 컬럼별로 어떤 값을 어디로 넣어야할지 보자

- rno 컬럼 : 댓글 번호는 최대 rno 컬럼을 구해서 1 더한 값을 넣을 것

- bno 컬럼 : 현재 view.jsp 에는 부모글 정보를 저장한 board 객체가 넘어오므로 ${board.number} 로 가져오면된다

- replytext 컬럼 : 댓글 내용, 사용자가 view.jsp 댓글 작성 부분에서 입력한 글을 의미

- replyer 컬럼 : 댓글 작성자를 저장함, 댓글 작성자를 구해와야한다

댓글 작성자 구하는 2가지 방법

1. 작성자명을 직접 입력하게 함

2. 로그인 해야만 댓글을 입력할 수 있게 하고, 세션에서 id 값을 가져와서, 그걸로 DB의 회원 이름을 구해옴

- 현재는 둘 다 하고 있지 않고 그냥 부모글 작성자의 이름이 댓글 작성자 이름 replyer 로 들어가게 된다

- regdate 컬럼 : sysdate

- updatedate 컬럼 : 처음엔 regdate 로 같은 값 삽입, 나중에 수정시엔 이 값 수정

 

댓글 처리 부분 (view.jsp 부분)

<script type="text/javascript">
	/* 	window.onload=function() {
	
	 } */
	$(function() {
		$('#slist').load('${path}/slist/num/${board.num}')
//		$('#list').load('${path}/list/pageNum/${pageNum}');
		$('#repInsert').click(function() {
			if (!frm.replytext.value) {
				alert('댓글 입력후에 클릭하시오');
				frm.replytext.focus();
				return false;
			}
			var frmData = $('form').serialize();
			// var frmData = 'replyer='+frm.replyer.value+'&bno='+
			//				  frm.bno.value+'&replytext='+frm.replytext.value;				  
			$.post('${path}/sInsert', frmData, function(data) {
				$('#slist').html(data);
				frm.replytext.value = '';
			});
		});
	});
</script>

함수 실행 시기

- load() : view.jsp 실행되자 마자 load() 함수가 실행된다

- click() : 댓글 작성 후 "확인" 버튼을 눌러야 아래의 click() 이 실행된다

- 댓글 목록 구하기 처리와 댓글 작성 처리로 나뉜다 * 아래에서 나눠서 설명

- 댓글 작성 후 다시 댓글 목록 구하기 요청을 하므로 댓글 목로 구하기 처리부터 설명


댓글 목록 구하기 처리 (view.jsp 부분 일부)

		$('#slist').load('${path}/slist/num/${board.num}')

- id 가 slist 인 태그를 불러옴, 즉 댓글 목록을 보여줄 공간인 div 태그를 가져왔다

- 그 div 태그에 load() 함수를 사용해서 "slist" 로 요청하고 부모글 번호 ${board.num} 를 전달한다

- 부모글 번호 를 전달해야하는 이유 : 댓글 중 bno 가 부모글 번호와 같은 댓글들을 리스트로 가져와서 출력해야하므로

- 그럼 그 요청으로 인해 브라우저에 출력되는 값이 돌아와서 div 태그 안에 보여지는 것이다, 출력되는 값은 가져와진 댓글 이므로, 댓글 목록이 div 태그 안에 보여짐, 

- 이 작업은 이 페이지 view.jsp 로 들어오자마자 자동으로 처리됨

+ load('${path}/slist/num/${board.num}') 는 load('slist?num=${board.num}') 와 같은 기능

 

- Controller 클래스  ReplyBoardController.java 에서 "slist" 요청 부분만

	// 댓글 목록 구하기
	@RequestMapping("/slist/num/{num}")
	public String slist(@PathVariable int num, Model model) {
		Board board = bs.select(num); // 부모 테이블의 상세 정보 구하기
		List<ReplyBoard> slist = rbs.list(num); // 댓글 목록
		model.addAttribute("slist", slist);
		model.addAttribute("board", board);
		return "slist";
	}

- 넘어오는 값은 부모글의 글 번호 num, 그걸 @PathVariable 로 옆의 변수 num 에 저장한다

- 넘어온 부모 글 번호 num 으로 BoardService 의 메소드 select() 로 부모 글의 상세 정보를 구한 후 객체 board 로 받아서 저장한다

- ReplyBoardService 의 메소드 list() 로 댓글 목록을 구한다, 이때, 넘어온 부모글 번호 num 을 전달한다 이 값으로 댓글 중 bno 가 num 인 댓글 목록을 가져올 것

- 여러개 데이터를 가져오므로 List 로 반환받는다

<돌아온 후>

- 구해온 해당 부모글의 댓글 목록 slist 와 부모 글 정보 객체 board 를 Model 객체에 저장해서 slist.jsp 로 전달

- 댓글 목록 slist 를 slist.jsp 에서 댓글 목록 출력을 하면, 그 브라우저에 출력된 내용이 load() 함수로 돌아가서 view.jsp 의 div 태그에 출력함

 

- Service 클래스 ReplyBoardServiceImpl.java 에서 list() 메소드 부분만

	public List<ReplyBoard> list(int num) {
		return rbd.list(num);
	}

- DAO 클래스 ReplyBoardDaoImpl.java 에서 list() 메소드 부분만

	public List<ReplyBoard> list(int bno) {
		return sst.selectList("rbns.list", bno);
	}

- 넘어온 부모글 번호를 매개변수 bno 로 받는다

 

- Mapper 파일 ReplyBoard.xml 에서 id 가 "list" 인 SQL문 부분만

	<select id="list" parameterType="int" resultMap="rbResult">
		select * from replyBoard where bno=#{bno} order by rno
	</select>

- 넘어온 값 #{bno} 는 부모글 번호이다

- 댓글들을 저장한 replyBoard 테이블에서 bno 컬럼의 값이 부모글 번호인 모든 댓글들을 검색해서 리스트로 돌려줌

+ bno 값이 같은 댓글들은 같은 부모 아래의 댓글들

 

- View 페이지 slist.jsp

- 이 페이지에 출력되는 내용을 view.jsp 의 load() 함수가 불러서, view.jsp 의 div 태그 안에 출력된다!

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	$(function() {
		$('.edit1').click(function() {
			var id  = $(this).attr('id');  // rno
			var txt = $('#td_'+id).text(); // replytext
			$('#td_'+id).html("<textarea rows='3' cols='30' id='tt_"+id+"'>"+txt
				+"</textarea>");
			$('#btn_'+id).html(
			   "<input type='button' value='확인' onclick='up("+id+")'> "
			  +"<input type='button' value='취소' onclick='lst()'>");
		});
	});
	function up(id) {
		var replytext = $('#tt_'+id).val();
		var formData = "rno="+id+'&replytext='+replytext
			+"&bno=${board.num}";
		$.post('${path}/repUpdate',formData, function(data) {
			$('#slist').html(data);
		});
	}
	function lst() {
		$('#slist').load('${path}/slist/num/${board.num}');
	}
	function del(rno,bno) {
		var formData="rno="+rno+"&bno="+bno;
		$.post("${path}/repDelete",formData, function(data) {
			$('#slist').html(data);
		});
	}
</script>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">댓글</h2>
		<table class="table table-bordered">
			<tr>
				<td>작성자</td>
				<td>내용</td>
				<td>수정일</td>
				<td></td>
			</tr>
			<c:forEach var="rb" items="${slist}">
				<tr>
					<td>${rb.replyer}</td>
					<td id="td_${rb.rno}">${rb.replytext}</td>
					<td>${rb.updatedate }</td>
					<td id="btn_${rb.rno}">
						<c:if test="${rb.replyer==board.writer }">
							<input type="button" value="수정" class="edit1" id="${rb.rno}">
							<input type="button" value="삭제" onclick="del(${rb.rno},${rb.bno})">
						</c:if></td>
				</tr>
			</c:forEach>
		</table>
	</div>
</body>
</html>

- 이 페이지에 출력되는 내용을 view.jsp 의 load() 함수가 불러서, view.jsp 의 div 태그 안에 출력된다!

- 해당 부모글의 댓글 목록 slist 와 부모 글 정보 객체 board 가 넘어왔다

- 넘어온 댓글 목록 slist 를 forEach 의 items 에 넣고 하나씩 댓글을 출력

+ 댓글 수정, 삭제 기능도 있다

 


- 댓글 목록 구하기 처리를 봤고 이제 다시 view.jsp 로 돌아와서 댓글 작성을 하는 처리를 보자

댓글 작성 처리 : 댓글 쓰고 "확인" 을 눌러서 click 이벤트 발생시  (view.jsp 부분 일부)

		$('#repInsert').click(function() {
			if (!frm.replytext.value) {
				alert('댓글 입력후에 클릭하시오');
				frm.replytext.focus();
				return false;
			}
			var frmData = $('form').serialize();
			// var frmData = 'replyer='+frm.replyer.value+'&bno='+
			//				  frm.bno.value+'&replytext='+frm.replytext.value;		
			// $.post('요청이름','전달될값','콜백함수');
			$.post('${path}/sInsert', frmData, function(data) {
				$('#slist').html(data);
				frm.replytext.value = '';
			});
		});

- 댓글 작성 후 "확인" 버튼을 누르면 click 이벤트 발생해서 click() 함수가 실행됨

- 윗부분은 유효성 검사

- 아랫부분에 작성한 댓글의 replyer, bno(부모글번호), replytext 값이 넘어가는 코드를 전달해야한다, 그 전달을 이 click() 함수 내에서 처리함

넘어가는 값

- 값들을 전달하기 위해 "sInsert" 로 요청하면서 frmData 를 전달함

- 넘어가는 값들 replyer, bno(부모글번호), replytext 를 변수 frmData 에 일일히 저장해야한다 (주석 부분)

- 여기선 대신 jQuery 를 이용해서 간략하게 form 태그 $('form') 으로 구한 후 serialize() 로 form 태그의 변수들을 한꺼번에 구해서 frmData 에 저장하는 방법 사용

- post() 함수로 전달되는 값을 여러개 쓸때는 변수=값&변수=값&변수=값 형태로 쓴다

+ 앞에 ? 는 파일명이 있는 경우만 파일명?변수=값&변수=값&변수=값 형태로 쓰는 것이다

- post 방식 요청이지만 형태만 마치 get 방식으로 값이 넘어가는 것 처럼 쓰는 것

출력

- 브라우저에 출력된 결과를 콜백함수로 받을때 data 란 이름으로 받아서 id 값이 slist 인 div 영역에 출력하고 있다

- .html(data) 에 의해 sInsert 요청에 의해 브라우저에 출력된 값이 id 가 div 인 영역에 출력되게 됨

 

+ post() 함수 형식

$.post('요청이름', '전달될값', '콜백함수')

+ 아래의 form 태그에 action 이 없었다

- 비동기로 처리하므로 action 대신 ajax post() 함수 사용해서 요청함

 

- Controller 클래스 ReplyBoardController.java 에서 "sInsert" 요청 부분만

	// 댓글 작성하기
	@RequestMapping("/sInsert")
	public String sInsert(ReplyBoard rb, Model model) {
		rbs.insert(rb);
		return "redirect:slist/num/" + rb.getBno();
	}

- 넘어온 replyer, bno (부모글번호), replytext 를 ReplyBoard 객체 rb 에 바로 전달받음

- ReplyBoard DTO 에 replyer, bno, replytext 를 저장할 프로퍼티가 있다

- ReplyService 클래스의 객체 rbs 로 insert() 를 호출, 이때 객체 rb 전달

<돌아온 후>

- 댓글 삽입 후 다시 댓글 목록을 불러와야함

- 여기서 바로 redirect: 로 댓글 목록 요청하는 "slist" 로 요청, 댓글 목록을 요청할때 부모 글 번호가 필요하다

- 넘어온 데이터 rb 의 bno 프로퍼티는 부모 글 번호이므로 그걸 getter 로 구해서 전달

- 그럼 댓글 목록을 다시 구해와서 load() 의 콜백함수로 돌아간 후 id 가 slist 인 div 태그 안에 댓글이 다시 출력됨 (비동기)

 

- Service 클래스 ReplyBoardService.java 에서 insert() 메소드 부분만

	public void insert(ReplyBoard rb) {
		rbd.insert(rb);
	}

- DAO 클래스 ReplyBoardDao.java 에서 insert() 메소드 부분만

	public void insert(ReplyBoard rb) {
		sst.insert("rbns.insert", rb);
	}

- Mapper 파일 ReplyBoard.xml 에서 id 가 "insert" 인 SQL문 부분만

<insert id="insert" parameterType="rb">
		<selectKey keyProperty="rno" order="BEFORE" resultType="int">
			select nvl(max(rno),0) + 1 from replyBoard
		</selectKey>
		insert into replyBoard values (#{rno},#{bno},#{replytext},
			#{replyer},sysdate,sysdate)
</insert>

- 이전 프로젝트에서 primary key 로 설정된 컬럼을 max 함수로 최대값을 구해서, 1 을 더한 후 글 번호로 넣었었다

- 지금은 따로 만들지 않고 한꺼번에 처리 할 것

- selectKey 태그를 사용해서 SQL문으로 rno 의 최대값을 구하고 1 증가시켜 댓글 삽입까지 여기 select SQL문에서 시킨다

 

selectKey

- selectKey 안의 select SQL 문에서 rno 의 최대값을 구하고 1 증가시키고 있음

- 그 1 증가된 값은 keyProperty 속성 값 "rno" 에 반환된다

- 그 "rno" 를 아래의 insert SQL문에서 바로 사용하고 있다 (화살표)

- order="BEFORE" 의 의미는 selectKey 안의 SQL문을 아래의 DML (insert) SQL문 보다 먼저 실행하라는 의미

- select 를 먼저 하고 다른 DML SQL문을 실행할떄 주로 selectKey 를 사용한다

+ selectKey 에서 돌려주는 값이 최대 rno 에서 1 증가된 rno (댓글 번호)값이므로 resultType 은 int 이다

 


댓글 수정

- slist.jsp 에서 td 태그에 출력하고 있는 댓글의 내용을 textarea 로 바꾼다

- 수정하고 "확인" 버튼 클릭시 수정 됨

 

- slist.jsp

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
	$(function() {
		$('.edit1').click(function() {
			var id  = $(this).attr('id');  // rno
			var txt = $('#td_'+id).text(); // replytext
			$('#td_'+id).html("<textarea rows='3' cols='30' id='tt_"+id+"'>"+txt
				+"</textarea>");
			$('#btn_'+id).html(
			   "<input type='button' value='확인' onclick='up("+id+")'> "
			  +"<input type='button' value='취소' onclick='lst()'>");
		});
	});
	function up(id) {
		var replytext = $('#tt_'+id).val();
		var formData = "rno="+id+'&replytext='+replytext
			+"&bno=${board.num}";
		$.post('${path}/repUpdate',formData, function(data) {
			$('#slist').html(data);
		});
	}
	function lst() {
		$('#slist').load('${path}/slist/num/${board.num}');
	}
	function del(rno,bno) {
		var formData="rno="+rno+"&bno="+bno;
		$.post("${path}/repDelete",formData, function(data) {
			$('#slist').html(data);
		});
	}
</script>
</head>
<body>
	<div class="container" align="center">
		<h2 class="text-primary">댓글</h2>
		<table class="table table-bordered">
			<tr>
				<td>작성자</td>
				<td>내용</td>
				<td>수정일</td>
				<td></td>
			</tr>
			<c:forEach var="rb" items="${slist}">
				<tr>
					<td>${rb.replyer}</td>
					<td id="td_${rb.rno}">${rb.replytext}</td>
					<td>${rb.updatedate }</td>
					<td id="btn_${rb.rno}">
						<c:if test="${rb.replyer==board.writer }">
							<input type="button" value="수정" class="edit1" id="${rb.rno}">
							<input type="button" value="삭제" onclick="del(${rb.rno},${rb.bno})">
						</c:if></td>
				</tr>
			</c:forEach>
		</table>
	</div>
</body>
</html>

 

forEach 태그 부분 (slist.jsp 부분)

- forEach 루프가 돌아갈때마다 td 태그의 id 값이 달라진다!

- 같은 "수정" 버튼이지만 "수정" 버튼의 id 값은 각 댓글의 댓글 번호 ${rb.rno} 이므로 댓글마다 "수정" 버튼은 다른 id 를 가지고 있게 된다

- 그래서 사용자가 어떤 댓글의 "수정" 버튼을 클릭했는지 알 수 있게 된다

- "수정" 버튼 뿐만 아니라 댓글 내용을 출력하는 두번쨰 td 태그의 id 값도 "td_${rb.rno}" 이고, 댓글마다 다르다

- 그 "수정" 을 클릭하면 두번째 td 태그에 출력되고 있는 내용이 textarea 로 바뀌어야한다

- 또한 "수정" 을 클릭하면 "수정", "삭제" 버튼 레이블이 "확인", "취소" 로 바뀜

+ "수정" 버튼의 class 값은 "edit1"

 

jQuery 부분 1 (slist.jsp 부분)

- 수정 버튼을 클릭했을때 click 이벤트 발생하면서 아래의 click() 함수 실행됨

$(function() {
		$('.edit1').click(function() {
			var id  = $(this).attr('id');  // rno
			var txt = $('#td_'+id).text(); // replytext
			$('#td_'+id).html("<textarea rows='3' cols='30' id='tt_"+id+"'>"+txt
				+"</textarea>");
			$('#btn_'+id).html(
			   "<input type='button' value='확인' onclick='up("+id+")'> "
			  +"<input type='button' value='취소' onclick='lst()'>");
		});
	});

1. 각 댓글의 수정 버튼 태그의 id 구하기

- class 가 edit1 인 태그를 $('.edit1') 으로 불러온다, 모든 수정버튼은 class 값이 edit1 으로 고정

- $(this) : 이벤트를 발생시킨 태그를 구함, 여기선 클릭된 수정 버튼 의 태그 input 태그를 구해서 id 속성 값을 가져옴

- 구해온 id 는 ${rb.rno} 로 변하는 값, 즉 각 댓글의 댓글 번호값을 구해서 변수 id 에 저장

2. 각 댓글의 내용이 출력되는 td 태그 구하기

- 그 댓글 번호인 id 를 사용해서 ${'td_'+id) 로 두번째 td 태그, 즉 내용이 출력되는 태그를 구한다

- $('td_'+id) 는 두번째 td 태그, .text() 로 그 댓글 내용을 구한 뒤 변수 txt 에 저장

3. 두번째 td 태그에서 출력되던 댓글 내용을 textarea 로 만들기

- $('#td_'+id) 로 구해온 두번째 td 태그에 .html() 함수를 사용해서 textarea 태그를 만들고 안의 내용으로 txt 를 넣음

- textarea 의 id 값은 'tt_' + id 값이다, 아래에서 textarea 에 입력한 값을 가져올때 사용할 것

4."수정", "삭제" 버튼을 "확인", "취소" 버튼으로 바꾸기

- "수정", "삭제" 버튼은 4번째 td 태그에 있다, 그 4번째 태그의 id 는 "btn_${rb.rno}" 이므로 ${'#btn_'+id) 로 구해온 뒤 html() 함수를 사용해서 "확인" "취소" 버튼을 만든다

5 "확인" 버튼 클릭시 onclick 을 통해 up() 메소드 호출, 이때 각 댓글의 글 번호값인 변수 id 를 넘겨줌

+ 이 "확인" 버튼을 누르면 실제 댓글 내용 update 가 수행됨

 

jQuery 부분 2 (slist.jsp 부분)

- "확인" 버튼 클릭시 up()함수 호출하며 DB 와 연동해서 댓글 내용을 수정

- 이때, 비동기적으로 처리한다

function up(id) { // '확인' 버튼을 클릭해서 댓글 내용을 수정
		var replytext = $('#tt_'+id).val();
		var formData = "rno="+id+'&replytext='+replytext
			+"&bno=${board.num}";
		$.post('${path}/repUpdate',formData, function(data) {
			$('#slist').html(data);
		});
	}

- 위에서 변경된 textarea 의 내용을 구해와야하므로 textarea 태그를 $('#tt_'+id) 를 써서 구해온다, val() 로 내용을 구해서 변수 replytext 에 저장

- "수정" 버튼을 눌렀을때만 rno, replytext 값이 존재하므로 serialize() 함수 사용 불가능, rno, replytext, bno(부모글번호) 를 일일히 써서 묶은 후 formData 에 저장

- post() 함수로 전달되는 값을 여러개 쓸때는 변수=값&변수=값&변수=값 형태로 쓴다

+ 앞에 ? 는 파일명이 있는 경우만 파일명?변수=값&변수=값&변수=값 형태로 쓰는 것이다

- post 방식 요청이지만 형태만 마치 get 방식으로 값이 넘어가는 것 처럼 쓰는 것

- $.post() 함수를 사용해서 "repUpdate" 요청, formData 전달

 

- Controller 클래스 ReplyBoardController.java 에서 "repUpdate" 요청 부분만

	// 댓글 내용 수정
	@RequestMapping("/repUpdate")
	public String repUpdate(ReplyBoard rb, Model model) {
		rbs.update(rb); // 댓글 내용 수정
		return "redirect:slist/num/" + rb.getBno();
	}

- 앞에서 넘어온 formData 안의 rno, replytext, bno(부모 글번호) 값을 ReplyBoard 객체 rb 로 받아서 저장

- update() 메소드를 사용해서 댓글 내용 수정, 객체 rb 전달

<돌아온 후>

- 댓글 내용 수정 후 다시 댓글 목록을 "slist" 로 요청하고 있다

- 그럼 slist.jsp 에 삭제된 댓글은 제외된 나머지 댓글 목록들이 출력된다, 이때 브라우저에 출력된 댓글 목록이 slist.jsp 에 있는 id 가 slist 인 div 태그 아래에 나타남

 

- Service, DAO 생략

- Mapper 파일 ReplyBoard.xml 에서 id 가 "update" 인 SQL문 부분만

	<update id="update" parameterType="rb">
		update replyBoard set replytext=#{replytext},
			updatedate=sysdate where rno=#{rno} 
	</update>

- 수정할 날짜를 현재 날짜로 바꿈

- 전달된 3가지 값 중 댓글 번호 rno 를 where 절에 넣어서 해당 내용 수정, replytext 로 댓글 내용 수정


댓글 삭제

jQuery 부분 3 (slist.jsp 부분)

-  slist.jsp 에서 삭제 버튼을 클릭했을때 click 이벤트 발생하면서 아래의 del() 함수 실행됨

<input type="button" value="삭제" onclick="del(${rb.rno},${rb.bno})">

- ${rb.rno} 는 해당 댓글의 댓글번호, ${rb.bno} 는 부모글의 번호

 

- slist.jsp 중 del() 함수

	function del(rno,bno) {
		var formData="rno="+rno+"&bno="+bno;
		$.post("${path}/repDelete",formData, function(data) {
			$('#slist').html(data);
		});
	}

- 받은 rno, bno 를 formData 에 묶어서 저장

- post() 함수로 전달되는 값을 여러개 쓸때는 변수=값&변수=값&변수=값 형태로 쓴다

+ 앞에 ? 는 파일명이 있는 경우만 파일명?변수=값&변수=값&변수=값 형태로 쓰는 것이다

- post 방식 요청이지만 형태만 마치 get 방식으로 값이 넘어가는 것 처럼 쓰는 것

- "repDelete" 로 요청하며 formData 전달

<콜백함수로 돌아온 후>

- id 가 slist 인 div 태그에 삭제된 댓글을 제외한 댓글 목록이 나타남

 

- Controller 클래스 ReplyBoardController.java 에서 "repDelete" 요청 부분만

	@RequestMapping("/repDelete")
	public String delete(ReplyBoard rb, Model model) {
		rbs.delete(rb.getRno());
		return "redirect:slist/num/" + rb.getBno();
	}

- 넘어온 값 들을 ReplyBoard 객체 rb 로 받고, 삭제를 위해 delete() 호출하면서 삭제할 댓글 번호 전달

<돌아온 후>

- 삭제 후 다시 댓글 목록을 가져오는 "slist" 로 요청하면서 부모글의 글 번호를 전달, 그래야 그 부모에 달린 댓글들을 가져옴

- 그럼 slist.jsp 에 삭제된 댓글은 제외된 나머지 댓글 목록들이 출력된다, 이때 브라우저에 출력된 댓글 목록이 slist.jsp 에 있는 id 가 slist 인 div 태그 아래에 나타남

 

- Service, DAO 생략

- Mapper 파일 ReplyBoard.xml 에서 id 가 "delete" 인 SQL문 부분만

	<delete id="delete" parameterType="int">
		delete from replyBoard where rno=#{rno}
	</delete>

+ Recent posts