genericFilter 通用过滤器

genericFilter 组件为数据加载器构建可配置的条件,并以交互式的组件形式展示。默认添加在标准实体视图中,例如,列表视图。

XML 元素

genericFilter

Java 类

GenericFilter

概览

Generic filter

过滤器组件包含:

  1. 带下拉框的 Refresh(刷新) 按钮

  2. 比较操作符选择器。

  3. Filter Settings(过滤器设置) 按钮。

  4. 保存的过滤器和配置列表。

  5. 条件的值字段。

  6. Add search condition(添加搜索条件) 链接按钮。

运行时使用

依据过滤器配置和 授予的权限,支持下列用户操作:

  • 创建一个临时过滤器,在当前视图打开期间有效。用户可以输入条件值、改变条件运算符或重置过滤器。

  • 使用应用程序提供的已保存过滤器和配置。用户不能编辑或移除,但在被授予 ui.genericfilter.modifyConfiguration 时可以进行复制。

  • 使用向导创建新过滤条件:

  • 用户有 ui.genericfilter.modifyConfiguration 角色时,保存、编辑、复制和移除个人运行时配置。

  • 用户有 ui.genericfilter.modifyGlobalConfiguration 角色时,能将运行时配置开放给所有用户或设为默认配置。

基本用法

使用时,组件必须与 CollectionContainer 或 KeyValueCollectionContainer 的加载器关联。在执行过滤时,会构建一个 Condition 并将其分配给该加载器;对于 JPA 实体,数据存储会将条件转换为 JPQL,因此,过滤条件最后在数据库中执行。

下面示例中,先声明了一个初始的年龄条件,然后从 Java 添加了另一个属性条件。XML 和控制器中过滤器的标识符必需一致,因为控制器会查询已有配置并对其进行扩展:

XML
<data>
    <collection id="customersDc"
                class="io.jmix.uisamples.entity.Customer"
                fetchPlan="_local">
        <loader id="customersDl">
            <query>
                <![CDATA[select e from Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<facets>
    <dataLoadCoordinator auto="true"/>
</facets>
<layout>
    <genericFilter id="genericFilter" dataLoader="customersDl">
        <properties include=".*"/>
    </genericFilter>
    <dataGrid id="customerDataGrid"
              dataContainer="customersDc"
              width="100%"
              minHeight="20em">
        <columns>
            <column property="name"/>
            <column property="lastName"/>
            <column property="age"/>
            <column property="active"/>
            <column property="grade"/>
        </columns>
    </dataGrid>
</layout>
Java
@ViewComponent
protected GenericFilter genericFilter;

@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;

@Subscribe
protected void onBeforeShow(BeforeShowEvent event) {
    initConfiguration();
}

protected void initConfiguration() {
    DataLoader dataLoader = genericFilter.getDataLoader();
    PropertyFilter<Integer> agePropertyFilter = craeteAgePropertyFilter(dataLoader);

    genericFilter.getCurrentConfiguration().getRootLogicalFilterComponent().add(agePropertyFilter);
    genericFilter.setCurrentConfiguration(genericFilter.getCurrentConfiguration());
}

protected PropertyFilter<Integer> craeteAgePropertyFilter(DataLoader dataLoader) {
    PropertyFilter<Integer> agePropertyFilter = uiComponents.create(PropertyFilter.class);
    agePropertyFilter.setConditionModificationDelegated(true);
    agePropertyFilter.setDataLoader(dataLoader);
    agePropertyFilter.setProperty("age");
    agePropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
    agePropertyFilter.setOperationEditable(true);

    agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            agePropertyFilter.getProperty()));
    agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            agePropertyFilter.getProperty(),
            agePropertyFilter.getOperation()
    ));

    return agePropertyFilter;
}

数据加载器可以有自己的 基础条件,在加载器的 condition 元素中设置,或通过 DataLoader.setCondition() 以编程方式设置。genericFilter 不会替换这个条件:配置的条件会与基础条件组合为 base AND configuration,包括在切换配置时也是如此。

属性条件

propertyFilter 将实体属性和比较运算符转换为数据加载器的条件。property 属性使用直接属性或属性路径,过滤器会生成与属性元数据匹配的 UI 组件。

属性的否定运算符遵循与 PropertyCondition 相同的空值处理规则。请参见 jmix.data.include-null-clause-in-not-conditions。

