[Playground] Spring 목록 API 페이지네이션 적용

Daeya·6일 전

Playground

목록 보기
3/7

API 엔드포인트에 쿼리스트링 붙이고 페이지 단위로 조회

GET /api/memos?page=1&size=5
GET /api/memos?status=ING&page=2&size=5

status 필터 다음으로, 목록을 한 번에 다 주지 않고 페이지 단위로 나눠 응답하도록 했다.


1. DBeaver에서 쿼리 확인

목록 (한 페이지)

SELECT ID      as 'id'
     , TITLE   as 'title'
     , CONTENT as 'content'
     , STATUS  as 'status'
  FROM MEMO
 WHERE DEL_YN = 'N'
   AND STATUS = 'ING'   -- 필터 있을 때만
 ORDER BY ID
 LIMIT 5 OFFSET 0;      -- 2페이지: OFFSET 5

개수 (전체 건수 — 페이지 수 계산용)

SELECT COUNT(*)
  FROM MEMO
 WHERE DEL_YN = 'N'
   AND STATUS = 'ING';

COUNT(*)는 목록 SELECT에 넣지 않고 쿼리를 따로 둔다.


2. Mapper.xml에 LIMIT/OFFSET + COUNT 쿼리 추가

기존 selectMemoList SELECT문 끝에 추가

ORDER BY ID
LIMIT #{size} OFFSET #{offset}

개수 조회용 쿼리 새로 추가 (selectMemoCount)

<select id="selectMemoCount" resultType="int">
    SELECT COUNT(*)
      FROM MEMO
     WHERE DEL_YN = 'N'
    <if test="status != null and status != ''">
        AND STATUS = #{status}
    </if>
</select>

status <if> 조건은 목록 쿼리와 동일하게 맞춘다.


3. Mapper.java에 메서드 추가

List<MemoVO> selectMemoList(MemoVO param);
int selectMemoCount(MemoVO param);

4. MemoVO에 검색용 필드 추가

private int size;
private int offset;
// getter / setter
  • DB 컬럼이 아니라 MyBatis에 넘기는 검색 조건
  • Controller의 page, size를 Service에서 offset으로 바꿔서 Mapper로 전달

5. MemoPageVO 추가 (응답용)

private List<MemoVO> items;
private int total;
private int page;
private int size;
// getter / setter

예전처럼 배열 [...]이 아니라 { items, total, page, size } 형태로 응답


6. Service에 페이지 조회 메서드 추가

public MemoPageVO selectMemoPage(String status, int page, int size) {
    MemoVO param = new MemoVO();
    param.setStatus(status);
    param.setSize(size);
    param.setOffset((page - 1) * size);

    int total = memoMapper.selectMemoCount(param);
    List<MemoVO> items = memoMapper.selectMemoList(param);

    MemoPageVO result = new MemoPageVO();
    result.setItems(items);
    result.setTotal(total);
    result.setPage(page);
    result.setSize(size);
    return result;
}
  • selectMemoList는 Mapper 그대로 (List 반환)
  • selectMemoPage가 count + list를 묶어서 MemoPageVO로 반환

7. Controller에 @RequestParam 추가

@GetMapping
public MemoPageVO list(
    @RequestParam(required = false) String status,
    @RequestParam(defaultValue = "1") int page,
    @RequestParam(defaultValue = "5") int size
) {
    return memoService.selectMemoPage(status, page, size);
}

8. Postman으로 확인

GET http://localhost:8080/playground/api/memos?page=1&size=5
GET http://localhost:8080/playground/api/memos?status=ING&page=2&size=5

응답 예:

{
  "items": [
    { "id": 1, "title": "...", "status": "READY" }
  ],
  "total": 10,
  "page": 1,
  "size": 5
}

정리

기능

  • GET /api/memos?page=1&size=5 → 5건만 반환 + total로 전체 개수
  • status 필터와 함께 사용 가능: ?status=ING&page=2&size=5

흐름 (요청 → DB)

Controller: @RequestParam page, size
→ Service: offset = (page - 1) * size, param 세팅
→ Mapper: selectMemoCount(param) + selectMemoList(param)
→ XML: status 있으면 AND STATUS = #{status}, 목록에 LIMIT / OFFSET
→ DB
→ MemoPageVO { items, total, page, size }

만든 순서 (DB → 요청)

  1. DBeaver: LIMIT / OFFSET / COUNT(*)
  2. Mapper.xml: LIMIT #{size} OFFSET #{offset} + selectMemoCount
  3. Mapper.java: selectMemoCount 추가
  4. MemoVO: size, offset
  5. MemoPageVO: items, total, page, size
  6. Service: selectMemoPage
  7. Controller: @RequestParam page, size
  8. Postman: GET .../api/memos?page=1&size=5

참고

profile
Daeya

0개의 댓글