Pagination and sorting with Spring Data

David Kumar Jan 2026
2 tabs
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;
    }
}
2 files · java Explain with highlit

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.