下面示例的 XML 中,在设计时配置添加了 customer 和 customer.grade 的条件。两者都使用 EQUAL 运算符并设置 operationEditable="true",因此,该过滤配置的运算符最初显示为 Equals,但在运行时可以在视图中更改。

Java 示例使用底层 API 构建等同的过滤器配置。每个 PropertyFilter 与 genericFilter 数据加载器关联,并分配生成的参数名和值组件。最后,将过滤器添加到该配置的根逻辑组件中。

XML
<genericFilter id="genericFilter" dataLoader="ordersDl">
    <properties include=".*"/>
    <configurations>
        <configuration id="defaultConfiguration" name="Configuration with property conditions" default="true">
            <propertyFilter property="customer" operation="EQUAL"
                            operationEditable="true"/>
            <propertyFilter property="customer.grade" operation="EQUAL"
                            operationEditable="true"/>
        </configuration>
    </configurations>
</genericFilter>
Java
@ViewComponent
protected GenericFilter genericFilter;

@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;

@Subscribe
protected void onInit(InitEvent event) {
    initConfiguration();
}

protected void initConfiguration() {
    DesignTimeConfiguration javaConfiguration = genericFilter.addConfiguration("javaConfiguration",
            "Programmatically defined configuration");
    DataLoader dataLoader = genericFilter.getDataLoader();

    javaConfiguration.getRootLogicalFilterComponent().add(createCustomerPropertyFilter(dataLoader));
    javaConfiguration.getRootLogicalFilterComponent().add(createGradePropertyFilter(dataLoader));
}

protected PropertyFilter<Customer> createCustomerPropertyFilter(DataLoader dataLoader) {
    PropertyFilter<Customer> customerPropertyFilter = uiComponents.create(PropertyFilter.class);

    customerPropertyFilter.setConditionModificationDelegated(true);
    customerPropertyFilter.setDataLoader(dataLoader);
    customerPropertyFilter.setProperty("customer");
    customerPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
    customerPropertyFilter.setOperationEditable(true);

    customerPropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            customerPropertyFilter.getProperty()));
    customerPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            customerPropertyFilter.getProperty(),
            customerPropertyFilter.getOperation()
    ));

    return customerPropertyFilter;
}

protected PropertyFilter<CustomerGrade> createGradePropertyFilter(DataLoader dataLoader) {
    PropertyFilter<CustomerGrade> gradePropertyFilter = uiComponents.create(PropertyFilter.class);
    gradePropertyFilter.setConditionModificationDelegated(true);
    gradePropertyFilter.setDataLoader(dataLoader);
    gradePropertyFilter.setProperty("customer.grade");
    gradePropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
    gradePropertyFilter.setOperationEditable(true);

    gradePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            gradePropertyFilter.getProperty()));
    gradePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            gradePropertyFilter.getProperty(),
            gradePropertyFilter.getOperation()
    ));

    return gradePropertyFilter;
}

JPQL 条件

使用 jpqlFilter 可以自定义 JPQL 谓词,当条件无法表示为属性值比较时使用。示例中,需要按 items 集合中的产品过滤订单:join 子句引入集合别名,where 子句将产品标识符与过滤器参数进行比较。

XML 示例声明 JPQL 条件命名空间,将 Product 设置为参数类,并在 condition 内嵌套 join 和 where 子句。运行时,参数类型决定条件显示的值组件类型。

Java 示例通过底层 API 创建相同的过滤器。将 where 和 join 子句传递给 setCondition(),分配参数类和标签,生成参数名和兼容的值组件,并将过滤器添加到以编程方式创建的设计时配置中。

定义 JPQL 条件时使用以下语法:

  • 可选的 join 子句(以 join 或 left join 开始),并使用 {E} 表示实体别名。

  • 在 where 子句中,使用 {E} 表示实体别名,使用 ? 表示过滤器提供的值。一个条件只能包含一个 ? 参数,还可以使用 会话和用户属性 参数。

  • 对于在 IN 表达式中使用的集合值参数,需启用过滤器的 hasInExpression 属性。

