Ленивая загрузка, поиск и сортировка в базе
grid.setItems(service.findAll()) загружает в память все строки сразу. Для трёх статей это нормально, для ста тысяч — нет. Ленивая загрузка решает это так: таблица сама просит у сервера только те строки, которые видны на экране, по 50 штук за раз. При прокрутке она запрашивает следующую порцию.
Запросы в репозитории и сервисе
Таблице нужны два запроса: «дай строки с N-й по M-ю» и «сколько всего строк». Добавим их с фильтром по заголовку:
// src/main/java/com/example/blog/PostRepository.java
package com.example.blog;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByTitleContainingIgnoreCase(String title, Pageable pageable);
long countByTitleContainingIgnoreCase(String title);
}Pageable — номер страницы, её размер и порядок сортировки. Spring Data превратит имя метода в SQL с LIKE, LIMIT и ORDER BY. В PostService добавьте:
// src/main/java/com/example/blog/PostService.java (новые методы)
public List<Post> find(String filter, Pageable pageable) {
return repository.findByTitleContainingIgnoreCase(filter, pageable);
}
public long count(String filter) {
return repository.countByTitleContainingIgnoreCase(filter);
}Нужен импорт org.springframework.data.domain.Pageable.
Таблица с ленивой загрузкой
// src/main/java/com/example/blog/views/PostListView.java
package com.example.blog.views;
import com.example.blog.Post;
import com.example.blog.PostService;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.data.VaadinSpringDataHelpers;
@Route("")
@PageTitle("Статьи")
public class PostListView extends VerticalLayout {
private final Grid<Post> grid = new Grid<>(Post.class, false);
private final TextField filter = new TextField();
public PostListView(PostService service) {
filter.setPlaceholder("Поиск по заголовку");
filter.setClearButtonVisible(true);
filter.setValueChangeMode(ValueChangeMode.LAZY);
filter.addValueChangeListener(event -> grid.getDataProvider().refreshAll());
grid.addColumn(Post::getTitle).setHeader("Заголовок").setSortProperty("title");
grid.addColumn(Post::getAuthor).setHeader("Автор").setSortProperty("author");
grid.addColumn(Post::getPublishedOn).setHeader("Дата").setSortProperty("publishedOn");
grid.setItems(
query -> service.find(filter.getValue(),
VaadinSpringDataHelpers.toSpringPageRequest(query)).stream(),
query -> (int) service.count(filter.getValue()));
add(filter, grid);
setSizeFull();
}
}Первая лямбда получает query со сдвигом, размером порции и сортировкой и возвращает поток строк. VaadinSpringDataHelpers.toSpringPageRequest переводит этот запрос в Pageable для Spring Data. Вторая лямбда возвращает общее число строк, чтобы полоса прокрутки была правильной длины.
Сортировка и фильтр
setSortProperty("title") включает сортировку колонки и говорит, по какому полю сущности сортировать в базе. При клике на заголовок таблица заново вызывает запрос, а в SQL появляется ORDER BY title.
Наберите в поле поиска «табл»: через полсекунды после паузы в таблице останется одна строка «Таблицы и формы». refreshAll() заставляет таблицу заново выполнить оба запроса с новым значением фильтра.
Сколько строк загружается
| Настройка | Значение по умолчанию |
|---|---|
Размер порции (setPageSize) | 50 строк |
| Когда грузится следующая порция | При прокрутке к концу загруженных строк |
| Где хранится состояние | В памяти сервера только видимая часть |
Частая ошибка
Первая лямбда игнорирует query и возвращает все строки:
// src/main/java/com/example/blog/views/PostListView.java (неправильно)
grid.setItems(query -> service.findAll().stream(), query -> service.findAll().size());Vaadin замечает, что запрос нарушен, и экран падает:
java.lang.IllegalStateException: The data provider hasn't ever called getLimit() or getPageSize() method on the provided query. It means that the the data provider breaks the contract and the returned stream contains unexpected data.Всегда передавайте сдвиг и размер из query в базу — проще всего через toSpringPageRequest(query). Если имя в setSortProperty не совпадёт с полем сущности, Spring Data ответит ошибкой No property 'date' found for type 'Post'.