☭DEVELOPER/#2 웹개발(자바기반 풀스택)

[BACKEND] 검색처리

조반짝 2023. 10. 4. 16:27
728x90
반응형

검색 기능과 SQL

Page268_Chapter12부터_Page326까지_Chapter15 검색처리까지_쿼리문메모_ex02_sql.sql
0.00MB

 

 

ex02 오라클에서 쿼리문을 추가해준다.

--변경부분을 실행함

제목과 내용을 활용으로 변경하면 활용이 들어간 데이터만 나온다.


MyBatis의 동적 SQL

MyBatis의 동적 태그

- if

- choose(when, otherwise)

- trim(where, set)

- foreach

 

<trim>

P.332

<!-- trim 태그의 prefix 속성은 실행될 쿼리문의 trim 태그문안에 쿼리 가장 앞에 붙여줍니다. -->

<!-- prefixOverrides 속서은 실행될 쿼리의 trim 태그문 안에 쿼리 가장 앞에 해당하는 무자들이 잇으면 자동으로 지워줍니다-->

 

<!-- trim 태그의 suffix 속성은 실행될 쿼리문의 trim 태그문 안에 쿼리 가장 뒤에 붙여줍니다. --> 
<!-- suffixOverrides 속성은 실행될 쿼리의 trim 태그문 안에 쿼리 가장 뒤에 해당하는 문자들이 있으면 자동으로 지워줍니다. -->

 


검색 조건 처리를 위한 Criteria의 변화

 

<Criteria.java>

 

boardMapper.xml

boardMappertest.java

검색 조건이 없는 경우

BoardMapper.xml 에서 choose 는 검색 조건이다.

검색 조건이 없는 경우에는 trim prefix 에 구문이 제거 되어서 choose는 없는 상태에서 검색이 된다.

검색 조건이 있는 경우

 

다중 검색

https://java119.tistory.com/103

 

 

[MyBatis] 동적 쿼리 <trim> 개념 및 문법 총 정리

속성 prefix : 실행될 쿼리의 문 안에 쿼리 가장 앞에 붙여준다. UPDATE board username=#{username},password=#{password} prefixOverrides : 실행될 쿼리의 문 안에 쿼리 가장 앞에 해당하는 문자들이 있으면 자동으로

java119.tistory.com

<블로그 참고하기!>


<sql><iclude>와 검색 데이터의 개수 처리

<sql>공통내용을 따로 빼서 적용할 수 있다.

 

조건영역을 다른 곳에서 쓰는데 매번 넣으면 복잡해 지기 때문에

include criteria 로 넣어주면 편리하다.

<sql> 태그는 id라는 속성을 이용해서 필요한 경우에 동일한 SQL의 일부를 재사용할 수 있게 한다.

<boardMapper.xml>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<!-- MyBatis xml 파일 작성 시 반드시 mapper 태그의 namespace 속성값을
     Mapper 인터페이스와 동일한 이름으로 설정해야 합니다. -->