XML
<view xmlns="http://jmix.io/schema/flowui/view"
      xmlns:c="http://jmix.io/schema/flowui/jpql-condition">
        <genericFilter id="genericFilter" dataLoader="ordersDl">
            <properties include=".*"/>
            <configurations>
                <configuration id="defaultConfiguration" name="Configuration with JPQL condition" default="true">
                    <jpqlFilter label="Order items contains"
                                parameterClass="io.jmix.uisamples.entity.Product">
                        <condition>
                            <c:jpql>
                                <c:join>join {E}.items i</c:join>
                                <c:where>i.product.id = ?</c:where>
                            </c:jpql>
                        </condition>
                    </jpqlFilter>
                </configuration>
            </configurations>
        </genericFilter>
Java
@ViewComponent
protected GenericFilter genericFilter;

@Autowired
protected UiComponents uiComponents;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected SingleFilterSupport singleFilterSupport;

@Subscribe
protected void onInit(InitEvent event) {
    initConfiguration();
}

protected void initConfiguration() {
    DesignTimeConfiguration javaConfiguration = genericFilter.addConfiguration("javaConfiguration",
            "Programmatically defined configuration");
    DataLoader dataLoader = genericFilter.getDataLoader();

    javaConfiguration.getRootLogicalFilterComponent().add(createProductJpqlFilter(dataLoader));
}

protected JpqlFilter<Product> createProductJpqlFilter(DataLoader dataLoader) {
    JpqlFilter<Product> jpqlFilter = uiComponents.create(JpqlFilter.class);

    jpqlFilter.setConditionModificationDelegated(true);
    jpqlFilter.setDataLoader(dataLoader);
    jpqlFilter.setCondition("i.product.id = ?", "join {E}.items i");
    jpqlFilter.setParameterClass(Product.class);
    jpqlFilter.setLabel("Order items contains");

    jpqlFilter.setParameterName(jpqlFilterSupport.generateParameterName(
            jpqlFilter.getId().orElse(null),
            jpqlFilter.getParameterClass().getSimpleName()));
    jpqlFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            jpqlFilter.hasInExpression(),
            jpqlFilter.getParameterClass()
    ));

    return jpqlFilter;
}

组合条件

groupFilter 使用 AND 或 OR 组合内部的过滤器组件。条件组也可以嵌套,配置的根逻辑组件使用其自身的操作组合其直接子项。

XML 示例创建一个 OR 组,包含 active 和 grade 属性过滤器。age 过滤器在该组条件之外,因此默认根操作生成以下表达式:

(active = false OR grade = STANDARD) AND age >= 30

Java 示例也构建相同的条件树。创建组过滤器和属性过滤器,将属性过滤器添加到组中,然后将组和 age 过滤器添加到配置的根元素。设置每个组件的当前值和该过滤配置存储的默认值,确保在选择该配置时能恢复相同的值。

XML
<genericFilter id="genericFilter" dataLoader="customersDl">
    <properties include=".*"/>
    <configurations>
        <configuration id="defaultConfiguration" name="Configuration with conditions grouping" default="true">
            <groupFilter operation="OR">
                <propertyFilter property="active" operation="EQUAL"
                                operationEditable="true" defaultValue="false"/>
                <propertyFilter property="grade" operation="EQUAL"
                                operationEditable="true" defaultValue="30"/>
            </groupFilter>
            <propertyFilter property="age" operation="GREATER_OR_EQUAL"
                            operationEditable="true" defaultValue="30"/>
        </configuration>
    </configurations>
</genericFilter>
Java
@ViewComponent
protected GenericFilter genericFilter;

@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected LogicalFilterSupport logicalFilterSupport;

@Subscribe
protected void onInit(InitEvent event) {
    initConfiguration();
}

protected void initConfiguration() {
    DesignTimeConfiguration javaConfiguration = genericFilter.addConfiguration("javaConfiguration",
            "Programmatically defined configuration");
    DataLoader dataLoader = genericFilter.getDataLoader();

    GroupFilter groupFilter = createGroupFilter(dataLoader);
    PropertyFilter<Boolean> activePropertyFilter = createActivePropertyFilter(dataLoader);
    PropertyFilter<CustomerGrade> gradePropertyFilter = createGradePropertyFilter(dataLoader);
    groupFilter.add(activePropertyFilter);
    groupFilter.add(gradePropertyFilter);

    PropertyFilter<Integer> agePropertyFilter = createAgePropertyFilter(dataLoader);

    javaConfiguration.getRootLogicalFilterComponent().add(groupFilter);
    javaConfiguration.getRootLogicalFilterComponent().add(agePropertyFilter);

    activePropertyFilter.setValue(false);
    javaConfiguration.setFilterComponentDefaultValue(activePropertyFilter.getParameterName(), false);

    gradePropertyFilter.setValue(CustomerGrade.STANDARD);
    javaConfiguration.setFilterComponentDefaultValue(gradePropertyFilter.getParameterName(), CustomerGrade.STANDARD);

    agePropertyFilter.setValue(30);
    javaConfiguration.setFilterComponentDefaultValue(agePropertyFilter.getParameterName(), 30);
}

