Filter 过滤器

Filter - 过滤器 组件是一个可对数据进行过滤的多功能工具。

这个组件支持按照任意条件对数据进行 快速过滤,同时也支持创建可重复使用的 过滤器配置

组件的 XML 名称:filter

基本用法

Filter 需要连接到一个独立的 CollectionContainerKeyValueCollectionContainer 中定义的数据加载器。过滤器生成一个 Condition 对象,后续加载器使用这个条件从 数据存储 加载数据。对于 JPA 实体,数据存储会修改生成的 JPQL 查询语句,因此数据过滤是在数据库级别完成的,从数据库仅加载了过滤后的数据至应用程序内存。

默认情况下,Jmix Studio 创建实体浏览界面和主从界面时会生成 Filter 组件。

在 XML 描述中声明 filter 的例子如下:

<data>
    <collection id="customersDc" class="ui.ex1.entity.Customer">
        <fetchPlan extends="_base">
            <property fetchPlan="_base" name="city"/>
            <property name="favouriteBrands" fetchPlan="_base"/>
        </fetchPlan>
        <loader id="customersDl">
            <query>
                <![CDATA[select e from uiex1_Customer e]]>
            </query>
        </loader>
    </collection>
</data>
<layout spacing="true" expand="customersTable">
    <filter dataLoader="customersDl" caption="Simple filter">
        <properties include=".*"/>
    </filter>
    <table id="customersTable"
           width="100%"
           dataContainer="customersDc">
        <columns>
            <column id="level"/>
            <column id="age"/>
            <column id="hobby"/>
            <column id="firstName"/>
            <column id="lastName"/>
            <column id="city"/>
            <column id="rewardPoints"/>
        </columns>
    </table>
</layout>

上面例子中,数据容器包含了 Customer 实体实例的集合。数据加载用 JPQL 查询语句加载集合。filter 组件通过 dataLoader 属性连接至数据加载器。数据通过与数据容器连接的 Table 组件展示。

一个典型的过滤器是这样的:

filter anatomy
  • 下拉菜单显示保存的过滤器和配置 (2).

  • 带下拉框的 Refresh(刷新) 按钮 (3)。

  • 运算符选择器 (4).

  • 条件值字段 (5).

  • 过滤器设置按钮 (6).

默认情况下,这个组件使用快速过滤模式。用户可以添加一组过滤条件进行一次数据搜索,一旦这个界面关掉之后,设置的过滤条件也就没了。

快速过滤示例

如果我们有 Customer 实体,并想实现下列功能:

  • Customer 浏览界面创建多条件的快速过滤器。

  • 保存该过滤器以便将来使用。

创建快速过滤

  • 点击 Add search condition(添加搜索条件) 链接(1)。

  • Properties(属性) 列表中选择 Age 属性。

  • 选择 Hobby 属性。

    选择的条件在过滤器面板顶部展示。

  • 修改条件值字段和运算符:

filter sample

保存过滤器

  • 点击过滤器设置图标(6),选择 Save with values(带值保存)

  • Save filter configuration - 保存过滤器配置 窗口内填写新的过滤器配置名称:

    filter sample save

之后,过滤器会保存并展示在 Refresh(刷新) 按钮的下拉列表中(3)。

filter sample refresh

Reset filter(重置过滤器) 菜单项可以用来重置当前已应用的搜索条件。

增加条件

如需创建一个快速过滤器,点击 Add search condition(添加搜索条件) 链接(1),会显示 Add condition(添加条件) 的界面:

filter add condition

下列是可用的过滤条件类型:

  • Properties(属性) - 实体和关联实体的属性,条件树展示持久化和 动态 实体属性。这些属性按照 properties 元素定义的规则展示。

  • Predefined conditions(预定义条件) 是开发者在 XML 描述的 conditions 元素中定义的条件。预定义条件最初不会添加至任何配置中,用户可以在 Add Condition(添加条件) 界面选择并添加至 运行时配置

  • Configurations(过滤器配置) 可以在设计时或运行时创建(通过 配置编辑器)。

选中的过滤条件会在过滤器区域顶部显示。这个 filter remove condition 条件删除图标会在每个条件的旁边显示,允许删除已选择的条件。

Create(新建) 按钮的下拉列表展示 已注册 的过滤器组件。默认有三个过滤器组件可用,PropertyFilterJpqlFilterGroupFilter

filter create filter button

项目中如果添加了 搜索 扩展组件,则还可以使用 全文搜索条件

因此用户有机会再运行时创建过滤器条件。

属性条件

Property conditions editor(属性条件编辑器) 支持用户配置 PropertyFilter 组件的属性。PropertyFilter 与实体属性相关。

filter property conditions

Property(属性) 字段选择实体属性。

Operation(运算符) 字段支持选择条件的 运算符。根据属性类型不同运算符也不同。

Parameter name(参数名) 属性用于设置查询参数的名称。可以用该名称引入配置中过滤器的相互依赖。如果未定义,则参数名随机生成。

可以在 Caption(标题) 字段设置属性过滤器条件的自定义标题。

Operation editable(运算符可编辑) 复选框设置是否显示运算符选择器。如果勾选,则支持在运行时选择条件运算符。

Operation caption visible(运算符标题可见) 复选框定义运算符文本的可见性。

可以在 Default value(默认值) 字段设置过滤条件的默认值。

JPQL 条件

JPQL conditions editor(JPQL 条件编辑器) 支持用户创建基于 JPQL 表达式的条件。

filter jpql conditions

Parameter type(参数类型) 字段,选择条件参数的 Java 类。No parameter 值支持创建无参数的条件。示例:

filter jpql conditions no parameters

Caption(标题) 字段必需。设置过滤器中该条件的显示名称。

Parameter name(参数名) 属性设置关联的查询语句参数的名称。可以用该名称引入配置中过滤器的相互依赖。如果未定义,则参数名随机生成。

Has IN expression(有 IN 表达式) 复选框定义 JPQL 表达式是否需要包含 IN 表达式。如果勾选,应用程序会使用 ValuesPicker 组件创建条件值列表。

可以在 Default value(默认值) 字段设置过滤条件的默认值。

Join 字段支持指定一个 JQPL 表达式,该表达式会被添加在数据加载器查询语句的 from 部分。如果要依赖关联实体集合的属性来创建一个复杂的过滤条件,可以用这个属性。这个属性值应该以 joinleft join 语句开头。表达式中用 {E} 占位符表示选择实体,而非实体的别名。

filter jpql conditions join

Where 字段支持指定一个 JQPL 表达式,该表达式会被添加在数据加载器查询语句的 where 部分。表达式中用 {E} 占位符表示选择实体,而非实体的别名。如果参数在上述 Parameter type(参数类型) 字段定义,则条件中最多只能有一个参数,用 ? 表示。除了这种需要用户输入的参数外,还可以使用 会话和用户属性 中的任意参数,示例:

{E}.code = ? and {E}.area = :session_area

组合条件

Group conditions editor(组合条件编辑器) 支持用户将多个条件组合成一个逻辑组合条件。

filter group conditions

Operation(运算符) 下拉列表可以选择逻辑运算符。

Caption(标题) 字段必需。设置过滤器中该条件的显示名称。

Operation caption visible(运算符标题可见) 复选框定义运算符文本的可见性。

如需添加条件,点击 Add(添加) 按钮。展示 Add condition(添加条件) 界面。

过滤器条件包含在树中。用户可以用 filter group conditions move down/filter group conditions move up 按钮调整条件的顺序,用 Remove(删除)Edit(编辑) 按钮删除或编辑。

配置

这里配置指的是一组过滤器组件。

LogicalFilterComponent 是配置的根元素。

配置不会存储所有组件的引用,而只保存至根元素的引用,从根元素可以获取其他过滤器组件。

配置可以在设计时或运行时通过 运行时配置编辑器 创建。

设计时配置

设计时的配置不能在运行时修改。但是,用户仍然可以用 Copy 操作将设计时配置的所有条件复制到运行时的配置中。

所有设计时配置都与保存的过滤器和配置一起在下拉菜单(2)中展示。

filter design time configuration

XML 描述中带有设计时配置的过滤器示例如下:

<filter dataLoader="customersDl"
        id="filterDesignTime"
        caption="Filter with design-time configurations">
    <properties include=".*"/>
    <configurations>
        <configuration id="configuration_age_hobby" operation="AND"
                       name="Age AND Hobby Configuration" default="true">
            <propertyFilter property="age" operation="GREATER"/>
            <propertyFilter property="hobby" operation="IN_LIST"/>
        </configuration>
        <configuration id="configuration_level_rewards_points" operation="OR"
                       name="Level OR Rewards Points Configuration">
            <propertyFilter property="level" operation="EQUAL"/>
            <propertyFilter property="rewardPoints" operation="LESS_OR_EQUAL"/>
        </configuration>
    </configurations>
</filter>

id 是必需属性,且在此过滤器中唯一。如果未指定 name 属性,那么 id 将作为 消息包 中的键值。

default XML 属性为过滤器设置默认的设计时配置。界面打开时自动展示。

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

运行时配置

如需在运行时创建、编辑或删除配置,用户需要有 ui.filter.modifyConfiguration 许可。

用配置(6)中的 Edit(编辑) 操作打开 Configuration editor(配置编辑器)

filter run time configuration

Configuration name(配置名称) 字段必需。配置名称与保存的过滤器和配置一起在下拉菜单(2)中展示。

Available for all users(所有用户可用) 复选框设置所有用户都能使用。有 ui.filter.modifyGlobalConfiguration 特殊权限的用户才能使用该复选框。

Default for all users(所有用户默认) 复选框设置当用户打开界面时,是否默认选择创建的配置。仅在 Available for all users(所有用户可用) 勾选时可用。

Configuration editor(配置编辑器) 的其他字段在 组合条件 中介绍。

过滤器元素

XML 中定义的 filter 可以包含内部元素。用于定义用户在 Add Condition(添加条件) 窗口中可选择的条件:

属性

properties 元素可以配置多个实体属性用于选择。该元素有下列属性:

  • include 必带属性。包含一个正则表达式,能匹配实体的属性名称。

  • exclude - 包含一个正则表达式,如果实体属性能匹配此项,那么会从之前的 include 配置中排除掉。

  • excludeProperties - 包含一个英文逗号分隔的应该被排除掉的属性路径列表。跟之前的 exclude 不同,这里支持遍历实体关系图,比如 customer.name

  • excludeRecursively - 设置 excludeProperties 里面定义的属性是否需要递归的排除掉。如果设置的 true,那么属性和它的嵌套属性,只要是相同名称的,都会被排除掉。

下面的例子中,我们声明带有 properties 内部元素的 filter 组件:

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

使用 + 前缀可以选择是否包含 动态属性,示例:

<filter id="filter"
        dataLoader="carsDl">
    <properties include=".*"
                excludeProperties="+PassengerNumberofseats"/>
</filter>

界面中不需要有 dynamicAttributes facet。

注意,如果动态属性是一个实体,则该实体内部的属性无法用来进行过滤。

使用 properties 时,实体的下列属性会被忽略:

  • 由于 安全许可 限制而不能访问的属性。

  • 集合属性(@OneToMany@ManyToMany)。

  • 非持久化属性。

  • 使用 @SystemLevel 注解的属性。

  • byte[] 类型的属性。

conditions

conditions 元素用来创建 预定义条件

下面的例子中,我们声明带有 conditions 内部元素的 filter 组件:

<filter id="filterWithСonditions"
        dataLoader="customersDl">
    <properties include=".*"/>
    <conditions>
        <propertyFilter property="hobby"
                        operation="NOT_IN_LIST"
                        operationEditable="true"
                        caption="Hobby condition"/>
    </conditions>
</filter>

conditions 元素可以包含任意数量的 propertyFilterjpqlFiltergroupFilter

如需在 Jmix Studio 中添加 conditions,可以在界面 XML 或者 Component Hierarchy 面板中选择组件,然后点击 Component Inspector 面板的 Add→Conditions 按钮。

configurations

configurations 元素用来创建 设计时配置

actions

actions - 可选元素,定义过滤器管理的操作列表。

框架在过滤器设置按钮(6filter settings popup 中提供下列默认操作:

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

  • Save with values(带值保存) - 由 FilterSaveWithValuesAction 实现(XML 中 type="filter_saveWithValues"),保存对过滤器的修改至当前配置,且使用条件字段(5)中的值作为过滤器的默认值。

  • Save as(另存为) - 由 FilterSaveAsAction 实现(XML 中 type="filter_saveAs"),将过滤器配置另存为新名称。

  • Edit(编辑) - 由 FilterEditAction 实现(XML 中 type="filter_edit"),编辑当前 运行时过滤器配置(打开 Configuration editor(配置编辑器) 界面)。对 设计时配置 禁用。

  • Remove(删除) - 由 FilterRemoveAction 实现(XML 中 type="filter_remove"),删除当前运行时过滤器配置。对 设计时配置 禁用。

  • Make default(设为默认) - 由 FilterMakeDefaultAction 实现(XML 中 type="filter_makeDefault"),将过滤器配置设置成界面默认。当界面打开时,这个过滤器会自动显示在过滤器区域。优先于设计时配置的 default 属性和运行时勾选的 Default for all users((所有用户默认))。如果界面未添加 screenSettings facet,则该功能不可用。

  • Copy(复制) - 由 FilterCopyAction 实现(XML 中 type="filter_copy"),将设计时配置的所有条件复制到运行时配置。

  • Clear values(清空值) - 由 FilterClearValuesAction 实现(XML 中 type="filter_clearValues"),清空过滤器条件值(5)。

  • Add(添加)FilterAddConditionAction 实现(XML 中 type="filter_addCondition"),为当前过滤器配置增加条件。

用户可以用内部的 actions 元素覆盖 默认 操作。示例:

<filter id="filterWithActions"
        dataLoader="customersDl">
    <properties include=".*"/>
    <actions>
        <action id="addCondition" type="filter_addCondition"/>
        <action id="clearValues" type="filter_clearValues"/>
    </actions>
</filter>

如需在 Jmix Studio 中添加 action,可以在界面 XML 或者 Component Hierarchy 面板中选择组件,然后点击 Component Inspector 面板的 Add→Action 按钮。

可以用 action 元素的 XML 属性配置通用的操作参数,参阅 Actions 了解详情。

过滤器属性

autoApply

autoApply 属性指定过滤器的应用时机。如果属性为 false,过滤器只有在每次点击 Refresh(刷新) 按钮时应用。如果属性为 true,则每次修改过滤器组件时会自动应用。默认值通过 jmix.ui.component.filter-auto-apply 属性定义。

columnsCount

columnsCount 设置一行显示的列数。默认值在 jmix.ui.component.filter-columns-count 属性设置。

captionPosition

captionPosition 属性定义过滤器子组件标题的位置:TOPLEFT,默认为 LEFT

权限许可

过滤器的高级管理功能需要特定的许可:

  • 如需新建、修改、删除过滤器 配置,用户需要有 ui.filter.modifyConfiguration 特殊权限。

  • 如需新建、修改运行时 JPQL 条件,用户需要有 ui.filter.modifyJpqlCondition 特殊权限。

可以直接给用户设置预定义的 UI: edit filters 资源角色,或自定义 角色 配置需要的权限许可。

编程式创建过滤器

下面示例中,我们将创建一个带 设计时配置Filter 组件并将该组件添加至 XML 描述定义的标签页中。

UiComponents 工厂在控制器中创建 Filter 组件。

@Autowired
protected UiComponents uiComponents;

@Autowired
protected CollectionLoader<Customer> customersDl;

@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onAfterInit(AfterInitEvent event) {
    Filter filter = uiComponents.create(Filter.NAME); (1)
    filter.setId("programmaticFilter");
    filter.setDataLoader(customersDl);
    filter.loadConfigurationsAndApplyDefault();

    DesignTimeConfiguration javaDefaultConfiguration =
            filter.addConfiguration("javaDefaultConfiguration",
                    "Default configuration"); (2)

    PropertyFilter<Integer> agePropertyFilter =
            uiComponents.create(PropertyFilter.NAME); (3)

    agePropertyFilter.setConditionModificationDelegated(true);
    agePropertyFilter.setDataLoader(customersDl);
    agePropertyFilter.setProperty("age");
    agePropertyFilter.setOperation(PropertyFilter.Operation.LESS_OR_EQUAL);
    agePropertyFilter.setOperationEditable(true);
    agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            agePropertyFilter.getProperty()));
    agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            customersDl.getContainer().getEntityMetaClass(),
            agePropertyFilter.getProperty(),
            agePropertyFilter.getOperation())); (4)

    javaDefaultConfiguration.getRootLogicalFilterComponent().add(agePropertyFilter); (5)
    filter.setCurrentConfiguration(javaDefaultConfiguration); (6)

    VBoxLayout tab = (VBoxLayout) getWindow()
            .getComponentNN("programmaticFilterTab"); (7)
    tab.add(filter); (8)
}
1 创建 Filter 并设置其属性。
2 添加设计时配置,id 为 javaDefaultConfiguration,名称为 Default configuration
3 创建 PropertyFilter 并设置其属性。
4 通过给定的 metaClass、实体属性和运算符生成过滤器值组件。
5 将创建的属性过滤器添加至 javaDefaultConfiguration 配置。
6 设置当前配置为 javaDefaultConfiguration 配置。
7 通过 id 获取标签页。
8 将创建的 Filter 组件添加至 programmaticFilterTab 标签页。

