TACO 프로젝트 회고록(2023-06-08)

윤현우·2023년 6월 8일
0

TACO 프로젝트 회고록

목록 보기
25/31
post-thumbnail

오늘은 메인페이지에서 제공하는 여러 게시글들에 대한 페이지네이션 기능들을 구현해보았다.

우선 페이지네이션이란, 필요한 데이터들을 페이지 별로 나타내는 것으로,

한 페이지에 수백만개에 해당하는 게시글 데이터들을 조회해 화면에 렌더링하는 경우, 클라이언트가 브라우저 혹은 모바일 기기로 이를 한 눈에 보기 어려움을 겪을 공산이 크다.

또한 클라이언트가 보지도 않을 데이터까지 DB에서 조회하여 네트워크를 통해 전달하기 때문에, 서버의 리소스가 불필요하게 낭비된다.

그래서 한 페이지에서는 N개의 데이터만 보여주고, 다음 페이지로 이동하라는 클라이언트의 추가 요청이 있을 때 마다 다음 순번의 N개의 데이터를 보여준다면 UX 및 리소스 측면의 단점을 보완할 수 있다.

그렇기에 페이지네이션 처리를 하는 것이다.

사실 무한 스크롤방식을 이용해 데이터 렌더링을 하려 했으나, 백엔드 파트에서 조금 더 공부하고자 페이지네이션 처리를 했다.

사실 이 전에 게시판을 만들어 보았을 때 페이지네이션 기능을 구현해 보았으나, 구현하기 많은 코드와 그 당시 코딩을 공부하기 초반이라 이해하지 못했다.

하지만 구글링을 하다가 Spring Data JPA를 이용해 페이지네이션 기능을 구현할 수 있는 것을 보았고, 이 방법이 나에게 맞을 것 같아 공부해 보았다.


PageController

// 메인페이지 게시글 리스트
    @GetMapping("/")
    public ResponseEntity<Page<PostEntity>> postList(Model model, @PageableDefault(page = 0,size = 20,sort = "postIndex",direction = Sort.Direction.DESC) Pageable pageable){
        // 로그인 세션 환경 설정

        Page<PostEntity> readAll = postService.readAll(pageable);

        // 게시글 최신순으로 정렬
        // 페이징 처리
        int nowPage = readAll.getPageable().getPageNumber()+1; //pageable이 갖고 있는 페이지는 0부터 시작하기 때문에
        int startPage = Math.max(nowPage -4,1);
        int endPage = Math.min(nowPage +5,readAll.getTotalPages());


        model.addAttribute("posts", readAll);
        model.addAttribute("nowPage", nowPage);
        model.addAttribute("startPage",startPage);
        model.addAttribute("endPage",endPage);

        

        return new ResponseEntity<>(readAll, HttpStatus.OK);
    }

Spring Data JPA 기능 중 JpaRepository가 있다.

현재 나는 이 레파지토리 인터페이스를 이용해 CRUD 및 기타 기능을 이용하고 있다.

JpaRepository의 부모 인터페이스로 PagingAndSortingRepository 에서 페이징과 소팅이라는 기능을 제공한다.

나는 이 PagingAndSortingRepository를 이용해 페이지네이션 처리를 할 것이다.

PagingAndSortingRepository를 이용하려면 Pageable이라는 인터페이스를 파라미터로 받아야 한다.

@PageableDefault

  • Pageable의 기본정보를 입력할 수 있다.
  • page : default 페이지
  • size : 한 페이지 게시글 수
  • sort : 정렬 기준 컬럼(여기에서는 글 번호 id)
  • direction : 정렬 순서 (보통 게시판은 최근 글이 위로 올라와 있기 때문에 역순으로 설정함.)

받아온 파라미터를 service 부분에 넘긴다.


PostService

    // 게시글 리스트 가져오기
    // 페이징 처리
    public Page<PostEntity> readAll(Pageable pageable){
        Page<PostEntity> list = postRepository.findAll(pageable);

        return list;
    }

JpaRepository 부모 인터 페이스인 PagingAndSortingRepository를 보면 findAll메서드에 Pageable인자가 들어가 있는 것을 확인 할 수 있다.

findAll메서드로 DB에서 게시글들을 Page형태로 받아와 반환한다.


