有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Vaadin流中使用数据提供程序的自定义组合框过滤?

我们目前使用的是Vaadin Flow版本12.0.7(由于种种原因,我们无法升级),我们希望覆盖ComboBox组件的过滤机制。我的意思是,当用户在组合框中输入输入时,我们希望改变搜索组合框后面项目的方式

我正在研究如何实现组合框的自定义筛选。更具体地说Filtering by a string一节看起来很有希望

根据Vaadin文档,我们实现了一个自定义界面,用于调整组合框的搜索方法:

public interface CustomerDataFilter {
    List<Customer> fetch(int offset, int limit, String filterText);
    int getCount(String filterText);
}

这是非常直截了当的,与文档示例的比例接近1:1

然后,我们根据文档创建了一个方法,用数据填充组合框。也几乎使用了文档中的1:1:

private DataProvider<Customer, String>
createDepartmentDataProvider(CustomerDataFilter service)
{
   return DataProvider.fromFilteringCallbacks(query -> {
       // getFilter returns Optional<String>
       String filter = query.getFilter().orElse(null);
       return service.fetch(query.getOffset(),
               query.getLimit(), filter).stream();
   }, query -> {
       String filter = query.getFilter().orElse(null);
       return service.getCount(filter);
   });
}

我们在初始化组合框的数据时调用上述方法。在这一点上,我们还实现了接口(尽管可能很难看)。然而,我们不太确定如何使用这两种接口方法。我们的第一个目标就是始终返回所有项目,忽略任何特定的筛选,这就是为什么我们始终返回整个sorted列表的原因。这只是为了测试我们是否改变了过滤

public void updateCustomerList() {
    List<Customer> sorted = CustomerService.getInstance().findAll();
    //for initial sorting
    sorted.sort(new CustomerComperator());

    DataProvider<Customer, String> test = createDepartmentDataProvider(new CustomerDataFilter() {

        @Override
        public int getCount(String filterText) {
            return 0;
        }

        @Override
        public List<Customer> fetch(int offset, int limit, String filterText) {
            return sorted;
        }
    });

    customerCompany.setItems(sorted);
    customerCompany.setDataProvider(test);
}

我们试图将getCount值增加到1,但一旦我们将其设置为高于0,就会出现以下异常:

The number of items returned by the data provider exceeds the limit specified by the query (1).

我们的猜测是,我们必须以某种方式调整getCountfetch方法,以实现我们的customsearch。这不会有问题,因为我们在组合框和filterText后面有数据。我们怎么会有点困惑,为什么我们也需要一个getCount方法,以及我们如何绕过显示的异常?我们的想法是让getCount总是像10一样返回,并在fetch中返回关于filterTextsorted列表的子集

有没有人能详细说明/帮助我们如何实现组合框的自定义过滤,或者为我们指出正确的方向


感谢Steffen Harbichs的回答,我们找到了实现过滤数据提供者的方法。基本上这就是所需要的一切:

public void updateCustomerList() {
    List<Customer> sorted = CustomerService.getInstance().findAll();
    sorted.sort(new CustomerComperator());
    customerCompany.setItems(sorted);

    ListDataProvider<Customer> listTest = new ListDataProvider<>(sorted);
    customerCompany.setDataProvider(listTest.filteringByPrefix(new CustomerProvider()));
}

CustomerProvider仅实现适用的数据提供程序接口。然后,我们可以简单地应用filteringByPrefix方法来更改过滤行为


共 (1) 个答案

  1. # 1 楼答案

    您的思路是正确的,但首先需要理解^{}的概念

    在客户端(浏览器),一旦用户与Vaadin进行了一些交互,Vaadin请求将数据显示在组合框中。请求的数据将类似于“数据中有多少项?”这是计数查询。假设你有100件物品。现在,下一个请求是“给我前40个要显示的项目”,这是获取查询。组合框将显示返回的项目。一旦用户向下滚动列表,就会发出另一个数据请求“给我接下来要显示的40个项目”等

    总之,首先要求DataProvider返回所有项的计数,然后根据需要逐页获取数据。这也适用于用户输入过滤器的情况。不同之处在于,计数和获取查询应该考虑过滤器

    示例:用户输入的筛选器“xyz”,现在只有50个项与此筛选器匹配(按名称或其他内容),所以您将在count方法中返回50个项,并且您的fetch方法将相应地进行筛选

    您遇到的异常只是指出,fetch方法返回的项目比Vaadin请求的多(查询参数中的“limit”参数)。这是因为您当前不处理偏移/限制

    您有两个选项来实现数据提供程序:

    使用ListDataProvider

    Vaadin提供了^{},这是列表DataProvider的一个实现。分页已经在实现中完成,您不必关心它。使用filteringBy方法根据输入的筛选文本筛选数据

    这种方法更简单,但不具有可扩展性。这意味着,如果您有许多项,您将消耗大量内存和CPU,因为整个数据都是从后端检索到列表中的。如果你认为你的物品数量很低,那么就采用这种方法

    或者实现您自己的数据提供者

    您可以实现自己的DataProvider。我建议首先扩展AbstractBackendDataProvider类(javadoc)。需要实现方法sizeInBackendfetchFromBackend。注意在fetch方法中实现分页的offset/limit参数

    如果将分页委托给数据库(例如SQL或无SQL数据库),则此方法是可扩展的。内存占用将很低,因为您只需在内存中保留一页