페이징 화면 처리

cy8erpsycho·2023년 8월 31일
0

스프링

목록 보기
20/29
post-thumbnail

페이징 화면 처리

화면 밑에 페이지 번호를 표시하고 사용자가 페이지 번호를 클릭할 수 있게 처리한다. 페이지를 보여주는 작업은 다음과 같은 과정을 통해서 진행한다.

  • 브자우저 주소창에서 페이지 번호를 전달해서 결과를 확인하는 단계
  • JSP에서 페이지 번호를 출력하는 단계
  • 각 페이지 번호에 클릭 이벤트 처리
  • 전체 데이터 개수를 반영해서 페이지 번호 조절

다음 그림과 같이 목록 페이지에서 조회 페이지, 수정 삭제 페이지까지 페이지 번호가 계속해서 유지되어야만 하기 때문에 끝까지 신경 써야하는 부분들이 많다.



한번에 게시글의 갯수를 보여주는 amount와 페이징을 알려주는 PageNum에 대해 알아보도록 하자.

페이지 처리에 필요한 정보들

  • 현재 페이지 번호(page)
  • 이전과 다음으로 이동 가능한 링크의 표시 여부(prev, next)
  • 화면에서 보여지는 페이지의 시작 번호와 끝 번호(startPage, endPage)

페이징의 끝 번호(endPage) 계산

this.endPage = (int)(Math.ceil(페이지 번호 / 10.0)) * 10;

endPage를 계산할 때, 데이터 타입은 숫자를 표현할 수 있는 더 일반적이고 더 큰 타입으로 형변환된다. 위의 우변의 연산 결과 타입은 double이 된다.

연산 후에는 좌변의 endPage의 데이터타입은 int이고 우변의 연산결과는 double이므로 형변환을 왼쪽에 맞춰준다. 실수타입을 정수타입으로 구겨넣어야 하기 때문에 강제로 형변환을 해야한다.

따라서 다음과 같이 코드를 작성한다.

endPage = (int) Math.ceil(cri.getPageNum() / 10.0)*10;

페이징의 시작 번호(startPage) 계산

화면에 10개씩 보여준다면 시작 번호는 무조건 끝 번호에서 9를 뺀 값이 된다.

this.startPage = this.endPage - 9;

total을 통한 endPage의 재계산

끝 번호(endPage)는 전체 데이터 수(total)에 의해 영향을 받는다.
예를 들어, 10개 씩 보여주는 경우 전체 데이터 수(total)가 80개라고 가정하면 끝 번호(endPage)는 10이 아닌 8이 되어야 한다.

만일 끝 번호(endPage)와 한 페이지당 출력되는 데이터 수(amount)의 곱이 전체 데이터 수(total)보다 크다면 끝 번호는 다시 total을 이용해서 계산되어야 한다.

int realEnd = (int)(Math.ceil((total*1.0) / cri.getAmount()));

위의 코드는 가장 가까운 정수로 올림하라는 의미이다.

예를 들어, 다음과 같은 페이지 인덱스가 있다고 가정해보자.

prev 1 2 3 4 5 6 7 8 9 next

88 → 9

realEnd를 계산할 때, 88개의 데이터가 있다. 이를 10(amount)으로 나눈 뒤 올림을 하면 이게 바로 맨 마지막의 페이지를 계산하는 수식이다. 결과적으로 위의 내용을 모두 종합하면 아래와 같은 코드를 작성할 수 있다.

realEnd = (int)(Math.ceil((total*1.0) / amount));

if (realEnd < this.endPage) {
	this.endPage = realEnd;
}

이전(prev)과 다음(next) 계산

prev 1 2 3 4 5 6 7 8 9 10 next

next를 누르게 되면

prev 11 12 13 14 15 16 17 18 19 20 next

11을 눌러도 12를 눌러도 20을 눌러도 위와 똑같은 인덱스 페이지가 보이게 된다.

realEnd가 의미하는 것은

prev 11 12 13 14 next

위와 같이 끝날 수 있도록 하게 한다.

this.prev = this.startPage > 1;
this.next = this.endPage < realEnd;


페이징 처리를 위한 클래스 설계

PageDTO 클래스를 도메인 패키지에 추가한다.

