Page 처리

Anyframe Web에서는 Page 처리에 대한 구현이 편리하도록 page 관련 Tag Library를 제공한다. 여기에서는 페이지 처리와 관련된 Page 객체, 각 영역별 Page 객체의 사용법 및 Page Tag Library를 통한 목록조회 화면의 구성에 대해 알아 본다.

페이지 처리 로직이 필요한 경우 다음과 같은 순서로 구현하면 된다.
Page 처리
  • Business Layer에서 목록조회에 해당하는 method에서는 return type을 Page로 지정하고 Page 객체 안의 attribute에 해당하는 값을 설정하여 Presentation Layer 로 전달
  • JSP 페이지에서는 pagenavigator Tag를 이용하여 Page 객체의 정보에 따라 Page 처리된 목록조회 화면을 구성함

Page 객체

Business Layer에서는 목록 조회에 관한 정보를 Page 객체에 담아 Presentation Layer로 보낸다. Page 객체는 anyframe.common-x.x.x.jar 에 포함되어 있으며 다음과 같은 정보를 가진다.
Page 객체 포함 정보
  • Collection objects : 게시물 목록정보
  • int currentPage : 현재페이지
  • int totalCount : 총 개수
  • int pageunit : 페이지 번호가 화면에 보여지는 개수
  • int pagasize : 한 페이지당 조회 개수
  • int maxPage : 최대 페이지 번호 (전체 페이지)
  • int beginUnitPage : 화면에 보여지는 페이지번호의 최소수 (해당 페이지 Unit의 최소 페이지)
  • int endUnitPage : 화면에 보여지는 페이지번호의 최대수 (해당 페이지 Unit의 최대 페이지)

다음은 Page 소스 코드의 일부이다.
package anyframe.common;

import java.util.*;
import java.io.Serializable;

public class Page implements Serializable {

    public static final Page EMPTY_PAGE = new Page(Collections.EMPTY_LIST, 0, 0);

    /**
     * 해당 Object의 목록
     */
    private Collection objects;

    /**
     * 현재페이지
     */
    private int currentPage;

    /**
     * 총 개수
     */
    private int totalCount;

    /**
     * 페이지 번호가 화면에 보여지는 개수
     */
    private int pageunit = 10;

    /**
     * 한 페이지당 조회 개수
     */
    private int pagesize = 10;

    /**
     * 최대 페이지 번호 (전체 페이지)
     */
    private int maxPage;

    /**
     * 화면에 보여지는 페이지번호의 최소수 (해당 페이지 Unit의 최소 페이지)
     */
    private int beginUnitPage;

    /**
     * 화면에 보여지는 페이지번호의 최대수 (해당 페이지 Unit의 최대 페이지)
     */
    private int endUnitPage;

    /**
     * Page Class의 Constructor ( pageunit & pagesize : 10 (default) )
     * 
     * @param objects
     *            Collection
     * @param currentPage
     * @param totalCount
     */
    public Page(Collection objects, int currentPage, int totalCount) {
        this.objects = objects;
        this.totalCount = totalCount;
        this.maxPage = pagesize==0? this.totalCount : (totalCount - 1) / pagesize + 1;
        this.currentPage = currentPage > maxPage ? maxPage : currentPage;
        this.beginUnitPage = ((currentPage - 1) / pageunit) * pageunit + 1;
        this.endUnitPage = beginUnitPage + (pageunit - 1);
    }
… 중략 …
}

Page 객체의 사용법 (DAO,Action,JSP의 예)

어플리케이션 전 영역에 걸쳐 페이지 처리의 구현과 관련된 핵심 부분을 실제 예를 통해 알아본다.

Samples

