본문 바로가기
프로젝트/자바 빈과 JSP만을 사용한 게시판 만들기

14장 검색및 페이징

by IT여행자 2020. 5. 10.
728x90

작업 파일 : /WebContent/board/select.jsp

 

검색 및 페이징 처리를 위한 웹 페이지들은 가장 많은 변화를 줄 수 있으며 , 처리 방법 또한 굉장히 다양한 요소를 품고 있는 페이지가 아닐까 합니다. 또한 검색 프로그램은 사용자 UI와 가장 밀접한 관계를 갖고 있기 때문에 MVC를 구현하고자 할 때 가장 어려운 부분 중 하나 이기도 합니다.

 

MVC: Model, View, Control를 의미하며, 대부분 데이터, UI, 제어의 의미를 갖고 있습니다.

 

검색 및 페이징 처리 페이지의 기본 흐름은 아주 단순합니다. '변경된 값을 사용하여 자신이 자신을 호출한다.' 입니다. 여기서 변경된 값이라는 것은 아래와 같습니다.

 

  • 검색어가 변경된 경우
  • 페이지를 이동한 경우
HTTP 프로토콜의 특징중 하나는 '데이터를 저장하지 않는다'입니다. 즉 어떤 요청이 들어왔을 때 해당 값을 화면에는 표시해 줄 수 있으나 페이지를 새로 고침하거나 다른 페이지로 이동했다가 되돌아 왔을 때 이전 값을 저장하지 못한다는 뜻입니다.

HTTP의 특성상 검색어를 변경해서 자신의 페이지를 다시 호출하거나 이동할 페이지 번호를 사용하여 페이지를 바꿨다고 하더라도 특정 조치를 하지 않는 한 검색어나 이동된 페이지 번호를 새로 고침 된 현재 페이지에서 재 사용할 수 없습니다.

 

로그인/로그아웃 처리를 할 때 이미 언급했지만, 현재의 값을 저장하여 자신이나 다음 페이지에 전달하는 방법 중 몇 가지를 더 언급하자면 아래와 같습니다.

 

  • GET 타입에 저장한 후 전달(url로 전달)
  • POST 타입으로 저장한 후 전달(form 태그로 전달)
  • 서버 Scope에 담은 후 사용(application, session, request, page)
  • Cookie 사용
  • HTML5의 Storage 사용(localStorage, sessionStorage)

각기 사용하는 형식이나 용도가 다르므로 이에 대한 상세한 내용은 JSP인문서나 HTML5 인문서를 참조해 주시고(ㅠㅠ), 본 프로젝트에서는 주로 GET 타입과 POST 타입만을 사용하도록 하겠습니다.

 

본 포스팅에서 사용할 데이터의 흐름은 대략 아래와 같습니다.

 

검색 데이터의 흐름

 


 

자 그럼 각 항목별로 세부 사항을 살펴 보도록 하겠습니다.

A. WEB

검색 페이지의 전체적인 레이아웃은 아래의 그림과 같이 만들도록 하겠습니다.

 

 

목록 및 검색 페이지

select.jsp 페이지의 가장 큰 특징은 '검색어나 페이징 정보를 갖고 자신이 자신을 재 호출한다.' 입니다. 또한 현재의 정보를 갖고 입력기능이나 상세보기 기능으로 분기하는 분기점이기도 합니다.

 

 

[WebContent/board/select.jsp 전체 코드]

<%@page import="bean.BoardController"%>
<%@page import="bean.Page"%>
<%@page import="bean.BoardVo"%>
<%@page import="java.util.List"%>
<%@page import="bean.BoardDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

    
<%

BoardController ctrl = new BoardController(request, response);
ctrl.select();
List<BoardVo> list = (List<BoardVo>)request.getAttribute("list");

Page p = (Page)request.getAttribute("page");