✍PageDTO.java

package com.zerock.domain;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString 
public class PageDTO {

	private int startPage;
	private int endPage;
	private int total;
	private boolean prev, next;
	private Criteria cri;
	
	public PageDTO() {
		
	}
	
	public PageDTO(Criteria cri, int total) {
		this.cri = cri;
		this.total = total;
		
		endPage = (int) Math.ceil(cri.getPageNum() / 10.0)*10;
		
		startPage = endPage-9;
		
		int realEnd = (int)(Math.ceil((total*1.0)/cri.getAmount()));
		
		if (realEnd < endPage) {
			endPage = realEnd;
		}
		
		prev = startPage > 1;
		next = endPage < realEnd;
		
	}
}


JSP에서 페이지 번호 출력

클라이언트에서 Criteria를 넘기고 백단에서 작업하기 위해서 BoardController에 Criteria 객체를 인자에 추가해준다. PageDTO를 구성하기 위해서는 전체 데이터 수가 필요한데, 아직 그 처리가 이루어지지 않았으므로 임의의 값으로 123을 지정한다.

✍BoardController.java

	@GetMapping("/list")
    public void list(Criteria cri, Model model) {
    	log.info("list : " + cri);
        model.addAttribute("list", service.getList(cri));
        model.addAttribute("pageMaker", new PageDTO(cri, 123));
    }  

✍list.jsp

위와 같이 구조를 대충 그려본 후 아래서 확인할 수 있다.

<div>
	<ul>
		<li>Prev</li>
		<c:foreach var="num" begin="1" end="10">
		<li>${num}</li>
		</c:foreach>
		<li>Next</li>
	</ul>
</div>

<div>
	<ul>
		<li>Prev</li>
		<c:foreach var="num" begin="${pageMaker.startPage}" 
        end="${pageMaker.endPage}">
		<li>${num}</li>
		</c:foreach>
		<li>Next</li>
	</ul>
</div>

그냥 list를 요청하면 되지 않는다. 아래와 같이 주소를 요청하면 된다.

보드컨트롤러에서 로그에서 찍도록한다

getter처리를한다

위와 같이 세팅을 모두 하면

위와 같이 요청을 했을때 다음을 확인할 수 있고

이걸 요청하게 되면 페이지가 넘어갔다는 의미이다. 다음페이지를 확인할 수 있다

PageNum : 내가 보고 있는 페이지

amount : 보여주는 페이지 수

페이지 번호 이벤트 처리

<div class='pull-right'>
	<ul class="pagination">
		<li class="paginate_button previous"><a href="#">Prev</a></li>
		<c:foreach var="num" begin="${pageMaker.startPage}" 
        end="${pageMaker.endPage}">
		<li class="paginate_button"><a href="#">${num}</a></li>
		</c:foreach>
		<li class="paginate_button next"><a href="#">Next</a></li>
	</ul>
</div>

위와 버튼 마다 앵커<a>를 걸어준다.

prev값이 True면 보여주고 False이면 숨기는 기능 조건 <c:if>을 다음과 같이 추가한다.

<div class='pull-right'>
	<ul class="pagination">
		<c:if test="${pageMaker.prev}">
		<li class="paginate_button previous"><a href="#">Prev</a></li>
		</c:if>
		<c:foreach var="num" begin="${pageMaker.startPage}" 
        end="${pageMaker.endPage}">
		<li class="paginate_button"><a href="#">${num}</a></li>
		</c:foreach>
		<c:if test="${pageMaker.next}">
		<li class="paginate_button next"><a href="#">Next</a></li>
		</c:if>
	</ul>
</div>

<c:if test="${pageMaker.prev}"> 가 true면 출력하고 false면 출력하지 않는다.
화면상의 조건에 따라서 prev와 next의 출력유무가 결정된다.

💡 그럼 이제 페이지 이동을 하게 만들어야 하는데 어떻게 해야할까?

<li class="paginate_button">
<a href="/board/list?pageNum=${num}&amount=10">${num}</a>
</li>

이렇게 코드를 작성할수 있다.

다른 방법으로는

위와 같이 코드를 작성후 자바스크립트를 이용할 수 있다.

