package com.example.demo.controller;
import com.example.demo.dto.PageResponse;
import com.example.demo.dto.UserDTO;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class PaginatedUserController {
private final UserService userService;
public PaginatedUserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public ResponseEntity<PageResponse<UserDTO>> getUsers(
@PageableDefault(size = 20, sort = "createdAt", direction = Sort.Direction.DESC)
Pageable pageable
) {
Page<User> page = userService.findAll(pageable);
PageResponse<UserDTO> response = PageResponse.of(
page.map(this::toDto)
);
return ResponseEntity.ok(response);
}
@GetMapping("/search")
public ResponseEntity<PageResponse<UserDTO>> searchUsers(
@RequestParam String query,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "ASC") String sortDir
) {
Sort.Direction direction = Sort.Direction.fromString(sortDir);
Pageable pageable = PageRequest.of(page, size, Sort.by(direction, sortBy));
Page<User> results = userService.search(query, pageable);
PageResponse<UserDTO> response = PageResponse.of(
results.map(this::toDto)
);
return ResponseEntity.ok(response);
}
@GetMapping("/active")
public ResponseEntity<PageResponse<UserDTO>> getActiveUsers(Pageable pageable) {
Page<User> page = userService.findByActive(true, pageable);
return ResponseEntity.ok(PageResponse.of(page.map(this::toDto)));
}
private UserDTO toDto(User user) {
UserDTO dto = new UserDTO();
dto.setId(user.getId());
dto.setName(user.getName());
dto.setEmail(user.getEmail());
return dto;
}
}
package com.example.demo.dto;
import lombok.Data;
import org.springframework.data.domain.Page;
import java.util.List;
@Data
public class PageResponse<T> {
private List<T> content;
private int pageNumber;
private int pageSize;
private long totalElements;
private int totalPages;
private boolean first;
private boolean last;
private boolean empty;
public static <T> PageResponse<T> of(Page<T> page) {
PageResponse<T> response = new PageResponse<>();
response.setContent(page.getContent());
response.setPageNumber(page.getNumber());
response.setPageSize(page.getSize());
response.setTotalElements(page.getTotalElements());
response.setTotalPages(page.getTotalPages());
response.setFirst(page.isFirst());
response.setLast(page.isLast());
response.setEmpty(page.isEmpty());
return response;
}
}
Spring Data provides elegant pagination and sorting mechanisms. Pageable interface defines page number, size, and sort parameters. Page wraps results with metadata—total elements, total pages, current page. Sort defines ordering by multiple properties. I use @PageableDefault for sensible defaults. Query methods accept Pageable automatically. Custom queries support pagination with Pageable parameters. DTOs should include pagination metadata for API clients. Offset-based pagination works for most cases; cursor-based pagination handles large datasets better. Sorting prevents inconsistent results across pages. Pagination reduces memory usage and improves response times. REST controllers use @RequestParam or Spring's automatic resolution. Proper pagination enhances user experience and system performance.
Related snips
class PostsController < ApplicationController
def index
@posts = Post.includes(:author)
.order(created_at: :desc)
.page(params[:page])
.per(10)
Turbo Frames: infinite scroll with lazy-loading frame
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
GraphQL API with Spring Boot
package com.example.starter.config;
import com.example.starter.properties.CustomProperties;
import com.example.starter.service.CustomService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Custom Spring Boot starters
package com.example.demo.config;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
Messaging with Apache Kafka
module Paginatable
extend ActiveSupport::Concern
MAX_PER_PAGE = 100
DEFAULT_PER_PAGE = 25
API Pagination Headers (Link + Total)
package com.example.demo.controller;
import com.example.demo.dto.FileMetadata;
import com.example.demo.service.FileStorageService;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
File upload and download handling
Share this code
Here's the card — post it anywhere.