%>    
    
    
<div id='board'>
	<h2 class='title'>자유 게시판</h2>
	<!-- a) -->
	<form name='frmBrd' method='post' id='frmBrd'>
		<input type='button' value=' 입 력 ' id='btnRegister'>
		<div>
			<input type='text' name='findStr' size='30' value="<%=p.getFindStr()%>">
			<input type='button' value=' 검 색 ' id='btnFind'>
			<input type='hidden' name='nowPage' value="<%=p.getNowPage()%>">
			<input type='hidden' name='serial'>
			
		</div>
	</form>
	<div class='table'>
	  <!-- b) -->
		<div class='theader'>
			<span class='serial'>순번</span>
			<span class='subject'>제목</span>
			<span class='worker'>작성자</span>
			<span class='mdate'>작성일</span>
			<span class='hit'>조회수</span>
		</div>
		<!-- c) -->
		<%for(BoardVo v : list){ %>
			<div class='row' onclick="board.view(<%=v.getSerial()%>)">
				<span class='serial'><%=v.getSerial() %></span>
				<span class='subject'><%=v.getSubject() %> (첨부 : <%=v.getAttCnt() %>)  </span>
				<span class='worker'><%=v.getWorker() %></span>
				<span class='mdate'><%=v.getMdate() %></span>
				<span class='hit'><%=v.getHit() %></span>
			</div>
		<%} %>
	</div>
	
	<!-- d) -->
	<div id='paging'>
		<%if(p.getStartPage()>p.getBlockSize()) {%>
			<input type='button' value='이전' onclick = 'board.goPage(<%=p.getStartPage()-1%>)'>
		<%} %>	
		
		<%for(int i=p.getStartPage() ; i<=p.getEndPage() ; i++){ %>
			<input type='button'  value='<%=i%>' class="<%=(i==p.getNowPage()? "here": "")%>" 
					onclick = 'board.goPage(<%=i%>)'>
		<%} %>
	
		<%if(p.getTotPage() > p.getEndPage()) {%>
			<input type='button'  value='다음' onclick = 'board.goPage(<%=p.getEndPage()+1%>)'>
		<%} %>
	
	</div>
	
</div>

BoardController에 전달되는 두 번째 파라미터 response 객체는 실제로 코스상에서는 사용되지 않습니다.

 

a) 부분 설명 :

<form/> 안에 있는 name='findStr', name='nowPage', name='serial'의 3개 태그가 검색 및 페이징 처리 장에서 가장 중요한 역할을 하는 태그들입니다.

  • name='findStr' :
    검색어를 입력한 뒤 검색 버튼을 클릭하면 JavaScript단에서 nowPage 태그에 1을 대입한 후 자신이 자신을 다시 호출합니다. 이때 현재 페이지가 호출되기 전의 findStr 값을 다시 표시해 주기 위해 value='<%=p.getFindStr()%>' 을 사용하여 자신에게 다시 전달된 값을 다시 대입하고 있습니다.
  • name='nowPage' :
    페이징 처리를 하기 위해서 가장 중심이 되는 요소입니다. 검색 버튼을 클릭하면 1의 값을, d) 부분의 페이지 번호를 클릭하면 해당 페이지 번호를 저장한 후 다시 자신을 호출하여 변경된 페이지의 내용이 표시되도록 합니다. 그러나 현재 페이지 번호를 굳이 화면에 보여줄 필요가 없기 때문에 hidden속성을 주었고, 현재 표시되고 있는 페이지의 상태 값이 저장되어 있어야 하기 때문에 검색어와 마찬가지로 value='<%=p.getNowPage()%>'를 사용하였습니다.
  • name='serial' :
    현재 검색 페이지에서 c) 부분의 한 행을 클릭하면 해당 행의 serial 번호를 저장하여 view.jsp 페이지로 이동시킬 예정입니다. 이때 사용자가 클릭한 행의 serial값을 hidden 형태로 저장합니다.

b) 부분 설명 :

게시판의 제목 부분입니다. CSS에서 스타일을 지정하기 위해 <span class=.../>와 같이 태그의 class 속성을 지정하고 문자열을 표시하였습니다.  <span/> 태그의 class 속성을 지정한 이유는 c) 부분에서 실제로 표시될 데이터들의 속성과 일치되는 부분들이 많이 있기 때문입니다. 사족을 더 달자면, id 속성은 표시된 전체 내용에서 한 개만 있어야 한다는 규약이 있고, class 속성은 한 개 이상 있을 수 있다는 의미입니다. 따라서 제목 부분과 리스트 된 데이터들이 같은 CSS 속성을 갖게 하기 위해서는 id속성보다는 class 속성을 사용하는 것이 정상이라 말할 수 있습니다.

 

 

c) 부분 설명 :

