스프링 Pageable 간단 사용법

이진우·2023년 7월 18일
0

스프링 학습

목록 보기
3/35

페이징이 왜 필요한가?

엄청 많은 데이터가 있고 사용자에게 그 데이터를 보여 준다고 해보자. 정말 모든 데이터를 사용자에게 제공해야 하는가? 그렇게 제공하는 것보다 데이터의 일부를 먼저 제공하는 것이 성능 측면에서 확실히 좋을 것이다.

Pageable은 왜 쓸까

확실히 Pageable을 쓸때 NativeQuery나 jpql을 사용하는 것보다 확실히 편리하다.

JPQL 사용시

일단 JPQL을 사용하면 limit 를 사용해서 범위를 제한하는 것이 힘들다.

NativeQuery 사용시

NativeQuery 사용시에는 limit를 사용할 수는 있지만 ,동적으로 2페이지에서 3페이지를 가져오기 혹은 4페이지에서 6페이지가져오기를 유연하게 수행하기가 힘들어 보인다.

Pageable 예제

도메인

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Member {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private int age;

    private String name;

    public Member(String name,int age){
        this.name=name;
        this.age=age;
    }

}

지극히 평범한 Member의 예를 들겠습니다. age를 가지고 이것저것 해보겠습니다.

Repository

import com.Pageable.paging.domain.Member;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface MemberRepository extends JpaRepository<Member,Long> {

    List<Member> findMemberByName(String name, Pageable pageable);

    @Query(value ="select * from member where name =:value order by age limit 3" ,nativeQuery = true)
    List<Member> findMemberNativeQuery(@Param("value")String name);



}

NativeQuery와 Pageable 모두 사용해 보겠습니다

Service

import com.Pageable.paging.PagingApplication;
import com.Pageable.paging.Repository.MemberRepository;
import com.Pageable.paging.domain.Member;
import com.Pageable.paging.dto.ShowDto;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
    private final MemberRepository memberRepository;
    @Transactional
    public void save(Member member){
        memberRepository.save(member);
    }

    public List<ShowDto> membersByPageable(){
        Pageable pageable= PageRequest.of(0,3, Sort.by("age"));
        return memberRepository.findMemberByName("jinu",pageable).stream().map(m->new ShowDto(m.getName(),m.getId(),m.getAge())).collect(Collectors.toList());
    }
    public List<ShowDto> membersByNativeQuery(){
        return memberRepository.findMemberNativeQuery("jinu").stream().map(m->new ShowDto(m.getName(),m.getId(),m.getAge())).collect(Collectors.toList());
    }
}

위에서 보듯이 Pageable 객체를 PageRequest.of로 생성해서 가져올 수 있습니다.
첫 번째 파라미터에는 페이지, 두번째 파라미터에는 가져올 갯수, 3번째는 정렬기준입니다.

Dto-MemberSignUpDto

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;

import javax.validation.constraints.NotNull;

@Data
@AllArgsConstructor
@RequiredArgsConstructor
public class MemberSignUpDto {
    @NotNull
    private String name;
    @NotNull
    private int age;

}

Dto-ShowDto

import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ShowDto {
    private String name;
    private Long id;
    private int age;
}

Controller

import com.Pageable.paging.domain.Member;
import com.Pageable.paging.dto.MemberSignUpDto;
import com.Pageable.paging.dto.ShowDto;
import com.Pageable.paging.service.MemberService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping("/api/member/save")
    public void save(@RequestBody  MemberSignUpDto memberSignUpDto){
        Member member=new Member(memberSignUpDto.getName(),memberSignUpDto.getAge());
        memberService.save(member);
    }

    @GetMapping("/api/member/showAllByPageable")
    public List<ShowDto> showAllByPageable(){
        return memberService.membersByPageable();
    }
    @GetMapping("/api/member/showAllByNativeQuery")
    public List<ShowDto> showAllByNativeQuery(){
        return memberService.membersByNativeQuery();
    }
}

이렇게 코드를 작성해 보았습니다. 먼저 postman을 통해서 데이터를 넣었습니다. 이 과정은 생략했습니다. 결국 제 db에는

이렇게 넣어 보았습니다.
이제 postman을 통해 실행하면

NativeQuery를 통해 실행할 경우

Pageable을 통해 실행할 경우


이렇게 결과는 같습니다.

여러가지 페이지,가져올 갯수를 편리하게 사용하고 싶습니다.

이 경우 코드를 조금만 수정하면 됩니다.

Controller

import com.Pageable.paging.domain.Member;
import com.Pageable.paging.dto.MemberSignUpDto;
import com.Pageable.paging.dto.ShowDto;
import com.Pageable.paging.service.MemberService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @PostMapping("/api/member/save")
    public void save(@RequestBody  MemberSignUpDto memberSignUpDto){
        Member member=new Member(memberSignUpDto.getName(),memberSignUpDto.getAge());
        memberService.save(member);
    }

    @GetMapping("/api/member/showAllByPageable")
    public List<ShowDto> showAllByPageable(Pageable pageable){
        return memberService.membersByPageable(pageable);
    }
    @GetMapping("/api/member/showAllByNativeQuery")
    public List<ShowDto> showAllByNativeQuery(){
        return memberService.membersByNativeQuery();
    }
}

이렇게 Controller에서 Pageable을 매개변수로 받으면 쿼리 파라미터로 sort와 size 그리고 정렬방식까지 넘길수 있습니다.

Service


import com.Pageable.paging.PagingApplication;
import com.Pageable.paging.Repository.MemberRepository;
import com.Pageable.paging.domain.Member;
import com.Pageable.paging.dto.ShowDto;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
    private final MemberRepository memberRepository;
    @Transactional
    public void save(Member member){
        memberRepository.save(member);
    }

    public List<ShowDto> membersByPageable(Pageable pageable){
        return memberRepository.findMemberByName("jinu",pageable).stream().map(m->new ShowDto(m.getName(),m.getId(),m.getAge())).collect(Collectors.toList());
    }
    public List<ShowDto> membersByNativeQuery(){
        return memberRepository.findMemberNativeQuery("jinu").stream().map(m->new ShowDto(m.getName(),m.getId(),m.getAge())).collect(Collectors.toList());
    }
}

코드 수정은 끝났습니다. 포스트맨을 통해서 결과를 확인해 봅시다.

이렇게 0페이지에서 3개의 데이터를 나이순으로 정렬해서 가지고 오고


이렇게 1페이지에서 3개의 데이터를 나이순으로 정렬해서 가지고 올 수 있습니다.


또한 정렬을 오름차순으로 할 건지 내림차순으로 정렬할 것인지 정할 수도 있습니다.

profile
기록을 통해 실력을 쌓아가자

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

정말 좋은 글 감사합니다!

답글 달기