Skip to main content

Валидации

Валидации позволяют проверить корректность входных данных для выполнения операций над объектом и виджетом.

Валидация объекта

Валидация объекта позволяет задать единые правила корректности входных данных для любых операций и выборок.

Все валидации объекта перечисляются в элементе <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="Пользователь с таким именем уже существует в системе"
server-moment="before-operation" severity="danger"
result="[0].get('CNT') == 0">
<invocation>
<sql>
SELECT count(1) as cnt
FROM user
WHERE username = :username
</sql>
</invocation>
<in>
<field id="username"/>
</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 &lt; 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:

Maven зависимость для интеграции с Bean 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:

Включение генерации валидаций JSR303 в объекте
<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.

Генератор <condition> валидаций по аннотации
/**
* Проверяет, что ввели только латинские символы
**/
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.

Точечная валидация поля с помощью 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, если нарушений не было.