검색어와 페이지 번호를 사용하여 사용자의 요청이 들어오면 BoardController에 의해서 분석되고, BoardController는 이제 적당한 BoardDao의 메서드를 호출하여 내용을 처리하게 합니다.  처리된 정보가 request 영역에 담기는데 이를 가져오는 코드는 아래와 같습니다.

BoardController ctrl = new BoardController(request, response);
ctrl.select();
List<BoardVo> list = (List<BoardVo>)request.getAttribute("list");

 

이렇게 처리된 list의 값을 반복문을 사용하여 화면에 출력하는 부분입니다. 이때 아래와 같이 45행 이하를 보면  list 객체를 반복 실행해서 목록을 보여줍니다.

 

<%for(BoardVo v : list){ %>
 ...
<% } %>

또한 참고로

<div class='row' onclick="board.view(<%=v.getSerial()%>)">

의 코드가 있는데 이는 해당 행을 클릭하면 serial 번호를 파라미터로 자바스크립트 함수 board.view()을 호출하여 해당 게시물의 상세보기 화면으로 이동시킵니다.

 

d) 설명 :

페이지 이동에 관한 버튼들이 존재합니다. 버튼을 클릭하면 페이지 번호를 갖고 자바스트립트의 board.goPage() 함수를 호출하여 페이지가 이동되도록 조치합니다. 이 부분은 Page.java 클래스 내에 pageComupte() 메서드 내용을 이해해야 하는데 이것에 대한 설명은 따로 하기로 하고, 계산된 페이지 정보를 가져오는 코드는 위의 16행과 같습니다. 

 

이때 현재 페이지만을 다르게 표시하기 위해 3항 연산식을 사용하여 class 속성을 'here' 또는 ''을 적용하였습니다.

 

<input type='button'  value='<%=i%>' class="<%=(i==p.getNowPage()? "here": "")%>" 

 

 

페이징 영역에서 사용하고 있는 변수들중 중요 변수의 의미와 용도를 보다 자세히 설명하면 아래와 같습니다.

 

 

페이징에 관련된 변수

 

Page.java 코드를 보면 위의 그림과 같은 각종 변수들이 동일한 이름으로 정의되어 있습니다. 위의 그림은 blockSize=10 일 때 예를 들은 것입니다. 버튼들을 클릭하면 자바스크립트의 board.goPage()함수를 호출하는 것은 공통사항입니다.

 

  • 이전 버튼 표시 여부 : 만약 startPage값이 blockSize인 10보다 작다면 더 이상 이전으로 이동할 수 없기 때문에 startPage 값이 blockSize값 보다 큰 경우에만 표시하였고, 만약 이전 버튼이 클릭되면 startPage-1 값을 주어 이전 블록의 끝 페이지로 이동하도록 하였습니다.
<%if(p.getStartPage()>p.getBlockSize()) {%>
	<input type='button' value='이전' onclick = 'board.goPage(<%=p.getStartPage()-1%>)'>
<%} %>	
  • 다음 버튼 표시 여부 : 계산된 전체 페이지의 개수(getTotPage())가 표시된 endPage 보다 크다면 더 표시될 페이지가 있는 경우이기 때문에 이때만 다음 페이지가 표시되며, 클릭되면 표시된 마지막 페이지(endPage)+1을 하여 다음 블록의 첫 페이지로 이동하도록 하였습니다.
<%if(p.getTotPage() > p.getEndPage()) {%>
	<input type='button'  value='다음' onclick = 'board.goPage(<%=p.getEndPage()+1%>)'>
<%} %>

 

  • 페이지 번호 클릭 : 페이지 번호를 클릭하면 표시된 번호를 board.goPage() 함수에 전달하고, 반복문에 의해 표시된 숫자가 nowPage와 동일하면 CSS가 적용되게 하기 위해 class='here' 값이 3항 연산자에 의해 처리됩니다.
<%for(int i=p.getStartPage() ; i<=p.getEndPage() ; i++){ %>
	<input type='button'  value='<%=i%>' class="<%=(i==p.getNowPage()? "here": "")%>" 
			onclick = 'board.goPage(<%=i%>)'>
<%} %>

board.goPage() 함수는 JavaScript 부분을 참고해 주시기 바랍니다.

 

[코딩 동영상-검색및 페이징 처리(묵음) #1]

 

[코딩 동영상-계층형 쿼리 문장 설명 및 테스트 (묵음) #2]