paging examples

This commit is contained in:
Tom Hombergs
2019-03-30 06:47:49 +01:00
parent b3532e2f1e
commit fb0aeb0a36
8 changed files with 153 additions and 26 deletions

View File

@@ -5,9 +5,11 @@ import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Data
@Table(name = "character")
class MovieCharacter {
@Id

View File

@@ -6,14 +6,29 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
interface MovieCharacterRepository extends CrudRepository<MovieCharacter, Long> {
interface MovieCharacterRepository
extends CrudRepository<MovieCharacter, Long> {
@Query("select c from MovieCharacter c")
Page<MovieCharacter> findAllPage(Pageable pageable);
@Query("select c from MovieCharacter c")
Slice<MovieCharacter> findAllSlice(Pageable pageable);
@Query("select c from MovieCharacter c")
List<MovieCharacter> findAllSorted(Sort sort);
Page<MovieCharacter> findByMovie(String movieName, Pageable pageable);
@Query("select c from MovieCharacter c where c.movie = :movie")
Slice<MovieCharacter> findByMovieCustom(
@Param("movie") String movieName, Pageable pageable);
@Query("select c from MovieCharacter c where c.movie = :movie")
List<MovieCharacter> findByMovieSorted(
@Param("movie") String movieName, Sort sort);
}

View File

@@ -3,10 +3,13 @@ package io.reflectoring.pagination;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -14,20 +17,31 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
class PaginatedController {
private final MovieCharacterRepository characterRepository;
private final MovieCharacterRepository characterRepository;
@GetMapping(path = "/characters/page")
Page<MovieCharacter> loadCharactersPage(Pageable pageable) {
return characterRepository.findAllPage(pageable);
}
@GetMapping(path = "/characters/page")
Page<MovieCharacter> loadCharactersPage(
@PageableDefault(page = 0, size = 20)
@SortDefault.SortDefaults({
@SortDefault(sort = "name", direction = Sort.Direction.DESC),
@SortDefault(sort = "id", direction = Sort.Direction.ASC)
}) Pageable pageable) {
return characterRepository.findAllPage(pageable);
}
@GetMapping(path = "/characters/sorted")
List<MovieCharacter> loadCharactersSorted(Sort sort) {
return characterRepository.findAllSorted(sort);
}
@GetMapping(path = "/characters/qualifier")
Page<MovieCharacter> loadCharactersPageWithQualifier(
@Qualifier("my") Pageable pageable) {
return characterRepository.findAllPage(pageable);
}
@GetMapping(path = "/characters/slice")
Slice<MovieCharacter> loadCharactersSlice(Pageable pageable) {
return characterRepository.findAllSlice(pageable);
}
@GetMapping(path = "/characters/sorted")
List<MovieCharacter> loadCharactersSorted(Sort sort) {
return characterRepository.findAllSorted(sort);
}
@GetMapping(path = "/characters/slice")
Slice<MovieCharacter> loadCharactersSlice(Pageable pageable) {
return characterRepository.findAllSlice(pageable);
}
}

View File

@@ -1,7 +1,9 @@
package io.reflectoring.pagination;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration;
@SpringBootApplication
public class PaginationApplication {

View File

@@ -1,9 +0,0 @@
package io.reflectoring.pagination;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
@Configuration
@EnableSpringDataWebSupport
class PaginationConfiguration {
}

View File

@@ -2,6 +2,5 @@ spring.data.web.pageable.size-parameter=size
spring.data.web.pageable.page-parameter=page
spring.data.web.pageable.default-page-size=10
spring.data.web.pageable.one-indexed-parameters=false
spring.data.web.pageable.max-page-size=10000
spring.data.web.pageable.prefix=
spring.data.web.pageable.prefix=2000
spring.data.web.pageable.qualifier-delimiter=_

View File

@@ -36,7 +36,7 @@ class PaginatedControllerTest {
mockMvc.perform(get("/characters/page")
.param("page", "5")
.param("size", "10")
.param("sort", "id, desc") // <-- no space after comma!!!
.param("sort", "id,desc") // <-- no space after comma!!!
.param("sort", "name,asc")) // <-- no space after comma!!!
.andExpect(status().isOk());
@@ -50,6 +50,56 @@ class PaginatedControllerTest {
assertThat(pageable).hasSort("id", Sort.Direction.DESC);
}
@Test
void evaluatesQualifier() throws Exception {
mockMvc.perform(get("/characters/qualifier")
.param("my_page", "5")
.param("my_size", "10")
.param("my_sort", "id,desc") // <-- no space after comma!!!
.param("my_sort", "name,asc")) // <-- no space after comma!!!
.andExpect(status().isOk());
ArgumentCaptor<Pageable> pageableCaptor = ArgumentCaptor.forClass(Pageable.class);
verify(characterRepository).findAllPage(pageableCaptor.capture());
PageRequest pageable = (PageRequest) pageableCaptor.getValue();
assertThat(pageable).hasPageNumber(5);
assertThat(pageable).hasPageSize(10);
assertThat(pageable).hasSort("name", Sort.Direction.ASC);
assertThat(pageable).hasSort("id", Sort.Direction.DESC);
}
@Test
void setsUpperPageLimit() throws Exception {
mockMvc.perform(get("/characters/page")
.param("size", "10000"))
.andExpect(status().isOk());
ArgumentCaptor<Pageable> pageableCaptor = ArgumentCaptor.forClass(Pageable.class);
verify(characterRepository).findAllPage(pageableCaptor.capture());
PageRequest pageable = (PageRequest) pageableCaptor.getValue();
assertThat(pageable).hasPageSize(2000);
}
@Test
void evaluatesPageableDefault() throws Exception {
mockMvc.perform(get("/characters/page"))
.andExpect(status().isOk());
ArgumentCaptor<Pageable> pageableCaptor = ArgumentCaptor.forClass(Pageable.class);
verify(characterRepository).findAllPage(pageableCaptor.capture());
PageRequest pageable = (PageRequest) pageableCaptor.getValue();
assertThat(pageable).hasPageNumber(0);
assertThat(pageable).hasPageSize(20);
assertThat(pageable).hasSort("name", Sort.Direction.DESC);
assertThat(pageable).hasSort("id", Sort.Direction.ASC);
}
@Test
void returnsSlice() throws Exception {

View File

@@ -0,0 +1,54 @@
package io.reflectoring.pagination;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import static io.reflectoring.pagination.PageableAssert.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(controllers = PaginatedController.class)
@TestPropertySource(properties = {
"spring.data.web.pageable.prefix=prefix_",
"spring.data.web.pageable.size-parameter=my-size",
"spring.data.web.pageable.page-parameter=my-page"
})
class PaginatedControllerWithCustomPagingPropertiesTest {
@MockBean
private MovieCharacterRepository characterRepository;
@Autowired
private MockMvc mockMvc;
@Test
void evaluatesPageableParameter() throws Exception {
mockMvc.perform(get("/characters/page")
.param("prefix_my-page", "5")
.param("prefix_my-size", "10")
.param("sort", "id,desc") // <-- no space after comma!!!
.param("sort", "name,asc")) // <-- no space after comma!!!
.andExpect(status().isOk());
ArgumentCaptor<Pageable> pageableCaptor = ArgumentCaptor.forClass(Pageable.class);
verify(characterRepository).findAllPage(pageableCaptor.capture());
PageRequest pageable = (PageRequest) pageableCaptor.getValue();
assertThat(pageable).hasPageNumber(5);
assertThat(pageable).hasPageSize(10);
assertThat(pageable).hasSort("name", Sort.Direction.ASC);
assertThat(pageable).hasSort("id", Sort.Direction.DESC);
}
}