☕
Spring + queryDSLでページングする方法(+ Pageable)
Spring + queryDSLでページングする方法(+ Pageable)
- Spring Boot3.1.3
- Java17
- queryDSL
- JPA
SpringでPaging処理をするよく使われる方法は二通りある。
- Pageableを使用する方法
-
queryDSLを使用する方法
- Pageable + queryDSLも使用できるが一般的に使う組み合わせではない。
- カスタムrequestオブジェクトとqueryDSLの組み合わせがよく使われる。
Pageable
ControllerでPageable
を因数として受け取る
PostController
@GetMapping("/posts")
public List<PostResponse> getList(Pageable pageable) {
return postService.getList(pageable);
}
Spring Data JPAのJpaRepository
を具現したPostRepository
を使用している。
-
JpaRepository
が提供するfindAll
メソッドにPageable
を渡すことが出来る
PostService
public List<PostResponse> getList(Pageable pageable) {
return postRepository
.findAll(pageable)
.stream()
.map(PostResponse::new)
.toList();
}
ページサイズの指定やソートはquery parameterで受け取る
ページの順番を指定
ページの順番は0
から始まる。
"/posts?page=0"
ページの順番を0
ではなく1
から始まりたい場合にはapplication.properties
に以下のオプションを使う。
applicaiton.properties
# http リクエストのみ効果がある
spring.data.web.pageable.one-indexed-parameters=true
サイズを指定する
1ページ当たりサイズを指定する
"/posts?page=0&size=5"
以下の設定でサイズの基本値を付与可能
applcation.properties
spring.data.web.pageable.default-page-size=5
ソート
id
を基準としてdesc整列。
-
,
に注意
"/posts?page=0&size=5&sort=id,desc"
queryDSLを使う方法
requestオブジェクトを生成
Pagination用のrequestオブジェクトを生成する
PostSearch.java
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PostSearch {
private static final int MAX_SIZE = 200;
@Builder.Default
private Integer page = 1;
@Builder.Default
private Integer size = 10;
public long getOffset() {
return (long) (Math.max(1, page) - 1) * Math.min(size, MAX_SIZE);
}
}
PostRepositoryCustom
インターフェースを生成
カスタムqueryDSLを使用してPaging処理をするためにカスタムPostRepositoryCustom
インターフェースを生成する。
PostRepositoryCustom
public interface PostRepositoryCustom {
List<Post> getList(PostSearch postSearch);
}
具現クラスを生成
具現クラスを生成する
static
インポートを使えばもっと綺麗に出来る。
PostRepositoryImpl
@RequiredArgsConstructor
public class PostRepositoryImpl implements PostRepositoryCustom {
private final JPAQueryFactory query;
@Override
public List<Post> getList(PostSearch postSearch) {
return query
.selectFrom(QPost.post)
.limit(postSearch.getSize()) // サイズ
.offset(postSearch.getOffset()) // offset
.orderBy(QPost.post.id.desc()) // ソート
.fetch();
}
}
PostRepository
に拡張させる
具現したクラスをPostRepository
に拡張させる
PostRepository
public interface PostRepository extends JpaRepository<Post, Long>, PostRepositoryCustom {
}
PostControllerとPostServiceで使用
postcontrollerで使用する
PostController
@GetMapping("/posts")
public List<PostResponse> getList(@ModelAttribute PostSearch request) {
return postService.getList(request);
}
postServiceで使用する
PostService
public List<PostResponse> getList(PostSearch postSearch) {
return postRepository.getList(postSearch)
.stream()
.map(PostResponse::new)
.toList();
}
これでクライアントからリクエスト時にquery parameterで値を指定して送ればいい
"/posts?page=1&size=20"
後追加的なpaging関連query parameterや基本値の変更等が必要な場合はPostSearch
に追加、修正すれば良い。
Discussion