submit
get
앵커방식
자바스크립트

<form id="actionForm" method="get" action="/board/list">
	<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
	<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
</form>
	$(".paginate_button a").on("click", function(e){
		alert("page click");
		e.preventDefault();
		$("#actionForm").submit();		
	});	

위와같이 작성하면 페이지를 클릭해도 url이 고정된다

서브밋을 하기 전에 전처리가 필요하다.

actionForm객체를 찾아서 인풋태그의 pageNum의 속성을 현재누른 (a태그)의 href값으로 바꿔라 라는 뜻이다.

페이지 세부 동작처리

<li class="paginate_button ${pageMaker.cri.pageNum == num ? "active" :"" }"><a href="${num}">${num}</a></li>

위와 같이 코드를 작성하면 active인 페이지의색상을 바꾼다

위에서는 클릭한 페이지를 클릭해도 계속해서 요청을 보내는데 이를 막으려면 어떤식으로 코드를 작성해야할까?

	$(".paginate_button a").on("click", function(e){

	if($("#actionForm").find("input[name='pageNum']").val() == $(this).attr("href")) {
			return;	
		}
		
		$("#actionForm").find("input[name='pageNum']").val($(this).attr("href"));
		$("#actionForm").submit();		
		
	});	

오후시간

질문

<c:foreach var="num" begin="${pageMaker.startPage}" end="${pageMaker.endPage}">
<li class="paginate_button ${pageMaker.cri.pageNum==num ? " active" :"" }"><a href="${num}">${num}</a></li>
</c:foreach>

num 변수는 위의 함수에서만 scope이 지정되어 있으니까

밑에서 쓸때 null 나오는게 당연하네

prev next

prev와 next를 작성한다.

보통 이전을 눌렀을때 1개씩 이동하는것이 일반적이다.

한꺼번에 이동을 시키냐, 1개씩 이동하는지는 개발자의 선택의 영역이다.

  • sql확인

  • xml 파일 작성
	<select id ="getListFromPaging" resultType="com.zerock.domain.BoardVO">
	<![CDATA[
	select bno, title, content, writer, regDate, updateDate
		from
		(select rownum rn, bno, title, content, writer, regDate, updateDate
		from tbl_board where rownum <= 20)
	where rn > 10
	]]>	
	</select>

  • boardMapper작성

  • service쪽 수정

실행순서

위의 123 부분에는 total record count가 들어가야 한다.

위와 같이 총 개수를 얻는 코드를 작성한다.

제일 먼저 작성할 코드는 Mapper와 xml이다.

위와 같이 코드를 작성한다.

테스트를 위와 같이 해본다.

서비스 인터페이스 추가와 구현을 추가한다.

테스트도 해본다

컨트롤러

페이지 번호 유지

25페이지에서 글을 보고 나서 목록클릭해서 왔을때 25페이지가 아닌 1페이지로 돌아왔다. 이걸 어떻게 해결하지?

정보를 전달하지 않아서 생기는 문제인데...

한번 코드를 수정해서 제대로 동작하도록 해보자!

get.jsp

pageMaker로 넘어오므로

이렇게 작성한다.

링크마다 위와 같이 설정되어있는걸 볼수있다.

조회페이지를 수정한다.

인자에 Criteria cri를 수정해준다

log.info로 데이터가 넘어오는지 확인한다. (인자가 자동으로 세팅된다)

get.jsp를 다음과 같이 수정한다.

컨트롤러의 모델에 addattribute를 해준다.

cri를 추가했다.

개발자 도구에서 위와같이 데이터가 cri값이 전달된것을 볼수있다.

아래의 두 코드는 같다.

지금까지 한것은 get에서 목록게시판으로 돌아갈때 페이지를 유지한 작업이다.

get, modify는 원래페이지로 간다.

수정하기 누르면 컨트롤러 가서 update.jsp

redirect를 할때 pageNum과 amount 붙여서 한다.



get.jsp

modify.jsp

컨트롤러에서 addFlashAttribute를
addAttributeㄹ로 바꿔야 하네


list.jsp수정

result 부분을 return문 아래로 이동시킨다

origin이 오면 반드시 result가 오니까!

0개의 댓글