genericFilter 的组件

对 genericFilter 的一些固定配置可以在 运行时 或 设计时 进行配置。本章提供设计时 genericFilter 的配置说明,包含三种预定义的过滤器组件:

框架支持自定义过滤器组件,并在 genericFilter 中使用。参阅 注册过滤器组件 章节。

propertyFilter

propertyFilter - 属性过滤器 可以基于实体的特定属性添加过滤条件。

该组件也可以单独使用。参阅 propertyFilter 属性过滤器。

本节的声明式和编程式配置都可以在视图中创建如下过滤器:

声明式配置

genericFilter 的配置可以在视图的 XML 文件中声明式指定。以下示例展示如何配置 propertyFilter:

<layout>
    <genericFilter dataLoader="customerDl"
                   id="genericFilterProperty"> (1)
        <properties include=".*"/>
        <configurations>
            <configuration id="propertyConfiguration"
                           default="true"
                           name="PropertyFilter">
                <propertyFilter property="age"
                                operation="GREATER_OR_EQUAL"
                                operationEditable="true"/> (2)
            </configuration>
        </configurations>
    </genericFilter>
</layout>
1 genericFilter 组件的绑定了数据加载器。
2 propertyFilter 根据 age 属性配置了一个过滤条件。

编程式配置

另一种定义的方式是在视图控制器中编程式配置:

@Autowired
private UiComponents uiComponents;

@ViewComponent
private GenericFilter pfdtcGenericFilter;

@Autowired
private SingleFilterSupport singleFilterSupport;

@Subscribe
public void onInit(final InitEvent event) {
    DesignTimeConfiguration javaDefaultConfigurationPF =
            pfdtcGenericFilter.addConfiguration("javaDefaultConfiguration",
                    "PropertyFilter configuration"); (1)
    DataLoader dataLoaderPF = pfdtcGenericFilter.getDataLoader();

    PropertyFilter<Integer> agePropertyFilter =
            uiComponents.create(PropertyFilter.class); (2)
    agePropertyFilter.setConditionModificationDelegated(true);
    agePropertyFilter.setDataLoader(dataLoaderPF);
    agePropertyFilter.setProperty("age");
    agePropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
    agePropertyFilter.setOperationEditable(true);
    agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
            agePropertyFilter.getProperty()));
    agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoaderPF.getContainer().getEntityMetaClass(),
            agePropertyFilter.getProperty(),
            agePropertyFilter.getOperation())); (3)
    javaDefaultConfigurationPF.getRootLogicalFilterComponent()
            .add(agePropertyFilter); (4)

    pfdtcGenericFilter.setCurrentConfiguration(javaDefaultConfigurationPF); (5)
}
1 添加一个设计时配置。方法接收两个参数:配置id和配置名。
2 创建一个 PropertyFilter 实例并设置其属性。
3 基于 metaClass、属性和运算符为该过滤器创建一个组件。
4 将过滤器添加至配置中。LogicalFilterComponent 是配置的根元素。
5 设置为当前配置。

jpqlFilter

jpqlFilter - JPQL 过滤器 支持使用 JPQL 查询进行过滤。原理是修改数据加载器的查询语句,添加可选的 join 和必需的 where 子句,实现对查询结果的修改。

本节的声明式和编程式配置都可以在视图中创建如下过滤器:

声明式配置

A genericFilter configuration can be specified declaratively, inside the XML view descriptor. See the following example for configuration with jpqlFilter:

<layout>
    <genericFilter dataLoader="customerDl"
                   id="genericFilterJpql"> (1)
        <properties include=".*"/>
        <configurations>
            <configuration id="jpqlConfiguration"
                           default="true"
                           name="JpqlFilter">
                <jpqlFilter parameterClass="java.lang.String"
                            label="City name is">
                    <condition>
                        <jpql>
                            <join>join {E}.city c</join> (2)
                            <where>c.name = ?</where> (3)
                        </jpql>
                    </condition>
                </jpqlFilter>
            </configuration>
        </configurations>
    </genericFilter>
</layout>
1 genericFilter 组件的绑定了数据加载器。
2 可选的 join 子句。
3 必需的 where 子句。? 表示需要由用户输入的参数。

当 parameterClass 是实体类型时,jpqlFilter 将所选实体的 标识符 作为查询参数传入,而非实体实例本身。与 where 子句中的关联实体 ID 进行比较,例如 {E}.customer.id = ? 。直接比较关联实体引用({E}.customer = ?)不会返回任何结果。

编程式配置

另一种定义的方式是在视图控制器中编程式配置:

@Autowired
private UiComponents uiComponents;

@Autowired
private SingleFilterSupport singleFilterSupport;

@ViewComponent
private GenericFilter jfdtcGenericFilter;

@Autowired
private JpqlFilterSupport jpqlFilterSupport;