PageController

		int nowPage = readAll.getPageable().getPageNumber()+1; //pageable이 갖고 있는 페이지는 0부터 시작하기 때문에
        int startPage = Math.max(nowPage -4,1);
        int endPage = Math.min(nowPage +5,readAll.getTotalPages());


        model.addAttribute("posts", readAll);
        model.addAttribute("nowPage", nowPage);
        model.addAttribute("startPage",startPage);
        model.addAttribute("endPage",endPage);

여기서 현재 나의 페이지, 첫 페이지, 그리고 마지막 페이지를 지정해 view단으로 데이터를 넘기면 자연스럽게 페이지네이션 처리가 된다.


이렇게 메인 페이지의 게시글들을 페이징 하였지만, 또 다른 문제가 있었다.

내가 기획한 이 프로젝트는 지역별로 게시글들을 나눌 수 있게 만들어 놓았다.

따라서 메인페이지 뿐만아니라 지역별로 필터링한 게시글들도 페이징 처리를 해야했다.

사실 어떤 방식으로 시작해야 할지 잘 몰랐다.

Pageable 인자를 받으면서 해당 데이터를 필터링해 페이징 처리를 해야 하는 것이기 때문에,

service 부분에서 필터링할 데이터와 Pageable 값을 같이 보내야 했다.

그러다 이전 게시글에서 확인할 수 있는 검색기능의 Containing이 생각이 났다.

분명 PagingAndSortingRepository에서는 findAll(Pageable pageable)메서드만 가능 했지만, 내가 만들어서 사용할 수 있지 않을까? 라는 생각을 했다.

그래서 바로 실행에 옮겼다.


PageController

    // 시/도 select box만 설정했을 경우
    @GetMapping("/{postSido}")
    public ResponseEntity<Page<PostEntity>> searchSido(@PathVariable("postSido") String postSido,
                                                            @PageableDefault(page = 0,size = 20,sort = "postIndex",direction = Sort.Direction.DESC) Pageable pageable,
                                                            Model model){
        Page<PostEntity> sidoList = postService.findSido(postSido, pageable);
        
        // 페이징 처리
        int nowPage = sidoList.getPageable().getPageNumber()+1; //pageable이 갖고 있는 페이지는 0부터 시작하기 때문에
        int startPage = Math.max(nowPage -4,1);
        int endPage = Math.min(nowPage +5,sidoList.getTotalPages());

        model.addAttribute("sidoList", sidoList);
        model.addAttribute("nowPage", nowPage);
        model.addAttribute("startPage",startPage);
        model.addAttribute("endPage",endPage);

               
        return new ResponseEntity<>(sidoList, HttpStatus.OK);
    }

메인 페이지 메서드와 다른 것은 service api로 넘어갈 때 postSido를 추가로 파라미터에 넣어 보낸다는 것이다.


PostService

    // 시도 select box 찾기
    public Page<PostEntity> findSido(String postSido, Pageable pageable) {
        Page<PostEntity> sidoList = postRepository.findByPostSidoContaining(postSido, pageable);

        return sidoList;
    }

findByPostSidoContaining메서드에 Pageable 인자를 추가로 넣어 Page 타입으로 데이터를 가져오게 하였다.

Page<PostEntity> findByPostSidoContaining(String postSido, Pageable pagealbe);

이 때, 가져오는 데이터는 postSido에 postSido라는 데이터를 포함하는 데이터만 가져오도록 하였다.

그 후, 가져온 데이터를 반환하는 것이었다.



해당 테스트는 시/도 설정을 용인시로 설정한 페이지의 마지막 페이지이다.
(기존 size는 20이지만 테스트를 위해 5로 변경)

보다시피 페이지에 따른 데이터들이 나왔다.

이렇게 필터링에 따른 데이터 페이징도 완성했다.


드디어 모든 기능들을 구현하였다.

이제 진짜 얼마 남지 않았다.

필터링에 따른 페이징 처리에 대해 애를 많이 썼는데, 혼자서 생각하여 문제를 해결한 것에 대해 정말 행복하고, 실력이 늘고 있구나에 대한 생각이 들었다.

남은 프로젝트도 열심히 하여 끝마치고 싶다.

profile
개발자가 되는 그날까지

0개의 댓글