현재의 리스트는 전체 데이터를 출력한다.

이것이 실제 사용될 경우 많은 데이터로 인해 문제를 발생시킬 수 있다.

즉, 예제는 몇 건 내지 몇 십 건의 데이터를 처리하기 때문에 문제가 없지만

실제 사용될 경우 몇 만에서 몇 십만의 데이터가 저장되기 때문에 한 페이지 실행되는데 아주 오랜 시간이 걸리고

웹 브라우저가 실행할 때도 메모리 부족 등의 문제가 발생할 수 있다.

따라서, 필요한 데이터만 가져오는 방식으로 처리해야 한다.

데이터가 얼마가 저장되어 있든지 필요로 하는 개수(화면에 출력하고자 하는 개수)만큼 가져오면

데이터 양과 관계없이 일정한 속도를 유지하게 된다.

이러한 처리를 페이징(Paging) 처리하고 한다.

이 부분은 많은 개발자들이 자주 실수하는 부분이며 웹 사이트 성능 저하의 주범이기도 하다.


다음과 같이 전체 데이터 개수가 9개가 있고 웹 페이지에는 3개씩 보여 준다고 가정한다.

1           

2           

3           

4           

5           

6           

7           

8           

9          

전체 페이지 수는 9 / 3으로 3이다.

첫 페이지의 데이터는 레코드 번호가 1부터 3까지

두 번째 페이지의 데이터는 레코드 번호가 4부터 6까지

세 번째 페이지의 데이터는 레코드 번호가 7부터 9가 된다.

여기에서 공식이 나오게 된다.

현재 페이지에 보여줄 데이터의 시작 번호 = (현재 페이지 – 1) * 출력 개수 + 1
현재 페이지에 보여줄 데이터의 종료 번호 = 시작 번호 + 출력개수  - 1


위 공식에 실제 페이지를 대입해 보면 

1 페이지의 시작 페이지는 = (1-1)* 3 + 1 = 1, 종료 페이지는 1 + 3 – 1 = 3
2 페이지의 시작 페이지는 = (2-1)* 3 + 1 = 4, 종료 페이지는 4 + 3 – 1 = 6
3 페이지의 시작 페이지는 = (3-1)* 3 + 1 = 7, 종료 페이지는 7 + 3 – 1 = 9

따라서, 다음과 같이 SQL 문이 실행되도록 만들면 되는 것이다.

MariaDB의 Limit는 주어진 레코드 번호 값에 해당하는 데이터를 가지고 오고, Oracle이나 MS-SQL은 Row_number나 TOP등의 명령어가 제공된다.

SELECT BRDNO, BRDTITLE,  ~~ 생략 ~~
          FROM TBL_BOARD
         WHERE BRDDELETEFLAG='N'
         ORDER BY BRDNO DESC
         LIMIT 1, 3

SELECT BRDNO, BRDTITLE,  ~~ 생략 ~~
          FROM TBL_BOARD
         WHERE BRDDELETEFLAG='N'
         ORDER BY BRDNO DESC
         LIMIT 4, 6

SELECT BRDNO, BRDTITLE,  ~~ 생략 ~~
          FROM TBL_BOARD
         WHERE BRDDELETEFLAG='N'
         ORDER BY BRDNO DESC
         LIMIT 7, 9

이렇게 데이터를 가지고 오고,

리스트의 하단에 전체 페이지 리스트를 보여 주어 사용자가 선택하도록 하면 된다.

페이지 리스트는 전체 데이터 수(9)를 구해서

보여주고자 하는 개수(3)로 나누어 전체 페이지 수(3)를 구하고

그 수만큼 반복해서 링크를 생성한다.


이상의 개념을 이해한 경우 직접 만들어서 사용하면 되고,

그렇지 못해도 문제는 없다.

Common 폴더에 PageVO 클래스에 만들어 두었기 때문에 가져다 사용하면 된다.

public class PageVO {
    private Integer displayRowCount=10;      // 출력할 데이터 개수
    private Integer rowStart, rowEnd;         // 시작행번호, 종료행 번호
    private Integer totPage, totRow=0,        // 전체 페이수, 전체 데이터 수
                         page, pageStart, pageEnd;    // 현재 페이지, 시작페이지, 종료페이지