@Subscribe
public void onInit(final InitEvent event) {
    DesignTimeConfiguration javaDefaultConfigurationJF =
            jfdtcGenericFilter.addConfiguration("javaDefaultConfiguration", "JpqlFilter configuration"); (1)
    DataLoader dataLoaderJF = jfdtcGenericFilter.getDataLoader();

    JpqlFilter<String> jpqlFilter =
            uiComponents.create(JpqlFilter.class); (2)
    jpqlFilter.setConditionModificationDelegated(true);
    jpqlFilter.setDataLoader(dataLoaderJF);
    jpqlFilter.setCondition("c.name = ?", "join {E}.city c");
    jpqlFilter.setParameterClass(String.class);
    jpqlFilter.setLabel("City name is");
    jpqlFilter.setParameterName(jpqlFilterSupport.generateParameterName(
            String.valueOf(jpqlFilter.getId()),
            jpqlFilter.getParameterClass().getSimpleName()));
    jpqlFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoaderJF.getContainer().getEntityMetaClass(),
            jpqlFilter.hasInExpression(),
            jpqlFilter.getParameterClass())); (3)
    javaDefaultConfigurationJF.getRootLogicalFilterComponent()
            .add(jpqlFilter); (4)

    jfdtcGenericFilter.setCurrentConfiguration(javaDefaultConfigurationJF); (5)
}

无参数过滤器

jpqlFilter 还支持创建无参数条件,用户只能选择是否使用该条件。

例如,直接在 where 子句中设置城市的名称。用户只能选择显示该城市的客户:

<layout>
    <genericFilter id="noParameterFilter"
            dataLoader="customerDl">
        <properties include=".*"/>
        <configurations>
            <configuration id="jpqlConfigurationNoParams"
                           name="JpqlFilter No parameters">
                <jpqlFilter label="Show customers from London"
                            parameterClass="java.lang.Void"
                            defaultValue="true"> (1)
                    <condition>
                        <jpql>
                            <join>join {E}.city c</join>
                            <where>c.name = 'London'</where> (2)
                        </jpql>
                    </condition>
                </jpqlFilter>
            </configuration>
        </configurations>
    </genericFilter>
</layout>
1 parameterClass="java.lang.Void" 表示过滤器无参数,defaultValue=true 表示会使用该条件。
2 城市名固定为 'London' 且无法在运行时修改。

另一种定义的方式是在视图控制器中编程式配置:

@Autowired
private UiComponents uiComponents;

@Autowired
private SingleFilterSupport singleFilterSupport;

@ViewComponent
private GenericFilter jfdtcGenericFilterNoParameter;

@Autowired
private JpqlFilterSupport jpqlFilterSupport;

@Subscribe
public void onInit(final InitEvent event) {
    DesignTimeConfiguration javaConfiguration = jfdtcGenericFilterNoParameter
            .addConfiguration("javaConfiguration", "No-parameter JpqlFilter configuration");
    DataLoader dataLoaderNoParam = jfdtcGenericFilterNoParameter.getDataLoader();

    JpqlFilter<Boolean> jpqlFilterNoParameter = uiComponents.create(JpqlFilter.class);
    jpqlFilterNoParameter.setConditionModificationDelegated(true);
    jpqlFilterNoParameter.setDataLoader(dataLoaderNoParam);
    jpqlFilterNoParameter.setCondition("c.name = 'London'", "join {E}.city c");
    jpqlFilterNoParameter.setParameterClass(Void.class);
    jpqlFilterNoParameter.setLabel("Show customers from London");
    jpqlFilterNoParameter.setParameterName(jpqlFilterSupport
            .generateParameterName(
                    String.valueOf(jpqlFilterNoParameter.getId()),
                    jpqlFilterNoParameter.getParameterClass().getSimpleName()));
    jpqlFilterNoParameter.setValueComponent(singleFilterSupport
            .generateValueComponent(dataLoaderNoParam.getContainer().getEntityMetaClass(),
                    jpqlFilterNoParameter.hasInExpression(),
                    jpqlFilterNoParameter.getParameterClass()));

    jpqlFilterNoParameter.setValue(true);
    javaConfiguration.setFilterComponentDefaultValue(
            jpqlFilterNoParameter.getParameterName(),
            jpqlFilterNoParameter.getValue());

    jfdtcGenericFilterNoParameter.setCurrentConfiguration(javaConfiguration);

    javaConfiguration.getRootLogicalFilterComponent()
            .add(jpqlFilterNoParameter);
}

groupFilter

groupFilter - 组合条件过滤器 是将多个条件绑定为一组。组内的条件可以使用逻辑运算符(AND 或 OR)连接。本节的声明式和编程式配置都可以在视图中创建如下过滤器:

声明式配置

genericFilter 的配置可以在视图的 XML 文件中声明式指定。以下示例展示如何配置 groupFilter,组合了两个 propertyFilter:

<genericFilter id="genericFilterGroup"
        dataLoader="customerDl">
    <properties include=".*"/>
    <configurations>
        <configuration id="groupFilter"
                       name="groupFilter"
                       default="true">
            <groupFilter operation="OR"> (1)
                <propertyFilter property="rewardPoints"
                                operation="GREATER_OR_EQUAL"
                                operationEditable="true"/>
                <propertyFilter property="hobby"
                                operation="EQUAL"
                                operationEditable="true"/>
            </groupFilter>
        </configuration>
    </configurations>
