게시판에 필요한 페이징 기능을 어떻게 할까. 찾아보니 대부분은 Pageable 전체를 자체 구현하거나 일부 기능만 자체 구현해 사용한다. 여기서는 Pageable객체를 사용해 Repository부터 Thymeleaf까지 직접 내려보겠다.

ArticleRepository

public List<Article> findByBoardIdPagination(Pageable page, long boardId) {
    return jdbcTemplate.query(QueryConst.ARTICLE_FIND_BY_BOARD_ID_PAGE,
            articleRowMapper(), boardId, page.getPageSize(), page.getOffset());
}

SQL

select * from ARTICLES where BOARD_ID = ? order by ID desc limit ? offset ?

ArticleService

public Page<ArticleListDto> findPageOfArticlesByBoardId(long boardId, int pageNum) {
    PageRequest pageable = PageRequest.of(pageNum, PageConst.PAGE_OFFSET);
    List<Article> articles = articleRepository.findByBoardIdPagination(pageable, boardId);
    List<ArticleListDto> returnArticles = getArticlesListDtoPage(articles);
    return new PageImpl<ArticleListDto>(returnArticles, pageable, articleRepository.count(boardId));
}

private List<ArticleListDto> getArticlesListDtoPage(List<Article> articles) {
    List<ArticleListDto> returnArticles = new ArrayList<>();
    articles.stream().filter(a -> !a.isDeleted()).forEach(a -> {
        try {
            returnArticles.add(ArticleListDto
                    .from(a, userService.findById(a.getAuthorId()).getNickname()));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    });
    return returnArticles;
}
  • 서비스부분은 DTO로 컨버팅하는 과정에서 개선의 여지가 있음.

Controller

@GetMapping(value = "/{id}")
public String list(@PathVariable("id") long boardId,
                   @RequestParam(value = "page", defaultValue = "1", required = false) int pageNum,
                   Model model) throws Exception {
    Page<ArticleListDto> articles = articleService.findPageOfArticlesByBoardId(boardId, pageNum - 1);
    String boardName = boardService.findById(boardId).getName();
    model.addAttribute("articles", articles);
    model.addAttribute("board_id", boardId);
    model.addAttribute("board_name", boardName);
    return "board/boardList";
}
  • 이 부분은 크게 손볼 것이 없는게 Page객체에 내려보내면 thymeleaf에서 쉽게 꺼내쓸 수 있음

Thymeleaf

<nav th:with="
          maxPage=${5},
          start=${(articles.number/maxPage)*maxPage + 1},
          end=(${(articles.totalPages == 0) ? 1 : (start + (maxPage - 1) < articles.totalPages ? start + (maxPage - 1) : articles.totalPages)})"
     aria-label="Page navigation">
    <ul class=" pagination justify-content-center">
        <li th:if="${start > 1}" class="page-item">
            <a class="page-link" th:href="@{'/board/' + ${board_id}(page=1)}">
                <i class="bi bi-chevron-double-left"></i>
            </a>
        </li>
        <li th:if="${start > 1}" class="page-item">
            <a class="page-link" th:href="@{'/board/' + ${board_id}(page=${start - 1})}">
                <i class="bi bi-chevron-left"></i>
            </a>
        </li>
        <li class="page-item"
            th:each="offset: ${#numbers.sequence(start, end)}"
            th:classappend="${offset == articles.number + 1} ? 'active'">
            <a class="page-link" th:href="@{'/board/' + ${board_id}(page=${offset})}"
               th:text="${offset}"></a>
        </li>
        <li th:if="${end < articles.totalPages}" class="page-item">
            <a class="page-link" th:href="@{'/board/' + ${board_id}(page=${start + maxPage})}">
                <i class="bi bi-chevron-right"></i>
            </a>
        </li>
        <li th:if="${end < articles.totalPages}" class="page-item">
            <a class="page-link" th:href="@{'/board/' + ${board_id}(page=${articles.totalPages})}">
                <i class="bi bi-chevron-double-right"></i>
            </a>
        </li>
    </ul>
</nav>

Pagable 하면서 찾아본 것들

  • https://javabydeveloper.com/spring-jdbctemplate-pagination-examples/
  • https://github.com/javabydeveloper/spring-boot/tree/master/spring-boot-jdbc-example/src/main/java/com/javabydeveloper
  • https://gist.github.com/mobynote/595b61d72a1a0363dc80b7eb785faef9
  • https://codereview.stackexchange.com/questions/163131/jdbc-query-with-limit-and-offset
  • https://to-dy.tistory.com/90
  • https://doublesprogramming.tistory.com/198

Comments