
스프링 부트와 mybatis를 이용하는 쇼핑몰 토이 팀 프로젝트 진행 중 나는 상품 영역을 담당하게 되었다.
그중 상품 리스트 페이지에서의 기능들 중 상품 카테고리를 선택하고 정렬하고 페이지를 넘어가는 것에 대한 구현이 필요했다.
사진으로 보면 다음과 같다.

왼쪽 사이드바에서 카테고리를 선택하고 정렬 기준을 고르고 정렬 버튼을 누른 후 페이징까지 호환이 되도록 동작해야 하는 것이었다.
프로젝트라는 것도 처음이고 어떻게 손을 대야 하는지 감도 오지 않아서 일단 실습 때 배운 대로 쿼리부터 작성했다.
내가 작성한 쿼리는 다음과 같다.
쿼리를 전부 작성하고 서비스 단계에서 세 조건을 모두 충족하는 페이지를 띄우고자 하는데 문제가 생겼다.
총 8가지에 해당하는 각각의 쿼리들은 모두 상품 dto 리스트를 반환하고 있고 모든 쿼리는 select * from product로 시작한다.
입력 없이 리스트를 반환하기만 하는 쿼리들을 통해 카테고리, 정렬, 페이징 기준을 모두 충족하는 상품 리스트를 반환할 방법이 없었다.
결국 쿼리를 수정해가며 서비스 단계에서 switch-case 문을 통해 접근을 해보고자 했다.

남아있는 그 때의 흔적.....
이렇게까지 하긴 했는데 이 메서드는 정렬이 된 페이지의 리스트를 반환할 뿐 카테고리 필터링은 할 수 없었다. (정렬 기준을 선택하거나 페이지를 넘기면 카테고리 정보를 잃어버린다.)
이 상황을 어떻게 해결해야 할까 한참 고민하던 중에 동기분이 동적쿼리에 대해 설명해주셨다. 나는 동적 쿼리라는 단어조차 처음 들어봤는데 이게 my-batis를 사용하는 유일한 이유라며 링크를 공유해주셨다.
https://mybatis.org/mybatis-3/ko/dynamic-sql.html
공유받은 공식 사이트를 보면서 공부를 조금 해보니까 어떻게 문제를 해결해야 할지 감이 오기 시작했다.
먼저 이 카테고리, 정렬, 페이징 이 세 요소의 관계를 정리해야 했다.
내가 생각한 바는 다음과 같다.
이후 다음과 같은 절차를 통해 문제를 해결해나갔다.
<select id="getFilteredAndSortedPage" parameterType="map" resultType="com.no1.book.domain.product.ProductDto">
SELECT *
FROM product
WHERE 1=1
<if test="cateKey != null and cateKey != ''">
AND cate_code LIKE CONCAT(#{cateKey}, '%')
</if>
ORDER BY
<choose>
<when test="sortKey == 'price'">
prod_base_price
</when>
<when test="sortKey == 'sales'">
total_sales
</when>
<otherwise>
reg_date
</otherwise>
</choose>
<choose>
<when test="sortOrder == 'desc'">
DESC
</when>
<otherwise>
ASC
</otherwise>
</choose>
,prod_name asc
LIMIT #{offset}, #{pageSize}
</select>
<form th:action="@{/product/list}" method="get" class="sort-form">
<input type="hidden" name="cateKey" th:value="${cateKey}"/>
<div class="sort-options">
<select name="sortKey">
<option value="date" th:selected="${sortKey == 'date'}">등록 날짜</option>
<option value="sales" th:selected="${sortKey == 'sales'}">판매량</option>
<option value="price" th:selected="${sortKey == 'price'}">가격</option>
</select>
<select name="sortOrder">
<option value="desc" th:selected="${sortOrder == 'desc'}">↓</option>
<option value="asc" th:selected="${sortOrder == 'asc'}">↑</option>
</select>
<button type="submit" class="btn btn-primary">정렬</button>
</div>
</form>
<a th:href="@{/product/list(cateKey=${cateKey}, sortKey=${sortKey}, sortOrder=${sortOrder}, page=${i}, pageSize=${ph.pageSize})}"
th:text="${i}" th:classappend="${ph.page == i} ? 'active' : ''"></a>
이러한 과정으로 카테고리-정렬-페이징 조건을 만족하는 상품 리스트를 반환할 수 있게 되었다.
삽질하는 시간이 너무 많았어서 시간이 너무 아깝다고 동기 형한테 징징거렸는데, 오히려 많은 시간 끝에 문제를 해결했으니 이 방법은 앞으로 절대 잊어버리지 않을거라는 말을 해주셨다.
앞으로도 문제를 직면하고 시간을 쏟을때마다 원리를 알고 기록해서 오래오래 써먹도록 해야겠다.