스프링 부트 게시판 프로젝트 - 12 | 게시글 페이징

seren-dev·2022년 9월 2일
1

게시글 페이징 기능 구현

게시판 컨트롤러 수정

BoardController


    @GetMapping
    public String postList(Model model,
                           @RequestParam(required = false, defaultValue = "0") Integer page,
                           @RequestParam(required = false, defaultValue = "5") Integer size) {
        model.addAttribute("resultMap", boardService.findAll(page, size));
        return "board/postList";
    }

    @GetMapping("/{postId}")
    public String postView(@PathVariable Long postId, Model model) {
        log.info("postView");

        Board post = boardService.findOne(postId).orElseThrow();
        model.addAttribute("post", post);

        return "board/post";
    }
  • postList() : 게시글 조회 메서드
    • 게시글 조회 메서드에 페이징 처리를 위한 파라미터를 받도록 한다.
    • defaultValue를 지정하여 게시글 조회 화면에서 기본적으로 첫페이지가 나타나고, 게시글 5개가 나타나도록 한다.

게시판 서비스 수정

BoardService


    /**
     * 게시글 전체 조회
     */
    public HashMap<String, Object> findAll(Integer page, Integer size) {
        HashMap<String, Object> listMap = new HashMap<>();
        Page<Board> list = boardRepository.findAll(PageRequest.of(page, size));

        listMap.put("list", list);
        listMap.put("paging", list.getPageable());
        listMap.put("totalCnt", list.getTotalElements());
        listMap.put("totalPage", list.getTotalPages());
        return listMap;
    }

Spring Data JPA에서는 페이지 처리를 위한 PageRequest 객체를 지원하므로 간단하게 페이징 처리를 할 수 있다.

  • findAll() : 게시글 전체 조회 메서드
    • HashMap<String, Object>를 반환

게시글 조회 뷰 템플릿 수정

postList.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.min.css}"
          href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

    <div id="wrapper">
        <div class="container">
            <div class="col-md-12">
                <div class="py-5 text-center">
                    <h2>게시판</h2>
                </div>
                <button class="btn btn-dark"
                        th:onclick="|location.href='@{/}'|" type="button">
                    홈 화면
                </button>

                <button class="btn btn-primary"
                        th:onclick="|location.href='@{/board/register}'|" type="button">
                    게시글 작성
                </button>

                <hr class="my-4">

                <table class="table">
                    <thead>
                    <tr>
                        <th width="10%">게시글번호</th>
                        <th width="">제목</th>
                        <th width="20%">작성자</th>
                        <th width="20%">작성일</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr th:each="list,index: ${resultMap.list}" th:with="paging=${resultMap.paging}">
                        <td>
                            <span th:text="${(resultMap.totalCnt - index.index) - (paging.pageNumber * paging.pageSize)}"></span>
                        </td>
                        </td>
                        <td>
                            <a th:href="@{/board/{postId}(postId=${list.id})}"
                            th:text="${list.title}">제목</a>
                        </td>
                        <td th:text="${list.user.loginId}">작성자</td>
                        <td th:text="${list.registerDate}">작성일</td>
                    </tr>
                    </tbody>
                </table>

                <div class="row">
                    <div class="col">
                        <ul class="pagination">
                            <li class="page-item" th:if="${resultMap.totalPage} > 0" th:each="index : ${#numbers.sequence(1, resultMap.totalPage)}"
                                th:with="paging=${resultMap.paging}">
                                <a class="page-link"
                                   th:href="@{/board/(page=${index-1},size=${paging.pageSize})}">
                                    <span th:text="${index}"></span>
                                </a>
                            </li>
                        </ul>
                    </div>
                </div>

                <hr class="my-4">

            </div>
        </div>
    </div>

