반응형
많은 양의 데이터를 한 곳에서 읽어 온다고 하면 db에 부하가 가기 마련이다.
이때 대용량 페이징 기법을 사용 하면 유용 할 것이다.
대부분의 사람들이 알고 있듯이, 페이징 시에 사용되는 토탈 갯수를 세지 않고
페이징 하고 싶은 총 갯수의 범위를 두고 작업을 하면 되겠다.
한화면의 페이징 범위 : 10
보여줄 목록 갯수 : 10
검색할 총 갯수 : 100
* 이전, 다음 표현 방법
이와 같이 한다면 다음과 이전을 택할때 101 개를 기준으로 검색을 하고 100개를 넘어간 101 갯수를 보유 시 "다음 " 페이지를 보여준다.
"이전" 페이지는 페이지 리스트 처음 페이지 번호가 한페이지에 보여지는 페이지 건수 보다 큰경우에만 보여 주도록 한다.
* 선택된 페이지만 보여줄 방법
firsDatatNo , lastDataNo 값 셋팅을 위해 페이지검색 타입에 따라 데이터를 정렬 시켜 준다.
다음 페이지 검색시 문제가 되지 않으나, 이전 페이지 선택시 firsDatatNo , lastDataNo 거꾸로 나올 수있기 때문이다.
JSP file
function fnPageLink(pageNo , pagingType) {
$( '#pageIndex').val(pageNo);
$( '#pagingType').val(pagingType);
if(pagingType == 'PAGING_AFTER' ) {
$( '#FIRST_DATA_NO').val($( '#LAST_DATA_NO').val());
} else if((pagingType == 'PAGING_BEFOR' )){
$( '#FIRST_DATA_NO').val(eval($( '#FIRST_DATA_NO').val()-1));
}
$( '#searchForm').attr( 'action', '').submit();
}
...
< input type= "text" name = "FIRST_DATA_NO" id= "FIRST_DATA_NO" value= " <%= pagingList.getPaginationInfo().getFirstDataNo()%> " >
<input type = "text" name= "LAST_DATA_NO" id= "LAST_DATA_NO" value= " <%= pagingList.getPaginationInfo().getLastDataNo() %> ">
<input type = "text" name= "pagingType" id= "pagingType" value = "">
<input type = "hidden" name= "pageIndex" id= "pageIndex" value= "${pageIndex} " >
<input type = "hidden" name= "projectNo" id= "projectNo" value = "<%= sfProject.getProjectNo()%> ">
....
Controller file
Map<String , Object> searchOption = new HashMap<>();
int pageIndex = ServletRequestUtils.getIntParameter (request, "pageIndex", 1);
long projectNo = NumberUtils. toLong( request.getParameter( "projectNo" ), -1 );
searchOption.put("pagingType", ServletRequestUtils.getStringParameter(request, "pagingType" ));
searchOption.put( "FIRST_DATA_NO", ServletRequestUtils.getStringParameter(request, "FIRST_DATA_NO" ));
또한
// 데이터 정렬 if ( StringUtils.defaultString((String)dataMap.get( "pagingType"), "") .equals("PAGING_BEFOR" )) { Collections. reverse( list ); } if(list.size() > 0) { Map<String, Object> aa= (Map<String, Object>)list.get(0); try { String firstDataNo = String.valueOf((Long)aa.get( "no")); paginationInfo.setFirstDataNo(Integer. parseInt(firstDataNo)); } catch (Exception e) { } } if(list.size() > 100) { Map<String, Object> aa= (Map<String, Object>)list.get(list.size() -1); try { String lastDataNo = String.valueOf((Long)aa.get( "no")); paginationInfo.setLastDataNo(Integer. parseInt(lastDataNo)); } catch (Exception e) { } } pagingList.setPaginationInfo (paginationInfo); List<Object> pageDataList = new ArrayList<>(); // 화면에 보여줄 뷰잉 데이터만 따로 분리한다. int offSet = ( currentPageNo - (paginationInfo.getFirstPageNoOnPageList()) ) * pageSize; for( int i = 0; i < 10 && ( offSet + i) < list.size() ; i++ ) { pageDataList.add( list.get( offSet + i ) ); } pagingList.setSelectList(list); // 검색된 전체 데이터 pagingList.setPageDataList(pageDataList); // 화면에 보여줄 데이터 |
* 필요한 변수
private int pageItemCount ; // 한페이지에 보여줄 아이템 갯수 private int pageSize; // 한페이지에 보여지는 페이지 건수 private int currentPageNo; // 선택한 페이지 번호 private int firstDataNo; // 첫번째 데이터 번호값 private int lastDataNo; // 마지막 데이터 번호값 private int firstPageNoOnPageList; // 페이지 리스트 처음 페이지 번호 private int lastPageNoOnPageList; // 페이지 리스트 마지막 페이지 번호 private int firstRecordIndex; // 페이지 검색 시작점 |
* 페이지 시작점 = (선택 번호-1) * (한페이지에 보여줄 아이템 갯수)
(1 - 1 ) * 10 = 0
(2 - 1 ) * 10 = 10
limit 0 offset 10
limit 10 offset 10
* 처음 페이지 = ((선택 번호-1) * (한페이지에 보여줄 아이템 갯수)) * (한페이지에 보여줄 아이템 갯수) +1
(((1 - 1 ) * 10) / 10 )+1 = 1
(((2 - 1 ) * 10) / 10 )+1 = 1
.
.
.
(((11 - 1 ) * 10) / 10 )+1 = 11
* Parameter 로 pageType 과 FIRST_DATA_NO 를 받아 사용한다.
* 이전 과 다음 Query 설정
- 다음 페이지 와 페이지 선택시는 "<=" 기준보다 작거나 같은것으로 검색, 정렬은 역순 DESC
ex ) <= 1500 , DESC
- 이전 페이지는 ">" 기준보다 큰것으로 검색 하며, 정렬은 정순 ASC
ex ) > 1500 , ASC
< choose> <when test = "pagingType != 'PAGING_BEFOR' and pagingType != null"> <if test = "FIRST_DATA_NO != null and FIRST_DATA_NO != 1"> AND no <![CDATA[<= ]]> #{FIRST_DATA_NO} </if > </when > <when test = "pagingType == 'PAGING_BEFOR' and pagingType != null"> AND no <![CDATA[ > ]]> #{FIRST_DATA_NO} </when > <otherwise ></otherwise > </choose > < choose> <when test = "pagingType != 'PAGING_BEFOR' and pagingType != null"> <if test = "FIRST_DATA_NO != null and FIRST_DATA_NO != 1"> h.no desc , </if > </when > <when test = "pagingType == 'PAGING_BEFOR' and pagingType != null"> h.no asc , </when > <otherwise ></otherwise > </choose > Limit 101 |
* 페이징 렌더러 (페이징 표시를 화면에 보여주기 위한 작업)
- 화면에 보여줄 페이지 계산 = (전체 검색된 아이템 갯수 -1 / 페이지 사이즈)+1
import java.text.MessageFormat; /** * previousPageLabel [이전] * nextPageLabel [다음] * @author ask * */ public class PaginationRenderer { public String previousPageLabel = "<li><a href=\"#\" class=\"prev\" onclick=\"{0}({1},{2}); return false;\">이전</a></li>" ; public String currentPageLabel = "<li class=\"active\"><a href=\"javascript:;\">{0}</a></li>"; public String otherPageLabel = "<li><a href=\"#\" onclick=\"{0}({1}); return false;\">{2}</a></li>"; public String nextPageLabel = "<li><a href=\"#\" class=\"next\" onclick=\"{0}({1},{2}); return false;\">다음</a></li>" ; public String renderPagination(PaginationInfo paginationInfo,PagingList pagingList , String jsFunction) { int currentPageNo = paginationInfo.getCurrentPageNo(); // 선택한 페이지 번호 int selectListSize = pagingList.getSelectList().size(); // 검색된 페이지의 전체 아이템 갯수 int firstPageNoOnPageList = paginationInfo.getFirstPageNoOnPageList(); // 현재 페이지의 시작점 EX:) 1/11/21 int pageViewingNo = (( selectListSize -1 ) / 10 ) + 1; // 화면에 보여줄 페이지 계산(1~10) 몇개 ((전체 사이즈 -1 / 기준 페이지 사이즈 ))+1 StringBuffer sb = new StringBuffer(); sb.append( "<ul class=\"pagination\">\n" ); // 페이지의 시작점 즉 첫 번호가 10보다 큰경우만 이전 표시 if(firstPageNoOnPageList > 10) { sb.append(MessageFormat. format( previousPageLabel, new Object[] { jsFunction, Integer.toString(firstPageNoOnPageList - paginationInfo.getPageSize()) , "\'PAGING_BEFOR\'" })); // 이전 (첫번째 페이지 번호 - 페이지 사이즈) } //검색된 사이즈 양 만큼 번호 표시, 기본 10 그리고 pageViewingNo 의 조건 for ( int i = 0 ; i < 10 && i < pageViewingNo ; i++) { if (i+(firstPageNoOnPageList) == currentPageNo) { sb.append(MessageFormat. format( currentPageLabel, new Object[] { Integer.toString((i) + firstPageNoOnPageList) })); } else { sb.append(MessageFormat. format( otherPageLabel, new Object[] { jsFunction, Integer.toString((i) + firstPageNoOnPageList), Integer.toString((i) + firstPageNoOnPageList) })); } } // 100 건 이상인 경우만 "다음" 페이지 표시 if(selectListSize > 100){ sb.append(MessageFormat. format( nextPageLabel, new Object[] { jsFunction, Integer.toString(firstPageNoOnPageList+paginationInfo.getPageSize()) , "\'PAGING_AFTER\'" })); // 다음 (처음 페이지 번호 + 페이지 사이즈) } sb.append( "</ul>\n"); return sb.toString(); } } |
반응형
'Spring' 카테고리의 다른 글
Junit Test [A ServletContext is required to configure default servlet handling] (0) | 2015.11.02 |
---|---|
Spring RestTemplate Sample (0) | 2015.09.25 |
Spring initBinder - @vaild / JSR 303 (0) | 2014.04.07 |
spring / twitter 연동 (twitter4j) (4) | 2013.12.18 |
spring 3.2 / tiles3 (2) | 2013.12.18 |