protected GroupFilter createGroupFilter(DataLoader dataLoader) {
    GroupFilter groupFilter = uiComponents.create(GroupFilter.class);
    groupFilter.setConditionModificationDelegated(true);
    groupFilter.setDataLoader(dataLoader);
    groupFilter.setOperation(LogicalFilterComponent.Operation.OR);

    return groupFilter;
}

protected PropertyFilter<Boolean> createActivePropertyFilter(DataLoader dataLoader) {
    PropertyFilter<Boolean> activePropertyFilter = uiComponents.create(PropertyFilter.class);
    activePropertyFilter.setConditionModificationDelegated(true);
    activePropertyFilter.setDataLoader(dataLoader);
    activePropertyFilter.setProperty("active");
    activePropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
    activePropertyFilter.setOperationEditable(true);

    activePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            activePropertyFilter.getProperty()));
    activePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            activePropertyFilter.getProperty(),
            activePropertyFilter.getOperation()
    ));

    return activePropertyFilter;
}

protected PropertyFilter<CustomerGrade> createGradePropertyFilter(DataLoader dataLoader) {
    PropertyFilter<CustomerGrade> gradePropertyFilter = uiComponents.create(PropertyFilter.class);
    gradePropertyFilter.setConditionModificationDelegated(true);
    gradePropertyFilter.setDataLoader(dataLoader);
    gradePropertyFilter.setProperty("grade");
    gradePropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
    gradePropertyFilter.setOperationEditable(true);

    gradePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            gradePropertyFilter.getProperty()));
    gradePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            gradePropertyFilter.getProperty(),
            gradePropertyFilter.getOperation()
    ));

    return gradePropertyFilter;
}

protected PropertyFilter<Integer> createAgePropertyFilter(DataLoader dataLoader) {
    PropertyFilter<Integer> agePropertyFilter = uiComponents.create(PropertyFilter.class);
    agePropertyFilter.setConditionModificationDelegated(true);
    agePropertyFilter.setDataLoader(dataLoader);
    agePropertyFilter.setProperty("age");
    agePropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
    agePropertyFilter.setOperationEditable(true);

    agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            agePropertyFilter.getProperty()));
    agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoader.getContainer().getEntityMetaClass(),
            agePropertyFilter.getProperty(),
            agePropertyFilter.getOperation()
    ));

    return agePropertyFilter;
}

设计时配置

过滤器的一个配置是注册到 genericFilter 中的命名条件树。设计时配置在 XML 中使用过滤器的 configurations 元素声明。

示例在一个配置中声明了三个属性过滤器。default="true" 表示该配置在视图打开时处于激活状态,因此其默认值会在生成的值组件中设置:

<genericFilter id="genericFilter" dataLoader="customersDl">
    <properties include=".*"/>
    <configurations>
        <configuration id="defaultConfiguration" name="Configuration with multiple conditions"
                       default="true">
            <propertyFilter property="age" operation="GREATER_OR_EQUAL"
                            operationEditable="true" defaultValue="30"/>
            <propertyFilter property="grade" operation="EQUAL"
                            operationEditable="true" defaultValue="20"/>
            <propertyFilter property="active" operation="EQUAL"
                            operationEditable="true" defaultValue="true"/>
        </configuration>
    </configurations>
</genericFilter>

请确保每个配置都设置了 id 属性,并且在 genericFilter 中唯一。如果未设置 name 属性,则 id 被视为 消息包 中的键值。可以使用 default 属性设置默认配置。

如需在 Jmix Studio 中添加设计时配置,可以在界面 XML 或者 Jmix UI 结构面板中选择 genericFilter 组件,然后点击 Component Inspector 面板的 Add → Configurations → Design-time configuration 按钮。

