Vaadin CallbackDataProvider 如何进行异步获取数据?
How to Vaadin CallbackDataProvider make an asyncronous fetch data?
Vaadin 14.CallbackDataProvider。当服务缓慢且应答时间较长时,连接到 CallbackDataProvider 的网格将全部冻结 UI。
一些例子:
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.provider.CallbackDataProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouteAlias;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class GridWithSortableColumnsView extends VerticalLayout {
public GridWithSortableColumnsView() {
addClassName("dialogwithgrid-view");
setSizeFull();
// prepare Data
List<GridRow> gridRows = new LinkedList<>();
for (int i = 0; i < 10000; i++) {
gridRows.add(new GridRow(i, RandomStringUtils.randomAlphanumeric(10)));
}
CallbackDataProvider<GridRow, Void> dataProvider = new CallbackDataProvider<>(
query -> {
// Slow service answer is here
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Notification.show("Offset=" + query.getOffset() + " Limit=" + query.getLimit());
return gridRows.stream()
.sorted((o1, o2) -> StringUtils.compare(o1.getCol05(), o2.getCol05()))
.skip(query.getOffset())
.limit(query.getLimit());
},
query -> gridRows.size());
Grid<GridRow> grid = new Grid<>();
grid.setPageSize(10);
grid.setSizeFull();
grid.addColumn(GridRow::getId).setHeader("Id");
grid.addColumn(GridRow::getCol05).setHeader("col05");
grid.setDataProvider(dataProvider);
add(grid);
}
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor
@Getter
@Setter
public static class GridRow {
@EqualsAndHashCode.Include
private int id;
private String col05;
}
}
会话锁定,所有 UI 组件在滚动此网格时冻结。
它如何更快和异步?我考虑在自己的 DataProvider 中缓存 extends CallbackDataProvider,但它会在 Grid 在第一次请求时收到空数据后填充,并且只能在一段时间后再次刷新 DataProvider 才能使用。这对我没有用。在我的实际项目中,获取的数据经常变化并且有大量的项目,一个网格最多 100000 个项目,所以我需要使用请求大小有限的 CallbackDataProvider。
Vaadin 23:
在 Vaadin 23 中现在有一个新功能,它允许您为 DataCommunicator 定义执行器以用于与 Grid 的异步操作。如果该值为 null,DataCommunicator 将同步运行,这是默认值。如果定义了执行器,执行器将获取回调 运行,并使用 UI#access(..)
更新网格。这需要启用推送。
grid.getDataCommunicator().enablePushUpdates(Executors.newCachedThreadPool());
Vaadin 14:
可以尝试使用缓存来减少查询时间。您可以使用像 ehcache 这样的通用缓存,也可以将缓存集成到您的数据提供程序中。它是特定于应用程序的,哪个更适合您,全局缓存还是本地缓存。
如果查询仍然需要那么长时间,那么我会为您提出替代方法 UI。不使用回调数据提供程序,而是将 Grid 与内存数据提供程序一起使用,但不要立即将整个数据加载到数据提供程序。而是创建分页视图。当用户点击时查询新数据,例如“下一个”/“上一个”等按钮。并在查询完成时使用 UI#access
异步方法更新 UI。
您可以使用专用于 searching/filtering 的 附加 数据库/搜索引擎,它可以非常快速地为您的网格提供数据。 Elasticsearch 是该用例的不错选择。
搜索引擎仅适用于您的网格。对于所有其他用例(输入表单、处理等),您进一步使用当前数据库。
当然要实现更新机制。每当当前数据库中的数据发生变化时,您都必须通知 Elasticsearch 系统并在那里更新数据。
Vaadin 14.CallbackDataProvider。当服务缓慢且应答时间较长时,连接到 CallbackDataProvider 的网格将全部冻结 UI。 一些例子:
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.data.provider.CallbackDataProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouteAlias;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class GridWithSortableColumnsView extends VerticalLayout {
public GridWithSortableColumnsView() {
addClassName("dialogwithgrid-view");
setSizeFull();
// prepare Data
List<GridRow> gridRows = new LinkedList<>();
for (int i = 0; i < 10000; i++) {
gridRows.add(new GridRow(i, RandomStringUtils.randomAlphanumeric(10)));
}
CallbackDataProvider<GridRow, Void> dataProvider = new CallbackDataProvider<>(
query -> {
// Slow service answer is here
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Notification.show("Offset=" + query.getOffset() + " Limit=" + query.getLimit());
return gridRows.stream()
.sorted((o1, o2) -> StringUtils.compare(o1.getCol05(), o2.getCol05()))
.skip(query.getOffset())
.limit(query.getLimit());
},
query -> gridRows.size());
Grid<GridRow> grid = new Grid<>();
grid.setPageSize(10);
grid.setSizeFull();
grid.addColumn(GridRow::getId).setHeader("Id");
grid.addColumn(GridRow::getCol05).setHeader("col05");
grid.setDataProvider(dataProvider);
add(grid);
}
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@AllArgsConstructor
@Getter
@Setter
public static class GridRow {
@EqualsAndHashCode.Include
private int id;
private String col05;
}
}
会话锁定,所有 UI 组件在滚动此网格时冻结。 它如何更快和异步?我考虑在自己的 DataProvider 中缓存 extends CallbackDataProvider,但它会在 Grid 在第一次请求时收到空数据后填充,并且只能在一段时间后再次刷新 DataProvider 才能使用。这对我没有用。在我的实际项目中,获取的数据经常变化并且有大量的项目,一个网格最多 100000 个项目,所以我需要使用请求大小有限的 CallbackDataProvider。
Vaadin 23:
在 Vaadin 23 中现在有一个新功能,它允许您为 DataCommunicator 定义执行器以用于与 Grid 的异步操作。如果该值为 null,DataCommunicator 将同步运行,这是默认值。如果定义了执行器,执行器将获取回调 运行,并使用 UI#access(..)
更新网格。这需要启用推送。
grid.getDataCommunicator().enablePushUpdates(Executors.newCachedThreadPool());
Vaadin 14:
可以尝试使用缓存来减少查询时间。您可以使用像 ehcache 这样的通用缓存,也可以将缓存集成到您的数据提供程序中。它是特定于应用程序的,哪个更适合您,全局缓存还是本地缓存。
如果查询仍然需要那么长时间,那么我会为您提出替代方法 UI。不使用回调数据提供程序,而是将 Grid 与内存数据提供程序一起使用,但不要立即将整个数据加载到数据提供程序。而是创建分页视图。当用户点击时查询新数据,例如“下一个”/“上一个”等按钮。并在查询完成时使用 UI#access
异步方法更新 UI。
您可以使用专用于 searching/filtering 的 附加 数据库/搜索引擎,它可以非常快速地为您的网格提供数据。 Elasticsearch 是该用例的不错选择。
搜索引擎仅适用于您的网格。对于所有其他用例(输入表单、处理等),您进一步使用当前数据库。
当然要实现更新机制。每当当前数据库中的数据发生变化时,您都必须通知 Elasticsearch 系统并在那里更新数据。