티스토리 뷰

Paging

페이징은 말그대로 Page화 하는 것이다. 조회 결과가 매우 많은 경우 일정한 크기를 갖는 페이지로 조회 목록을 쪼개는 것이다. 따라서 채팅, 검색 결과 등 조회 결과가 매우 많은 곳에서 유용하게 사용될 수 있다. 

 

이러한 기능을 Spring Data Jpa에서 Pageable이라는 이름으로 제공하고 있다.

 

페이지 조건을 줄 때는 주로 Size, Page, Sort 3가지 값을 필요로 한다.

  • Size는 Page의 개수를 의미한다. 즉 100개의 목록이 있을 때 size가 9라면 12개의 페이지가 생성되고 마지막 페이지에는 1개의 목록만이 있게 된다.
  • Page는 생성된 페이지를 접근할 때 사용하는 인덱스이다. 0번부터 시작한다.
  • Sort는 페이지를 자르기 전에 먼저 목록을 정렬하고 자를 수 있는데 이때 정렬할 기준값을 설정하게 된다.
    • Sort.By("기준 컬럼 프로퍼티명").desending() 또는 .asending()으로 오름차순 내림차순을 정해줄 수 있다.
    • 기준 값으로 하고자하는 값은 객체에 존재하는 컬럼의 프로퍼티명을 적어주면 된다.

Spring Data Jpa 

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
  • Pageable은 페이징 관련 기능을 갖고 있는 인터페이스이다.
  • Page는 페이징 처리의 반환값으로 말그대로 조회 결과의 한 페이지를 의미한다.

이것을 JpaRepository를 사용하고 있는 레포지토리 인터페이스에서 사용해주면 된다.

페이징 사용 예시

1. Paging 기법을 사용할 레포지토리에 pageable을 매개변수로 받는 추상메소드를 추가한다.

Repository

@Repository
public interface ChatMessageRepository extends JpaRepository<ChatMessage, Long> {
	Page<ChatMessage> findAllByChatRoomSeq(Long chatRoomSeq, Pageable pageable);
}

필자는 채팅룸에 들어있는 채팅 메시지를 페이징을 통해 가져오려고 한다. 따라서 ChatMessage 레포지토리에서 특정 chatRoom의 번호로 채팅목록을 조회하는데 여기에 pageable을 같이 넘기도록 했다.

2. 검색 조건을 PageRequest로 만들어서 보낸다.

PageRequest는 Pageable 인터페이스의 구현체중 하나이다.

 

이 클래스는 of() 등의 메소드를 통해 크기가 M인 N번 페이지를 K로 오름차순 정렬해서 가져와라 등 실질적인 페이징 처리의 조건 관련 기능을 갖고 있다.

 

PageRequest 클래스

 

나는 메시지의 생성시간을 기준으로 잡고 내림차순으로(최신순) page의 size를 20으로 잡아서 조회하도록 하겠다. 이때 0번 page가 가장 빠른 페이지 이며, 정렬 조건에 따라 가장 최근에 입력한 메시지가 나오게 된다.

 

Controller

@GetMapping("/all")
@ApiOperation(value = "채팅방 메세지 조회", notes = "페이징 방식으로 채팅방의 메시지를 최근 순서로 조회합니다.")
public ListResult<ChatMessageRes> getAllChats(
        @ApiParam(value = "채팅방 SEQ") @RequestParam Long chatRoomSeq,
        @ApiParam(value = "PAGE 번호 (0부터)") @RequestParamdefaultValue = "0" int page,
        @ApiParam(value = "PAGE 크기") @RequestParam(defaultValue = "20") int size
) {
    try {
        PageRequest pageRequest = PageRequest.of(page, size, Sort.by("regDate").descending());
        return responseService.getListResult(
                chatService.findAllChats(chatRoomSeq, pageRequest).getContent()
        );
    } catch (Exception e) {
        e.printStackTrace();
        throw new BussinessException(e.getMessage());
    }
}
  • 이때 Sort.by()에는 레포지토리에서 pageable을 받는 객체의 정렬할 필드명을 넣어주면 된다.
  • 기본적으로 가장 최신 메시지를 조회하기 위해 0번 페이지를 조회하도록 한다.
  • 이렇게 전달 받은 값으로 적절한 조건이 들어있는 PageRequest를 만들어서 전달한다.

3. PageRequest 검색 조건을 레포지토리의 추상메소드에 전달한다.

Service

@Transactional(readOnly = true)
public Page<ChatMessageRes> findAllChats(Long chatRoomSeq, Pageable pageRequest) {
    return chatMessageRepository.findAllByChatRoomSeq(chatRoomSeq, pageRequest)
            .map(ChatMessage::toDto);
}
  • PageRequest는 Pageable의 구현체이므로 Pageable로 받을 수 있다.
  • controller에서 전달한 조건을 그대로 repository에 전달해주고 이를 Dto로 변환해서 Page로 감싸서 반환하도록 한다.
  • Controller는 Page객체 내에 존재하는 ChatMessageRes를 꺼내서 반환한다.

결과

1번방의 채팅을 3개씩 가지는 페이지 중 0번 조회

{
    "success": true,
    "code": 1,
    "message": "성공",
    "data": [
        {
            "chatType": "CHAT",
            "imagePathUrl": null,
            "senderProfileImgUrl": "",
            "message": "대답 마지막",
            "senderId": "testtest2",
            "regDate": "2022-03-13 16:31:32",
            "chatRoomId": 1
        },
        {
            "chatType": "CHAT",
            "imagePathUrl": null,
            "senderProfileImgUrl": "",
            "message": "대화 마지막",
            "senderId": "testtest1",
            "regDate": "2022-03-13 16:31:27",
            "chatRoomId": 1
        },
        {
            "chatType": "CHAT",
            "imagePathUrl": null,
            "senderProfileImgUrl": "",
            "message": "대화3",
            "senderId": "testtest1",
            "regDate": "2022-03-13 16:31:09",
            "chatRoomId": 1
        }
    ]
}

시간을 보면 최신순으로 정렬되어 먼저 나오는 것을 볼 수 있다.

Spring Web MVC + 페이징

스프링 웹 MVC를 사용하는 경우 페이징을 더욱 쉽게 활용할 수 있는 방법이 있다.

 

API의 URL 파리미터로 Pageable을 넣어주면 자동으로 관련 매개변수를 바인딩 해서 처리해준다.

 

예시

@GetMapping("/all")
@ApiOperation(value = "채팅방 메세지 조회", notes = "페이징 방식으로 채팅방의 메시지를 최근 순서로 조회합니다.")
public ListResult<ChatMessageRes> getAllChats(
        @ApiParam(value = "채팅방 SEQ") @RequestParam Long chatRoomSeq,
        Pageable pageable
) {
    try {
        return responseService.getListResult(
                chatService.findAllChats(chatRoomSeq, pageable).getContent()
        );
    } catch (Exception e) {
        e.printStackTrace();
        throw new BussinessException(e.getMessage());
    }
}
  • Api의 @GetMapping에서 pageable을 파라미터에 넣어놓으면 자동으로 PageRequest를 생성해서 넣어준다.
  • 즉, API 호출 시 page, size, sort 등을 url 파라미터로 넣어주면 알아서 바인딩 되어 PageRequest를 생성하여 전달한다.
  • http://localhost:9090/v1/api/chat/all?chatRoomSeq=1&page=0&size=2&sort=regDate.desc 이런 식으로 넣어주면 위에서 처리한 방식과 똑같은 결과가 나오게 된다.

 

반응형
Comments
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday