Как и было обещано в прошлый раз, я собираюсь познакомиться с некоторыми функциями платформы CUBA , которые я считаю очень ценными. Я собираюсь написать здесь ряд статей, начиная с элементарных аспектов, таких как пользовательский интерфейс, фильтрация, безопасность для некоторых продвинутых частей, таких как веб-портал, расширяемость, аудит, динамические атрибуты и так далее.
Особенности CUBA # 1 — Общий фильтр
В этом посте я хочу рассказать о функциональности общего фильтра. Но прежде чем мы запачкаем руки техническими деталями, давайте начнем с изучения базовых сценариев использования, к которым относится эта функция.
Как пользователь получает данные, которые действительно необходимы
Мы будем придерживаться примера из предыдущей статьи:
Основываясь на этой модели сущностей, давайте подумаем о некоторых возможных требованиях к фильтрации, которые могут иметь пользователи.
Во-первых, существуют определенные фильтры для самого объекта и его прямых атрибутов:
-
Показать всех клиентов в Нью-Йорке
-
Показать все заказы в 2015 году
-
Показать все товары по цене не менее 350 $
-
Показать все заказы в состоянии «ЗАВЕРШЕНО»
Далее у нас есть фильтры, основанные на ассоциациях 1: 1 / N: 1:
-
-
Список всех клиентов, которые живут в Далласе (через адрес объекта)
-
Показать все продукты в категории «Ноутбуки»
Наконец, у нас есть фильтры, основанные на отношении 1: N / M: N:
-
Перечислите всех клиентов, у которых есть хотя бы один заказ в 2015 году
-
Перечислите все заказы, имеющие не более 5 позиций
-
Перечислите все заказы, где общее количество позиций превышает 200 $
Это общие категории для требований к фильтрам, которые охватывают, вероятно, около 80% случаев использования.
Программный способ решения этих проблем
Я обычно использую для обработки такого рода требований следующее: для начала я бы начал пытаться понять, чего на самом деле хочет достичь пользователь, путем фильтрации. Обычно фильтрация используется для уменьшения количества экземпляров сущностей для текущего рабочего процесса. Примером этого может быть «фильтрация только заказов, которые не были оплачены вовремя» — рабочий процесс в этом случае будет выглядеть как «отправка просроченного уведомления». Другой способ использования фильтрации — использовать результат в качестве основы для отчетности (этот случай не рассматривается в этом сообщении в блоге).
Какова бы ни была причина, когда я знаю, каковы критерии фильтрации, самое простое решение для меня, как для разработчика, — это сразу же его кодировать. Чтобы привести пример реализации, в Grails я бы придумал что-то вроде этого на сервере:
class OrderController {
//...
Date now = new Date()
respond Order.where { dueDate > now }.list(params)
//...
}
Этот кусок кода может уже сделать работу. На интерфейсе сработает выпадающий список или кнопка переключения. Другой возможностью будет получение данных по ссылке, в которой будет храниться информация фильтра.
Какой бы реализация не выглядела — фундаментальным аспектом для меня, как для разработчика, является необходимость заранее знать требования, потому что они должны быть реализованы программно.
Общие решения для этих проблем
Вместо непосредственной реализации решения фильтра, есть более общий подход, который также довольно распространен. В этом случае разработчик заранее не знает требований к фильтру, а позволяет пользователю решать, что искать или фильтровать. Для этого возможные условия фильтра должны быть выведены из базовых типов данных атрибутов.
Эта модель может рассматриваться как похожая на механизм фильтрации Excel . В зависимости от типа данных текущего столбца, Excel предоставляет возможности фильтрации, которые имеют смысл в этом контексте. Можно отфильтровать дату, чтобы она находилась в определенном диапазоне, число должно быть «больше» или «меньше чем», строка может содержать определенную подстроку и так далее. Поскольку Excel на самом деле не знает об объектах и отношениях, поиск или фильтрация ассоциаций невозможна. Таким образом, этот механизм фильтрации применим только в определенной степени.
Что CUBA приносит на стол
Итак, вот идет CUBA и говорит нам: есть «универсальный фильтр», который позволяет вам фильтровать практически любые виды поднабора данных, о которых мы могли бы подумать. Теперь, чтобы глубже взглянуть на это;
Я создал демонстрационное приложение , которое реализует модель предметной области, о которой я упоминал выше. Здесь мы видим список товаров, доступных в нашем магазине. Вверху таблицы данных вы найдете раздел фильтров, который позволяет вам определить фильтры для этой таблицы. При нажатии на ссылку «Добавить условие поиска» фильтр CUBA извлекает и отображает все связанные атрибуты базового объекта, в данном случае Product. На самом деле, не только локальные атрибуты объекта появляются, механизм фильтрации также детализирует до связанных объектов и их атрибутов (и их связанных объектов и их атрибутов и …).
После выбора некоторых доступных атрибутов раздел фильтра в таблице заполняется соответствующими полями условий. В зависимости от типов атрибутов способы определения условий могут быть разными.
Вот пример, показывающий комбинацию различных условий фильтрации:
Условия фильтрации могут быть в разных режимах в зависимости от типа атрибута. Фильтр текстового атрибута может быть, например; начинается с или содержит данный текст и так далее. Даты могут быть отфильтрованы с помощью соответствующих возможностей фильтра даты, как до или после заданной даты. Перечисления, а также связи N: 1 будут выбираться через выпадающий список. Режимы условий для этого типа: установлено , в списке , =, и т.д. Я мог бы пойти и на описание различных типов данных и их режимов фильтрации, но я оставлю это на данный момент. Если вы хотите , чтобы увидеть значительную мощность этих фильтров, вы сможете найти очень хорошую документацию здесь .
То, что я пока продемонстрировал, в значительной степени представляет собой лишь простую инфраструктуру, которую CUBA предоставляет пользователю и разработчику в отношении фильтрации. Если подумать об этом, то это также довольно много функциональности, которая позволяет пользователю выполнять фильтрацию самостоятельно.
Как вы можете видеть, ничто не мешает мне, как разработчику, разрешать пользователю выбирать необходимые условия фильтрации, вместо того чтобы выполнять их вручную.
Что я должен сделать, чтобы сделать эту работу?
Итак, интересный вопрос, который можно задать, может быть: «Сколько усилий нужно для реализации этой функции в качестве разработчика?» Чтобы увидеть это, вам нужно заглянуть в файл определения пользовательского интерфейса для экрана списка продуктов. В основном это выглядит примерно так:
<filter id="filter" datasource="productsDs">
<properties include=".*"/>
</filter>
Это оно! На самом деле нет, потому что вам придется определить источник данных productsDs , который вы также можете найти в XML-дескрипторе .
Чтобы быть еще более точным, вам часто не нужно писать определение самостоятельно. Вместо этого вы можете использовать CUBA Studio для создания строительных лесов.
В этом случае вам необходимо загрузить и установить CUBA Studio, выполнить клон git из примера проекта , открыть проект, посмотреть на сущность вашего продукта (как вы видели выше) и попросить студию сгенерировать для нее стандартные экраны. , После ответа на несколько вопросов о различных параметрах этого шага генерации он приведет к точному файлу XML-дескриптора для браузера списка этой сущности, включая функции фильтрации.
А как же настоящий тяжелый материал?
Пройдя через это, мне в голову пришли две вещи. Во-первых, это только для специальных сценариев фильтрации. Как я могу предварительно определить эти фильтры, чтобы моим пользователям не приходилось подбирать их снова и снова? Во-вторых, часто существуют требования к фильтрации, которые выходят за рамки описанных возможностей. Как это решается CUBA?
У платформы также есть решения для этих возражений. Я расскажу оба в следующей части этой серии.