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만 동적으로 바뀐다.
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부터)
기존 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>로 허용한 컬럼만 분기
private String sort;
private String order;
// getter / setter
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만 허용 → 나머지는 idorder: asc, desc만 허용 → 나머지는 asc<choose> + Service 화이트리스트 = SQL injection 방지@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);
}
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로 목록 정렬Controller: @RequestParam sort, order
→ Service: resolveSort() / resolveOrder() 화이트리스트
→ Mapper: selectMemoList(param)
→ XML: <choose>로 ORDER BY 동적 처리
→ DB
ORDER BY ID ASC / ORDER BY CREATED_AT DESC<choose>로 ORDER BYsort, orderresolveSort() / resolveOrder()@RequestParam sort, order<if><choose> (컬럼명은 #{} 불가)