
Pagination은 대량의 데이터를 한 번에 불러오지 않고, 일정한 크기로 나눠 순차적으로 조회하는 기법Pageable은 페이징과 정렬 정보를 캡슐화하는 인터페이스page : 페이지 번호size : 페이지 크기, 한 페이지에 포함된 데이터 개수sort : 정렬 조건PageRequest의 of() 메서드를 사용해 pageable을 생성 Pageable pageable = PageRequest.of(0, 10);
<T>Page<T>는 페이징된 데이터와 페이징 정보를 포함하는 객체Pageable을 바탕으로 페이징된 데이터와 정보를 반환 Pageable pageable = PageRequest.of(0, 10);
Page<Item> page = itemRepository.findAll(pageable);
<T>Page<T>인터페이스는 Slice<T>인터페이스를 상속한다.Slice<T>는 데이터 일부를 나타내는 개념으로, 일반적인 페이징 기능과 유사하지만Slice<T> 는 전체 데이터 개수를 조회하는 추가 쿼리(COUNT(*))를 실행하지 않기 때문에 성능이 더 좋다.PagedModel<T>은 Page<T> 객체를 JSON으로 안정적으로 직렬화하기 위한 DTO다.new PagedModel<>(page)를 호출하여 사용한다.📍 PagedModel로 Response를 내려준 경우
{
"content": [
{
"id": 5,
"title": "제목5",
"content": "내용5",
"createdAt": "2025-02-08T21:40:53.042102"
},
{
"id": 4,
"title": "제목4",
"content": "내용4",
"createdAt": "2025-02-08T21:40:49.318999"
},
{
"id": 3,
"title": "제목3",
"content": "내용3",
"createdAt": "2025-02-08T21:40:45.312505"
},
{
"id": 2,
"title": "제목2",
"content": "내용2",
"createdAt": "2025-02-08T21:40:41.082873"
},
{
"id": 1,
"title": "제목1",
"content": "내용1",
"createdAt": "2025-02-08T21:40:31.956687"
}
],
"page": {
"size": 15,
"number": 0,
"totalElements": 5,
"totalPages": 1
}
}
📍 Page로 Response를 내려준 경우
{
"content": [
{
"id": 5,
"title": "제목5",
"content": "내용5",
"createdAt": "2025-02-08T21:40:53.042102"
},
{
"id": 4,
"title": "제목4",
"content": "내용4",
"createdAt": "2025-02-08T21:40:49.318999"
},
{
"id": 3,
"title": "제목3",
"content": "내용3",
"createdAt": "2025-02-08T21:40:45.312505"
},
{
"id": 2,
"title": "제목2",
"content": "내용2",
"createdAt": "2025-02-08T21:40:41.082873"
},
{
"id": 1,
"title": "제목1",
"content": "내용1",
"createdAt": "2025-02-08T21:40:31.956687"
}
],
"pageable": {
"pageNumber": 0,
"pageSize": 15,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"offset": 0,
"paged": true,
"unpaged": false
},
"last": true,
"totalPages": 1,
"totalElements": 5,
"size": 15,
"number": 0,
"sort": {
"empty": false,
"sorted": true,
"unsorted": false
},
"first": true,
"numberOfElements": 5,
"empty": false
}
PagedMoel이 훨씬 깔끔하다. 불필요한 정보들을 걷어낸 느낌? 애용하자📂 controller.java
@GetMapping("/posts")
public PagedModel<PostResponse> getAllPosts(@RequestParam(name = "page", defaultValue = "1") int page,
@RequestParam(name = "size", defaultValue = "15") int size) {
if(size > 100){ size = 100; }
Pageable pageable = PageRequest.of(page-1, size, Sort.by("createdAt").descending());
return postService.getAllPosts(pageable);
}
📂 service.java
@Transactional(readOnly = true)
public PagedModel<PostResponse> getAllPosts(Pageable pageable){
Page<PostResponse> postResponses = postRepository.findAll(pageable)
.map(PostResponse::new);
return new PagedModel<>(postResponses);
}
📂 repository.java
Page<Post> findAll(Pageable pageable);
왜인진 잘 모르겠으나 그냥 느낌적인 느낌 ..
그래도 곰곰히 이 불편한 느낌에 대한 이유를 꼽아보자면
@RequestParam으로 page와 size를 받아야 할까?page와 size를 따로 받지 않고 그냥 Pageable로 받아도 되지 않나?"데이터 조회 개수는 최대 100까지" 라는 요구사항으로 인해if(size > 100){ size = 100;
다른 사람 코드 좀 보고싶다
더 나은게 있으면 차용 좀 하게