DAO 에서의 처리
다음은 Business Layer의 목록조회에 해당하는 DAO method 소스 코드 예이다.
public Page getUserList(SearchVO searchVO) throws Exception {
	int pageIndex = searchVO.getPageIndex();
	int pageSize = propertiesService.getInt("PAGE_SIZE");
	int pageUnit = propertiesService.getInt("PAGE_UNIT");
..
	HashMap userListMap = queryService.findWithRowCount("getUserList",
				iVal, pageIndex, pageSize);
	ArrayList resultList = (ArrayList) userListMap.get(IQueryService.LIST);
	int totalSize = ((Long) userListMap.get(IQueryService.COUNT)).intValue();
	Page resultPage = new Page(resultList, (new Integer(pageIndex)).intValue()
	                                         , totalSize, pageUnit, pageSize);

	return resultPage;
}
위의 예에서는 클라이언트로부터 전달된 현재 페이지 번호(pageIndex)와 별도의 외부 설정된 pageSize, pageUnit 을 파라메터로 Anyframe Core Framework 에서 제공하는 Technical Services 의 하나인 Query Service 의 findWithRowCount 메소드를 호출하고 있다. (Query Service - Pagination 에 대한 자세한 내용은 Core Framework > Technical Services > Query > Use Cases > Paging 을 참조) 조회 결과로 얻어진 리스트와 totalSize를 더하여 Page 객체를 생성한 후 return 하고 있다.
Action 에서의 처리
다음은 목록조회 Action 클래스 소스 코드 예이다.
public class GetUserListAction extends DefaultActionSupport {

..
	public ActionForward process(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {
		..
        Page resultPage = userService.getUserList(searchVO);

        int pageSize = propertiesService.getInt("PAGE_SIZE");
		..
        request.setAttribute("page", resultPage);
        request.setAttribute("pageSize", new Integer(pageSize));
        return mapping.findForward("success");
	}
}
Action 클래스에서는 Business Layer에서 return 한 Page 객체를 request에 저장하여 JSP에서 사용할 수 있게 한다.
JSP 에서의 처리
다음은 목록조회 화면 JSP 소스 코드 예이다.
//page 처리로직을 구현한 custom tag를 사용하기 위한 설정
<%@ taglib uri='/WEB-INF/anyframe-page.tld' prefix='anyframe' %>
//Page 객체를 사용하기 위한 import
<%@ page import="anyframe.common.Page" %>
... 중략 ... 
<%
	Page resultPage = (Page)request.getAttribute("page");
	ArrayList resultList = (ArrayList)resultPage.getList();	
..
	int pageSize = ((Integer)request.getAttribute("pageSize")).intValue();
%> 
..
//현재 페이지 정보를 유지하기 위한 hidden 값 
<input type="hidden" name="pageIndex" value="<%=resultPage.getCurrentPage()%>">
             <anyframe:pagenavigator linkUrl="javascript:fncGetUserList(2);" 
                 pages="<%=resultPage%>" formName="listForm"
              firstImg="sample/images/ct_btn_pre.gif" 
              prevImg="sample/images/ct_btn_pre01.gif" 
              lastImg="sample/images/ct_btn_next.gif" 
              nextImg="sample/images/ct_btn_next01.gif" />
… 후략 …
목록조회에 해당하는 JSP에서는 Anyframe Web에서 제공하는 pagenavigator 태그를 사용하여 페이지 네비게이션 버튼 영역을 쉽게 처리하고 있다.

Page Tag Class 및 TLD

위의 JSP 코드에서 확인할 수 있는 바와 같이 page 처리를 하기위하여 <anyframe:pagenavigator> 라는 Tag를 정의하고 있다. 관련 Tag Handler Class 및 Tag Library Descriptor(tld) 는 다음과 같다.
Tag Handler
이 Tag의 Class는 PageNavigatorTag이며 소스 코드는 다음과 같다.
package anyframe.web.struts.common.util;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;
import anyframe.common.Page;

public class PageNavigatorTag extends TagSupport {
private String firstImg = "anyframe/web/image/page/page_before1.gif";
    private String prevImg = "anyframe/web/image/page/page_before.gif";
    private String lastImg = "anyframe/web/image/page/page_after1.gif";
    private String nextImg = "anyframe/web/image/page/page_after.gif";
    private String imgHeight = "13";
    private String imgWidth = "15";
    private String numClass = "page";
    private String clickNumClass = "page_s";
    private String formName = "forms[0]";
private String linkUrl = "";
    private Page pages = Page.EMPTY_PAGE;
    private int currentPage = 1;

    public int doStartTag() throws JspException {
        try {
            JspWriter out = pageContext.getOut();
            String page_num_script = "javascript:document." + getFormName()
                    + ".pageIndex.value=";

            out.print("<table border='0' cellspacing='0' cellpadding='0'><tr>");
            if (pages.hasPreviousPageUnit()) {
                out.print("<td><a href='" + page_num_script
                        + pages.getPageOfPreviousPageUnit() + ";" + linkUrl
                        + "'>");
                out.print("<img src='" + firstImg + "' width='" + imgWidth
                        + "' height='" + imgHeight + "' border='0' ></a></td>");
            } 
…
// 이하 getter/setter method는 생략
…

TLD
Page tag 의 tld 는 다음과 같다.
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC 
  "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" 
  "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd"> 
<taglib>
  <tlibversion>1.0</tlibversion>
  <jspversion>1.1</jspversion>
  <shortname>Anyframe Page</shortname>
   <tag>
    <name>pagenavigator</name>
    <tagclass>anyframe.web.struts.common.util.PageNavigatorTag</tagclass>
    <bodycontent>JSP</bodycontent>
    <attribute>
      <name>firstImg</name>
      <required>false</required>
      <rtexprvalue>true</rtexprvalue>      
    </attribute>    
    <attribute>
      <name>prevImg</name>
      <required>false</required>
      <rtexprvalue>true</rtexprvalue>      
    </attribute>  
    <attribute>
      <name>lastImg</name>
      <required>false</required>
      <rtexprvalue>true</rtexprvalue>      
    </attribute> 
… 중략 … 
</tag>
</taglib>

Resources