</body>
  • th:each="list,index: ${resultMap.list}" th:with="paging=${resultMap.paging}"
  • th:text="${(resultMap.totalCnt - index.index) - (paging.pageNumber * paging.pageSize)}" : 게시글 번호 지정
  • th:href="@{/board/{postId}(postId=${list.id})}" : 게시글 제목을 클릭하면 해당 게시글 상세 조회 화면으로 이동한다.
  • th:if="${resultMap.totalPage} > 0" : page 개수가 1개 이상이라면, 태그를 출력한다.
  • th:href="@{/board/(page=${index-1},size=${paging.pageSize})}" : 쿼리 파라미터로 현재 페이지 번호와 페이지 크기를 전달한다.
  • th:each : 반복하려는 html 엘리먼트에 사용하여 콜렉션(Collection)을 반복
    th:each="콜렉션 변수명, status 변수명:${리스트}"
  • th:with : 변수형태의 값을 재정의
    th:with="변수명=${...}"
    참고: https://kitty-geno.tistory.com/124

게시글 상세 조회 뷰 템플릿 수정

  • 게시글 번호가 안 나타나도록 게시글 번호 <div>태그 삭제

게시글 조회 화면


문제점

게시글 조회 화면을 보면 가장 최근에 작성한 게시글이 1번이 되어 마지막 페이지에 나타난다.
내가 원하는 요구사항은 가장 최근에 작성한 게시글이 마지막 번호가 되어 가장 첫 페이지에 나타나도록 하는 것이다.

해결

구글링을 통해서 해결 방법을 찾았다.

  • BoardController에서 Pageable 객체를 생성하고 정렬 순서, 사이즈 등의 정보를 넣은 다음, boardService.findAll(pageable)를 호출해 파라미터로 넘긴다.
  • BoardService에서 PageRequest 객체 대신 Pageable 객체를 사용한다.
  • 참고 : Spring Boot JPA 게시판 페이징 처리 구현

BoardController 수정

@GetMapping
    public String postList(Model model,
                           @PageableDefault(sort = "id", direction = Sort.Direction.DESC, size = 5) Pageable pageable) {
        model.addAttribute("resultMap", boardService.findAll(pageable));
        return "board/postList";
    }

@PageableDefault 어노테이션을 사용해 간단하게 구현한다.

  • id를 기준으로 내림차순으로 정렬한다.

@PageableDefault

  • size : 한 페이지에 담을 모델의 수를 정할 수 있다. 기본 값은 10이다.
  • sort : 정렬의 기준이 되는 속성을 정한다.
  • direction : 오름차순과 내림차순 중 기준을 선택할 수 있다.
  • Pageable pageable : PageableDefault 값을 갖고 있는 변수를 선언한다.

BoardService 수정

	/**
     * 게시글 전체 조회
     */
    public HashMap<String, Object> findAll(Pageable page) {
        HashMap<String, Object> listMap = new HashMap<>();
        Page<Board> list = boardRepository.findAll(page);

        listMap.put("list", list);
        listMap.put("paging", list.getPageable());
        listMap.put("totalCnt", list.getTotalElements());
        listMap.put("totalPage", list.getTotalPages());
        return listMap;
    }
  • Spring Data JPA에서 페이징 처리와 정렬은 findAll() 메소드로 한다.
  • findAll() 메소드 파라미터로 pageable을 넣어준다.

PageRequest를 사용해도 page를 정렬 할 수 있다.
ex) boardRepository.findAll(PageRequest.of(page, 5, Sort.by(Sort.Direction.DESC, "id")));

postList.html 수정

			<div class="row">
                    <div class="col">
                        <ul class="pagination">
                            <li class="page-item" th:if="${resultMap.totalPage} > 0" th:each="index : ${#numbers.sequence(1, resultMap.totalPage)}"
                                th:with="paging=${resultMap.paging}">
                                <a class="page-link"
                                   th:href="@{/board/(page=${index-1})}">
                                    <span th:text="${index}"></span>
                                </a>
                            </li>
                        </ul>
                    </div>
                </div>
  • 불필요한 size 파라미터 삭제

결과 화면


http://localhost:8080/board
http://localhost:8080/board/?page=0

http://localhost:8080/board/?page=1

0개의 댓글