Пагинация и фильтрация данных в REST API с использованием Spring
При работе с большими наборами данных в REST API критически важна поддержка пагинации и фильтрации. Они позволяют улучшить производительность приложения, сократить нагрузку на сервер и предоставить клиентам удобные способы получать нужные данные.
1. Пагинация (Pagination) в Spring
Пагинация позволяет разделить большие объемы данных на страницы и возвращать их по частям. В Spring Boot пагинация реализуется с помощью Spring Data JPA.
Подключение пагинации в проекте
Spring Data JPA предоставляет интерфейсы и аннотации для легкой реализации пагинации.
Добавьте параметр Pageable в методы репозитория:
Page — это контейнер, который содержит данные текущей страницы и мета-информацию (например, общее количество страниц).
Pageable — это интерфейс для параметров пагинации: номер страницы, размер страницы и сортировка.
Использование Pageable в контроллере:
Пример запроса с пагинацией:
Пример ответа:
2. Фильтрация данных в REST API
Фильтрация позволяет клиентам задавать условия, по которым нужно отбирать данные.
Подходы к фильтрации
Фильтрация по параметрам запроса (Request Parameters): Используется для простой фильтрации данных.
Динамическая фильтрация с помощью Specification или Criteria:
Применяется для сложных и многоуровневых условий.
Фильтрация по параметрам запроса
Реализация простого поиска с фильтрацией:
Добавьте методы в репозиторий:
#Java #Training #Spring #Pagination #Filter
При работе с большими наборами данных в REST API критически важна поддержка пагинации и фильтрации. Они позволяют улучшить производительность приложения, сократить нагрузку на сервер и предоставить клиентам удобные способы получать нужные данные.
1. Пагинация (Pagination) в Spring
Пагинация позволяет разделить большие объемы данных на страницы и возвращать их по частям. В Spring Boot пагинация реализуется с помощью Spring Data JPA.
Подключение пагинации в проекте
Spring Data JPA предоставляет интерфейсы и аннотации для легкой реализации пагинации.
Добавьте параметр Pageable в методы репозитория:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
Page<User> findAll(Pageable pageable);
}
Page — это контейнер, который содержит данные текущей страницы и мета-информацию (например, общее количество страниц).
Pageable — это интерфейс для параметров пагинации: номер страницы, размер страницы и сортировка.
Использование Pageable в контроллере:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping
public ResponseEntity<Page<User>> getAllUsers(Pageable pageable) {
Page<User> users = userRepository.findAll(pageable);
return ResponseEntity.ok(users);
}
}
Пример запроса с пагинацией:
GET /api/users?page=0&size=5&sort=name,asc
page — номер страницы (начинается с 0).
size — количество элементов на странице.
sort — параметры сортировки (поле,направление).
Пример ответа:
{
"content": [
{"id": 1, "name": "John", "email": "john@example.com"},
{"id": 2, "name": "Jane", "email": "jane@example.com"}
],
"pageable": {
"pageNumber": 0,
"pageSize": 5
},
"totalPages": 2,
"totalElements": 10,
"last": false
}
2. Фильтрация данных в REST API
Фильтрация позволяет клиентам задавать условия, по которым нужно отбирать данные.
Подходы к фильтрации
Фильтрация по параметрам запроса (Request Parameters): Используется для простой фильтрации данных.
Динамическая фильтрация с помощью Specification или Criteria:
Применяется для сложных и многоуровневых условий.
Фильтрация по параметрам запроса
Реализация простого поиска с фильтрацией:
Добавьте методы в репозиторий:
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByNameContaining(String name);
List<User> findByAgeGreaterThanEqual(Integer age);
}
#Java #Training #Spring #Pagination #Filter
Добавьте фильтры в контроллер:
Примеры запросов:
Фильтрация по имени:
Фильтрация по возрасту:
Динамическая фильтрация с использованием Specification
Для сложных фильтров можно использовать Spring Data JPA Specification.
Добавьте зависимость:
Создайте Specification для фильтрации:
Расширьте репозиторий:
Добавьте динамическую фильтрацию в контроллер:
Пример запроса с фильтрацией:
3. Пагинация и фильтрация вместе
Совмещение пагинации и фильтрации:
Пример запроса:
#Java #Training #Spring #Pagination #Filter
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age) {
if (name != null) {
return ResponseEntity.ok(userRepository.findByNameContaining(name));
} else if (age != null) {
return ResponseEntity.ok(userRepository.findByAgeGreaterThanEqual(age));
} else {
return ResponseEntity.ok(userRepository.findAll());
}
}
}
Примеры запросов:
Фильтрация по имени:
GET /api/users/search?name=John
Фильтрация по возрасту:
GET /api/users/search?age=30
Динамическая фильтрация с использованием Specification
Для сложных фильтров можно использовать Spring Data JPA Specification.
Добавьте зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Создайте Specification для фильтрации:
import org.springframework.data.jpa.domain.Specification;
public class UserSpecification {
public static Specification<User> hasName(String name) {
return (root, query, cb) -> cb.like(root.get("name"), "%" + name + "%");
}
public static Specification<User> hasAgeGreaterThan(Integer age) {
return (root, query, cb) -> cb.greaterThanOrEqualTo(root.get("age"), age);
}
}
Расширьте репозиторий:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}
Добавьте динамическую фильтрацию в контроллер:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserRepository userRepository;
@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/filter")
public ResponseEntity<List<User>> filterUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age) {
Specification<User> spec = Specification.where(null);
if (name != null) {
spec = spec.and(UserSpecification.hasName(name));
}
if (age != null) {
spec = spec.and(UserSpecification.hasAgeGreaterThan(age));
}
return ResponseEntity.ok(userRepository.findAll(spec));
}
}
Пример запроса с фильтрацией:
GET /api/users/filter?name=Jane&age=25
3. Пагинация и фильтрация вместе
Совмещение пагинации и фильтрации:
@GetMapping("/filter")
public ResponseEntity<Page<User>> filterUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age,
Pageable pageable) {
Specification<User> spec = Specification.where(null);
if (name != null) {
spec = spec.and(UserSpecification.hasName(name));
}
if (age != null) {
spec = spec.and(UserSpecification.hasAgeGreaterThan(age));
}
Page<User> result = userRepository.findAll(spec, pageable);
return ResponseEntity.ok(result);
}
Пример запроса:
GET /api/users/filter?name=Jane&page=0&size=5&sort=age,desc
#Java #Training #Spring #Pagination #Filter
@Filter в Hibernate
Аннотация @Filter позволяет динамически применять условия фильтрации к сущностям или коллекциям на уровне базы данных. Она используется для ограничения выборки данных в зависимости от заданных параметров. Находится в пакете org.hibernate.annotations.
Параметры и настройки
Аннотация @Filter имеет следующие атрибуты:
name (обязательный, String):
Уникальное имя фильтра, которое используется для его активации/деактивации в сессии.
Пример: @Filter(name = "activeUserFilter").
condition (необязательный, String):
SQL-условие, которое добавляется в запрос при активации фильтра.
Может содержать параметры (например, :param), которые задаются во время выполнения.
Пример: @Filter(name = "activeUserFilter", condition = "is_active = :activeStatus").
deduceAliasInjectionPoints (необязательный, boolean, default = true):
Определяет, должен ли Hibernate автоматически подставлять алиасы таблиц в условие.
Если false, условие должно содержать явные алиасы.
Жизненный цикл фильтра
Объявление фильтра:
Фильтр определяется на уровне класса сущности (@Entity) или коллекции (@ElementCollection, @OneToMany и др.).
Пример:
Активация фильтра в сессии:
Фильтр не активен по умолчанию, его нужно включать явно в Session или EntityManager.
Пример:
Применение в запросах:
После активации фильтр автоматически добавляет условие ко всем запросам, связанным с сущностью.
Для @OneToMany и других коллекций фильтр применяется при загрузке ассоциаций.
Деактивация фильтра:
Фильтр можно отключить:
Механизмы Hibernate и Spring, связанные с @Filter
1. @FilterDef и @ParamDef
@FilterDef определяет фильтр и его параметры.
@ParamDef задает тип параметра (например, String, boolean).
Должен быть указан на уровне класса (обычно на @Entity или в package-info.java).
2. Интеграция с Spring Data JPA
Фильтры можно активировать в Spring-репозиториях через EntityManager:
3. Глобальная настройка фильтров в Spring Boot
Можно автоматически включать фильтры для всех запросов через @PostConstruct:
Варианты настройки и применения
1. Фильтрация коллекций
2. Множественные фильтры
3. Динамическое управление фильтрами
#Java #Training #Hard #Spring #Hibernate #Filter #FilterDef
Аннотация @Filter позволяет динамически применять условия фильтрации к сущностям или коллекциям на уровне базы данных. Она используется для ограничения выборки данных в зависимости от заданных параметров. Находится в пакете org.hibernate.annotations.
Параметры и настройки
Аннотация @Filter имеет следующие атрибуты:
name (обязательный, String):
Уникальное имя фильтра, которое используется для его активации/деактивации в сессии.
Пример: @Filter(name = "activeUserFilter").
condition (необязательный, String):
SQL-условие, которое добавляется в запрос при активации фильтра.
Может содержать параметры (например, :param), которые задаются во время выполнения.
Пример: @Filter(name = "activeUserFilter", condition = "is_active = :activeStatus").
deduceAliasInjectionPoints (необязательный, boolean, default = true):
Определяет, должен ли Hibernate автоматически подставлять алиасы таблиц в условие.
Если false, условие должно содержать явные алиасы.
Жизненный цикл фильтра
Объявление фильтра:
Фильтр определяется на уровне класса сущности (@Entity) или коллекции (@ElementCollection, @OneToMany и др.).
Пример:
@Entity
@FilterDef(name = "activeUserFilter",
condition = "is_active = :activeStatus",
parameters = @ParamDef(name = "activeStatus", type = boolean.class))
@Filter(name = "activeUserFilter")
public class User { ... }
Активация фильтра в сессии:
Фильтр не активен по умолчанию, его нужно включать явно в Session или EntityManager.
Пример:
session.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
Применение в запросах:
После активации фильтр автоматически добавляет условие ко всем запросам, связанным с сущностью.
Для @OneToMany и других коллекций фильтр применяется при загрузке ассоциаций.
Деактивация фильтра:
Фильтр можно отключить:
session.disableFilter("activeUserFilter");
Механизмы Hibernate и Spring, связанные с @Filter
1. @FilterDef и @ParamDef
@FilterDef определяет фильтр и его параметры.
@ParamDef задает тип параметра (например, String, boolean).
Должен быть указан на уровне класса (обычно на @Entity или в package-info.java).
2. Интеграция с Spring Data JPA
Фильтры можно активировать в Spring-репозиториях через EntityManager:
@Repository
public class UserRepository {
@PersistenceContext
private EntityManager em;
public List<User> findActiveUsers() {
em.unwrap(Session.class)
.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
return em.createQuery("FROM User", User.class).getResultList();
}
}
3. Глобальная настройка фильтров в Spring Boot
Можно автоматически включать фильтры для всех запросов через @PostConstruct:
@Component
public class HibernateFilterConfig {
@PersistenceContext
private EntityManager em;
@PostConstruct
public void init() {
Session session = em.unwrap(Session.class);
session.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
}
}
Варианты настройки и применения
1. Фильтрация коллекций
@Entity
public class Department {
@OneToMany(mappedBy = "department")
@Filter(name = "activeUserFilter", condition = "is_active = :activeStatus")
private List<User> users;
}
2. Множественные фильтры
@Entity
@FilterDef(name = "activeFilter", condition = "is_active = :active")
@FilterDef(name = "roleFilter", condition = "role = :roleName")
@Filter(name = "activeFilter")
@Filter(name = "roleFilter")
public class User { ... }
3. Динамическое управление фильтрами
// Включение разных параметров в runtime
session.enableFilter("activeUserFilter")
.setParameter("activeStatus", true);
session.enableFilter("roleFilter")
.setParameter("roleName", "ADMIN");
#Java #Training #Hard #Spring #Hibernate #Filter #FilterDef