Spring Boot ve Spring Data JPA ile Sayfalama
Bu yazıda Spring Data JPA ile rest servislerde sayfalama üzerinde duracağız. Sayfalama için URL’den hem sayfada listelenecek ürün adetini hem de sayfa numarasını parametre olarak alacağız.
- Spring Boot 2.3.6
- Java 8
- Lombok
- Maven
- H2
Aşağıdaki bağımlılıklarımızı pom.xml’e ekliyoruz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> |
Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Entity @Table(name = "Products") @Data @AllArgsConstructor @NoArgsConstructor public class Product { @Id private Long id; @Column private String name; @Column private String imageUrl; @Column private BigDecimal amount; } |
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
@RestController public class ProductController { @Autowired private ProductService productService; @GetMapping(value = "/products") public ResponseEntity<Page<Product>> fetchProducts( @RequestParam(required = false, name = "productName") String productName, @RequestParam(defaultValue = "0", name = "page") int page, @RequestParam(defaultValue = "5", name = "size") int size) { return new ResponseEntity<>(productService.getAllProducts(productName, page, size), HttpStatus.OK); } @GetMapping(value = "/products/{productName}") public ResponseEntity<Product> fetchProducts( @PathVariable(required = true, name = "productName") String productName) { return new ResponseEntity<>(productService.getProductByName(productName), HttpStatus.OK); } } |
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
@Service public class ProductService { @Autowired private ProductRespository productRespository; public Page<Product> getAllProducts(String productName, int page, int size) { Pageable pageable = createPageable(page, size); if (StringUtils.isEmpty(productName)) { return productRespository.findAll(pageable); } return productRespository.findByNameContaining(productName, pageable); } private Pageable createPageable(int page, int size) { Pageable pageable = PageRequest.of(page, size, Sort.by("id")); Pageable pageable1 = PageRequest.of(page, size); Pageable pageable2 = PageRequest.of(page, size, Direction.ASC, "id"); return pageable; } public Product getProductByName(String productName) { return productRespository.findByNameIgnoreCase(productName); } } |
Repository katmanına göndereceğimiz Pageable objesini burada hazırlıyoruz. Bu class Spring data’nın sunduğu bir interface. PageRequest ise Pageable’dan kalıtılmış bir class ve gördüğümüz üzere overload edilmiş üç metoda sahip. Controller katmanından aldığımız sayfa numarasını ve listelenecek ürün adetini ve isterseniz sıralamanın nasıl olmasını gerektiğini bu metodlara verebilirsiniz.
Respository
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Repository public interface ProductRespository extends PagingAndSortingRepository<Product, Long> { Page<Product> findAll(Pageable pageable); Page<Product> findByNameContaining(String productName, Pageable pageable); Product findByNameIgnoreCase(String productName); } |
Burada methodun dönüş tipi Page. Bu interface aşağıdaki yorum satırında da söylediği gibi içerdiği liste hakkında bilgi verir. Bazı faydalı bilgiler aynı zamanda Slice‘da da mevcut. Slice’dan extends edildiği zaten gözüküyor, ben uzatmamak için buraya kodu eklemeyeceğim fakat incelenmesinde fayda var.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/** * A page is a sublist of a list of objects. It allows gain information about the position of it in the containing * entire list. * * @param <T> * @author Oliver Gierke */ public interface Page<T> extends Slice<T> { static <T> Page<T> empty() { return empty(Pageable.unpaged()); } static <T> Page<T> empty(Pageable pageable) { return new PageImpl<>(Collections.emptyList(), pageable, 0); } int getTotalPages(); long getTotalElements(); <U> Page<U> map(Function<? super T, ? extends U> converter); } |
Son olarak ise listelemek için kayıt gerektiği için uygulama ayağa kalkerken tabloya aşağıdaki gibi kayıt atabiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
@SpringBootApplication public class RestservicePaginationApplication { @Autowired private ProductRespository respository; public static void main(String[] args) { SpringApplication.run(RestservicePaginationApplication.class, args); } @PostConstruct private void insertProducts() { List<Product> productList = new ArrayList<>(); for (int i = 1; i <= 30; i++) { String productName = "Product".concat(" " + i); productList .add(new Product(new Long(i), productName, "https://bilisim.io/".concat(productName), getAmount())); } respository.saveAll(productList); } private BigDecimal getAmount() { double amount = ThreadLocalRandom.current().nextDouble(55, 500); return BigDecimal.valueOf(amount); } } |
http://localhost:8080/products
ya da
http://localhost:8080/products?page=0&size=5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
// { "content": [ { "id": 1, "name": "Product 1", "imageUrl": "https://bilisim.io/Product_1", "amount": 178.75 }, { "id": 2, "name": "Product 2", "imageUrl": "https://bilisim.io/Product_2", "amount": 487.33 }, { "id": 3, "name": "Product 3", "imageUrl": "https://bilisim.io/Product_3", "amount": 224.34 }, { "id": 4, "name": "Product 4", "imageUrl": "https://bilisim.io/Product_4", "amount": 58.25 }, { "id": 5, "name": "Product 5", "imageUrl": "https://bilisim.io/Product_5", "amount": 74.59 } ], "pageable": { "sort": { "sorted": true, "unsorted": false, "empty": false }, "offset": 0, "pageNumber": 0, "pageSize": 5, "unpaged": false, "paged": true }, "totalPages": 6, "totalElements": 30, "last": false, "numberOfElements": 5, "first": true, "sort": { "sorted": true, "unsorted": false, "empty": false }, "size": 5, "number": 0, "empty": false } |
https://github.com/cemdrman/restservice-pagination/tree/master
Faydalı olması dileğiyle.