Backend/Spring Framework

[Thymeleaf] 게시판 페이징 구현

mopil 2022. 6. 24. 02:00
반응형

[ek tour 리뉴얼 프로젝트 중 기록]

Thymeleaf 활용하여 어드민 백오피스 메인 페이지 페이징 기능과 검색 기능을 구현하면서 삽질했던 내용을 기록한다.

 

# Controller

@GetMapping("/main")
public String main(@Login Admin loginAdmin,
                   Model model,
                   @PageableDefault(size = PageConfig.PAGE_PER_COUNT, sort = PageConfig.SORT_STANDARD, direction = Sort.Direction.DESC) Pageable pageable) {
    if (loginAdmin == null) return "login";
    Page<Estimate> eList = estimateService.findAllByPageAdmin(pageable);
    model.addAttribute("eList", eList);
    model.addAttribute("maxPage", 10);
    model.addAttribute("adminSearchForm", new AdminSearchForm());
    return "mainPage";
}

findAllByPageAdmin 메소드는 레포지토리에서 바로 Page로 Estimate 엔티티를 가져오는 메소드다.

maxPage는 한 페이지바 당 최대 10개의 페이지를 보여줄 것을 의미한다.

(ex. 1 2 3 4 5 6 7 8 9 10 > >> ... << < 11 12 13 14)

adminSearchForm은 밑에 검색 기능에서 다시 설명하겠다.

 

@PageableDefault의 PageConfig는 그냥 값을 한 곳에 저장해서 사용하게 끔 만든 커스텀 객체이다.

 

# mainPage.html

<table class="table table-striped table-hover" style="table-layout: fixed">
    <thead class="table-light">
        <tr>
            <th scope="col" style="width: 50px;">번호</th>
            <th scope="col">요청자</th>
            <th scope="col">연락처</th>
            <th scope="col">여행구분</th>
            <th scope="col">출발일</th>
            <th scope="col">도착일</th>
            <th scope="col">출발지</th>
            <th scope="col">도착지</th>
            <th scope="col">차량구분</th>
            <th scope="col">요청일</th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="e: ${eList}">
            <td th:text="${e.id}"></td>
            <td th:text="${e.name}"></td>
            <td th:text="${e.phone}"></td>
            <td th:text="${e.travelType}"></td>
            <td th:text="${e.departDate}"></td>
            <td th:text="${e.arrivalDate}"></td>
            <td th:text="${e.departPlace}"></td>
            <td th:text="${e.arrivalPlace}"></td>
            <td th:text="${e.vehicleType}"></td>
            <td th:text="${e.createdDate}"></td>
        </tr>
    </tbody>
</table>

게시물들을 보여줄 태그는 th:each를 이용해서 보여준다. e는 여기서 견적요청을 의미한다.

 

# 페이징 네비게이션 바

페이지를 선택하는 하단의 바를 그리는 로직이다. 이 부분이 이 글의 핵심이다.

<nav style="text-align: center;">
    <ul class="pagination" th:with="start=${(eList.number/maxPage)*maxPage + 1}, end=(${(eList.totalPages == 0) ? 1 : (start + (maxPage - 1) < eList.totalPages ? start + (maxPage - 1) : eList.totalPages)})">
        <li th:if="${start > 1}">
            <a th:href="@{/admin/main(page=0)}" th:text="'<<'"></a>
        </li>
        <li th:if="${start > 1}">
            <a th:href="@{/admin/main(page=${start - maxPage})}" th:text="'<'"></a>
        </li>

        <li th:each="page: ${#numbers.sequence(start, end)}">
            <a th:text="${page}" th:href="@{/admin/main(page=${page - 1})}"></a>
        </li>

        <li th:if="${end < eList.totalPages}">
            <a th:href="@{/admin/main(page=${start + maxPage})}" th:text="'>'"></a>
        </li>
        <li th:if="${end < eList.totalPages}">
            <a th:href="@{/admin/main(page=${eList.totalPages - 1})}" th:text="'>>'"></a>
        </li>
    </ul>
</nav>

로직이 복잡해 보이지만, 하나하나 뜯어보면 그렇게 어렵지 않다.

 

<ul class="pagination" th:with="start=${(eList.number/maxPage)*maxPage + 1}, end=(${(eList.totalPages == 0) ? 1 : (start + (maxPage - 1) < eList.totalPages ? start + (maxPage - 1) : eList.totalPages)})">

th:with으로 start, end 변수를 정의해서 사용한다. 

 

<li th:if="${start > 1}">
    <a th:href="@{/admin/main(page=0)}" th:text="'<<'"></a>
</li>
<li th:if="${start > 1}">
    <a th:href="@{/admin/main(page=${start - maxPage})}" th:text="'<'"></a>
</li>

<< 버튼과 < 버튼을 그리는 로직이다. 1번째 페이지 옆에는 생기지 않는다.

(ex << < 1 2 3 이런 식으로 생기지 않는다는 말이다.)

 

<li th:each="page: ${#numbers.sequence(start, end)}">
    <a th:text="${page}" th:href="@{/admin/main(page=${page - 1})}"></a>
</li>

1 2 3 4와 같이 페이지 네비게이션 바 숫자들을 넣는 로직이다.

#number.sequence를 이용하면 start부터 end까지 숫자를 하나씩 올려가며 넣을 수 있다.

(number는 타임리프 숫자를 편리하게 다룰 수 있는 내장 유틸리티이다.)

 

<li th:if="${end < eList.totalPages}">
    <a th:href="@{/admin/main(page=${start + maxPage})}" th:text="'>'"></a>
</li>
<li th:if="${end < eList.totalPages}">
    <a th:href="@{/admin/main(page=${eList.totalPages - 1})}" th:text="'>>'"></a>
</li>

>> 버튼과 > 버튼을 그리는 로직이다.

totalPages 속성은 eList 즉, Page의 내장 속성인데, 이렇게 호출하면 getTotalPages()가 호출돼서 값이 들어가게 된다.

 

페이징 결과물1
페이징 결과물2

 

반응형