    public void pageCalculate(Integer total) {
        getPage();
        totRow  = total;
        totPage    = (int) ( total / displayRowCount );
       
        if ( total % displayRowCount > 0 ) totPage++;

        pageStart = (page - (page - 1) % 10) ;
        pageEnd = pageStart + 9;
        if (pageEnd > totPage) pageEnd = totPage;
       
        rowStart = ((page - 1) * displayRowCount) + 1 ;
        rowEnd = rowStart + displayRowCount -1;
    }
~~ 생략 ~~

이 코드를 간단하게 설명하면 전체 데이터 개수(total)를 받아서 totRow에 보관한다.

전체 데이터수를 출력하고자 하는 개수(displayRowCount)로 나누어

전체 페이지(totPage)를 계산한다.

무조건 올림을 해야 정확한 페이지 수를 얻을 수 있다.

예로 데이터 수가 21 개 일 때 단순 나누기를 하면 2페이지가 나온다.

무조건 올림을 해야 정확한 3페이지를 얻을 수 있다.

그래서 나눈 후 나머지가 있으면 전체 페이지(totPage) 값을 1증가 시킨다.

시작 행 번호(rowStart)와 종료 행 번호(rowEnd)는 앞서 언급한 공식을 이용하여 생성하였다. 

시작페이지(pageStart), 종료페이지(pageEnd)는 설명하지 않는다.

다만, 데이터가 수천, 수 만 일 경우 페이지도 수백, 수천이 된다.

모든 페이지를 보여 줄 수 없기 때문에

페이지 리스트에 대한 페이징 처리를 하게 되고 이것을 의미한다.

원리는 같지만 이상의 것만으로 복잡해서 넘어간다.

차후 코드를 살펴 보기 바란다.


먼저, 컨트롤을 수정한다.

@RequestMapping(value = "/board2List")
public String boardList(PageVO pageVO, ModelMap modelMap) throws Exception {

        pageVO.pageCalculate( boardSvc.selectBoardCount() ); // startRow, endRow

        List<?> listview   = boardSvc.selectBoardList(pageVO);
       
        modelMap.addAttribute("listview", listview);
        modelMap.addAttribute("pageVO", pageVO);

        return "board2/boardList";
}

board2Ctr.java

board2List의 파라메터로 PageVO 클래스 값을 받아오는 것은

사용자가 선택한 페이지 값을 알기 위한 것이다.

값이 없는 경우(Null) 1 페이지로 처리한다.

앞서 언급한 데로 PageVO에 메소드로 pageCalculate가 정의 되어 있기 때문에

서비스에서 전체 데이터 개수(COUNT)를 구하는 SQL문을 실행한다.

<select id="selectBoard2Count" resultType="Integer" >
        SELECT COUNT(*)
          FROM TBL_BOARD
         WHERE BRDDELETEFLAG='N'
</select>

Board2.xml

public Integer selectBoardCount() throws Exception {
    return sqlSession.selectOne("selectBoard2Count");
}

board2Svc.java

pageVO에서 시작 행 번호(rowStart)와 종료 행 번호(rowEnd)를 계산해서(pageCalculate) 가지고 있기 때문에,

selectBoardList를 호출 할때 파라메터로 넘겨준다.

이 값들은 다음과 같이 사용된다.

    <select id="selectBoard2List" resultType="gu.board2.boardVO" parameterType="gu.common.PageVO">
        SELECT BRDNO, BRDTITLE, BRDWRITER, DATE_FORMAT(BRDDATE,'%Y-%m-%d') BRDDATE, BRDHIT
          FROM TBL_BOARD
         WHERE BRDDELETEFLAG='N'
         ORDER BY BRDNO DESC
         LIMIT ${rowStart-1}, 10 (주의)
    </select>

board2.xml

public List<?> selectBoardList(PageVO param) throws Exception {
    return sqlSession.selectList("selectBoard2List", param);
}

board2Svc.java

이상의 처리로 페이징 처리는 끝났다.

10개 이상의 데이터를 넣고 실행해보면 10 개만 출력되는 것을 알 수 있다.



  주의: 앞서 필요한 데이터를 가져오는 부분에 대한 설명에 있어서

LIMIT 1, 3

~~

LIMIT 4, 6

~~

LIMIT 7, 9 는

첫 번째부터 세 번째, 네 번째부터 여섯 번째 등으로 설명하기 하기 위한 것이고

MariaDB(Mysql)의 LIMIT 문은

첫 번째부터 세 개, 네 번째부터 세 개로 사용해야 한다.

따라서

LIMIT 1, 3

~~

LIMIT 4, 3

~~

LIMIT 7, 3 으로 사용해야 하고

앞서의 Mybatis SQL문(board2.xml)에서는 그렇게 사용하고 있다.

Oracle이나 MS-SQL에서 Row_number를 사용할 경우에는

앞서의 설명대로 사용하여 LIMIT ${rowStart-1}, ${rowEnd}로 표현해서 사용한다.



이제 JSP에서 리스트 하단에 페이지 번호들이 나오게 처리해야 하다.

시작페이지(pageStart)부터 종료페이지(pageEnd)까지 반복하면서(forEach)하면 그 값을 링크를 걸어서 출력(out)하면 된다.

              </c:forEach>
        </tbody>
    </table>
<c:if test="${pageVO.totPage>1}">
<div class="paging">
    <c:forEach var="i" begin="${pageVO.pageStart}" end="${pageVO.pageEnd}" step="1">
        <c:url var="pageLink" value="board2List">
        <c:param name="page" value="${i}" />
        </c:url>                       
            <a href="${pageLink}"><c:out value="${i}"/></a>
    </c:forEach>
</div>
</c:if>  

boardList.jsp

이 코드에서 현재 페이지(paveVO.page)는 링크를 걸지 않게 만들면 더 좋을 것이니 직접 해 보길 바란다.


게시물들은 등록된 후 수정되고 삭제 된다.

삭제 된 경우 리스트에서 보여 주는 글 번호가 들쑥날쭉 보이면서 뭔가 문제가 있는 것처럼 보인다. 

아래의 계산식을 사용하면 깨끗하게 이어진 새로운 번호가 보이게 된다. 

다음 코드를 사용해 보고 계산식은 각자 확인해 보길 바란다.

<tr>
    <td>
        <c:out value="${pageVO.totRow-((pageVO.page-1)*pageVO.displayRowCount + status.index)}"/>                   
    </td>
    <td><a href="${link}"><c:out value="${listview.brdtitle}"/></a></td>
    <td><c:out value="${listview.brdwriter}"/></td>
    <td><c:out value="${listview.brddate}"/></td>
    <td><c:out value="${listview.brdhit}"/></td>
</tr>

boardList.jsp















+ Recent posts