设计时配置会出现在配置选择器中,但其条件树在运行时无法编辑或移除。Copy 操作会将配置复制为一个可编辑的运行时配置;请参见 保存和管理配置。

编程式创建过滤器

可以使用 builder 的流式 API 在 Java 中创建和配置 genericFilter,该 API 有两个入口点:

  • filterComponentBuilder() 创建过滤组件 – propertyFilter、jpqlFilter 和 groupFilter。

  • runtimeConfigurationBuilder() 用这些组件组装一个 RunTimeConfiguration,并将其注册到过滤器中。

Builder 会在内部执行所有必需的初始化(条件修改代理、参数名称和生成值组件),因此以编程方式构建的组件与在 XML 中声明的组件行为完全一致。父 genericFilter 必须有一个 DataLoader;否则 builder 的方法会抛出 IllegalStateException。

Builder API 目前为实验性功能,可能在未来的 Jmix 版本中发生变化。

以下示例创建了一个 genericFilter,构建了一个属性条件,并注册了一个配置:

@Autowired
private UiComponents uiComponents;

@ViewComponent
private VerticalLayout programmaticFilterBox;

@ViewComponent
private CollectionLoader<Customer> customerDl;

@Subscribe
public void onInit(final InitEvent event) {
    GenericFilter genericFilter = uiComponents.create(GenericFilter.class); (1)
    genericFilter.setId("programmaticFilter");
    genericFilter.setDataLoader(customerDl);
    genericFilter.loadConfigurationsAndApplyDefault();
    programmaticFilterBox.add(genericFilter); (2)

    PropertyFilter<Integer> agePropertyFilter = genericFilter.filterComponentBuilder() (3)
            .<Integer>propertyFilter()
            .property("age")
            .operation(PropertyFilter.Operation.LESS_OR_EQUAL)
            .operationEditable(true)
            .build();

    genericFilter.runtimeConfigurationBuilder() (4)
            .id("javaConfiguration")
            .name("Default configuration")
            .add(agePropertyFilter)
            .makeCurrent() (5)
            .buildAndRegister(); (6)
}
1 用 uiComponents 工厂创建 genericFilter。
2 将 genericFilter 放入视图中声明的 vbox 内。
3 使用 filterComponentBuilder() 构建一个 PropertyFilter。
4 使用 runtimeConfigurationBuilder() 注册一个运行时配置,并添加过滤器。
5 立即激活该配置。这里并不是将配置持久化为默认配置,而只是将配置设为当前配置。
6 构建并注册配置。每个 builder 实例都是单次使用的。

构建过滤组件

filterComponentBuilder() 为每种组件类型返回专用的 builder。所有 builder 都是单次使用的,生成一个可直接添加的组件。

属性过滤器

propertyFilter() 按实体属性进行过滤,包括实体嵌套属性 — property() 可以使用属性路径,例如 customer.city.name。值编辑器会根据属性类型自动生成。除非调用 operationEditable(true)(允许用户在运行时更改操作),否则操作是固定的;operationTextVisible(false) 隐藏字段旁边显示的操作标签。传递给 defaultValue() 的值会自动设置为组件的默认值。

PropertyFilter<Integer> ageFilter = genericFilter.filterComponentBuilder()
        .<Integer>propertyFilter()
        .property("age")
        .operation(PropertyFilter.Operation.GREATER_OR_EQUAL)
        .operationEditable(true)
        .build();

JPQL 过滤器(复选框)

jpqlFilter()(无参数)创建一个 void 过滤器:一个复选框,用于开启或关闭固定的 WHERE 子句。其值类型为 Boolean,因此 defaultValue(true) 使条件默认生效。

JpqlFilter<Boolean> hasRewardPoints = genericFilter.filterComponentBuilder()
        .jpqlFilter()
        .where("{E}.rewardPoints > 0")
        .label("Has reward points")
        .defaultValue(true)
        .build();

JPQL Filter(有类型)

jpqlFilter(Class) 创建一个 有类型 的过滤器:用户输入的值绑定到查询参数,编辑器与给定的 Class 匹配。在 where() 中使用 {E} 作为实体别名和一个命名参数来编写条件,然后使用 parameterName() 声明其名称。添加 join() 来扩展 FROM 子句,或者当值是一个集合(in 条件)时使用 hasInExpression(true)。

