Валидации
Валидации позволяют проверить корректность входных данных для выполнения операций над объектом и виджетом.
#
Валидация объектаВалидация объекта позволяет задать единые правила корректности входных данных для любых операций и выборок.
Все валидации объекта перечисляются в элементе <validations>
:
<object>
<validations> ... <!-- Валидации объекта --> </validations></object>
#
Способы валидацийСуществует два основных способа валидаций:
- Проверка входных данных по условиям
- Проверка целостности данных на уровне БД
#
Проверка входных данных по условиямПо условиям можно проверить корректность значения поля, его взаимосвязи с другими полями.
Проверка по условию записывается в элементе <condition>
:
<validations> <condition id="checkAdult" message="Запрещено для детей. Ваш возраст {age}, что меньше 18." field-id="age">age >= 18</condition></validations>
Атрибут id
задаёт идентификатор валидации в объекте.
В дальнейшем, через id
на валидацию можно будет сослаться в тех местах,
где она должна сработать.
В теле элемента <condition>
задается условие на языке javaScript.
Атрибутом field-id
можно задать поле, под которым появится сообщение валидации.
Если условие будет верным (вернёт true
), то валидация пройдёт успешно.
Если же будет не верным (вернёт false
), то появится сообщение message
.
В сообщении можно использовать ссылки на поля входных данных. Ссылки записываются в фигурных скобках.
#
Проверка целостности данных на уровне БДЧтобы проверить целостность данных, необходимо сделать запрос к источнику данных с помощью провайдеров.
Проверка целостности данных задаётся в элементе <constraint>
:
<validations> <constraint id="checkUniqueName" message="Пользователь с таким именем уже существует в системе" result="[0].cnt == 0"> <invocation> <sql> SELECT count(1) as cnt FROM user WHERE username = :username </sql> </invocation> <in> <field id="username"/> <field id="id"/> </in> </constraint></validations>
Обращение к провайдеру данных задаётся в элементе <invocation>
.
В элементе <in>
задаются входные параметры провайдера.
Одновременно, эти параметры являются триггерами срабатывания валидации.
В элементе <out>
задаются выходные параметры провайдера.
На них можно ссылаться в сообщении валидации.
В атрибуте result
задаётся условие проверки результата.
Условие записывается на языке SpEL.
Если условие будет верным (вернёт true
), то валидация пройдёт успешно.
Если же будет не верным (вернёт false
), то появится сообщение message
.
#
Проверка обязательности заполненияЧтобы проверить обязательность заполнения поля,
можно поставить атрибут required="true"
для входящего параметра операции:
<operation> <in> <field id="name" required="true"/> </in></operation>
В этом случае для поля выполняется стандартная проверка заполненности и выводится сообщение.
Если требуется вывести не стандартное сообщение, можно создать специальную валидацию <mandatory>
:
<validations> <mandatory id="requiredName" field-id="name" message="Имя должно быть заполнено"/></validations>
#
Серьезность валидацииВалидации могут иметь разный уровень серьезности:
Уровни серьёзности валидаций
Уровень | Описание | Цвет сообщения |
---|---|---|
danger | Прерывает выполнение действий. | Красный |
warning | Предупреждает об отклонениях в прошедшем действии. | Желтый |
info | Информирует об особенностях прошедших или будущих действий. | Голубой |
success | Даёт положительную обратную связь. | Зеленый |
Уровень задаётся в атрибуте severity
:
<validations> <condition level="warning"> ... </condition></validations>
По умолчанию danger
.
#
Момент срабатывания на сервереВалидации могут быть вызваны на сервере в разные моменты жизненного цикла объекта.
Серверные моменты вызова валидации
Момент | Описание | Случаи использования |
---|---|---|
before-operation | Перед выполнением операции | Проверка входных данных |
before-query | Перед получением данных выборки | Проверка ограничений фильтрации |
after-success-query | После успешного получения данных выборки | Информирование о результатах |
after-fail-query | После неудачного получения данных выборки | Информирование об ошибках |
after-success-operation | После успешного выполнения операции | Положительная обратная связь |
after-fail-operation | После неудачного выполнения операции | Отрицательная обратная связь |
Момент валидации задаётся атрибутом server-moment
:
<validations> <condition server-moment="before-query"> ... </condition></validations>
По умолчанию before-operation
при severity равном danger
или warning
,
иначе - after-success-operation
#
Отключение валидацииВалидацию можно выключить полностью или при определенных условиях.
За это отвечает атрибут enabled
.
Атрибут enabled
принимает true
или false
,
или выражение javaScript записанное в фигурных скобках:
<validations> <mandatory id="requiredMaidenNameForWomen" field-id="maidenName" enabled="{gender == 'woman'}"/></validations>
#
Валидация операцийДля операций можно ограничить список валидаций объекта применимых к ней. Ограничить можно белым и черным списком.
В случае белого списка только валидации перечисленные в нём будут применимы к операции:
<operation id="delete"> <validations white-list="checkDependencies"/></operation>
В случае черного списка все валидации кроме перечисленных в нём будут применимы к операции:
<operation id="create"> <validations black-list="checkDependencies"/></operation>
#
Вложенная валидация операцийВ операции можно задать и саму валидацию:
<operation> <validations> <condition>...</condition> <constraint>...</constraint> </validations></operation>
Вложенные валидации применимы к операции всегда и могут сочетаться с белыми и черными списками валидаций объекта.
#
Валидация с диалогом выбораВ N2O есть возможность использовать диалоги для подтверждения действий пользователя. Это особенно полезно в ситуациях, когда мы хотим убедиться, что пользователь точно уверен в выполняемом действии.
#
Настраиваемый диалогДиалог настраивается таким же образом, что и любой другой тип валидации.
Отличие диалога от <constraint>
валидации в наличии настраиваемого тулбара (меню кнопок).
В качестве действий кнопок можно использовать все стандартные действия.
Вызов диалога возможен в любой момент: до выполнения операции (before-operation
),
после выполнения успешной (after-success-operation
) и после операции,
закончившейся ошибкой (after-fail-operation
).
Для того, чтобы не допустить повторного вызова диалога, можно воспользоваться
атрибутом enabled
и дополнительным параметром:
<operation id="create"> <invocation>...</invocation> <in> <!-- параметр для отключения вызова диалога --> <field id="validated" param="validated"/> </in> <validations> <!-- диалог не вызывается, если validated=true --> <dialog id="dialog" server-moment="before-operation" result="#this < 3" enabled="{typeof(validated) === 'undefined' || validated == false}" message="Достигнут лимит по количеству пользователей. Вы уверены, что хотите добавить еще одного?"> <invocation> ... </invocation> <toolbar> <button id="yes" label="Да"> <invoke operation-id="create"> <!-- отправка validated=true, после подтверждения --> <header-param name="validated" value="true"/> </invoke> </button> <button label="Отмена"> <close/> </button> </toolbar> </dialog> </validations></operation>
#
Использование диалога с вызовом провайдера данных и безВызовы провайдера данных не являются обязательными в диалоге.
Отсюда будут отличаться и множество параметров, используемых для
вычисления корректности валидации в атрибуте result
.
- В случае вызова провайдера данных в качестве таких параметров, будут использоваться параметры, приходящие с сервера
- В случае отсутствия - входящие параметры. Таким образом мы можем осуществить предварительную проверку данных перед отправкой их на сервер
#
Валидация полейВалидации объекта можно прикреплять к полям формы. В этом случае сообщение валидации появится под выбранным полем.
Для прикрепления к полю используется атрибут field-id
:
<validations> <condition id="checkAdult" field-id="age">...</condition></validations>
В самих полях так же можно указать список валидаций, сообщения которых прикрепятся к полю.
Это задаётся в элементе <validations>
:
<input-text id="age"> <validations white-list="checkAdult"/></input-text>
#
Вложенная валидация поляВ поле можно задать и саму валидацию:
<input-text> <validations> <condition>...</condition> <constraint>...</constraint> </validations></input-text>
Вложенные валидации в поле выполняются всегда и могут сочетаться с белым списком валидаций объекта.
#
Bean Validation (JSR 303)Стандарт JSR303 Bean Validation позволяет валидировать java сущности по аннотациям.
N2O умеет считывать аннотации с bean сущностей и генерировать по ним <constraint>
и <condition>
валидации.
Для использования нужно подключить библиотеку n2o-validation
:
<dependency> <groupId>net.n2oapp.framework</groupId> <artifactId>n2o-validation</artifactId> <version>${n2o.version}</version></dependency>
#
Генерация constraint валидацийЧтобы сгенерировать валидации по аннотациям JSR303, необходимо подключить схему расширений:
http://n2oapp.net/framework/config/schema/bean-validation-1.0
И включить автоматическую генерацию валидаций с помощью атрибута generate
:
<object xmlns="http://n2oapp.net/framework/config/schema/object-4.0" xmlns:bv="http://n2oapp.net/framework/config/schema/bean-validation-1.0" entity-class="com.example.MyEntity" bv:generate="true"> ...</object>
После этого в объекте будут автоматически созданы <constraint>
валидации по сущности entity-class
.
tip
Генерация работает и для кастомных валидаторов, если для них реализован ConstraintValidator.
Идентификаторы <constraint>
валидаций генерируется по следующему шаблону:
$bv_{id}
, где id
идентификатор in параметра.
Например, $bv_name
.
important
Для корректной работы автоматической генерации валидаций требуется, чтобы поле с одним и тем же id всегда мапилось в одно и то же поле сущности.
#
Генерация condition валидацийВалидации <condition>
работают на JavaScript выражениях и
выполняются быстрее <constraint>
, так как не обращаются к серверу.
По умолчанию <condition>
валидации генерируются только для стандартных
аннотаций: @Max
, @Min
, @Pattern
, @Size
, @Future
, @Past
.
Для генерации валидаций по собственным аннотациям требуется реализовать
интерфейс ConditionBeanValidator
и зарегистрировать его в качестве
Spring Bean.
/** * Проверяет, что ввели только латинские символы **/public class LatinValidator implements ConditionBeanValidator<Latin> {
/** * Конвертирует JSR303 валидацию в JavaScript выражение * @param annotation аннотация * @param param свойство в модели виджета * @return condition валидация */ @Override public N2oCondition evaluate(Latin annotation, String param) { N2oCondition condition = new N2oCondition(); condition.setMessage("Допустимы только латинские буквы"); condition.setExpression("/[a-zA-Z]/i.test(" + param + ")"); return condition; }
@Override public Class<Latin> getType() { return Latin.class; }}
В объекте N2oCondition
необходимо задать только expression
и message
поля.
Остальные поля установит N2O при генерации.
Идентификаторы <condition>
валидаций генерируется по следующему шаблону:
$bv_{id}_{annotation}
, где id
идентификатор in параметра, а annotation
простое имя класса аннотации.
Например, $bv_name_latin
.
#
Автоматическая установка обязательных полейПри включенной генерации валидаций bv:generate="true"
, по аннотациям @NotNull
автоматически заполняются атрибуты required="true"
у полей объекта.
#
Точечная валидация поляАвтоматическую генерацию валидаций не всегда удобно использовать, из-за того, что она применяется ко всем полям без исключений. Иногда может потребоваться валидация только по конкретным полям или аннотациям.
Для таких случаев можно использовать специальный провайдер данных bv:validate
.
<object xmlns="http://n2oapp.net/framework/config/schema/object-4.0" xmlns:bv="http://n2oapp.net/framework/config/schema/bean-validation-1.0.xml" entity-class="com.example.MyEntity"> ... <validations> <constraint id="myBeanValidation" message="Произошла ошибка {mess} со значением {invalid}" result="#this == null" severity="danger"> <invocation> <bv:validate property="name" annotation-class="javax.validation.constraints.Pattern"/> </invocation> <in> <field id="name" mapping="name"/> </in> <out> <field id="mess" mapping="message"/> <field id="invalid" mapping="invalidValue"/> </out> </constraint> </validations></object>
В атрибуте property
задаётся поле сущности,
которое требуется проверить по JSR303 валидациям.
По умолчанию будут проверены все аннотации на этом поле.
Если требуется проверить только одну аннотацию, можно указать её класс через атрибут annotation-class
.
Результатом вызова будет объект класса ConstraintViolation
,
если были нарушения, или null
, если нарушений не было.