[Playground] Spring 목록 API 정렬 적용(feat. ORDER BY)

Daeya·2일 전

Playground

목록 보기
4/4

API 엔드포인트에 쿼리스트링 붙이고 정렬

GET /api/memos?sort=id&order=asc
GET /api/memos?sort=createdAt&order=desc
GET /api/memos?status=ING&keyword=메모&sort=id&order=desc&page=1&size=5

검색 다음으로 sort, order 파라미터를 추가했다.
status 필터·keyword 검색과 같은 패턴이고, XML에서 ORDER BY만 동적으로 바뀐다.


1. DBeaver에서 쿼리 확인

id 오름차순

SELECT ID, TITLE, CONTENT, STATUS, CREATED_AT
  FROM MEMO
 WHERE DEL_YN = 'N'
 ORDER BY ID ASC
 LIMIT 5 OFFSET 0;

등록일 내림차순

SELECT ID, TITLE, CONTENT, STATUS, CREATED_AT
  FROM MEMO
 WHERE DEL_YN = 'N'
 ORDER BY CREATED_AT DESC
 LIMIT 5 OFFSET 0;

sort=id&order=asc → id 1, 2, 3…
sort=id&order=desc → id 25, 24, 23… (큰 id부터)


2. Mapper.xml에 ORDER BY 동적 처리

기존 ORDER BY ID<choose>로 교체

ORDER BY
<choose>
    <when test="sort == 'createdAt'">CREATED_AT</when>
    <otherwise>ID</otherwise>
</choose>
<choose>
    <when test="order == 'desc'">DESC</when>
    <otherwise>ASC</otherwise>
</choose>

#{sort}값 바인딩이라 컬럼명에 못 씀
ORDER BY #{sort}ORDER BY 'id' (문자열) 되어서 틀림
그래서 <choose>허용한 컬럼만 분기


3. MemoVO에 검색용 필드 추가

private String sort;
private String order;
// getter / setter
  • DB 컬럼이 아니라 MyBatis에 넘기는 검색 조건

4. Service에 화이트리스트 + param 전달

public MemoPageVO selectMemoPage(String status, String keyword, String sort, String order, int page, int size) {
    MemoVO param = new MemoVO();
    param.setStatus(status);
    param.setKeyword(keyword);
    param.setSort(resolveSort(sort));
    param.setOrder(resolveOrder(order));
    // ...
}

private String resolveSort(String sort) {
    return "createdAt".equals(sort) ? "createdAt" : "id";
}

private String resolveOrder(String order) {
    return "desc".equalsIgnoreCase(order) ? "desc" : "asc";
}
  • sort: id, createdAt만 허용 → 나머지는 id
  • order: asc, desc만 허용 → 나머지는 asc
  • XML <choose> + Service 화이트리스트 = SQL injection 방지

5. Controller에 @RequestParam 추가

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

6. Postman으로 확인

GET http://localhost:8080/playground/api/memos?sort=id&order=asc
GET http://localhost:8080/playground/api/memos?sort=id&order=desc
GET http://localhost:8080/playground/api/memos?sort=createdAt&order=desc
GET http://localhost:8080/playground/api/memos?status=ING&keyword=메모&sort=id&order=desc&page=1&size=5


정리

기능

  • sort=id|createdAt, order=asc|desc로 목록 정렬
  • status · keyword · page · size와 함께 사용 가능

흐름 (요청 → DB)

Controller: @RequestParam sort, order
→ Service: resolveSort() / resolveOrder() 화이트리스트
→ Mapper: selectMemoList(param)
→ XML: <choose>ORDER BY 동적 처리
→ DB

만든 순서 (DB → 요청)

  1. DBeaver: ORDER BY ID ASC / ORDER BY CREATED_AT DESC
  2. Mapper.xml: <choose>로 ORDER BY
  3. MemoVO: sort, order
  4. Service: resolveSort() / resolveOrder()
  5. Controller: @RequestParam sort, order
  6. Postman 확인

status/keyword와 다른 점

  • WHERE 조건 → <if>
  • ORDER BY 컬럼 → <choose> (컬럼명은 #{} 불가)
  • 허용 값은 Service에서 한 번 더 걸러줌

참고

profile
Daeya

0개의 댓글