JpqlFilter<Integer> minAge = genericFilter.filterComponentBuilder()
        .jpqlFilter(Integer.class)
        .where("{E}.age >= :minAge")
        .parameterName("minAge")
        .label("Minimum age")
        .build();

分组过滤器

groupFilter() 用逻辑操作组合不同条件 — AND(默认)或 OR。分组本身也是一个过滤组件,因此可以嵌套组来表达复杂的布尔逻辑。使用 add() 或 addAll() 添加子项。

GroupFilter orGroup = genericFilter.filterComponentBuilder()
        .groupFilter()
        .operation(LogicalFilterComponent.Operation.OR)
        .addAll(hasRewardPoints, minAge)
        .build();

构建运行时配置

runtimeConfigurationBuilder() 创建一个 RunTimeConfiguration,并将其注册到过滤器中。

genericFilter.runtimeConfigurationBuilder()
        .id("dynamicConfiguration")
        .name("Dynamic configuration")
        .add(ageFilter, 18) (1)
        .add(orGroup) (2)
        .makeCurrent() (3)
        .allowDeletion() (4)
        .buildAndRegister();
1 添加一个带类型和默认值的组件;值类型在编译时检查。使用不带默认值的 add(component),或使用 addAll(components…​) 可以一次添加多个。
2 添加上面构建的分组。
3 立即激活配置。不是持久化的默认配置标记。
4 允许用户删除此配置。默认情况下,使用 builder 创建的配置受保护,用户不能删除。

请注意:

  • 每个 builder 实例是单次使用的 — 两次调用 build() 或 buildAndRegister() 会抛出 IllegalStateException。

  • 配置的 id 在过滤器内必须唯一。

  • 父 genericFilter 必须有一个 DataLoader。

Builder 创建的是一个 RunTimeConfiguration。没有用于 DesignTimeConfiguration 的 builder。如需在较低级别以编程方式创建配置,请使用 addConfiguration(id, name)(返回一个 DesignTimeConfiguration)并直接创建和添加过滤组件,或者构建一个 RunTimeConfiguration 并使用 addConfiguration(configuration) 注册。这是 builder API 所替代的低级别方法。
有关每个 builder 功能的可运行示例,请参见 UI 示例 中的 GenericFilter 部分。

权限

为用户分配以下特定权限可以允许用户配置过滤器:

  • ui.genericfilter.modifyConfiguration 允许用户创建、编辑和移除自己的运行时配置。

  • ui.genericfilter.modifyGlobalConfiguration 允许用户创建、编辑和移除对所有用户可用的配置。

  • ui.genericfilter.modifyJpqlCondition 允许用户在运行时创建和更改 JPQL 条件。

样式版本

使用 themeNames 属性设置组件样式。

样式 描述 支持的主题

filled

为过滤器的 header 使用填充背景样式。

Aura, Lumo

reverse

将切换指示器放在摘要文本之前。

Aura, Lumo

small

使过滤器的 header 更紧凑。

Aura, Lumo

XML 属性

下面是 genericFilter 的特殊属性:

名称 描述 默认值

applyShortcut

设置执行非自动过滤条件的 键盘快捷键。

jmix.ui.component.filter-apply-shortcut

autoApply

等过滤条件变更后,是否立即执行。false 时,用户需通过操作按钮或快捷键执行。

jmix.ui.component.filter-auto-apply

dataLoader

关联的 数据加载器。

—

opened

控制条件面板是否展开。

true

propertyHierarchyDepth

设置条件中最多可以嵌套的实体属性层数。

2

summaryText

设置条件面板上方显示的简短文本。

Filter

下面是 genericFilter 支持的其他通用属性:

事件和处理器

下面是 genericFilter 的特殊事件和处理器:

名称 描述

ConfigurationChangeEvent

当前的配置变更时发出,包括选中和重置。

ConfigurationRefreshEvent

当前的配置编辑完成后发出。

OpenedChangeEvent

当 opened 状态变更时发出。

propertyFiltersPredicate

在被提供给用户创建的属性条件之前先对实体属性进行测试。

下面是 genericFilter 支持的其他通用事件:

XML 内部元素

一个 genericFilter 可以包含 actions、conditions、configurations、properties、responsiveSteps 和 tooltip 作为其内部元素。下面是过滤器特定内部元素的介绍。

actions