</genericFilter>

编程式配置

另一种定义的方式是在视图控制器中编程式配置:

@Autowired
private UiComponents uiComponents;

@Autowired
private SingleFilterSupport singleFilterSupport;

@ViewComponent
private GenericFilter gfdtcGenericFilter;

@Subscribe
public void onInit(final InitEvent event) {
    DesignTimeConfiguration javaDefaultConfigurationGF =
            gfdtcGenericFilter.addConfiguration("javaDefaultConfiguration",
                    "GroupFilter configuration"); (1)
    DataLoader dataLoaderGF = gfdtcGenericFilter.getDataLoader();

    GroupFilter groupFilter =
            uiComponents.create(GroupFilter.class); (2)
    groupFilter.setConditionModificationDelegated(true);
    groupFilter.setDataLoader(dataLoaderGF);
    groupFilter.setOperation(LogicalFilterComponent.Operation.OR); (3)

    PropertyFilter<Integer> rewardsPropertyFilter =
            uiComponents.create(PropertyFilter.class);
    rewardsPropertyFilter.setConditionModificationDelegated(true);
    rewardsPropertyFilter.setDataLoader(dataLoaderGF);
    rewardsPropertyFilter.setProperty("rewardPoints");
    rewardsPropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
    rewardsPropertyFilter.setOperationEditable(true);
    rewardsPropertyFilter.setParameterName(PropertyConditionUtils
            .generateParameterName(rewardsPropertyFilter.getProperty()));
    rewardsPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoaderGF.getContainer().getEntityMetaClass(),
            rewardsPropertyFilter.getProperty(),
            rewardsPropertyFilter.getOperation()));

    groupFilter.add(rewardsPropertyFilter); (4)

    PropertyFilter<String> hobbyPropertyFilter =
            uiComponents.create(PropertyFilter.class);
    hobbyPropertyFilter.setConditionModificationDelegated(true);
    hobbyPropertyFilter.setDataLoader(dataLoaderGF);
    hobbyPropertyFilter.setProperty("hobby");
    hobbyPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
    hobbyPropertyFilter.setOperationEditable(true);
    hobbyPropertyFilter.setParameterName(PropertyConditionUtils
            .generateParameterName(hobbyPropertyFilter.getProperty()));
    hobbyPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
            dataLoaderGF.getContainer().getEntityMetaClass(),
            hobbyPropertyFilter.getProperty(),
            hobbyPropertyFilter.getOperation()));

    groupFilter.add(hobbyPropertyFilter); (5)
    javaDefaultConfigurationGF.getRootLogicalFilterComponent()
            .add(groupFilter); (6)
}
1 添加一个设计时配置,方法接收两个参数:配置id和配置名。
2 创建 GroupFilter 组件,并设置其属性。
3 设置 OR 运算符。
4 添加 PropertyFilter 作为第一个条件,按照奖励点数对用户进行过滤。
5 添加 PropertyFilter 作为第二个条件,按照爱好对用户进行过滤。
6 将创建的组过滤器添加至配置。

注册过滤器组件

如需在框架内创建并注册 UI 过滤器组件,需要以下对象:

  • 一个组件类 - UI 组件,展示在 genericFilter 内部。

  • 一个模型类 - 保存过滤器组件的非持久化状态。模型类用来保存过滤器组件状态至数据库并在运行时展示该状态。模型类需要继承 FilterCondition 类。参考 PropertyFilterCondition 类作为示例。

  • 一个转换器类 - 在组件和模型之间转换。转换器类需实现 FilterConverter 接口。

  • 一个模型的详情界面。其标识符可以通过 withDetailViewId 方法指定。如果未指定标识符,则标识符默认为 JmixEnity 获取的模型名称加上 ViewRegistry.DETAIL_VIEW_SUFFIX 后缀。

PropertyFilter 注册示例:

@Bean("flowui_PropertyFilterRegistration")
public FilterComponentRegistration registerPropertyFilter() {
    return FilterComponentRegistrationBuilder.create(PropertyFilter.class,
                    PropertyFilterCondition.class,
                    PropertyFilterConverter.class)
            .build();
}

所有注册的过滤器组件都在 Add condition 对话框的 Create 中显示。

可以替换 Jmix 框架中注册的过滤器组件为自定义的组件,只需在 FilterComponentRegistration bean 使用 @Order 注解提高自定义组件的优先级。

样式版本

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

样式 描述 支持的主题

No predefined variants

内置的 propertyFilter、jpqlFilter 和 groupFilter 组件并未定义任何样式版本。请在应用程序主题中使用 themeNames 配置自定义样式。

自定义主题

XML 属性

下面是 genericFilter-components 支持的通用属性:

事件和处理器

下面是 genericFilter-components 支持的通用事件: