Pages and sorting
When there are thousands of posts, returning them in one response is out of the question: it is slow and pointless. The list is split into pages: a client asks, say, for the third page of 10 posts. Spring Data does this out of the box — just add a Pageable parameter to the method.
The controller
// src/main/java/com/example/blog/PostController.java
@GetMapping
public PagedModel<PostResponse> list(
@PageableDefault(size = 5, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
return new PagedModel<>(postService.findAll(pageable));
}Spring builds the Pageable from the page, size and sort address parameters itself. @PageableDefault sets the values when the parameters are missing: 5 posts, newest first. PagedModel (from org.springframework.data.web) turns the page into tidy JSON.
The service
// src/main/java/com/example/blog/PostService.java
public Page<PostResponse> findAll(Pageable pageable) {
return posts.findAll(pageable).map(PostResponse::from);
}JpaRepository already has findAll(Pageable). It returns a Page<Post> — the posts of one page plus information about all pages. The map method turns each entity into a response and keeps that information.
Requests
curl "http://localhost:8080/api/posts"
curl "http://localhost:8080/api/posts?page=1&size=3&sort=title,asc"The second request asks for the second page (numbering starts at zero) of 3 posts sorted by title. The response (post texts shortened):
{"content":[{"id":7,"title":"Oleg here",...},{"id":2,"title":"Spring Data JPA",...},{"id":4,"title":"Testing tips",...}],"page":{"size":3,"number":1,"totalElements":7,"totalPages":3}}content holds the posts of the page, page holds the page number, its size, the total number of posts and of pages. From these numbers a client draws a page switcher.
Hibernate ran two queries: for the posts and for their count:
Hibernate: select p1_0.id,p1_0.author_id,p1_0.body,p1_0.created_at,p1_0.title from posts p1_0 order by p1_0.title offset ? rows fetch first ? rows only
Hibernate: select count(p1_0.id) from posts p1_0Address parameters
| Parameter | Example | Meaning |
|---|---|---|
page | page=0 | Page number, from zero |
size | size=20 | Posts per page |
sort | sort=title,asc | Field and direction; can repeat: sort=author&sort=title |
So that a client cannot ask for a million rows at once, Spring caps size at 2000. The limit is changed with the spring.data.web.pageable.max-page-size setting.
Pages in your own queries
Pageable can be added as the last parameter of any repository method — both a name-based query and @Query:
// src/main/java/com/example/blog/PostRepository.java
Page<Post> findByAuthorUsername(String username, Pageable pageable);Common mistake
If a controller returns Page<PostResponse> directly, the response arrives, but the log shows a warning:
WARN ... Serializing PageImpl instances as-is is not supported, meaning that there is no guarantee about the stability of the resulting JSON structure!
For a stable JSON structure, please use Spring Data's PagedModel (globally via @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO))The internals of PageImpl may change in a new version, and clients would break. Wrap the page in PagedModel, as in this lesson.