定义过滤器管理的操作列表。框架在 Filter Settings(过滤器设置) generic filter settings button 中提供下列默认操作:

  • Save(保存) — 保存当前对过滤器配置的修改。由 FilterSaveAction 实现(XML 中 type="genericFilter_save")。

  • Save with values(带值保存) — 保存当前对过滤器配置的修改。,且使用条件字段 [5] 中的值作为过滤器的默认值。

  • Save as(另存为) — 将当前过滤器配置另存为新名称。由 FilterSaveAsAction 实现(XML 中 type="genericFilter_saveAs")。

  • Edit(编辑) — 打开当前 运行时配置 的编辑器。对 设计时配置 禁用。由 FilterEditAction 实现(XML 中 type="genericFilter_edit")。

  • Remove(移除) — removes the current 运行时配置. 对 设计时配置 禁用。由 FilterRemoveAction 实现(XML 中 type="genericFilter_remove")。

  • Copy(复制) — 复制当前的 运行时配置。由 FilterCopyAction 实现(XML 中 type="genericFilter_copy")。

  • Clear values(清空值) — 清空过滤器条件值 [5]。由 FilterClearValuesAction 实现(XML 中 type="genericFilter_clearValues")。

  • Add(添加) — 为当前的配置添加一个条件。由 FilterAddConditionAction 实现(XML 中 type="genericFilter_addCondition")。

  • Reset(重置) — 将组件重置回空的快速过滤器。由 FilterResetAction 实现(XML 中 type="genericFilter_reset")。

开发者可以覆盖 generic filter settings button 菜单内的操作:

<genericFilter id="filterWithActions" dataLoader="customerDl">
    <properties include=".*"/>
    <actions>
        <action id="addCondition" type="genericFilter_addCondition"/>
        <action id="clearValues" type="genericFilter_reset"/>
    </actions>
</genericFilter>

示例中将默认的操作列表替换成了 Add 和 Reset。

conditions

用来声明 预定义条件。

示例:

<genericFilter id="filterWithCondition" dataLoader="customerDl">
    <properties include=".*"/>
    <conditions>
        <propertyFilter property="hobby" enabled="true" operation="STARTS_WITH"/>
    </conditions>
</genericFilter>

configurations

用来声明 设计时配置。

properties

定义哪些实体属性可以用于过滤条件。该元素有下列属性:

  • include — 设置一个正则表达式,该表达式匹配的实体属性将被包含在可选属性中。

  • exclude — 设置一个正则表达式,该表达式匹配的实体属性将被排除在可选属性之外。

  • excludeProperties — 设置一个英文逗号分隔的应该被排除掉的属性或属性路径列表。示例:customer.name。

  • excludeRecursively — 设置 excludeProperties 里面定义的属性是否需要在对象图中递归地排除掉。如果设置的 true,那么属性和它的子属性都会被排除掉。

示例:

<genericFilter id="filterWithProperties" dataLoader="customerDl">
    <properties include=".*"
                exclude="(hobby)|(age)"
                excludeProperties="id"
                excludeRecursively="true"/>
</genericFilter>

可以包含或排除集合(@OneToMany 或 @ManyToMany)属性。

过滤器条件中可以包含 动态属性。视图中不必包含 dynamicAttributes facet。

通过 + 前缀指定动态属性:

<genericFilter id="genericFilter"
               dataLoader="carsDl">
    <properties include=".*"
                excludeProperties="+passengerNumberOfSeats"/>/>
</genericFilter>

注意:如果属性是一个实体而非简单值,则不能使用实体的属性作为过滤器条件。

以下实体属性会被忽略:

  • 由于安全权限导致无法访问的属性

  • 非持久化属性

  • 带 @SystemLevel 注解的属性

  • byte[] 类型的属性

responsiveSteps

根据可用空间确定搜索条件显示的列数。默认情况下,搜索条件分两列显示,当布局的宽度较小时,调整为单列。

以下过滤器覆盖了默认行为,将布局调整为一列、两列或三列,并将标签放在顶部:

<layout>
    <genericFilter dataLoader="customerDl">
        <responsiveSteps>
            <responsiveStep minWidth="0" columns="1"/>
            <responsiveStep minWidth="30em" columns="2"/>
            <responsiveStep minWidth="50em" columns="3" labelsPosition="TOP"/>
        </responsiveSteps>
    </genericFilter>
</layout>