Filter 过滤器

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

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

组件的 XML 名称:filter。

基本用法

Filter 需要连接到一个独立的 CollectionContainer 或 KeyValueCollectionContainer 中定义的数据加载器。过滤器生成一个 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(新建) 按钮的下拉列表展示 已注册 的过滤器组件。默认有三个过滤器组件可用,PropertyFilter、JpqlFilter 和 GroupFilter:

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 部分。如果要依赖关联实体集合的属性来创建一个复杂的过滤条件,可以用这个属性。这个属性值应该以 join 和 left 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 元素可以包含任意数量的 propertyFilter、jpqlFilter 或 groupFilter。

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

configurations

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

actions

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

框架在过滤器设置按钮(6)filter 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 属性定义过滤器子组件标题的位置:TOP 或 LEFT,默认为 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 元素