페이징처리 (Page 인터페이스)

김종조·2026년 4월 6일
post-thumbnail

페이징 처리에 Page 인터페이스를 쓰는 이유
단순히 DB에서 데이터를 가져와 List<?> 형태로 넘겨주면, 프론트엔드는 다음 정보를 알 수 없다.

  • 전체 페이지가 몇 개인가?
  • 지금 내가 보고 있는 페이지가 어디인가?
  • 이전/다음 페이지 버튼을 보여줘야 하는가?

Page 인터페이스는 실제 데이터(content)와 함께 이러한 페이징 처리에 대한 정보들까지 하나의 객체로 묶어 제공한다.

QueryDSL과의 궁합
복잡합 검색 조건을 안전하게 처리하면서, 페이징 처리를 동시에 할 수 있다.
우선 프론트엔드에서 페이지 정보를 알려줘야 사용자가 현재 어디에 있고, 앞으로 어디로 갈 수 있는지 길을 잃지 않게 해준다.

게시글 목록을 조회하는 함수

// 기본값 0
    const searchList = (page = 0) => {
        axios
            .get("http://localhost:8080/boards", {
                params: {
                    keyword: keyword,
                    page: page, // 첫번째 페이지 0부터 시작
                    size: 3, // 한 페이지에 보여줄 개수
                },
            })
            .then((res) => {
                console.log(res);
                setPageData(res.data);
            });
    };

QueryDSL 코드

public Page<ResponseBoard> getBoards(String keyword, Pageable pageable) {

        // 실제 데이터를 가져오는 쿼리
        List<ResponseBoard> content = queryFactory
                .select(Projections.constructor(ResponseBoard.class,
                        board.id,
                        board.writer,
                        board.title,
                        board.content,
                        board.writeAt
                ))
                .from(board)
                .where(
                        keyword != null ?
                                board.writer.contains(keyword).or(board.title.contains(keyword).or(board.content.contains(keyword)))
                                : null
                )
                .offset(pageable.getOffset()) // 시작 지점
                .limit(pageable.getPageSize()) // 페이지 당 개수
                .orderBy(board.writeAt.desc()) // 최신순 정렬
                .fetch();

        // 전체 개수 조회
        Long total = queryFactory
                .select(board.count())
                .from(board)
                .where(
                        keyword != null ?
                                board.writer.contains(keyword).or(board.title.contains(keyword).or(board.content.contains(keyword)))
                                : null
                )
                .fetchOne();


        return new PageImpl<>(content, pageable, total != null ? total : 0L);

    }

백엔드에서 Page 인터페이스 주요 메서드

메서드명반환타입설명
getOffset()long현재 페이지 조회를 위해 건너뛸 행의 수
getPageSize()int한 페이지에 담길 최대 항목 개수
getPageNumber()int요청받은 형재 페이지 번호
getContent()List<T>조회된 실제 데이터 목록
getNumber()int현재 페이지 번호를 반환(0부터)
getSize()int한 페이지당 보여줄 데이터 개수
getTotalPages()int전체 페이지 개수
getTotalElements()longDB에 저장된 전체 데이터 개수
isFirst()boolean현재 페이지가 첫번째 페이지인지 확인
isLast()boolean현재 페이지가 마지막 페이지인지 확인
hasNext()boolean다음 페이지가 존재하는지 확인
hasPrevious()boolean이전 페이지가 존재하는지 확인

프론트엔드에 꼭 전달해야할 핵심 데이터

JSON 필드명설명
content목록 출력
number현재 위치 표시
totalPages버튼 개수 생성: 1부터 totalPages까지 번호 버튼 생성
totalElements정보 제공: 화면 상단에 '총 123건의 게시물이 있습니다'
first이전 버튼 제어: true면 '이전' 버튼을 숨김
last다음 버튼 제어: true면 '다음' 버튼을 숨김
size목록 개수 확인: 현재 한 페이지에 몇 개씩 보여주고 있는지 확인
profile
웹 개발 공부 기록

0개의 댓글