Hansel
검색 구현(Pageable, Thymeleaf) 본문
1. 카테고리 및 이름 검색(현재)
2. 쿼리 최적화
3. 전체 점검 및 테스트
현재 검색이 가능하도록 검색 후 페이징 처리가 필요하다.
페이징 처리는 이미 되어있다.
검색과 관련하여 항상 골치 아픈 일은 검색을 한 뒤 해당 검색 파라미터를 유지하면서 페이징을 하는 것이다.
만약 이러한 처리를 해주지 않는다면 검색 후 2,3,4 번 등의 페이지로 이동할 때 검색은 해제되고 단순한 페이징으로 바뀐다.
초기 화면이 ?name=ab 이라면
페이징을 유지한 뒤에는 ?name=ab&page=2가 되어야 한다. 하지만 적절한 처리가 없다면
?page=2가 되버릴 것이다.
home html의 검색폼과 카테고리 셀렉트 박스 폼이다.
th:field를 이용해 이전에 사용한 검색값이나 셀렉트 값을 유지할 수 있다.
(해당 영역의 값에 ${}안에 명시된 변수의 값을 넣어준다.)
home 메서드는 페이징에 사용될 pageable과 필요한 파라미터 2개를 받는다.
하지만 검색 요청이 없을 수 있으니 required는 false로 처리한다.
Pageable의 객체를 받아 첫 시작 페이지의 숫자를 정한다(page(int))
그 후 요청된 파라미터에 맞게 페이징 처리를 해준다.
paging 객체는 페이징을 좀 더 간편하게 하려고 만들었다.
전체 페이지 수와 현재 페이지, 파라미터 등을 받아 타임리프에서 간편하게 사용할 수 있다.
타임리프와 매핑하여 사용하는 것은 조금 뒤에 살펴보자.
서비스단에 작성된 페이지 관련 로직이다.
각 파라미터에 맞는 데이터만 가져와 DTO로 변환한 뒤 반환한다.
PageRequest.of에 들어가는 매개변수는 현재 페이지의 인덱스와 해당 페이지에서 보여줄 객체의 수이다.
아래는 타임리프에서 사용될 페이지 관련 태그들이다.
<div class="pagination">
<ul class="container"
th:with="start = ${paging.start}, last=${paging.last}">
<li th:style="${seller.first} ? 'display:none'">
<a th:if="${paging.keyWord!=null}" th:href="${seller.first} ? '#' : @{/?keyWord={key}(page=${paging.number},key=${paging.keyWord})}" class="btn">❮ Prev</a>
<a th:if="${paging.category!=null}" th:href="${seller.first} ? '#' : @{/?category={cat}(page=${paging.number},cat=${paging.category})}" class="btn">❮ Prev</a>
<a th:if="${paging.keyWord==null && paging.category==null}" th:href="${seller.first} ? '#' : @{/(page=${paging.number})}" class="btn">❮ Prev</a>
</li>
<li th:each="p : ${#numbers.sequence(start,last)}">
<a th:if="${paging.keyWord!=null && p==paging.number+1 }"
th:href="@{/?keyWord={key}(page=${p},key=${paging.keyWord})}"
th:text="${p}"
class="btn btn--sub">num</a>
<a th:if="${p!=paging.number+1 && paging.keyWord!=null}"
th:href="@{/?keyWord={key}(page=${p},key=${paging.keyWord})}"
th:text="${p}"
class="btn">num</a>
<a th:if="${paging.category!=null && p==paging.number+1 }"
th:href="@{/?category={cat}(page=${p},cat=${paging.category})}"
th:text="${p}"
class="btn btn--sub">num</a>
<a th:if="${paging.category!=null && p!=paging.number+1 }"
th:href="@{/?category={cat}(page=${p},cat=${paging.category})}"
th:text="${p}"
class="btn">num</a>
<a th:if="${paging.keyWord == null && paging.category==null && p==paging.number+1}"
th:href="@{/(page=${p})}"
th:text="${p}"
class="btn btn--sub">num</a>
<a th:if="${p!=paging.number+1 && paging.category==null && paging.keyWord==null}"
th:href="@{/(page=${p})}"
th:text="${p}"
class="btn">num</a>
</li>
<!-- paging.number = 현재 페이지, start = 페이징에서 첫번째, last=페이징에서 마지막,-->
<li th:style="${seller.last} ? 'display:none'">
<a th:if="${paging.keyWord!=null}" th:href="${seller.last} ? '#' : @{/?keyWord={key}(page=${seller.number+2},key=${paging.keyWord})}" class="btn">Next ❯</a>
<a th:if="${paging.category!=null}" th:href="${seller.last} ? '#' : @{/?category={cat}(page=${seller.number+2},cat=${paging.category})}" class="btn">Next ❯</a>
<a th:if="${paging.category==null && paging.keyWord==null}" th:href="${seller.last} ? '#' : @{/(page=${seller.number+2})}" class="btn">Next ❯</a>
</li>
</ul>
</div>
카테고리와 검색어에 따라 페이징이 구분되어야 하기 때문에 관련 태그들이 조금 많은편이다.
each문에서 사용하는 start, last는 최대 몇개의 페이지 버튼을 보여줄지와 관련이 있다.
위의 Paging 객체에서 그걸 따로 처리했고 나는 최대 1~10까지의 페이지 버튼만 보여주기 위해 따로 처리했다.
페이징과 관련된 쿼리는 countQuery까지 작성해야한다.
페이징과 관련된 쿼리는 JPA가 자동으로 countQuery를 작성하긴 하지만 그게 정확하지 않아 아직까진 문제가 있다고 한다.
따라서 필요한 데이터에 맞게 count쿼리 또한 작성해줘야 한다.
select 쿼리에 distinct가 쓰여있는데 예전에 작성해둔거라 아직 남아있다.
하지만 seller(M) : category(1)인 관계라 distinct는 굳이 필요하지 않다.
결과
다음
1. 쿼리 최적화
2. 전체 점검 및 테스트
'프로젝트 > 과정' 카테고리의 다른 글
@OneToOne 매핑 주의사항 (Eager / Lazy) (0) | 2022.05.30 |
---|---|
쿼리 분석 및 리팩토링 1 (0) | 2022.05.29 |
회원가입 과정 변경하기 / Ajax, RestController, 카카오API (0) | 2022.05.23 |
결제 도입하기 4 / 기타 수정사항(ResponseEntity) (0) | 2022.05.21 |
결제 도입하기 3 / 아임포트 테스트 (0) | 2022.05.18 |