3.5.2.1.18. Filter
В этом разделе:
Компонент Filter
− универсальное средство фильтрации списков сущностей, извлекаемых из базы данных для отображения в табличном виде. Компонент позволяет производить быструю фильтрацию данных по произвольному набору условий, а также создавать фильтры для многократного использования.
Filter
должен быть связан с контейнером CollectionContainer через data loader либо с источником данных collectionDatasource
, содержащим запрос на JPQL. Принцип действия фильтра основан на модификации этого запроса в соответствии с критериями, заданными пользователем. Таким образом, фильтрация осуществляется на уровне БД при выполнении транслированного из JPQL в SQL запроса, и на Middleware и клиентский уровень загружаются только отобранные данные.
Использование фильтра
Типичный фильтр выглядит следующим образом:
По умолчанию, компонент находится в режиме быстрой фильтрации. Это означает, что пользователь может добавить набор условий для однократного поиска данных. После закрытия экрана просмотра экземпляров сущности условия будут удалены.
Для того чтобы создать быстрый фильтр, нажмите на ссылку Add search condition (Добавить условие поиска). Отобразится экран выбора условий:
Рассмотрим возможные типы условий:
-
Properties (Атрибуты) – атрибуты данной сущности и связанных с ней сущностей. Отображаются персистентные атрибуты, явно заданные в элементе
property
XML-описателя фильтра, либо соответствующие правилам, указанным в элементе properties. -
Custom conditions (Специальные условия) – условия, заданные разработчиком в элементах
custom
XML-дескриптора фильтра. -
Create new (Создать новое) – позволяет создать новое произвольное условие на JPQL. Данный пункт доступен пользователю, если у него есть специфическое разрешение
cuba.gui.filter.customConditions
.
Выбранные условия отображаются в верхней части панель фильтра. Рядом с каждым условием находится кнопка , позволяющая удалить их из набора.
Быстрый фильтр можно сохранить для повторного использования в дальнейшем. Для этого нажмите на кнопку настроек фильтра и выберите Save/Save as (Сохранить/Сохранить как). Во всплывающем окне задайте имя нового фильтра:
Фильтр будет сохранен в выпадающем меню кнопки Search (Поиск).
Пункт меню Reset filter (Сбросить фильтр) позволяет сбросить все текущие условия поиска.
Кнопка настроек фильтра содержит выпадающий список опций для управления фильтром:
-
Save (Сохранить) – сохранить изменения в текущем фильтре.
-
Save with values (Сохранить со значениями) – сохранить изменения в текущем фильтре, использовав значения в редакторах параметров фильтра как значения по умолчанию.
-
Save as (Сохранить как) – сохранить фильтр под новым именем.
-
Edit (Редактировать) – открыть редактор фильтра (см. ниже).
-
Make default (Установить по умолчанию) – установить фильтр по умолчанию для данного экрана. Фильтр будет автоматически выводиться на панель при каждом открытии экрана.
-
Remove (Удалить) – удалить текущий фильтр.
-
Pin applied (Закрепить) – использовать результаты последнего поиска для последовательной фильтрации данных (см. Последовательное наложение фильтров).
-
Save as search folder (Сохранить как папку поиска) – создать папку поиска на основе текущего фильтра.
-
Save as application folder (Сохранить как папку приложения) – создать папку приложения на основе текущего фильтра. Эта опция доступна только пользователям со специфическим разрешением
cuba.gui.appFolder.global
.
Опция Edit открывает редактор фильтра, который дает возможность расширенной настройки текущего фильтра:
Название фильтра указывается в поле Filter name (Имя фильтра). Это имя будет отображаться в списке доступных фильтров для текущего экрана.
Фильтр можно сделать global (то есть доступным для всех пользователей) с помощью установки флажка Available for all users (Общий) для всех пользователей и global default с помощью флажка Global default. Для этих операций пользователю требуется специфическое разрешение CUBA > Фильтр > Создание/изменение глобальных фильтров. Если фильтр помечен как global default, то он будет автоматически выбран при открытии экрана пользователями. Каждый пользователь может установить свой собственный фильтр по умолчанию с помощью флажка Default (По умолчанию). Эта настройка имеет приоритет над global default.
В дереве содержатся условия фильтра. Условия можно добавлять с помощью кнопки Add (Добавить) менять местами при помощи кнопок / или удалять с помощью кнопки Remove (Удалить).
Группировку условий по И или ИЛИ можно добавить с помощью соответствующих кнопок. Все добавленные на верхний уровень (то есть без явной группировки) условия объединяются по И.
При выборе условия в дереве в правой части редактора открывается список его свойств.
С помощью соответствующих флажков можно сделать выбранное в таблице условие скрытым или обязательным для заполнения. Параметр скрытого условия не отображается пользователю, поэтому он должны быть введен во время редактирования фильтра.
Свойство Width позволяет задать ширину поля ввода параметра для текущего условия. По умолчанию, условия на панели фильтров отображаются в три колонки. Ширина поля равняется количеству колонок, которое оно может занять (1, 2 или 3).
Значение параметра текущего условия по умолчанию можно задать в поле Default value (Значение по умолчанию).
Специальный заголовок условия фильтрации можно задать в поле Caption (Заголовок).
Поле Operation позволяет выбрать оператор поиска. Список доступных операторов зависит от типа атрибута.
При поиске по атрибуту сущности с типом DateTime
и без аннотации @IgnoreUserTimeZone по умолчанию будет учитываться часовой пояс текущего пользователя. Чтобы учитывать часовой пояс для атрибута с типом Date
, необходимо установить флаг Use time zone в редакторе нового условия.
Описание компонента Filter
XML-имя компонента: filter
.
Пример объявления компонента в XML-дескрипторе экрана:
<data readOnly="true">
<collection id="carsDc" class="com.haulmont.sample.core.entity.Car" view="carBrowse">
<loader id="carsDl" maxResults="50">
<query>
<![CDATA[select e from sample_Car e order by e.createTs]]>
</query>
</loader>
</collection>
</data>
<layout expand="carsTable" spacing="true">
<filter id="filter" applyTo="carsTable" dataLoader="carsDl">
<properties include=".*"/>
</filter>
<table id="carsTable" width="100%" dataContainer="carsDc">
<columns>
<column id="vin"/>
<column id="colour"/>
<column id="model"/>
</columns>
<rowsCount/>
</table>
</layout>
Здесь в элементе data
определен data container, который выбирает экземпляры сущности Car
с помощью JPQL запроса. Для компонента filter
в его атрибуте loader
указан фильтруемый загрузчик data loader. Данные отображаются компонентом Table, связанным с этим же контейнером.
Элемент filter
может содержать вложенные элементы. Все они описывают условия, доступные пользователю для выбора в диалоге добавления условий:
-
properties
- позволяет сделать доступными сразу несколько атрибутов сущности. Данный элемент может иметь следующие атрибуты:-
include
- обязательный атрибут, содержит регулярное выражение, которому должно соответствовать имя атрибута сущности.
-
exclude
- содержит регулярное выражение, при соответствии которому атрибут сущности исключается из ранее включенных с помощьюinclude
.
-
excludeProperties
– содержит список атрибутов, разделённых запятыми, которые должны быть исключены из фильтрации. В отличие отexclude
, этот атрибут поддерживает путь по графу сущностей для указания каждого свойства в списке. Например,customer.name
.
-
excludeRecursively
- указывает, должны ли атрибуты, перечисленные вexcludeProperties
, быть рекурсивно исключены из полного графа сущностей. Если установленоtrue
, указанный атрибут и все одноименные атрибуты вглубь по графу сущностей не будут использоваться в фильтре.Пример:
<filter id="filter" applyTo="ordersTable" dataLoader="ordersDl"> <properties include=".*" exclude="(amount)|(id)" excludeProperties="version,createTs,createdBy,updateTs,updatedBy,deleteTs,deletedBy" excludeRecursively="true"/> </filter>
Чтобы программно исключить атрибуты из фильтра, используйте метод
setPropertiesFilterPredicate()
компонентаFilter
:filter.setPropertiesFilterPredicate(metaPropertyPath -> !metaPropertyPath.getMetaProperty().getName().equals("createTs"));
При использовании элемента
properties
автоматически игнорируются следующие атрибуты сущности:-
Недоступные в связи с разрешениями подсистемы безопасности.
-
Коллекции (
@OneToMany
,@ManyToMany
). -
Неперсистентные атрибуты.
-
Атрибуты, не имеющие локализованного названия.
-
Атрибуты, аннотированные
@SystemLevel
. -
Атрибуты типа
byte[]
. -
Атрибут
version
.
-
-
property
- явно включает атрибут сущности по имени. Данный элемент может иметь следующие атрибуты:-
name
- обязательный атрибут, содержит имя включаемого атрибута сущности. Может быть путем (через ".") по графу сущностей. Например:<filter id="transactionsFilter" dataLoader="transactionsDl" applyTo="table"> <properties include=".*" exclude="(masterTransaction)|(authCode)"/> <property name="creditCard.maskedPan" caption="msg://EmbeddedCreditCard.maskedPan"/> <property name="creditCard.startDate" caption="msg://EmbeddedCreditCard.startDate"/> </filter>
-
paramWhere
− задает выражение на JPQL для отбора списка значений параметра условия, если параметр является связанной сущностью. Вместо алиаса сущности параметра в выражении нужно использовать метку (placeholder){E}
.Например, предположим, что сущность
Car
имеет ссылку на сущностьModel
. Тогда список возможных значений параметра может быть ограничен только моделямиAudi
:<filter id="carsFilter" dataLoader="carsDl"> <property name="model" paramWhere="{E}.manufacturer = 'Audi'"/> </filter>
В выражении JPQL можно использовать параметры экрана, атрибуты сессии, а также компоненты экрана, в том числе отображающие другие параметры. Правила задания параметров запроса описаны в Dependencies Between Data Components и Запросы в CollectionDatasourceImpl.
Пример использования параметра сессии и параметра экрана:
{E}.createdBy = :session$userLogin and {E}.name like :param$groupName
Используя
paramWhere
можно вводить зависимости между параметрами. Например, предположим, чтоManufacturer
является отдельной сущностью. То естьCar
ссылается наModel
, которая в свою очередь ссылается наManufacturer
. Тогда для фильтра поCar
можно создать два условия: первое для выбораManufacturer
и второе для выбораModel
. Чтобы ограничить список моделей выбранным перед этим производителем, добавьте в выражениеparamWhere
параметр:{E}.manufacturer.id = :component$filter.model_manufacturer90062
Здесь параметр ссылается на компонент, отображающий параметр Manufacturer. Имя компонента, отображающего параметр условия, можно узнать, вызвав контекстное меню на строке таблицы условий в редакторе фильтра:
-
paramView
− задает представление, с которым будет загружаться список значений параметра условия, если параметр является связанной сущностью. Например,_local
. Если не указано, используется_minimal
.
-
-
custom
- элемент, определяющий произвольное условие. Содержимым элемента должно быть выражение на JPQL (возможно использование JPQL Macros), которое будет добавлено в условиеwhere
запроса контейнера данных. Вместо алиаса отбираемой сущности в выражении нужно использовать метку (placeholder){E}
. Параметр условия может быть только один, и если он есть, обозначается символом?
.Значение условия может содержать спецсимволы, например "%" или "_" для оператора "like". Если вам нужно экранировать эти символы, добавьте в условие
escape '<char>'
, например:{E}.name like ? escape '\'
Тогда если в значении параметра условия будет передано
foo\%
, поиск будет интерпретировать "%" как символ в имени а не как спецсимвол.Пример фильтра с произвольными условиями:
<filter id="carsFilter" dataLoader="carsDl"> <properties include=".*"/> <custom name="vin" paramClass="java.lang.String" caption="msg://vin"> {E}.vin like ? </custom> <custom name="colour" paramClass="com.company.sample.entity.Colour" caption="msg://colour" inExpr="true"> ({E}.colour.id in (?)) </custom> <custom name="repair" paramClass="java.lang.String" caption="msg://repair" join="join {E}.repairs cr"> cr.description like ? </custom> <custom name="updateTs" caption="msg://updateTs"> @between({E}.updateTs, now-1, now+1, day) </custom> </filter>
Созданные
custom
условия отображаются в секции Специальные условия диалога добавления условий:Атрибуты элемента
custom
:-
name
− обязательный атрибут - имя условия.
-
paramClass
− Java-класс параметра условия. Если параметр отсутствует, то данный атрибут не обязателен.
-
inExpr
− должен быть установлен вtrue
, если выражение JPQL содержит условиеin (?)
. При этом пользователь будет иметь возможность ввести несколько значений параметра данного условия.
-
join
− необязательный атрибут для задания строки, которая будет добавлена в секциюfrom
запроса контейнера данных. Это может потребоваться для создания условия по атрибуту связанной коллекции. Значение данного атрибута должно включать в себя предложенияjoin
илиleft join
.Например, предположим что сущность
Car
имеет атрибутrepairs
, который представляет собой коллекцию экземпляров связанной сущностиRepair
. Тогда для фильтрацииCar
по атрибутуdescription
сущностиRepair
можно написать следующее условие:<filter id="carsFilter" dataLoader="carsDl"> <custom name="repair" caption="msg://repair" paramClass="java.lang.String" join="join {E}.repairs cr"> cr.description like ? </custom> </filter>
При использовании такого условия исходный запрос контейнера:
select c from sample$Car c order by c.createTs
будет трансформирован в следующий:
select c from sample$Car c join c.repairs cr where (cr.description like ?) order by c.createTs
-
paramWhere
− задает выражение на JPQL для отбора списка значений параметра условия, если параметр является связанной сущностью. См. описание одноименного атрибута элементаproperty
. -
paramView
− задает представление, с которым будет загружаться список значений параметра условия, если параметр является связанной сущностью. См. описание одноименного атрибута элементаproperty
.
-
Атрибуты filter
:
-
editable
- если значение этого атрибута равноfalse
, то кнопка Фильтр скрывается.
-
manualApplyRequired
− определяет, в какой момент будет применяться фильтр. Если значение атрибута равноfalse
, то фильтр (пустой или по умолчанию) будет применяться сразу при открытии экрана. Это означает, что контейнер данных будет обновлен и связанные компоненты (например,Table
) отобразят данные. Если значение атрибута равноtrue
, то фильтр будет применяться только после нажатия на кнопку Search.Данный атрибут имеет приоритет над свойством приложения cuba.gui.genericFilterManualApplyRequired.
-
useMaxResults
− ограничивает размер страницы загружаемых в контейнер данных экземпляров сущности. По умолчаниюtrue
.Если значение этого атрибута равно
false
, то фильтр не будет отображать поле Show rows. Количество записей в контейнере (и соответственно, показываемых таблицей) будет ограничено только параметромMaxFetchUI
механизма статистики сущностей, по умолчанию - 10000.Если данный атрибут не указан, или равен
true
, то поле Show rows отображается, если у пользователя также есть специфическое разрешение cuba.gui.filter.maxResults. Если разрешениеcuba.gui.filter.maxResults
отсутствует, то фильтр будет принудительно отбирать только первые N строк без возможности пользователя отключить это или указать другое N. Число N определяется параметрамиFetchUI
,DefaultFetchUI
, получаемыми из механизма статистики сущностей.На рисунке далее показан вид фильтра со значением атрибута
useMaxResults="true"
, запретом специфического разрешенияcuba.gui.filter.maxResults
и параметромDefaultFetchUI=2
-
textMaxResults
- позволяет использовать текстовое поле вместо выпадающего списка в качестве поля Show rows. По умолчаниюfalse
.
-
folderActionsEnabled
− при указании значенияfalse
позволяет скрыть следующие действия с фильтром: Сохранить как папку поиска, Сохранить как папку приложения. По умолчанию значение атрибута равноtrue
, действия Сохранить как папку поиска, Сохранить как папку приложения доступны.
-
applyTo
− необязательный атрибут, содержит идентификатор компонента, с которым связан фильтр. Используется в случае, когда необходимо иметь доступ к представлениям связанного компонента-таблицы. Например, сохраняя фильтр как папку поиска или как папку приложения, можно указать, какое представление будет применяться при просмотре этой папки.
-
columnsCount
- задает количество колонок с условиями для конкретного фильтра. Значение по умолчанию - 3.
-
defaultMode
- задает режим фильтра при открытии экрана. Возможные значения:generic
иfts
. При указании значенияfts
фильтр будет открыт в режиме полнотекстового поиска (если сущность индексируется). Значение по умолчанию -generic
.
-
modeSwitchVisible
- определяет видимость чек-бокса для перевода фильтра в режим полнотекстового поиска. Если полнотекстовый поиск невозможен, то чек-бокс будет невидим независимо от указанного значения. Возможные значения атрибута:true
иfalse
.
Методы интерфейса Filter:
-
setBorderVisible()
- определяет видимость границы фильтра. Значение по умолчанию -true
.
Слушатели компонента Filter:
-
ExpandedStateChangeListener
- позволяет отслеживать изменения состояния компонента (свёрнутое/развёрнутое).
-
FilterEntityChangeListener
- срабатывает при первом выборе фильтра и дальнейшем выборе сохранённых фильтров.
- Атрибуты filter
-
applyTo - caption - captionAsHtml - columnsCount - css - dataLoader - datasource - defaultMode - description - descriptionAsHtml - editable - enable - box.expandRatio - folderActionsEnabled - id - manualApplyRequired - margin - modeSwitchVisible - settingsEnabled - stylename - textMaxResults - useMaxResults - visible - width
- Элементы filter
-
custom - properties - property
- Атрибуты properties
- Атрибуты property
-
caption - name - paramView - paramWhere
- Атрибуты custom
-
caption - name - inExpr - join - paramClass - paramView - paramWhere
- API
-
addExpandedStateChangeListener - addFilterEntityChangeListener - applySettings - getMargin - saveSettings - setMargin
Права пользователей
-
Для создания/изменения/удаления глобальных (доступных всем пользователям) фильтров пользователь должен иметь разрешение
cuba.gui.filter.global
. -
Для создания/изменения
custom
условий пользователь должен иметь разрешениеcuba.gui.filter.customConditions
. -
Чтобы иметь возможность изменять максимальное количество строк на странице таблицы с помощью флажка и поля Show rows пользователь должен иметь разрешение
cuba.gui.filter.maxResults
. См. также атрибут фильтра useMaxResults.
Информация о том, как настраивать специфические разрешения, приведена в руководстве Подсистема безопасности.
Внешние параметры для управления фильтрами
-
Общесистемные параметры
Следующие свойства приложения влияют на поведение фильтров:
-
cuba.gui.genericFilterManualApplyRequired − позволяет отключить автоматическое применение фильтра (то есть загрузку данных) сразу при открытии экрана. См. также атрибут фильтра manualApplyRequired.
-
cuba.gui.genericFilterChecking − позволяет включить проверку заполненности хотя-бы одного условия перед применением фильтра.
-
cuba.gui.genericFilterControlsLayout − определяет расположение элементов внутри фильтра.
-
cuba.allowQueryFromSelected позволяет отключить механизм последовательного наложения фильтров.
-
cuba.gui.genericFilterColumnsCount - задает количество колонок по умолчанию для размещения условий фильтра. См также атрибут фильтра columnsCount.
-
cuba.gui.genericFilterConditionsLocation - задает расположение панели условий.
-
cuba.gui.genericFilterPopupListSize - задает количество позиций в выпадающем списке кнопки Search.
-
cuba.gui.genericFilterTrimParamValues - определяет, нужно ли обрезать пробелы в начале и конце строки текстового поиска.
-
-
Параметры вызова экрана
При вызове экрана можно указать, какой фильтр и с какими параметрами должен быть применен сразу после открытия экрана. Для этого фильтр должен быть заранее создан, сохранен в базе данных, и соответствующая запись в таблице
SEC_FILTER
должна иметь заполненное полеCODE
. Параметры вызова экрана задаются в конфигурационном файлеweb-menu.xml
.Чтобы сохранить фильтр в базе данных, необходимо добавить скрипт вставки фильтра в скрипт
30.create-db.sql
сущности. Для генерации скрипта найдите фильтр в справочнике Entity Inspector меню Administration, в контекстном меню выберите System Information, нажмите на кнопку Script for insert и скопируйте текст скрипта.Теперь можно добавить скрипт к экрану. Для указания кода фильтра в экран следует передать параметр с именем, равным идентификатору компонента фильтра в данном экране. Значением параметра должен быть код фильтра, который нужно установить и применить.
Для установки значений параметров фильтра в экран нужно передать параметры с именами, равными именам параметров, и значения в виде строк.
Пример описателя пункта главного меню, устанавливающего в открываемом экране
sample$Car.browse
в компонентеcarsFilter
фильтр с кодомFilterByVIN
, с подстановкой в параметр условияcomponent$carsFilter.vin79216
значенияTMA
:<item id="sample$Car.browse"> <param name="carsFilter" value="FilterByVIN"/> <param name="component$carsFilter.vin79216" value="TMA"/> </item>
Следует отметить, что фильтр с установленным полем
CODE
обладает особыми свойствами:-
Его не могут редактировать пользователи.
-
Название такого фильтра можно отображать на нескольких языках. Для этого в главном пакете сообщений приложения должна быть строка с ключом, равным коду фильтра.
-
Последовательное наложение фильтров
При включенном свойстве приложения cuba.allowQueryFromSelected в пользовательском интерфейсе компонента можно закреплять последний примененный фильтр и текущие результаты фильтрации. После этого можно выбрать другой фильтр или параметры и применить их на уже выбранных записях.
Данный подход позволяет решить две проблемы:
-
Декомпозировать сложные фильтры.
-
Применять фильтры на записи, отобранные с помощью папок приложения или поиска.
Чтобы применить этот механизм в пользовательском интерфейсе, выберите и примените один из фильтров. Затем нажмите на кнопку настроек фильтра и выберите Pin applied (Закрепить). Фильтр закрепится в верхней части панели фильтров. Далее можно применить к выбранным записям другой фильтр. Так последовательно можно накладывать друг на друга любое количество фильтров. Также фильтры можно удалять последовательно с помощью кнопки .
Механизм последовательного наложения фильтров основан на возможности DataManager выполнять последовательные запросы.
API для работы с параметрами фильтра
Интерфейс Filter
предоставляет методы для установки и чтения значений параметра фильтра из кода контроллера экрана:
-
setParamValue(String paramName, Object value)
-
getParamValue(String paramName)
paramName
- имя параметра фильтра. Имя параметра фильтра является составной частью имени компонента, отображающего значение параметра фильтра. Как получить имя компонента рассматривалось выше. Имя параметра - это часть имени компонента, находящаяся после последней точки. Например, если имя компонента component$filter.model_manufacturer90062
, то имя параметра фильтра model_manufacturer90062
.
Обратите внимание, что в обработчике InitEvent контроллера экрана данные методы использовать нельзя, т.к. в этот момент фильтр еще не проинициализирован. Вы можете работать с параметрами фильтра в обработчике BeforeShowEvent.
Режим полнотекстового поиска в фильтре
Если контейнер данных фильтра содержит сущности, индексируемые системой полнотекстового поиска (см. Платформа CUBA. Полнотекстовый поиск), то в фильтре становится доступным режим полнотекстового поиска. Чтобы переключиться в него, используйте флажок Full-Text Search ("Полнотекстовый поиск").
В этом режиме фильтр имеет поля для ввода критериев поиска, и поиск производится по индексируемым подсистемой FTS полям сущности.
Если таблица указана в атрибуте applyTo, то при наведении указателя мыши на строку таблицы во всплывающем окне будет написано, в каких полях сущности было найдено условие поиска.
Для скрытия переключателя режима фильтра установите значение false
атрибуту фильтра modeSwitchVisible.
Если необходимо, чтобы фильтр по умолчанию открывался в режиме полнотекстового поиска, установите значение fts
атрибуту defaultMode.
Полнотекстовый поиск может использоваться совместно с любым количеством условий универсального фильтра:
Выбрать условие FTS condition можно в окне выбора условий фильтра.