<mapper namespace="org.zerock.mapper.BoardMapper">

	<!-- Page338 아래 BoardMapper.xml의 목록과 데이터 개수 처리 소스 코딩 -->
	<!-- sql태그와 include 태그 활용 검색 데이터의 개수 처리 -->
	<!-- MyBatis는 sql 태그를 이용해서 SQL의 일부를 별도로 보관하고, 필요한 경우에 include 시키는 형태로 사용할 수 있습니다. -->
	<sql id ="criteria">
		<trim prefix="(" suffix=") AND" prefixOverrides="OR">
				<foreach item="type" collection="typeArr">
					<trim prefix="OR">
						<choose>
							<when test="type == 'T'.toString()">
								title like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'C'.toString()">
								content like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'W'.toString()">
								writer like '%'||#{keyword}||'%'
							</when>
						</choose>
					</trim>
				</foreach>
			</trim>
	</sql>
	
	
   <!-- select 태그의 id 속성값은 메서드의 이름과 일치하게 작성합니다.
      	resultType 속성의 값은 select 쿼리의 결과를 특정 클래스의 객체로
                  만들기 위해서 설정합니다. -->  
	<!-- select * from tbl_board WHERE bno > 0; -->   
	<select id="getlist" resultType="org.zerock.domain.BoardVO">
   	<!-- MyBatis xml 파일 작성에 사용한 CDATA 부분은 XML에서 부등호를
            사용하기 위해서 사용합니다. 쿼리문이 한 눈에 보임, 관리 측면에서 XML활용하기 좋음-->
	<!-- ↓ @SELECT 역할을 함  -->
	<![CDATA[
		select * from tbl_board WHERE bno > 0
	]]>
	</select>
	
   <!-- create(insert) 처리 -->
   <!-- MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용하고,
       	 필요한 파라미터를 처리하는 ?에 대한 치환은 #{속성}을 이용해서 처리합니다. -->
       	 
   <!-- insert만 처리되고 생성된 PK 값을 알 필요가 없는 경우 -->
   <!-- insert into tbl_board (bno, title, content, writer)
		values (seq_board.nextval, '테스트 제목', '테스트 내용', 'user00'); -->
   <insert id="insert">
   		insert into tbl_board (bno, title, content, writer) values (seq_board.nextval, #{title}, #{content}, #{writer})
   </insert>
   
   <!-- insert문이 실행되고 생성된 PK 값을 알아야 하는 경우 -->
   <insert id="insertSelectKey">
   <!-- selectKey는 주로 PK값을 미리(BEFORE) SQL을 통해서 처리해 두고
             특정한 이름으로 결과를 보관하는 방식입니다. -->
      <selectKey keyProperty="bno" order="BEFORE" resultType="long">
      	SELECT seq_board.nextval from dual
      </selectKey>
      	<!-- bno 를 지정하면 select에서  값을 가져옴, 연계값이 있을 때 먼저 만들어진 게시물을 조회하고 처리-->
      	insert into tbl_board (bno, title, content, writer) values (#{bno}, #{title}, #{content}, #{writer})
   </insert>
   
   <!-- read(select) 처리 -->
   <!-- select * from tbl_board where bno =3; -->
   <select id="read" resultType="org.zerock.domain.BoardVO">
   		select * from tbl_board where bno = #{bno}
   </select>
   
   <!-- DELETE 처리 -->
   <!-- delete from tbl_board where bno = 40 -->
   <delete id="delete">
   		delete from tbl_board where bno = #{bno}
   </delete>
   
   <!-- UPDATE 처리 -->
   <!-- 기존에 있는 글을 인지 한 다음에 처리 -->
   <!-- update 칼럼이 최종 수정 시간을 의미하는 칼럼이기 때문에 현재 시간으로 변경해 줍니다.
       	regdate 칼럼은 최초 등록 생성 시간이므로 수정하지 않습니다. #{title}과 같은
              부분은 파라미터로 전달된 BoardVO 객체의 getTitle()과 같은 메서드들을
              호출해서 파라미터들이 처리 됩니다. -->
   <!-- UPDATE tbl_board set title = '수정된 제목', content = '수정된 내용', writer = '김국진', updatedate = sysdate where bno = 5;  -->
   <update id="update">
   		UPDATE tbl_board set title = #{title}, content = #{content}, writer = #{writer}, updatedate = sysdate where bno = #{bno}
   </update>
   
	<!-- SELECT BNO, TITLE, CONTENT, WRITER, REGDATE, UPDATEDATE
		FROM(
		SELECT
		/*+ INDEX_DESC(tbl_board pk_board)*/
		ROWNUM rn, bno, title, content, WRITER, REGDATE, UPDATEDATE
		from tbl_board
		where ROWNUM <=20
		)
		WHERE RN > 10;
		(ROWNUM이 11 ~ 20 번까지 기준으로 데이터보여줘) 
	-->
   
   
   <!-- Page294 : 아래에 getListWithPageing 메서드 처리 태그르 추가해줍니다-->
   <select id="getListWithPaging" resultType="org.zerock.domain.BoardVO">
   		<![CDATA[
   			SELECT BNO, TITLE, CONTENT, WRITER, REGDATE, UPDATEDATE
			FROM(
			SELECT
			/*+ INDEX_DESC(tbl_board pk_board)*/
			ROWNUM rn, bno, title, content, WRITER, REGDATE, UPDATEDATE
			from tbl_board
			where
			]]>
			
			<!-- Page339 include 태그 삽입 적용함 -->
			<include refid="criteria" ></include>
			
		<!-- foreach 태그를 이용해서 검색 조건을 처리하는데 typeArr 속성을 이용합니다. MyBatis는 원하는 속성을 찾을 
			때 getTypeArr() 메서드와 같이 이름에 기반을 두어서 검색하기 때문에 Criteria에서 만들어둔 getTypleArr() 
			메서드 결과문인 문자열의 배열이 foreach의 대상이 됩니다. 참고로, MyBatis는 엄격하게 Java Beans 규칙을 따르지 
			않고, get/set 메서드만을 활용하는 방식입니다. choose 안쪽의 동적 SQL은 'OR title... OR content... 
			OR writer...' 와 같은 구문을 만들어내게 됩니다. 그래서 바깥쪽에서는 trim을 이용해서 맨 앞에서 생성되는 'OR'를 
			없애줍니다. 
		-->
		<!-- 	
			<trim prefix="(" suffix=") AND" prefixOverrides="OR">
				<foreach item="type" collection="typeArr">
					<trim prefix="OR">
						<choose>
							<when test="type == 'T'.toString()">
								title like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'C'.toString()">
								content like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'W'.toString()">
								writer like '%'||#{keyword}||'%'
							</when>
						</choose>
					</trim>
				</foreach>
			</trim>
		 -->	
			
			<![CDATA[
			
			 ROWNUM <= #{pageNum} * #{amount}
			)
			WHERE RN > (#{pageNum}-1) * #{amount}
   		]]>
   </select>
   
   <!-- SELECT COUNT(*) FROM tbl_board WHERE bno > 0; -->
   <!-- Page339 소스 코딩할 때 아래 3줄 구문은 주석 처리해줍니다. -->
   <!--  
   <select id="getTotalCount" resultType="int">
   		SELECT COUNT(*) FROM tbl_board WHERE bno > 0
   </select>
   -->

	<!-- Page339 소스 하단 select 태그 id="getTotalCount" 소스 코딩 -->
	<!-- 위에 sql 태그는 id 속성을 이용해서 필요한 경우에 동일한 SQL의 일부를 재사용할 수 있게 합니다. -->
	<select id="getTotalCount" resultType="int">
   		SELECT COUNT(*) FROM tbl_board 
   		WHERE 
   			<include refid="criteria"></include>
   		bno > 0
   </select>
</mapper>

화면에서 검색 조건 처리

 

목록화면에서 검색처리


검색 버튼의 이벤트 처리

검색 조건 검색창에 입력된 내용을 애플리케이션을 인지하고 검색버튼을 누르면(onclick) 넘어가게한다.

백단에서는 db와 비교해서 검색처리를 화면에 응답하게 해야한다.

검색 이벤트 처리를 자바스크립트로 처리해야한다.

검색할 때 공백 조심!!

/>/> 공백 없이 사용!!!

<list.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 기본 태그 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 갱신 날짜 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@include file="../includes/header.jsp"%>

<div class="row">
	<div class="col-lg-12">
		<h1 class="page-header">Board(게시판)</h1>
	</div>
	<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
	<div class="col-lg-12">
		<div class="panel panel-default">
			<div class="panel-heading">
				Board List Page
				<button id="regBtn" type="button" class="btn btn-xs pull-right">Register
					New Board</button>
			</div>
			<!-- /.panel-heading -->
			<div class="panel-body">
				<table width="100%"
					class="table table-striped table-bordered table-hover"
					id="dataTables-example">
					<thead>
						<tr>
							<th>#번호</th>
							<th>제목</th>
							<th>작성자</th>
							<th>작성일</th>
							<th>수정일</th>
						</tr>
					</thead>
					<!-- Model에 담긴 데이터 출력 : '/board/list'를
                                                                          실행했을 때 앞서 BoardController는 Model을 이용해서
                                                                          게시물의 목록을 'list'라는 이름으로 담아서 전달했으므로
                                 list.jsp에서는 이것을 출력합니다.
                                                                          출력은 JSTL을 이용해서 처리합니다.-->
					<c:forEach items="${list}" var="board">
						<tr>
							<td><c:out value="${board.bno}"></c:out></td>
							<!--  a 태그에 target="_blank" 속성을 적용하면 새창으로 글 상세 내용을 보여줌 -->
							<!-- Page314 소스 코딩할 때, 아래 2줄 소스는 주석처리를 합니다! -->
							<!-- 
							<td><a href='/board/get?bno=<c:out value="${board.bno}"/>'>
									<c:out value="${board.title}" />
							</a></td>
							 -->
							 
							 <!-- Page314 : 이벤트 처리를 위한 a 태그에 class 속성 move 를 적용해줍니다 -->
							 
							<td><a class="move" href='<c:out value="${board.bno}" />'> <c:out value="${board.title}" /></a></td>
							<td><c:out value="${board.writer}"></c:out></td>
							<td><fmt:formatDate value="${board.regdate}"
									pattern="yyyy-MM-DD" /></td>
							<td><fmt:formatDate value="${board.updateDate}"
									pattern="yyyy-MM-DD" /></td>
					</c:forEach>
				
				</table>
				<!-- /.table-responsive -->
				
				<div class="row">
					<div class="col-lg-12">
						<form action="/board/list" id="searchForm" method="get">
							<select name= "type">
								<option value= "" <c:out value="${pageMaker.cri.type == null?'selected':''}"/>>&lt;검색조건선택&gt;</option>
								<option value= "T" <c:out value="${pageMaker.cri.type eq 'T'?'selected':''}"/>>제목</option>
								<option value= "C" <c:out value="${pageMaker.cri.type eq 'C'?'selected':''}"/>>내용</option>
								<option value= 'W' <c:out value="${pageMaker.cri.type eq 'W'?'selected':''}"/>>작성자</option>
								<option value= "TC" <c:out value="${pageMaker.cri.type eq 'TC'?'selected':''}"/>>제목 or 내용</option>
								<option value= "TW" <c:out value="${pageMaker.cri.type eq 'TW'?'selected':''}"/>>제목 or 작성자</option>
								<option value= "TWC" <c:out value="${pageMaker.cri.type eq 'TWC'?'selected':''}"/>>제목 or 내용 or 작성자</option>
							</select>
							
							<input type="text" name="keyword" value="<c:out value="${pageMaker.cri.keyword}"/>"/>
							<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}"/> 
							<input type="hidden" name="amount" value="${pageMaker.cri.amount}"/> 
												
							
							<button class="btn btn=default">검색(Search)</button>
						</form>
					</div>
				</div>
				
				<!-- Page308 pagination 붙여넣기 적용 후에 Ctrl + Shift + F 클릭 적용해줌 -->
				<div class='pull-right'>
					<ul class="pagination">
						<c:if test ="${pageMaker.prev}">
							<li class="paginate_button previous"><a href = "${pageMaker.startPage-1}">Previous</a></li>
						</c:if>
						<c:forEach var = "num" begin = "${pageMaker.startPage}" end = "${pageMaker.endPage}">
							<li class="paginate_button"><a href="${num}">${num}</a></li>
						</c:forEach>
						<c:if test ="${pageMaker.next}">
							<li class="paginate_button next"><a href = "${pageMaker.endPage+1}">Next</a></li>
						</c:if>
					</ul>
				</div> <!-- end Pagination -->
				
				<!-- Page311 : 실제 페이지를 클릭하면 동작을 하는 부분은 별도의 form태그를 이용해서 처리하도록 합니다! -->
				<form action="/board/list" id="actionForm" method="get">
					<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
					<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
					<input type="hidden" name="type"  value="<c:out value="${pageMaker.cri.type}"/>"/>
					<input type="hidden" name="keyword"  value="<c:out value="${pageMaker.cri.keyword}"/>"/>
					
				</form>

				<!-- Modal -->
				<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
					aria-labelledby="myModalLabel" aria-hidden="true">
					<div class="modal-dialog">
						<div class="modal-content">
							<div class="modal-header">
								<button type="button" class="close" data-dismiss="modal"
									aria-hidden="true">&times;</button>
								<h4 class="modal-title" id="myModalLabel">처리 알림!</h4>
							</div>
							<div class="modal-body">처리가 완료되었습니다.</div>
							<div class="modal-footer">
								<button type="button" class="btn btn-default"
									data-dismiss="modal">Close</button>
								<button type="button" class="btn btn-primary">Save
									changes</button>
							</div>
						</div>
						<!-- /.modal-content -->
					</div>
					<!-- /.modal-dialog -->
				</div>
				<!-- /.modal -->

			</div>
			<!-- /.panel-body -->
		</div>
		<!-- /.panel -->
	</div>
	<!-- /.col-lg-12 -->
</div>
<!-- /.row -->

<script type="text/javascript">
	// 새로운 게시물의 번호는 BoardController의 addFlashAttribute() 메서드로
	// 저장되었기 때문에 한 번도 사용된 적이 없다면 사용자가 "/board/list"를 호출하거나,
	// '새로고침'을 통해서 호출하는 경우 아무런 내용이 없게 됩니다.
	// 또한, addFlashAttribute() 메서드를 이용해서 일회성으로만 데이터를 사용할 수 
	// 있으므로 이를 이용하여 경고창이나 모달창 등을 보여주는 방식으로 처리할 수 있습니다.
	$(document).ready(
			function() {
				var result = '<c:out value="${result}"/>';

				// 모달창 관련 자바스크립트 소스 코딩(시작)   
				// checkModal() 함수는 파라미터에 따라서 모달창을 보여주거나 내용을 수정한 뒤
				// 보이도록 처리합니다. checkModal()에서는 새로운 게시글이 작성되는 경우
				// RedirectAttributes로 게시물의 번호가 전송되므로 이를 이용해서 모달창의 내용을
				// 수정 처리합니다. $("#modal").modal('show')를 호출하면 모달창이 보이게 됩니다.
				// 실행 확인은 웹 프로젝트 실행 후 '/board/register'를 이용해서 새로운 게시물을 작성하고
				// 나면 자동으로 '/board/list'로 이동하면서 모달창이 보이게 됩니다

				// 글이 등록된 이후에 리스트를 보여준다. addflash~ result 속성 에 게시물이 들어온다
				// 글 등록을 누르면 리스트페이지가 불러들어지면서 모달창으로 몇번글이 등록되었습니다 > 확인 누르면 리스트가 뜬다.
				checkModal(result);

				history.replaceState({}, null, null);
				function checkModal(result) {
					if (result === '') {
						return;
					}
					// === 문자열,타입까지 맞아야한다

					if (parseInt(result) > 0) {
						$(".modal-body").html(
								"게시글" + parseInt(result) + "번이 등록되었습니다!");
					}
					$("#myModal").modal("show");
				}
				// 모달 창 관련 자바스크립트 소스 코딩(종료)	

				// list.jsp에서  Register New Board 버튼 클릭하면
				// 게시물의 등록 웹페이지로 이동 처리 합니다
				$('#regBtn').on("click", function() {
					self.location = "/board/register";
				});
				
				// Page312 a 태그가 원래의 동작을 못하도록 JavaScriopt 처리를 합니다.
				var actionForm = $("#actionForm");
				$(".paginate_button a").on("click", function (e) {
					
					e.preventDefault();
					
					console.log('click');
					
					actionForm.find("input[name='pageNum']").val($(this).attr("href"));
					actionForm.submit();
				});
				
				// Page315 : list.jsp 게시물 조회를 위한 이벤트 처리 추가
				$(".move").on("click", function(e) {
					e.preventDefault();
					actionForm.append("<input type='hidden' name='bno' value='"+$(this).attr("href")+"'>");
					actionForm.attr("action", "/board/get");
					actionForm.submit();
				});
				
				// Page342 자바스크립트 소스 코딩 시작
				var searchForm = $("#searchForm");
				
				$("#searchForm button").on("click", function (e) {
					// 검색 조건을 선택하지 안했을 경우
					if(!searchForm.find("option:selected").val()){
						alert("검색 종류를 선택해 주시기 바랍니다!");
						return false;
					}
					
					// 키워드를 입력 안할 경우
					if(!searchForm.find("input[name='keyword']").val()){
						alert("키워드를 입력해 주시기 바랍니다!");
						return false;
					}
					
					// 여러 종류들 중에서 검색 버튼을 클릭하면 기본 검색 결과 페이지는  1페이지를 하도록 수정처리합니다.
					searchForm.find("input[name='pageNum']").val("1");
					// 브라우저에서 검색 버튼을 클릭하면 form 태그의 전송은 막고,
					// 페이지의 번호는 1이 되도록 처리합니다.
					// 화면에서 키워드가 없다면 검색을 하지 않도록 제어합니다.
					e.preventDefault();
					searchForm.submit();
				});
				// Page342 자바스크립트 소스 코딩 끝
			});
</script>

<%@include file="../includes/footer.jsp"%>

<modify.jsp>

<boardcontroller.java>

<boardmapper.xml>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<!-- MyBatis xml 파일 작성 시 반드시 mapper 태그의 namespace 속성값을
     Mapper 인터페이스와 동일한 이름으로 설정해야 합니다. -->
<mapper namespace="org.zerock.mapper.BoardMapper">

	<!-- Page338 아래 BoardMapper.xml의 목록과 데이터 개수 처리 소스 코딩 -->
	<!-- sql태그와 include 태그 활용 검색 데이터의 개수 처리 -->
	<!-- MyBatis는 sql 태그를 이용해서 SQL의 일부를 별도로 보관하고, 필요한 경우에 include 시키는 형태로 사용할 수 있습니다. -->
	<sql id ="criteria">
		<trim prefix="(" suffix=") AND" prefixOverrides="OR">
				<foreach item="type" collection="typeArr">
					<trim prefix="OR">
						<choose>
							<when test="type == 'T'.toString()">
								title like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'C'.toString()">
								content like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'W'.toString()">
								WRITER like '%'||#{keyword}||'%'
							</when>
						</choose>
					</trim>
				</foreach>
			</trim>
	</sql>
	
	
   <!-- select 태그의 id 속성값은 메서드의 이름과 일치하게 작성합니다.
      	resultType 속성의 값은 select 쿼리의 결과를 특정 클래스의 객체로
                  만들기 위해서 설정합니다. -->  
	<!-- select * from tbl_board WHERE bno > 0; -->   
	<select id="getlist" resultType="org.zerock.domain.BoardVO">
   	<!-- MyBatis xml 파일 작성에 사용한 CDATA 부분은 XML에서 부등호를
            사용하기 위해서 사용합니다. 쿼리문이 한 눈에 보임, 관리 측면에서 XML활용하기 좋음-->
	<!-- ↓ @SELECT 역할을 함  -->
	<![CDATA[
		select * from tbl_board WHERE bno > 0
	]]>
	</select>
	
   <!-- create(insert) 처리 -->
   <!-- MyBatis는 내부적으로 JDBC의 PreparedStatement를 활용하고,
       	 필요한 파라미터를 처리하는 ?에 대한 치환은 #{속성}을 이용해서 처리합니다. -->
       	 
   <!-- insert만 처리되고 생성된 PK 값을 알 필요가 없는 경우 -->
   <!-- insert into tbl_board (bno, title, content, writer)
		values (seq_board.nextval, '테스트 제목', '테스트 내용', 'user00'); -->
   <insert id="insert">
   		insert into tbl_board (bno, title, content, writer) values (seq_board.nextval, #{title}, #{content}, #{writer})
   </insert>
   
   <!-- insert문이 실행되고 생성된 PK 값을 알아야 하는 경우 -->
   <insert id="insertSelectKey">
   <!-- selectKey는 주로 PK값을 미리(BEFORE) SQL을 통해서 처리해 두고
             특정한 이름으로 결과를 보관하는 방식입니다. -->
      <selectKey keyProperty="bno" order="BEFORE" resultType="long">
      	SELECT seq_board.nextval from dual
      </selectKey>
      	<!-- bno 를 지정하면 select에서  값을 가져옴, 연계값이 있을 때 먼저 만들어진 게시물을 조회하고 처리-->
      	insert into tbl_board (bno, title, content, writer) values (#{bno}, #{title}, #{content}, #{writer})
   </insert>
   
   <!-- read(select) 처리 -->
   <!-- select * from tbl_board where bno =3; -->
   <select id="read" resultType="org.zerock.domain.BoardVO">
   		select * from tbl_board where bno = #{bno}
   </select>
   
   <!-- DELETE 처리 -->
   <!-- delete from tbl_board where bno = 40 -->
   <delete id="delete">
   		delete from tbl_board where bno = #{bno}
   </delete>
   
   <!-- UPDATE 처리 -->
   <!-- 기존에 있는 글을 인지 한 다음에 처리 -->
   <!-- update 칼럼이 최종 수정 시간을 의미하는 칼럼이기 때문에 현재 시간으로 변경해 줍니다.
       	regdate 칼럼은 최초 등록 생성 시간이므로 수정하지 않습니다. #{title}과 같은
              부분은 파라미터로 전달된 BoardVO 객체의 getTitle()과 같은 메서드들을
              호출해서 파라미터들이 처리 됩니다. -->
   <!-- UPDATE tbl_board set title = '수정된 제목', content = '수정된 내용', writer = '김국진', updatedate = sysdate where bno = 5;  -->
   <update id="update">
   		UPDATE tbl_board set title = #{title}, content = #{content}, writer = #{writer}, updatedate = sysdate where bno = #{bno}
   </update>
   
	<!-- SELECT BNO, TITLE, CONTENT, WRITER, REGDATE, UPDATEDATE
		FROM(
		SELECT
		/*+ INDEX_DESC(tbl_board pk_board)*/
		ROWNUM rn, bno, title, content, WRITER, REGDATE, UPDATEDATE
		from tbl_board
		where ROWNUM <=20
		)
		WHERE RN > 10;
		(ROWNUM이 11 ~ 20 번까지 기준으로 데이터보여줘) 
	-->
   
   
   <!-- Page294 : 아래에 getListWithPageing 메서드 처리 태그르 추가해줍니다-->
   <select id="getListWithPaging" resultType="org.zerock.domain.BoardVO">
   		<![CDATA[
   			SELECT BNO, TITLE, CONTENT, WRITER, REGDATE, UPDATEDATE
			FROM(
			SELECT
			/*+ INDEX_DESC(tbl_board pk_board)*/
			ROWNUM rn, bno, title, content, WRITER, REGDATE, UPDATEDATE
			from tbl_board
			where
			]]>
			
			<!-- Page339 include 태그 삽입 적용함 -->
			<include refid="criteria" ></include>
			
		<!-- foreach 태그를 이용해서 검색 조건을 처리하는데 typeArr 속성을 이용합니다. MyBatis는 원하는 속성을 찾을 
			때 getTypeArr() 메서드와 같이 이름에 기반을 두어서 검색하기 때문에 Criteria에서 만들어둔 getTypleArr() 
			메서드 결과문인 문자열의 배열이 foreach의 대상이 됩니다. 참고로, MyBatis는 엄격하게 Java Beans 규칙을 따르지 
			않고, get/set 메서드만을 활용하는 방식입니다. choose 안쪽의 동적 SQL은 'OR title... OR content... 
			OR writer...' 와 같은 구문을 만들어내게 됩니다. 그래서 바깥쪽에서는 trim을 이용해서 맨 앞에서 생성되는 'OR'를 
			없애줍니다. 
		-->
		<!-- 	
			<trim prefix="(" suffix=") AND" prefixOverrides="OR">
				<foreach item="type" collection="typeArr">
					<trim prefix="OR">
						<choose>
							<when test="type == 'T'.toString()">
								title like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'C'.toString()">
								content like '%'||#{keyword}||'%'
							</when>
							<when test="type == 'W'.toString()">
								writer like '%'||#{keyword}||'%'
							</when>
						</choose>
					</trim>
				</foreach>
			</trim>
		 -->	
			
			<![CDATA[
			
			 ROWNUM <= #{pageNum} * #{amount}
			)
			WHERE RN > (#{pageNum}-1) * #{amount}
   		]]>
   </select>
   
   <!-- SELECT COUNT(*) FROM tbl_board WHERE bno > 0; -->
   <!-- Page339 소스 코딩할 때 아래 3줄 구문은 주석 처리해줍니다. -->
   <!--  
   <select id="getTotalCount" resultType="int">
   		SELECT COUNT(*) FROM tbl_board WHERE bno > 0
   </select>
   -->

	<!-- Page339 소스 하단 select 태그 id="getTotalCount" 소스 코딩 -->
	<!-- 위에 sql 태그는 id 속성을 이용해서 필요한 경우에 동일한 SQL의 일부를 재사용할 수 있게 합니다. -->
	<select id="getTotalCount" resultType="int">
   		SELECT COUNT(*) FROM tbl_board 
   		WHERE 
   			<include refid="criteria"></include>
   		bno > 0
   </select>
</mapper>

<get.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- 기본 태그 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
	<!-- 갱신 날짜 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@include file="../includes/header.jsp" %>

<div class="row">
	<div class="col-lg-12">
		<h1 class="page-header">Board Read(게시글 상세보기)</h1>
	</div>
	<!-- col-lg-12 -->
</div>
<!-- /.row -->

<div class="row">
	<div class="col-lg-12">
		<div class="panel panel-default">
			<div class="panel-heading">Board Read</div>
			<!-- /.panel-heading -->
			<div class="panel-bady">
					<div class="form-group">
						<label>Bno</label>
						<input class="form-control" name="bno" value='<c:out value="${board.bno}"/>' readonly="readonly">
					</div>				
					<div class="form-group">
						<label>Title</label>
						<input class="form-control" name="title" value='<c:out value="${board.title}"/>' readonly="readonly">
					</div>				
					<div class="form-group">
						<label>Text area</label>
	                 	<textarea rows="3" class="form-control" name="content" readonly="readonly"><c:out value="${board.content}" /></textarea>
					</div>				
					<div class="form-group">
						<label>Writer</label>
						<input class="form-control" name="writer" value='<c:out value="${board.writer}"/>' readonly="readonly">
					</div>		
					
					<button data-oper='modify' class="btn btn-default" onclick="location.href='/board/modify?bno=<c:out value="${board.bno}"/> '" > 글내용 수정(Modify)</button>		
					<button data-oper='list' class="btn btn-info" onclick="location.href='/board/list'">글 목록보기(List)</button>	
					
					<!-- Page317 : 기존 get.jsp 에서 버튼을 클릭하면 form 태그를 이용하는 방식이기에 
					                                  데이터를 추가해서 이동하도록 수정 코딩합니다. -->
					<form id="operForm" action="/board/modify" method="get">
						<input type="hidden" id="bno" name="bno" value="<c:out value ="${board.bno}"/>">
						<input type="hidden" name="pageNum" value="<c:out value ="${cri.pageNum}"/>">
						<input type="hidden" name="amount" value="<c:out value ="${cri.amount}"/>">
						<input type="hidden" name="type"  value="<c:out value="${cri.type}"/>"/>
					<input type="hidden" name="keyword"  value="<c:out value="${cri.keyword}"/>"/>
					</form>
						
			</div> <!-- end panel-body -->
		</div> <!-- end panel -->
	</div> <!-- end col-lg-12 -->
</div> <!-- end row -->

<script type="text/javascript">
	$(document).ready(function() {
		var operForm = $("#operForm");
		
		$("button[data-oper='modify']").on("click", function(e){
			operForm.attr("action", "/board/modify").submit();
		});
		
		$("button[data-oper='list']").on("click", function(e) {
	         // 사용자가 수정 버튼을 누르는 경우에는 bno 값을 같이 전달하고,
	         // <form> 태그를 submit 시켜서 처리합니다.
	         // 만일 사용자가 list로 이동하는 경우에는 아직 아무런 데이터도 필요하지 않으므로
	         // <form> 태그 내의 bno 태그를 지우고 submit() 메서드를 통해서
	         // 리스트 페이지로 이동합니다.
			operForm.find("#bno").remove();
			operForm.attr("action", "/board/list")
			operForm.submit();
		});
	});
</script>


<%@include file="../includes/footer.jsp" %>

<list.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!-- 기본 태그 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 갱신 날짜 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<%@include file="../includes/header.jsp"%>

<div class="row">
	<div class="col-lg-12">
		<h1 class="page-header">Board(게시판)</h1>
	</div>
	<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
	<div class="col-lg-12">
		<div class="panel panel-default">
			<div class="panel-heading">
				Board List Page
				<button id="regBtn" type="button" class="btn btn-xs pull-right">Register
					New Board</button>
			</div>
			<!-- /.panel-heading -->
			<div class="panel-body">
				<table width="100%"
					class="table table-striped table-bordered table-hover"
					id="dataTables-example">
					<thead>
						<tr>
							<th>#번호</th>
							<th>제목</th>
							<th>작성자</th>
							<th>작성일</th>
							<th>수정일</th>
						</tr>
					</thead>
					<!-- Model에 담긴 데이터 출력 : '/board/list'를
                                                                          실행했을 때 앞서 BoardController는 Model을 이용해서
                                                                          게시물의 목록을 'list'라는 이름으로 담아서 전달했으므로
                                 list.jsp에서는 이것을 출력합니다.
                                                                          출력은 JSTL을 이용해서 처리합니다.-->
					<c:forEach items="${list}" var="board">
						<tr>
							<td><c:out value="${board.bno}"></c:out></td>
							<!--  a 태그에 target="_blank" 속성을 적용하면 새창으로 글 상세 내용을 보여줌 -->
							<!-- Page314 소스 코딩할 때, 아래 2줄 소스는 주석처리를 합니다! -->
							<!-- 
							<td><a href='/board/get?bno=<c:out value="${board.bno}"/>'>
									<c:out value="${board.title}" />
							</a></td>
							 -->
							 
							 <!-- Page314 : 이벤트 처리를 위한 a 태그에 class 속성 move 를 적용해줍니다 -->
							 
							<td><a class="move" href='<c:out value="${board.bno}" />'> <c:out value="${board.title}" /></a></td>
							<td><c:out value="${board.writer}"></c:out></td>
							<td><fmt:formatDate value="${board.regdate}"
									pattern="yyyy-MM-DD" /></td>
							<td><fmt:formatDate value="${board.updateDate}"
									pattern="yyyy-MM-DD" /></td>
					</c:forEach>
				
				</table>
				<!-- /.table-responsive -->
				
				<div class="row">
					<div class="col-lg-12">
						<form action="/board/list" id="searchForm" method="get">
							<select name= "type">
								<option value= "" <c:out value="${pageMaker.cri.type == null?'selected':''}"/>>&lt;검색조건선택&gt;</option>
								<option value= "T" <c:out value="${pageMaker.cri.type eq 'T'?'selected':''}"/>>제목</option>
								<option value= "C" <c:out value="${pageMaker.cri.type eq 'C'?'selected':''}"/>>내용</option>
								<option value= 'W' <c:out value="${pageMaker.cri.type eq 'W'?'selected':''}"/>>작성자</option>
								<option value= "TC" <c:out value="${pageMaker.cri.type eq 'TC'?'selected':''}"/>>제목 or 내용</option>
								<option value= "TW" <c:out value="${pageMaker.cri.type eq 'TW'?'selected':''}"/>>제목 or 작성자</option>
								<option value= "TWC" <c:out value="${pageMaker.cri.type eq 'TWC'?'selected':''}"/>>제목 or 내용 or 작성자</option>
							</select>
							
							<input type="text" name="keyword" value="<c:out value="${pageMaker.cri.keyword}"/>"/>
							<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}"/> 
							<input type="hidden" name="amount" value="${pageMaker.cri.amount}"/> 
												
							
							<button class="btn btn=default">검색(Search)</button>
						</form>
					</div>
				</div>
				
				<!-- Page308 pagination 붙여넣기 적용 후에 Ctrl + Shift + F 클릭 적용해줌 -->
				<div class='pull-right'>
					<ul class="pagination">
						<c:if test ="${pageMaker.prev}">
							<li class="paginate_button previous"><a href = "${pageMaker.startPage-1}">Previous</a></li>
						</c:if>
						<c:forEach var = "num" begin = "${pageMaker.startPage}" end = "${pageMaker.endPage}">
							<li class="paginate_button"><a href="${num}">${num}</a></li>
						</c:forEach>
						<c:if test ="${pageMaker.next}">
							<li class="paginate_button next"><a href = "${pageMaker.endPage+1}">Next</a></li>
						</c:if>
					</ul>
				</div> <!-- end Pagination -->
				
				<!-- Page311 : 실제 페이지를 클릭하면 동작을 하는 부분은 별도의 form태그를 이용해서 처리하도록 합니다! -->
				<form action="/board/list" id="actionForm" method="get">
					<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
					<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
					<input type="hidden" name="type"  value="<c:out value="${pageMaker.cri.type}"/>"/>
					<input type="hidden" name="keyword"  value="<c:out value="${pageMaker.cri.keyword}"/>"/>
					
				</form>

				<!-- Modal -->
				<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
					aria-labelledby="myModalLabel" aria-hidden="true">
					<div class="modal-dialog">
						<div class="modal-content">
							<div class="modal-header">
								<button type="button" class="close" data-dismiss="modal"
									aria-hidden="true">&times;</button>
								<h4 class="modal-title" id="myModalLabel">처리 알림!</h4>
							</div>
							<div class="modal-body">처리가 완료되었습니다.</div>
							<div class="modal-footer">
								<button type="button" class="btn btn-default"
									data-dismiss="modal">Close</button>
								<button type="button" class="btn btn-primary">Save
									changes</button>
							</div>
						</div>
						<!-- /.modal-content -->
					</div>
					<!-- /.modal-dialog -->
				</div>
				<!-- /.modal -->

			</div>
			<!-- /.panel-body -->
		</div>
		<!-- /.panel -->
	</div>
	<!-- /.col-lg-12 -->
</div>
<!-- /.row -->

<script type="text/javascript">
	// 새로운 게시물의 번호는 BoardController의 addFlashAttribute() 메서드로
	// 저장되었기 때문에 한 번도 사용된 적이 없다면 사용자가 "/board/list"를 호출하거나,
	// '새로고침'을 통해서 호출하는 경우 아무런 내용이 없게 됩니다.
	// 또한, addFlashAttribute() 메서드를 이용해서 일회성으로만 데이터를 사용할 수 
	// 있으므로 이를 이용하여 경고창이나 모달창 등을 보여주는 방식으로 처리할 수 있습니다.
	$(document).ready(
			function() {
				var result = '<c:out value="${result}"/>';

				// 모달창 관련 자바스크립트 소스 코딩(시작)   
				// checkModal() 함수는 파라미터에 따라서 모달창을 보여주거나 내용을 수정한 뒤
				// 보이도록 처리합니다. checkModal()에서는 새로운 게시글이 작성되는 경우
				// RedirectAttributes로 게시물의 번호가 전송되므로 이를 이용해서 모달창의 내용을
				// 수정 처리합니다. $("#modal").modal('show')를 호출하면 모달창이 보이게 됩니다.
				// 실행 확인은 웹 프로젝트 실행 후 '/board/register'를 이용해서 새로운 게시물을 작성하고
				// 나면 자동으로 '/board/list'로 이동하면서 모달창이 보이게 됩니다

				// 글이 등록된 이후에 리스트를 보여준다. addflash~ result 속성 에 게시물이 들어온다
				// 글 등록을 누르면 리스트페이지가 불러들어지면서 모달창으로 몇번글이 등록되었습니다 > 확인 누르면 리스트가 뜬다.
				checkModal(result);

				history.replaceState({}, null, null);
				function checkModal(result) {
					if (result === '') {
						return;
					}
					// === 문자열,타입까지 맞아야한다

					if (parseInt(result) > 0) {
						$(".modal-body").html(
								"게시글" + parseInt(result) + "번이 등록되었습니다!");
					}
					$("#myModal").modal("show");
				}
				// 모달 창 관련 자바스크립트 소스 코딩(종료)	

				// list.jsp에서  Register New Board 버튼 클릭하면
				// 게시물의 등록 웹페이지로 이동 처리 합니다
				$('#regBtn').on("click", function() {
					self.location = "/board/register";
				});
				
				// Page312 a 태그가 원래의 동작을 못하도록 JavaScriopt 처리를 합니다.
				var actionForm = $("#actionForm");
				$(".paginate_button a").on("click", function (e) {
					
					e.preventDefault();
					
					console.log('click');
					
					actionForm.find("input[name='pageNum']").val($(this).attr("href"));
					actionForm.submit();
				});
				
				// Page315 : list.jsp 게시물 조회를 위한 이벤트 처리 추가
				$(".move").on("click", function(e) {
					e.preventDefault();
					actionForm.append("<input type='hidden' name='bno' value='"+$(this).attr("href")+"'>");
					actionForm.attr("action", "/board/get");
					actionForm.submit();
				});
				
				// Page342 자바스크립트 소스 코딩 시작
				var searchForm = $("#searchForm");
				
				$("#searchForm button").on("click", function (e) {
					// 검색 조건을 선택하지 안했을 경우
					if(!searchForm.find("option:selected").val()){
						alert("검색 종류를 선택해 주시기 바랍니다!");
						return false;
					}
					
					// 키워드를 입력 안할 경우
					if(!searchForm.find("input[name='keyword']").val()){
						alert("키워드를 입력해 주시기 바랍니다!");
						return false;
					}
					
					// 여러 종류들 중에서 검색 버튼을 클릭하면 기본 검색 결과 페이지는  1페이지를 하도록 수정처리합니다.
					searchForm.find("input[name='pageNum']").val("1");
					// 브라우저에서 검색 버튼을 클릭하면 form 태그의 전송은 막고,
					// 페이지의 번호는 1이 되도록 처리합니다.
					// 화면에서 키워드가 없다면 검색을 하지 않도록 제어합니다.
					e.preventDefault();
					searchForm.submit();
				});
				// Page342 자바스크립트 소스 코딩 끝
			});
</script>

<%@include file="../includes/footer.jsp"%>

<modify.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- 기본 태그 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
	<!-- 갱신 날짜 -->
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<%@include file="../includes/header.jsp" %>

<div class="row">
	<div class="col-lg-12">
		<h1 class="page-header">Board Modify(게시글 수정하기)</h1>
	</div>
	<!-- col-lg-12 -->
</div>
<!-- /.row -->

<div class="row">
	<div class="col-lg-12">
		<div class="panel panel-default">
			<div class="panel-heading">Board Modify Page</div>
			<!-- /.panel-heading -->
			<div class="panel-bady">
				<form action="/board/modify" role="form" method="post">
				
				<!--  Page319 위에 modify.jsp 소스 코딩 시작 : 앞서 get.jsp 소스 재사용 -->
				<input type="hidden" name="pageNum" value="<c:out value ="${cri.pageNum}"/>">
				<input type="hidden" name="amount" value="<c:out value ="${cri.amount}"/>">
				<input type="hidden" name="type" value="${cri.type}"/> 
				<input type="hidden" name="keyword" value="${cri.keyword}"/> 
				<!--  Page319 위에 modify.jsp 소스 코딩 끝 : 앞서 get.jsp 소스 재사용 -->
				
					<div class="form-group">
						<label>Bno</label>
						<input class="form-control" name="bno" value='<c:out value="${board.bno}"/>' readonly="readonly">
					</div>				
					<div class="form-group">
						<label>Title</label>
						<input class="form-control" name="title" value='<c:out value="${board.title}"/>'>
					</div>				
					<div class="form-group">
						<label>Text area</label>
	                 	<textarea rows="3" class="form-control" name="content"><c:out value="${board.content}"/></textarea>
					</div>				
					<div class="form-group">
						<label>Writer</label>
						<input class="form-control" name="writer" value='<c:out value="${board.writer}"/>' readonly="readonly">
					</div>		
					<div class="form-group">
						<label>RegiDate</label>
						<input class="form-control" name="regdate" value='<fmt:formatDate pattern="yyyy/MM/dd" value= "${board.regdate}"/>' readonly="readonly">
					</div>		
					<div class="form-group">
						<label>Update Date</label>
						<input class="form-control" name="updateDate" value='<fmt:formatDate pattern="yyyy/MM/dd" value= "${board.updateDate}"/>' readonly="readonly">
					</div>		
					
					<button data-oper='modify' class="btn btn-default" onclick="location.href='/board/modify?bno=<c:out value="${board.bno}"/> '">글수정(Modify)</button>		
					<button type="submit" data-oper='remove' class="btn btn-danger">글내용 삭제(Remove)</button>
					<button data-oper='list' class="btn btn-info" onclick="location.href='/board/list'">글 목록보기(List)</button>	
				</form>	
			</div> <!-- end panel-body -->
		</div> <!-- end panel -->
	</div> <!-- end col-lg-12 -->
</div> <!-- end row -->

<script type="text/javascript">
	
	$(document).ready(function name() {
		var formObj = $("form");
		
		$('button').on("click", function(e) {
	      // form 태그의 모든 버튼은 기본적으로 submit으로 처리하기 때문에
	      // e.preventDefault()로 기본 동작을 막고 마지막에 직접 submit()을 수행합니다.
	      e.preventDefault();
	      // 자바스크립트에서는 button 태그의 'data-oper' 속성을 이용해서
	      // 원하는 기능을 동작하도록 처리합니다.
	      var operation = $(this).data("oper");
	      
	      console.log(operation);
	      if (operation === 'remove') {
	      formObj.attr("action", "/board/remove");
		}else if (operation === 'list'){
			 // move to list
	         // 수정된 내용은 클릭한 버튼이 List인 경우 action 속성과 method 속성을
	         // 변경합니다. '/board/list'로의 이동은 아무런 파라미터가 없기 때문에
	         // form 태그의 모든 내용은 삭제한 상태에서 submit()을 진행합니다. 
	         formObj.attr("action", "/board/list").attr("method","get");
			 
			         // Page 321 수정/삭제 페이지에서 목록 페이지로 이동 처리
			         // 페이지 이동의 마지막은 수정/삭제를 취소하고 다시 목록 페이지로 이동하는 것입니다.
			         // 목록 페이지는 오직 pageNum과 amount만을 사용하므로 form 태그의
			         // 다른 내용들은 삭제하고 필요한 내용만을 다시 추가하는 형태가 편리합니다.
			         // 만일 사용자가 'List' 버튼을 클릭한다면 form 태그에서 필요한 부분만 잠시
			         // 복사(clone)해서 보관해 두고, form 태그 내의 모든 내용은 지워버립니다(empty)
			         // 이후에 다시 필요한 태그들만 추가해서 '/board/list'를 호출하는 형태를 이용합니다.
				             
			         // Page 321 자바스크립트 소스 추가 시작
			         var pageNumTag = $("input[name='pageNum']").clone();
			         var amountTag = $("input[name='amount']").clone();
			         var amountTag = $("input[name='keyword']").clone();
			         var amountTag = $("input[name='type']").clone();
			         // Page 321 자바스크립트 소스 추가 끝
			         
				 formObj.empty();
		         // Page 321 자바스크립트 소스 추가 시작
		         formObj.append(pageNumTag);
		         formObj.append(amountTag);
		         formObj.append(keywordTag);
		         formObj.append(typeTag);
		         // Page 321 자바스크립트 소스 추가 끝
			}	
			formObj.submit();
		});
	});
</script>


<%@include file="../includes/footer.jsp" %>

<boardcontroller.java>

package org.zerock.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.zerock.domain.BoardVO;
import org.zerock.domain.Criteria;
import org.zerock.domain.PageDTO;
import org.zerock.service.BoardService;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Controller
@Log4j
@RequestMapping("/board/*")
@AllArgsConstructor
public class BoardController {

	private BoardService service;
	
//	// Page300 소스코딩 할 때, 아래 5줄 소스는 주석 처리를 해줍니다.
//	@GetMapping("/list")
//	public void list(Model model) {
//		log.info("list 글 목록 조회를 처리합니다!");
//		model.addAttribute("list", service.getlList());
		// 컨트롤러에서 뷰로 데이터 넘길 때 쓰는 뷰모델에 속성명을 추가하여 서비스에 담긴 겟리스트를 list에 담아서 처리함
//	}
	
	// Page300 :  페이징 매개변수 적용 /list 소스 코딩을 아래와 같이 5줄추가합니다.
	@GetMapping("/list")
	public void list(Criteria cri, Model model) {
		log.info("list 글 목록 조회를 처리합니다!" + cri);
		model.addAttribute("list", service.getList(cri));
		
		int total = service.getTotal(cri);
		
		log.info("total 전체 데이터 수 = " + total);
		
		
														// total 변수 데이터 수 = 123로 가정함
														// realEnd 13페이지로 13다음에 next없음
//		model.addAttribute("pageMaker", new PageDTO(cri, 123));
		model.addAttribute("pageMaker", new PageDTO(cri, total));
		
	}
	
	
	
	// Page238 11.3 등록 입력 페이지와 등록 처리
	// 게시물의 등록 작업은 POST방식으로 처리하지만,
	// 화면에서 입력을 받아야 하므로 GET 방식으로 입력 페이지를 볼 수 있도록
	// BoardController에 메서드를 추가해 줍니다.
	// register() 메서드는 입력 페이지를 보여주는 역할만을 하기 때문에
	// 별도의 처리가 필요하지 않습니다.
	@GetMapping("/register")
	public void register() {
		
	}
	
	
	
	@PostMapping("/register") // @PostMapping() POST 방식 URL 메핑
	   // register() 메서드는 String을 리턴 타입으로 지정하고, Redirect Attributes를
	   // 파라미터로 지정합니다. 이것은 등록 작업이 끝난 후 다시 목록 화면으로 이동하기 위함이며,
	   // 추가적으로 새롭게 등록된 게시물의 번호를 같이 전달하기 위해서 RedirectAttributes를
	   // 이용합니다. 이때, 리턴 시에는 "redirect:" 접두어를 사용하는데,
	   // 이것을 이용하면 스프링 MVC가 내부적으로 response.sendRedirect()를 처리해 주기
	   // 때문에 편리합니다.
	public String register(BoardVO board, RedirectAttributes rttr) {
		log.info("regiser(등록): " + board);
		service.register(board);
		rttr.addFlashAttribute("result", board.getBno());
		//redirect : 갱신해서 보내줌
		return "redirect:/board/list";
	}
	
	   // 조회 처리와 테스트 : 등록처리와 유사하게 조회 처리도 BoardController를 이용해서
	   // 처리할 수 있습니다. 특별한 경우가 아니라면 조회는 GET 방식으로 처리하므로,
	   // @GetMapping을 이용합니다.
//	   @GetMapping({"/get","/modify"})
	   // Page316 소스 코딩할 때, 아래 5줄 소스 주석처리합니다.
	   // BoardController의 get() 메서드에는 bno 값을 좀 더 명시적으로 처리하는
	   // @RequestParam을 이용해서 지정합니다.(파라미터 이름과 변수 이름을 기준으로 동작하기
	   // 때문에 생략해도 됩니다). 또한 화면 쪽으로 해당 번호의 게시물을 전달해야 하므로
	   // Model을 파라미터로 지정합니다.
	   
//	   public void get(@RequestParam("bno") Long bno, Model model) {
//		   log.info("/get 조회처리");
//		   log.info("/get or modify 조회처리");
//		   model.addAttribute("board", service.get(bno));
//	   }
	   
	   // Page316 : 조회 페이지에서 다시 목록 페이지로 이동 : 페이지 번호 유지를 위한 BoardController 소스 코딩을 해줍니다.
	   @GetMapping({"/get","/modify"})
	   public void get(@RequestParam("bno") Long bno, @ModelAttribute("cri") Criteria cri, Model model) {
		   
		   log.info("/get or modify 조회처리");
		   model.addAttribute("board", service.get(bno));
	   }
	   
	   // 수정 처리와 테스트 : 수정 작업은 등록과 비슷합니다. 변경된 내용을 수집해서
	   // BoardVO 파라미터로 처리하고, BoardService를 호출합니다. 수정 작업을 시작하는
	   // 화면의 경우에는 GET 방식으로 접근하지만 실제 작업은 POST 방식으로 동작하므로
	   // @PostMapping을 이용해서 처리합니다.
	   @PostMapping("/modify")
	   public String modify(BoardVO board, @ModelAttribute("cri") Criteria cri, RedirectAttributes rttr) {
		   log.info("modify: 수정 처리" + board);
		   // service.modify() 메서드는 수정 여부를 boolean으로 처리하므로
		   // 이것을 이용해서 성공한 경우에만 RedirectAttributes에 추가합니다.
		   if (service.modify(board)) {
			   rttr.addFlashAttribute("result","success");
		   }
		   
		   rttr.addAttribute("pageNum", cri.getPageNum());
		   rttr.addAttribute("amount", cri.getAmount());
		   rttr.addAttribute("type", cri.getType());
		   rttr.addAttribute("keyword", cri.getKeyword());
		   
		   return "redirect:/board/list";
	   }
	   // 삭제 처리와 테스트 : 삭제 처리도 조회와 유사하게 BoardController와 테스트 코드를
	   // 작성합니다. 삭제는 반드시 POST 방식으로만 처리합니다.
	   @PostMapping("/remove")
	   public String remove(@RequestParam("bno") Long bno,  @ModelAttribute("cri") Criteria cri, RedirectAttributes rttr) {
		   log.info("remove : 삭제 처리 " + bno);
		      // BoardController의 remove() 메서드는 삭제 후 페이지의 이동이 필요하므로
		      // RedirectAttributes를 파라미터로 사용하고, 'redirect'를 이용해서
		      // 삭제 처리 후에 다시 목록 페이지로 이동 처리 합니다.
		   if (service.remove(bno)) {
			rttr.addFlashAttribute("result", "success");
		}
		   
		   rttr.addAttribute("pageNum", cri.getPageNum());
		   rttr.addAttribute("amount", cri.getAmount());
		   rttr.addAttribute("type", cri.getType());
		   rttr.addAttribute("keyword", cri.getKeyword());
		   
		   return "redirect:/board/list";
	   }
}

 

728x90
반응형