Компоненты Filter
Filter может использовать специальные компоненты фильтра в качестве условий. Компоненты фильтра должны реализовывать интерфейс FilterComponent
.
По умолчанию доступны три компонента фильтра:
Чтобы создать собственный компонент см. Регистрация компонента Filter.
PropertyFilter
Компонент PropertyFilter
можно использовать внутри компонента Filter
и отдельно.
Приведенный ниже пример показывает, как создать конфигурацию во время разработки с помощью PropertyFilter
в XML-дескрипторе:
<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"
id="filterPropertyFilter"
caption="PropertyFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="propertyConfiguration"
default="true"
name="PropertyFilter">
<propertyFilter property="age"
operation="GREATER_OR_EQUAL"
operationEditable="true"/>
</configuration>
</configurations>
</filter>
</layout>
Также конфигурацию времени разработки можно создать в классе контроллера экрана:
@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaDefaultConfigurationPF =
pfdtcFilter.addConfiguration("javaDefaultConfiguration",
"Default configuration"); (1)
DataLoader dataLoaderPF = pfdtcFilter.getDataLoader();
PropertyFilter<City> cityPropertyFilter =
uiComponents.create(PropertyFilter.NAME); (2)
cityPropertyFilter.setConditionModificationDelegated(true);
cityPropertyFilter.setDataLoader(dataLoaderPF);
cityPropertyFilter.setProperty("city");
cityPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
cityPropertyFilter.setOperationEditable(true);
cityPropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
cityPropertyFilter.getProperty()));
cityPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderPF.getContainer().getEntityMetaClass(),
cityPropertyFilter.getProperty(),
cityPropertyFilter.getOperation())); (3)
javaDefaultConfigurationPF.getRootLogicalFilterComponent()
.add(cityPropertyFilter); (4)
PropertyFilter<Level> levelPropertyFilter =
uiComponents.create(PropertyFilter.NAME);
levelPropertyFilter.setConditionModificationDelegated(true);
levelPropertyFilter.setDataLoader(dataLoaderPF);
levelPropertyFilter.setProperty("level");
levelPropertyFilter.setOperation(PropertyFilter.Operation.EQUAL);
levelPropertyFilter.setOperationEditable(true);
levelPropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
levelPropertyFilter.getProperty()));
levelPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderPF.getContainer().getEntityMetaClass(),
levelPropertyFilter.getProperty(),
levelPropertyFilter.getOperation()
));
javaDefaultConfigurationPF.getRootLogicalFilterComponent().add(levelPropertyFilter);
pfdtcFilter.setCurrentConfiguration(javaDefaultConfigurationPF); (5)
}
1 | Добавляет конфигурацию во время разработки с id javaDefaultConfiguration и именем Default configuration . |
2 | Создает компонент PropertyFilter и задает его свойства. |
3 | Генерирует компонент значения фильтра по заданному metaClass, свойству сущности и операции. |
4 | Добавляет созданный фильтр свойств в конфигурацию javaDefaultConfiguration . |
5 | Устанавливает конфигурацию javaDefaultConfiguration в качестве текущей. |
Дополнительную информацию см. в разделе PropertyFilter.
JpqlFilter
JpqlFilter
– это компонент UI, используемый для фильтрации сущностей, которых возвращает DataLoader
. Он содержит выражения JPQL, которые будут добавлены в секции from
и where
запроса загрузчика данных. Данный компонент может автоматически отображать правильную компоновку для установки значения условия. В общем случае компоновка JpqlFilter
содержит надпись и поле для редактирования значения условия. Данный компонент можно использовать только внутри компонента Filter
.
Приведенный ниже пример показывает, как создать конфигурацию во время разработки с помощью JpqlFilter
:
<window xmlns="http://jmix.io/schema/ui/window"
caption="msg://filterScreen.caption"
xmlns:c="http://jmix.io/schema/ui/jpql-condition"> (1)
<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 id="filterJpqlFilter"
dataLoader="customersDl"
caption="JpqlFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="jpqlConfiguration"
default="true"
name="JpqlFilter">
<jpqlFilter caption="Name like"
parameterClass="java.lang.String">
<condition>
<c:jpql>
<c:where>{E}.firstName like ?</c:where> (2)
</c:jpql>
</condition>
</jpqlFilter>
</configuration>
</configurations>
</filter>
</layout>
</window>
1 | Вы должны добавить пространство имен условий JPQL. |
2 | Определите условие JPQL с необязательным элементом join и обязательным элементом where . |
Чтобы настроить условие JPQL, определите элемент condition
внутри jpqlFilter
с необязательным элементом join и обязательным элементом where. В приведенном ниже примере создадим jpqlFilter
с элементами join
и where
:
<filter id="filterJpqlFilter"
dataLoader="customersDl"
caption="JpqlFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="jpqlConfigurationWithJoin"
name="JpqlFilter with Join">
<jpqlFilter caption="Customers with brand"
parameterClass="ui.ex1.entity.Brand">
<condition>
<c:jpql>
<c:join>join {E}.favouriteBrands i</c:join>
<c:where>i.id = ?</c:where>
</c:jpql>
</condition>
</jpqlFilter>
</configuration>
</configurations>
</filter>
Атрибуты jpqlFilter
внутри компонента filter
:
-
Используя атрибут
defaultValue
можно установить значение по умолчанию для условия фильтра.
-
Для атрибута
hasInExpression
должно быть установлено значениеtrue
, если выражение JPQL содержит условияin (?)
. В этом случае приложение будет использовать компонент ValuesPicker. Таким образом, пользователь сможет ввести несколько значений параметров условия.Ниже приведен пример
jpqlFilter
с атрибутомhasInExpression
:<filter id="filterJpqlFilter" dataLoader="customersDl" caption="JpqlFilter variations"> <properties include=".*"/> <configurations> <configuration id="jpqlConfigurationInExpr" name="JpqlFilter with IN expression"> <jpqlFilter caption="City in" parameterClass="ui.ex1.entity.City" hasInExpression="true"> <condition> <c:jpql> <c:where>{E}.city in ?</c:where> </c:jpql> </condition> </jpqlFilter> </configuration> </configurations> </filter>
-
parameterClass
– обязательный атрибут; определяет класс Java параметра условия.
-
parameterName
– имя параметра запроса. Это имя можно использовать для введения зависимостей между компонентами фильтра в конфигурации. Если значение не задано, то имя параметра генерируется случайным образом.
Также конфигурацию времени разработки можно создать в классе контроллера экрана:
@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaDefaultConfigurationJF =
jfdtcFilter.addConfiguration("javaDefaultConfiguration",
"Default configuration"); (1)
DataLoader dataLoaderJF = jfdtcFilter.getDataLoader();
JpqlFilter<Brand> jpqlFilter =
uiComponents.create(JpqlFilter.NAME); (2)
jpqlFilter.setFrame(getWindow());
jpqlFilter.setConditionModificationDelegated(true);
jpqlFilter.setDataLoader(dataLoaderJF);
jpqlFilter.setCondition("i.id = ?", "join {E}.favouriteBrands i");
jpqlFilter.setParameterClass(Brand.class);
jpqlFilter.setCaption("Select the brand");
jpqlFilter.setParameterName(jpqlFilterSupport.generateParameterName(
jpqlFilter.getId(),
jpqlFilter.getParameterClass().getSimpleName()));
jpqlFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderJF.getContainer().getEntityMetaClass(),
jpqlFilter.hasInExpression(),
jpqlFilter.getParameterClass())); (3)
javaDefaultConfigurationJF.getRootLogicalFilterComponent()
.add(jpqlFilter); (4)
jfdtcFilter.setCurrentConfiguration(javaDefaultConfigurationJF); (5)
}
1 | Добавляет конфигурацию во время разработки с id javaDefaultConfiguration и именем Default configuration . |
2 | Создает компонент JpqlFilter и задает его свойства. |
3 | Генерирует компонент значения фильтра по заданному metaClass и типу значения. |
4 | Добавляет созданный фильтр JPQL в конфигурацию javaDefaultConfiguration . |
5 | Устанавливает конфигурацию javaDefaultConfiguration в качестве текущей. |
Фильтр без параметров
Можно определить запрос без параметров. Для этого установите значение parameterClass
равным java.lang.Void
и используйте java.lang.Boolean
как значение:
-
true
означает, что выражения JPQL из секцийwhere
иjoin
будут добавлены в запрос загрузчика данных. -
false
не будет загружать выражения из секцийwhere
иjoin
.
Например:
<filter id="parameterlessFilter"
dataLoader="customersDl"
caption="JPQL Filter without Parameters">
<properties include=".*"/>
<configurations>
<configuration id="jpqlConfigurationNoParams"
name="JPQL Filter without Parameters">
<jpqlFilter caption="Customers from London"
parameterClass="java.lang.Void"
defaultValue="true"> (1)
<condition>
<c:jpql>
<c:join>join {E}.city c</c:join> (2)
<c:where>c.name = 'London'</c:where>
</c:jpql>
</condition>
</jpqlFilter>
</configuration>
</configurations>
</filter>
1 | parameterClass="java.lang.Void" определяет, что фильтр не имеет параметров, а defaultValue="true" определяет, что выражения join и where будут добавлены к запросу загрузчика данных по умолчанию. |
2 | Определите условие JPQL с необязательным элементом join и обязательным элементом where . |
Ниже приведен пример создания фильтра JPQL без параметров в классе контроллера экрана:
@Autowired
private Filter parameterlessFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaConfiguration = parameterlessFilter
.addConfiguration("javaConfiguration", "Java configuration");
DataLoader dataLoader = parameterlessFilter.getDataLoader();
JpqlFilter<Boolean> jpqlFilterNoParams = uiComponents.create(JpqlFilter.NAME);
jpqlFilterNoParams.setFrame(getWindow());
jpqlFilterNoParams.setConditionModificationDelegated(true);
jpqlFilterNoParams.setDataLoader(dataLoader);
jpqlFilterNoParams.setCondition("{E}.age > 21", null);
jpqlFilterNoParams.setParameterClass(Void.class);
jpqlFilterNoParams.setCaption("Customer's age > 21");
jpqlFilterNoParams.setParameterName(jpqlFilterSupport
.generateParameterName(jpqlFilterNoParams.getId(),
jpqlFilterNoParams.getParameterClass().getSimpleName()));
jpqlFilterNoParams.setValueComponent(singleFilterSupport
.generateValueComponent(dataLoader.getContainer().getEntityMetaClass(),
jpqlFilterNoParams.hasInExpression(),
jpqlFilterNoParams.getParameterClass()
));
jpqlFilterNoParams.setValue(true);
javaConfiguration.setFilterComponentDefaultValue(
jpqlFilterNoParams.getParameterName(),
jpqlFilterNoParams.getValue());
javaConfiguration.getRootLogicalFilterComponent().add(jpqlFilterNoParams);
}
Конфигурация фильтра JPQL без параметров также может быть создана во время выполнения:
GroupFilter
Компонент GroupFilter
представляет собой композитный компонент, который имеет GroupBoxLayout с ResponsiveGridLayout в качестве корневого контейнера. Этот компонент необходим для объединения нескольких условий в логическую группу с использованием логических операторов (AND
или OR
). Данный компонент можно использовать только внутри компонента Filter
.
Приведенный ниже пример показывает, как создать конфигурацию во время разработки с GroupFilter
:
<filter id="filterGroupFilter"
dataLoader="customersDl"
caption="GroupFilter variations">
<properties include=".*"/>
<configurations>
<configuration id="groupFilter"
name="Simple groupFilter"
default="true">
<groupFilter operation="OR">
<propertyFilter property="age"
operation="GREATER_OR_EQUAL"
operationEditable="true"/>
<propertyFilter property="city"
operation="EQUAL"
operationEditable="true"/>
</groupFilter>
</configuration>
</configurations>
</filter>
Атрибут operation
является обязательным. Доступны две логические операции:
-
AND
– это операция по умолчанию. -
OR
.
Также конфигурацию времени разработки можно создать в классе контроллера экрана:
@Autowired
protected UiComponents uiComponents;
@Autowired
protected SingleFilterSupport singleFilterSupport;
@Autowired
protected Filter pfdtcFilter;
@Autowired
protected Filter jfdtcFilter;
@Autowired
protected JpqlFilterSupport jpqlFilterSupport;
@Autowired
protected Filter gfdtcFilter;
@Subscribe
protected void onInit(InitEvent event) {
DesignTimeConfiguration javaDefaultConfigurationGF =
gfdtcFilter.addConfiguration("javaDefaultConfiguration",
"Default configuration"); (1)
DataLoader dataLoaderGF = gfdtcFilter.getDataLoader();
GroupFilter groupFilter =
uiComponents.create(GroupFilter.NAME); (2)
groupFilter.setConditionModificationDelegated(true);
groupFilter.setDataLoader(dataLoaderGF);
groupFilter.setOperation(LogicalFilterComponent.Operation.OR); (3)
PropertyFilter<Integer> pointsPropertyFilter =
uiComponents.create(PropertyFilter.NAME); (4)
pointsPropertyFilter.setConditionModificationDelegated(true);
pointsPropertyFilter.setDataLoader(dataLoaderGF);
pointsPropertyFilter.setProperty("rewardPoints");
pointsPropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
pointsPropertyFilter.setOperationEditable(true);
pointsPropertyFilter.setParameterName(PropertyConditionUtils
.generateParameterName(pointsPropertyFilter.getProperty()));
pointsPropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderGF.getContainer().getEntityMetaClass(),
pointsPropertyFilter.getProperty(),
pointsPropertyFilter.getOperation()));
groupFilter.add(pointsPropertyFilter); (5)
PropertyFilter<Hobby> hobbyPropertyFilter =
uiComponents.create(PropertyFilter.NAME);
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); (6)
javaDefaultConfigurationGF.getRootLogicalFilterComponent().add(groupFilter); (7)
PropertyFilter<Integer> agePropertyFilter =
uiComponents.create(PropertyFilter.NAME);
agePropertyFilter.setConditionModificationDelegated(true);
agePropertyFilter.setDataLoader(dataLoaderGF);
agePropertyFilter.setProperty("age");
agePropertyFilter.setOperation(PropertyFilter.Operation.GREATER_OR_EQUAL);
agePropertyFilter.setOperationEditable(true);
agePropertyFilter.setParameterName(PropertyConditionUtils.generateParameterName(
agePropertyFilter.getProperty()));
agePropertyFilter.setValueComponent(singleFilterSupport.generateValueComponent(
dataLoaderGF.getContainer().getEntityMetaClass(),
agePropertyFilter.getProperty(),
agePropertyFilter.getOperation()
));
javaDefaultConfigurationGF.getRootLogicalFilterComponent().add(agePropertyFilter);
pointsPropertyFilter.setValue(1000);
javaDefaultConfigurationGF.setFilterComponentDefaultValue(
pointsPropertyFilter.getParameterName(), 1000); (8)
hobbyPropertyFilter.setValue(Hobby.FISHING);
javaDefaultConfigurationGF.setFilterComponentDefaultValue(
hobbyPropertyFilter.getParameterName(), Hobby.FISHING);
agePropertyFilter.setValue(30);
javaDefaultConfigurationGF.setFilterComponentDefaultValue(
agePropertyFilter.getParameterName(), 30);
}
1 | Добавляет конфигурацию во время разработки с id javaDefaultConfiguration и именем Default configuration . |
2 | Создает компонент GroupFilter и задает его свойства. |
3 | Задает логическую операцию OR для groupFilter . |
4 | Создает компонент PropertyFilter и задает его свойства. |
5 | Добавляет pointsPropertyFilter к groupFilter . |
6 | Добавляет hobbyPropertyFilter к groupFilter . |
7 | Добавляет созданный групповой фильтр в конфигурацию javaDefaultConfiguration . |
8 | Задает значение по умолчанию pointsPropertyFilter для конфигурации javaDefaultConfiguration по имени параметра. |
Регистрация компонента Filter
Чтобы создать и зарегистрировать UI-компонент фильтра во фреймворке, нужны следующие объекты:
-
Класс компонента – компонент UI, который будет отображаться внутри компонента
Filter
. Класс компонента должен расширять классFilterComponent
. В качестве примера рассмотрим классPropertyFilter
. -
Модель – неперсистентный класс, который содержит состояние компонента фильтра. Модель используется для сохранения состояния компонента фильтра в базе данных и отображения и изменения этого состояния во время выполнения. Класс модели должен расширять класс
FilterCondition
. В качестве примера рассмотрим классPropertyFilterCondition
. -
Класс конвертера необходим для конвертирования между компонентом и моделью. Класс конвертера должен реализовывать интерфейс
FilterConverter
. -
Экран редактирования – экран редактирования модели. Если идентификатор не указан, то будет использоваться идентификатор по умолчанию (например,
modelName.edit
,PropertyFilterCondition.edit
).
Пример регистрации PropertyFilter
:
@Bean
public FilterComponentRegistration registerPropertyFilter() {
return FilterComponentRegistrationBuilder.create(PropertyFilter.class,
PropertyFilterCondition.class,
PropertyFilterConverter.class)
.withEditScreenId("ui_PropertyFilterCondition.edit")
.build();
}
Все зарегистрированные компоненты фильтра отображаются по нажатию всплывающей кнопки в диалоговом окне Add Condition
.
Зарегистрированный во фреймворке Jmix компонент фильтра можно заменить своей собственной реализацией, указав аннотацию @Order
в бине FilterComponentRegistration
(например, для расширения набора атрибутов модели, сохраняемых фильтром).
Все XML-атрибуты
Просматривать и редактировать атрибуты, применимые к компоненту, можно с помощью панели инспектора Jmix UI в конструкторе экранов Studio. |
XML-атрибуты JpqlFilter
align - caption - captionAsHtml - colspan - contextHelpText - contextHelpTextHtmlEnabled - css - defaultValue - description - descriptionAsHtml - editable - enable - box.expandRatio - hasInExpression - height - htmlSanitizerEnabled - icon - id - parameterClass - parameterName - required - requiredMessage - responsive - rowspan - stylename - tabIndex - visible - width
XML-атрибуты GroupFilter
align - caption - captionAsHtml - colspan - description - descriptionAsHtml - enable - box.expandRatio - height - htmlSanitizerEnabled - icon - id - operation - operationCaptionVisible - responsive - rowspan - stylename - visible - width