페이징

jjang9·2024년 2월 28일
post-thumbnail

오늘 JPA 방식으로 하는 페이징을 배웠는데,
이해하기 어려운 뭔가 복잡하고 고급진 방법의 페이징을 했다.
흐름이 헷갈리고, 처음보는 메서드들과 내장 인터페이스들이 날 아주 혼란스럽게 했다.

흐름부터 천천히 이해해보려고 한다.

쓰일 페이지들

  • PageRequestDTO
  • PageResultDTO
  • HomeController (controller)
  • GuestServiceImpl (service interface)
  • GuestService (service)

1. 먼저 PageRequestDTO 부터 가보자

이 DTO는 PageList 요청 처리를 하는 목적이다.
JPA 에서 사용하는 Pageable Type 객체 생성을 목표로 한다.

💭 Pageable 은 무엇인가?

✔ 스프링 데이터 JPA에서 제공하는 강력한 페이징 & 정렬 기능을 정의한 인터페이스 이다.
✔ PageRequest 는 이 인터페이스의 구현 클래스 이다.
--- Sort type 을 인자로 전달 할 수 있음.
--- Sort 객체는 한개 이상의 컬럼값을 이용해서 정렬을 지정할수 있음.


그럼 클래스 작성을 시작한다.
이 클래스에서 필요로 하는 변수들은 선언해주고,
메서드 PageRequestDTO에서는 생성자를 만들어 주었다.

💭 아 여기서 @Data 는 롬복의 애노테이션인데,
재사용을 가능하게 하는 Getter, Setter 등 의 태그들의 집합체 이다.


getPageable 을 생성해 준다.
위에서 설명한 PageRequest 객체에 of를 써서 page, size, sort 의 조건을 리턴해주는 것이다.
** of는 페이징을 해올 테이터의 조건을 적어주는 메서드이다.
JPA에서 pageNo는 0부터 시작하기 때문에 page -1 을 해주었다. 단, application.properties에서 변경가능함.
sort는 필요시 사용을 위해 넣어줌.

~~ 여기까지 페이징 시 몇 개를 볼지, 몇 페이지를 볼지 DTO를 작성해줌.


2. HomeController로 가보겠다.


페이징을 위해 만든 gpage 메서드 이다.

💘 빨강 네모칸은 아까 만든 PageRequestDTO 객체를 만들어서 출력할 pageNo, Page당 출력할 row갯수를 입력해서 requestDTO 에 담아줬다.
💛 노란 네모는 위에서 만든 requestDTO를 service.pageList 를 실행해서 resultDTO 에 담아주었다.
🎀 분홍 네모는 반복문을 이용하여 리스트를 보여주는 부분이다.
💚 초록 네모는 경로를 지정해서 return 해주었다.

3. service에 가서 💛 의 실행을 보자.

service 와 serviceImpl 이 있는데

service부터 보자면

PageRequestDTO를 넣어 PageResultDTO 타입을 반환하는 pageList를 만들어 주었다.

오버라이딩을 했을 serviceImpl을 보면

🎈 첫번째로,

Pageable pageable = requestDTO.getPageable(Sort.by("gno"));

pageable 이라는 객체에 페이지 요청 정보를 담는다.
💭 getPageable 이 그런 기능이란다.

🎈 두번째로,

Page<Guestbook> result = repository.findAll(pageable);

repository 를 실행한다.
result 에 전체 레코드를 불러온다.
💭 .findAll 은 전체 레코드를 불러오는 기능.
위에서 pageable 을 만들어줬으니 그 조건에 맞는 레코드를 result에 담는 과정이라 할 수 있다.

🎈 세번째로.

Function<Guestbook, GuestbookDTO> fn = 
						( entity -> entityToDto(entity) );

Service에 정의한 entityToDto 메서드를 이용해서 entity를 Dto로 변환해준다.
람다식을 인자로 직접 사용해도 됨.
💭 람다식 은 다른 게시물에 자세히 업로드 하도록 하겠다.
💭 Optional< T> 도 정리가 필요하다.

4. PageResultDTO

위 HomeController의 분홍 네모를 다시 가져와서 보자면

resultDTO.getDtoList 에 무엇이 실행되었는지 확인해야한다.

📋 PageList 결과 처리 DTO

  • JPA 를 사용하는 Respository에서는 Page 처리결과를 Page< Entity> 타입으로 (제네릭 형태) return 하기 때문에 서비스 계층에서 이를 처리할 수 있도록 하는 DTO클래스가 필요하다.
  • Page< Entity> 객체들을 DTO 객체로 변환해서 List 에 담아준다. ✨✨
  • 화면 출력을 위한 페이지 정보를 구성한다.

📋 Function <T, R>

  • T 타입을 입력받아 R 타입으로 리턴한다.
  • FunctionalInterface

📋 Collection의 계층도

  • Collection (i) -> List (i) -> ArrayList (c)

📋 interface Collector

  • 스트림의 collect() 메서드에서 사용될 메서드를 정의해놓은 인터페이스

📋 IntStream

  • Java 8에서 추가된 Stream Interface의 한 종류
  • int 형식의 요소들을 처리하기 위한 메소드들을 제공
  • int 배열의 요소를 합산하거나, 필터링하거나, 매핑하는 기능을 지원
  • 기본자료형 int 형식의 연산에 최적화 되어있어 성능적으로 이점을 가진다.

메서드 PageResultDTO.
Page< EN> 타입을 이용해 최종 List< DTO> 를 생성한다.
✨Function<EN, DTO> : Entity 객체들을 DTO로 변환함을 의미한다.
💭 EN이라는 것은 Entity타입이라고 정해져 있는 것인가 아님 어디선가 선언해준 것인가?

dtoList = 
	result.stream().map(fn).collect(Collectors.toList());
  • Stream()
    • 배열, 컬렉션 등을 대상으로 하여 스트림을 생성해줌.
    • 스트림은 forEach(), filter(), sum(), map() 등 다양한 연산을 할수있는 메서드 제공한다.
    • 메모리 상에서 일어나는 흐름.
  • map(fn)
    • 스트림 요소 중에서 원하는 필드만 뽑아내거나, 특정 형태로 변환해야 할 때 사용
    • Entity 객체들을 DTO로 변환
  • collect()
    • 스트림의 요소들을 수집하는 최종연산
    • Collectors 클래스의 toList(): 스트림의 모든 요소를 List 로 수집


그리고 makePageList 메서드 이다.
변수들을 다 지정해주고
pageList를 작성한다.

pageList = 
	IntStream.rangeClosed(start, end).boxed().collect(Collectors.toList());
  • IntStream
    • 기본자료형 int 형식의 연산에 최적화되어 있는 스트림 인터페이스
  • rangeClosed()
    • start ~ end 까지 즉, 종료값을 포함해서 return한다.
  • boxed()
    • 숫자 (int) 스트림을 일반스트림(객체형)으로 변환한다.


여기까지 JPA 방식의 페이징 흐름 정리 및 메서드 정리.

🤓 느낀점
설명이 복잡하다고 느껴지지만 이건 분명 '페이징을 편리하게 하는 방법'이다.
처음보는 문법들이 많아 흐름을 따라가는데 놓쳐서 힘든 수업이긴 했지만
지금은 일단 문법을 알아두고 흐름만 헷갈리지 않게 잘 정리해두면, 나중에 다시 페이징을 사용하려 할 때,
그때는 편.리.하.게 사용할 수 있지 않을까 생각한다.

profile
안녕하세요! jjang9 입니다( ̄︶ ̄)

0개의 댓글