事件和处理器

如需使用 Jmix Studio 生成处理器的桩代码,需要在界面 XML 描述或者 Jmix UI 层级结构面板选中该组件,然后用 Jmix UI 组件面板的 Handlers 标签页生成。

或者可以使用界面控制器顶部面板的 Generate Handler 按钮。

ContextHelpIconClickHandler

ExpandedStateChangeEvent

ConfigurationChangeEvent

ConfigurationChangeEvent配置 修改后发送。下面例子展示订阅 filter 的该事件:

@Subscribe("filter")
public void onFilterConfigurationChange(Filter.ConfigurationChangeEvent event) {
    notifications.create()
            .withCaption("Before: " + event.getPreviousConfiguration().getName() +
                    ". After: " + event.getNewConfiguration().getName())
            .show();
}

如需以编程的方式注册事件处理器,使用组件的 addConfigurationChangeListener() 方法。

PropertiesFilterPredicate

如需以编程的方式 包含排除 属性,使用 PropertiesFilterPredicate

@Install(to = "filter", subject = "propertiesFilterPredicate")
private boolean filterPropertiesFilterPredicate(MetaPropertyPath metaPropertyPath) {
    return !metaPropertyPath.getMetaProperty().getName().equals("hobby");
}

这个判断被添加到当前的属性过滤判断中,并测试具有给定路径的属性是否可用于过滤。

如需以编程的方式添加判断,使用组件的 addPropertiesFilterPredicate() 方法。生成的判断是一个组合判断,由给定的判断和当前属性过滤的判断一起组成一个 AND 条件。

XML 属性

可以使用 Studio 界面设计器的 Jmix UI 组件面板查看和编辑组件的属性。

Filter XML 元素