공기밥 프로젝트 5(타임리프, jpa를 활용한 페이징 처리)

Jay_u·2023년 8월 13일
0

프로젝트

목록 보기
5/5
post-thumbnail

주말에 스터디를 참여하며 많이 들었던 말이
웹 개발자는 처음부터 끝까지 게시판을 생각해야 한다는 말이었다.

게시판을 만들 때 CRUD 기능이 필요하고
여기서 Read는 페이징 처리 기능이 필수적이다.
오늘은 공기밥에 페이징 처리를 적용하는 과정을 적어보겠다.


Controller

먼저 컨트롤러에서 Pageable을 받아준다.
이전 내 게시글을 보면 알겠지만 원래는 pageNo만 받아서 pageRequest를 직접 만들어 repository에 줬다. 하지만 이러한 과정은 객체지향적이지 않다고 생각했다.
컨트롤러에서 page에 대한 모든 세팅을 하고 시작하는 것이다.

    @GetMapping("/restaurant/list")
    public ModelAndView getResturantList(HttpServletRequest request, @PageableDefault(page = 1, size = 5)Pageable pageable) {
    }

Service

Page<Place> placePage = null;
        try {
            int page = pageable.getPageNumber();
            // page 번호 예외처리 (음수인 경우)
            if(page <= 0) {
                return null;
            }

            if(request.getParameter("selectedDistrict") == null || "".equals(request.getParameter("selectedDistrict").trim())) {
                return placePage;
            }

            int districtId = Integer.parseInt(request.getParameter("selectedDistrict"));
            PageRequest pageRequest = PageRequest.of(page-1, pageable.getPageSize(), Sort.by("place_id").descending());
            placePage = placeRepository.findByDistrictId(pageRequest, districtId);

            return placePage;
        }
        catch (NumberFormatException e) {
            // 도시 id 지역 id가 숫자가 아닌 값이 들어올 경우 예외처리
            log.info("NumberFormatException 에러 발생 : " + e.toString());
            return null;
        }

page 번호가 음수인 경우 예외처리를 해준다.
page 번호에 특수문자가 글자가 들어갈 경우 page 번호에는 0이 들어가게 된다.
공백을 넣게 되면 default 값인 1이 들어가는데 왜 그럴까?
그건 Spring Data JPA의 방식에 따라 0으로 처리되기 때문이다.

그래서 컨트롤러에서 받은 pageable을 가지고 pagereqeust에 정렬 속성을 추가하여 jpa에 던저준다.

받은 페이지를 컨트롤러에 리턴한다.


페이지바


@GetMapping("/restaurant/list")
    public ModelAndView getResturantList(HttpServletRequest request, @PageableDefault(page = 1, size = 5)Pageable pageable) {
        ModelAndView model = new ModelAndView();
        List<City> cities = restaurantService.getCities();
        Page<Place> placePage = restaurantService.getPageByDistrictId(request, pageable);

        if(placePage != null) {
            // 페이지 바 만들기
            int blockSize = 5;
            int startPage = (((int) Math.ceil(((double) pageable.getPageNumber() / blockSize))) - 1) * blockSize + 1;
            int endPage = Math.min(startPage + blockSize - 1, placePage.getTotalPages());
            model.addObject("startPage", startPage);
            model.addObject("endPage", endPage);
        }

페이지 바는 다른 블로그에서 참고했는데

startPage에 대한 설정이 어려울 것 같아 설명을 해보겠다.
pageable.getPageNumber는 현재 페이지 번호를 리턴하는데
page의 시작값은 0이다. 0 1 2 3~ 이런식인것을 항상 인지해야 한다.

(Math.ceil(0 / 5) - 1) 5 + 1 =
( (1) - 1)
5 + 1 = 1

(Math.ceil(1 / 5) - 1) 5 + 1 =
( (1) - 1)
5 + 1 = 1

(Math.ceil(5 / 5) - 1) 5 + 1 =
( (1) - 1)
5 + 1 = 1

--

(Math.ceil(6 / 5) - 1) 5 + 1 =
( (2) - 1)
5 + 1 = 6

(Math.ceil(11 / 5) - 1) 5 + 1 =
( (3) - 1)
5 + 1 = 11

뭐 이런식이다.

Math.min(startPage + blockSize - 1, placePage.getTotalPages());
참고로 이건 전체 페이지 번호를 가져와서
만약 블록 크기 보다 작게 되면 (5개의 블록보다 작은 경우 3페이지가 끝이거나 6페이지가 끝이거나) 그 부분을 선택하기 위한 것이다.

그렇지 않으면 5, 10, 15가 끝 페이지가 될 것이다.


View


            <div class="pagebar-wrap" th:if="${placePage != null} ">
                <!-- 맨처음 버튼 -->
                <a th:href="@{/restaurant/list(selectedCity=${selectedCity}, selectedDistrict=${selectedDistrict}, page=1)}"><<</a>
                <!-- 이전 버튼 -->
                <a th:href="@{${placePage.first} ? '' : @{/restaurant/list(selectedCity=${selectedCity}, selectedDistrict=${selectedDistrict}, page=${placePage.number})}}">이전</a>

                <!-- 페이지 바 -->
                <span th:each="page: ${#numbers.sequence(startPage, endPage)}">
                    <span th:if="${page == placePage.number + 1} " th:text="${page}" th:style="${'margin: 0 2vw; color: red'}"></span>
                    <span th:unless="${page == placePage.number + 1}">
                        <a th:href="@{/restaurant/list(selectedCity=${selectedCity}, selectedDistrict=${selectedDistrict}, page=${page})}" th:text="${page}"></a>
                    </span>
                </span>

                <!-- 다음 버튼 -->
                <a th:href="@{${placePage.last} ? '' : @{/restaurant/list(selectedCity=${selectedCity}, selectedDistrict=${selectedDistrict}, page=${placePage.number+2})}}">다음</a>

                <!-- 맨마지막 페이지 버튼 -->
                <a th:href="@{/restaurant/list(selectedCity=${selectedCity}, selectedDistrict=${selectedDistrict}, page=${placePage.totalPages})}">>></a>
            </div>

타임리프 문법이 어려워서 정말 공부하면서 작성했다...

완성

profile
정확한 정보를 전달할려고 노력합니다.

0개의 댓글