[JPA] ํ์ด์ง์ ์ฌ์ฉ๋๋ Page์ Slice
by rlaehddnd0422Spring Data JPA์์ ์ฌ์ฉํ๋ Page์ Slice์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
Page์ ๋ํด์๋ ์ด ์ ์ JPA๋ฅผ ๊ณต๋ถํ๋ฉด์ ์งง๊ฒ๋๋ง ๋ค๋ค๋ณด์๋๋ฐ, ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํ ๋ Slice๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ํ์ด์ง์ ์ฌ์ฉ๋๋ Page์ Slice์ ๋ํด ์์ธํ ๊ธฐ๋กํด๋ณด๋ ค ํฉ๋๋ค.
Page, Slice๊ฐ ๋ฌด์์ด๊ณ ์ด๋์ ์ฌ์ฉ๋ ๊น?
Spring Data JPA๋ ํ์ด์ง์ ์ํด ๋ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์ ๊ณตํ๋๋ฐ ์ด๊ฒ์ด ๋ฐ๋ก Slice์ Page์ ๋๋ค.
์ฌ๊ธฐ์ ๋งํ๋ ํ์ด์ง์ด ๋ฌด์์ด๋ ?
์ฐ๋ฆฌ๊ฐ ํ์ด์ง์ด๋ ์ฌ์ฉ์๊ฐ ์ด๋ ํ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ์ ๋, ์ ์ฒด ๋ฐ์ดํฐ ์ค ์ผ๋ถ๋ฅผ ์ํ๋ ์ ๋ ฌ ๋ฐฉ์์ผ๋ก ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ ๋๋ค.
ํ์ด์ง์ ์ด๋ป๊ฒ ์ ์ฉํ ๊น?
ํ์ด์ง ๊ธฐ๋ฒ ๊ตฌํ์ ์ํด ๊ธฐ๋ณธ์ ์ผ๋ก ์์์ผ ํ๋ ํ๋ผ๋ฏธํฐ๋ค์ด ์์ต๋๋ค.
- page : ํ์ด์ง ๊ธฐ๋ฒ์ด ์ ์ฉ๋์์ ๋, ์ํ๋ ํ์ด์ง
- size : ํด๋น ํ์ด์ง์ ๋ด์ ๋ฐ์ดํฐ ๊ฐ์
- sort : ์ ๋ ฌ ๊ธฐ์ค
์ด ํ๋ผ๋ฏธํฐ๋ค์ ๋ฐ์์ ์ค๋ช ํ Pageable ๊ตฌํ์ฒด์ ๋ด์ ํ์ด์ง์ ์ค์ ํฉ๋๋ค.
Repository ์ฝ๋์์ ๋ฉ์๋๋ฅผ ๋ณด๋ฉด ํ๋ผ๋ฏธํฐ๋ก Pageable ๊ฐ์ฒด๋ฅผ ๋ฐ์ต๋๋ค.
public interface PostRepository extends JpaRepository<Post, Long>, QPostRepository{
Page<Post> findPageBy(Pageable pageable);
Pageable ๊ฐ์ฒด๋ Pagination์ ์ํ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๊ฐ์ฒด๋ก Pageable์ ์ธํฐํ์ด์ค์ด๋ฏ๋ก Pageable์ ๊ตฌํ์ฒด์ธ PageRequest ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด Pageable ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด์ธ PageRequest ์์ฑ์์ ํ๋ผ๋ฏธํฐ์ ์์์ ์์ ํ page, size, sort๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ข ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์์๋ด ์๋ค.
Controller ๊ณ์ธต์ ๋๋ค. Pageable๋ฅผ Argument๋ก ์ค์ ํด๋๋ฉด, ํด๋น ๋ฉ์๋์์ Pagination ์ ๋ณด๋ฅผ ์ถ์ถํ ์ ์๋๋ก ๋์์ค๋๋ค. ๋ฐ๋ผ์, "/postList" GetMapping ์์ฒญ ์ page, size, sort๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ํจ๊ป ์์ฒญํ์ฌ Paging ์ ๋ณด๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
@GetMapping("/postList")
public ResponseEntity<PostDto> postList(Pageable pageable){
Page<PostDto> postList = postService.getPage(pageable);
return new ResponseEntity<>(postList,HttpStatus.OK);
}
Service ๊ณ์ธต์ ๋๋ค. Controller๊ณ์ธต์์ ์์ฒญํ ํ์ด์ง ์ ๋ณด๋ฅผ Pageable ๊ตฌํ์ฒด์ ๋ด์ Repository ๊ณ์ธต์ ์ ๊ทผํ์ฌ ํ์ด์ง๋ ์ ๋ณด๋ฅผ ํ ๋๋ก ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด์ต๋๋ค.
public Page<Post> getPage(Pageable pageable) {
int page = pageable.getPageNumber();
int size = pageable.getPageSize();
PageRequest.of(page, size, Sort.by(Sort.Direction.DESC));
return postRepository.findPageBy(pageable);
}
๋ง์ฝ ํด๋ผ์ด์ธํธ๊ฐ Page, Size, Sort ์ ๋ณด๋ฅผ ํ๋ผ๋ฏธํฐ์ ์ฟผ๋ฆฌ์คํธ๋ง์ผ๋ก ๋๊ฒจ์ฃผ์ง ์๋๋ค๋ฉด, ์ ๋ ฌ๋์ง ์์ 20๊ฐ์ฉ ๋ถ๋ฆฌ๋ ํ์ด์ง ์ค ์ฒซ ํ์ด์ง๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด @PageDefault ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ ํ์ด์ง ์ ๋ณด๊ฐ ํจ๊ป ์์ฒญ๋์ง ์์ ๋์ ๋๋นํ์ฌ ๊ธฐ๋ณธ์ ์ธ ํ์ด์ง ์ ๋ณด๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
+ @PageableDefault
@GetMapping("/postList")
public ResponseEntity<PostDto> postList(@PageableDefault(
page = 0, size = 10, sort = "id", direction = Sort.Direction.DESC)
Pageable pageable){
Page<PostDto> postList = postService.getPage(pageable);
return new ResponseEntity<>(postList,HttpStatus.OK);
}
+ page ์ธ๋ฑ์ค๋ฅผ 1๋ถํฐ ์์ํ๋๋ก ์ค์
ํ๋ก ํธ์์๋ page index๋ฅผ 1๋ถํฐ ๊ณ์ฐํ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ Pageable์ page index๋ฅผ 0๋ถํฐ ๊ณ์ฐํฉ๋๋ค. ํ์์ ๋ฐ๋ผ ๋ฐ๊ฟ์ค ํ์๊ฐ ์์ต๋๋ค.
@Configuration
public class CustomPageableConfiguration {
@Bean
public PageableHandlerMethodArgumentResolverCustomizer customize() {
return p -> p.setOneIndexedParameters(true);
}
}
Sol1. CustomPageableConfiguration ํด๋์ค๋ฅผ ๋ง๋ค์ด pageableHandlerMethodArgumentResolverCustomizer๋ฅผ ์ปค์คํฐ๋ง์ด์ง ํด์ฃผ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ์ฌ๊ธฐ์ setOneIndexedParameters๋ฅผ true๋ก ์ค์ ํ๋ฉด page ์ธ๋ฑ์ค๊ฐ 1๋ถํฐ ์์ํ๋๋ก ์ค์ ํ ์ ์์ต๋๋ค.
spring.data.web.pageable.one-indexed-parameters=true
Sol2. ๋๋ application-yml ์ด๋ application-properties ์ค์ ์ ์ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ ํ์ด์ง ์ธ๋ฑ์ค๊ฐ 1๋ถํฐ ์์ํ๋๋ก ์ค์ ํ ์ ์์ต๋๋ค.
ํ์ด์ง ์ธ๋ฑ์ค๋ฅผ 1๋ถํฐ ์์ํ๋๋ก ์ค์ ํ๊ฒ ๋๋ฉด, ๋จ์ํ Controller์์ ๋ฐ๋ Pageable์ page๊ฐ์ด -1๋์ ์ ์ฅ๋ ๋ฟ์ ๋๋ค.
Pageable ๊ฐ์ฒด๋ ์ดํ ๋ฐํ๋ฐ์ Slice, Page๊ฐ์ฒด์์๋ page์ธ๋ฑ์ค๊ฐ ์ฌ์ ํ 0๋ถํฐ ์์ํ๊ธฐ ๋๋ฌธ์ ํ์ฌ ํ์ด์ง index๋ฅผ ๋ฐํํ๊ณ ์ถ๋ค๋ฉด ๋ฐ๋์ -1์ ํด์ฃผ์ด์ผ ํฉ๋๋ค. ์ ์ํด์ ์ฌ์ฉํ๋๋ก ํฉ์๋ค.
๊ธฐ๋ณธ์ ์ธ ํ์ด์ง ๊ฐ๋ ๊ณผ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ Repository๋ฅผ ๋ณด๋ฉด Page๋ฅผ ๊ฐ์ฒด๋ก ๋ฐ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด์ ์ ์ธ๊ธํ Slice๋ ์ธ์ ์ด๋ป๊ฒ ์ฌ์ฉ๋ ๊น์?
Slice
์ฌ์ค Page๋ Slice๊ณผ ์์๊ด๊ณ์ ๋๋ค.
public interface Page<T> extends Slice<T> {
๋ฐ๋ผ์ Slice๊ฐ ๊ฐ์ง ๋ชจ๋ ๋ฉ์๋๋ฅผ Page๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Page๊ฐ Slice์ ๋ค๋ฅธ ์ ์ ์กฐํ ์ฟผ๋ฆฌ ์ดํ ์ ์ฒด ๋ฐ์ดํฐ ๊ฐ์๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ๊ฐ ํ๋ฒ ๋ ์คํ๋๋ค๋ ์ ์ ๋๋ค.
Page interface Method
int getTotalPages();
/**
* Returns the total amount of elements.
*
* @return the total amount of elements
*/
long getTotalElements();
Slice interface Method
public interface Slice<T> extends Streamable<T> {
int getNumber();
int getSize();
int getNumberOfElements();
List<T> getContent();
boolean hasContent();
Sort getSort();
boolean isFirst();
boolean isLast();
boolean hasNext();
boolean hasPrevious();
default Pageable getPageable() {
return PageRequest.of(getNumber(), getSize(), getSort());
}
Pageable nextPageable();
Pageable previousPageable();
default Pageable nextOrLastPageable() {
return hasNext() ? nextPageable() : getPageable();
}
default Pageable previousOrFirstPageable() {
return hasPrevious() ? previousPageable() : getPageable();
}
}
Page vs Slice ์ด๋ค ๊ฑธ ์ฌ์ฉํด์ผ ํ ๊น?
Page๋ ๋ฐ๋ผ์ ์ ์ฒด ๋ฐ์ดํฐ ๊ฐ์๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ์ง ์๊ธฐ ๋๋ฌธ์ Slice์ ๋ค๋ฅด๊ฒ ์ ์ฒด ๋ฐ์ดํฐ ๊ฐ์๋ ์ ์ฒด ํ์ด์ง ์๊น์ง ํ์ธํ ์ ์์ต๋๋ค. ํ์ง๋ง ํ ๋ฒ ๋ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๊ฒ ๋๋ค๋ ์ ์์ ์ฌ์ฉ ๋ฐฉ์์ ๋ฐ๋ฅธ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
Slice์ ๊ฒฝ์ฐ ๋ฌดํ ์คํฌ๋กค ๊ตฌํ์์ ์ฌ์ฉํฉ๋๋ค.
๋ฌดํ ์คํฌ๋กค์ ์ฐ๋ฆฌ๊ฐ ์คํฌ๋กค ๋ฐ๊ฐ ์๋ ๋์ ๋ค๋ค๋ฅด๊ฒ ๋๋ฉด ์ถ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ ๊ธฐ๋ฅ์ ๋๋ค. ๋ฌดํ ์คํฌ๋กค์์๋ ์ ์ฒด ๋ฐ์ดํฐ ๊ฐ์๋ฅผ ์กฐํํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ ๊ตณ์ด Page๋ฅผ ์จ์ ์ฟผ๋ฆฌ๋ฅผ ๋ถํ์ํ๊ฒ ๋ ๋ฆด ํ์๊ฐ ์์ต๋๋ค.
Page๋ ์ ์ฒด ๋ฐ์ดํฐ ๊ฐ์๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ๋ฅผ ํ ๋ฒ ๋ ์คํํฉ๋๋ค. ๋ฐ๋ผ์ ์ ์ฒด ํ์ด์ง ๊ฐ์๋ ๋ฐ์ดํฐ ๊ฐ์๊ฐ ํ์ํ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend > Spring Data JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] Spring Data JPA ๊ตฌํ์ฒด(SimpleJpaRepository) ๋ถ์ (0) | 2023.05.22 |
---|---|
[JPA] Spring Data JPA - Web ํ์ฅ ๊ธฐ๋ฅ (0) | 2023.05.22 |
[JPA] Spring Data JPA - ํ์ฅ ๊ธฐ๋ฅ (0) | 2023.05.19 |
[JPA] Spring Data JPA - ์ฟผ๋ฆฌ ๋ฉ์๋ ๊ธฐ๋ฅ (0) | 2023.05.18 |
[JPA] JPQL ๋ฌธ๋ฒ 4 - ๋คํ์ฑ ์ฟผ๋ฆฌ, ์ํฐํฐ ์ง์ ์ฌ์ฉ, Named ์ฟผ๋ฆฌ (0) | 2023.05.10 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422