Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Создание и использование кастомного валидатора

Если стандартные валидаторы или Bean Validation не выполняют необходимую вам проверки, вы можете создать кастомный валидатор для валидации пользовательского ввода. Как объясняется в Модель валидации, существует два способа реализации кода валидации.

  • Реализуйте метод Managed-бина, который выполняет валидацию.

  • Предоставьте реализацию интерфейса javax.faces.validator.Validator для выполнения проверки.

Пишем метод для выполнения валидации объясняет, как реализовать метод Managed-бина для выполнения валидации. В оставшейся части этого раздела объясняется, как реализовать интерфейс Validator.

Если вы решили реализовать интерфейс Validator и хотите, чтобы автор страницы настраивал атрибуты валидатора со страницы, вы также должны указать кастомный тег для регистрации валидатора в компоненте.

Если вы предпочитаете настраивать атрибуты в реализации Validator, вы можете отказаться от указания кастомного тега и вместо этого позволить автору страницы зарегистрировать валидатор в компоненте с помощью тега f:validator, как описано в Использование кастомного валидатора.

Вы также можете создать свойство Managed-бина, которое принимает и возвращает созданную реализацию Validator, как описано в Запись свойств, привязанных к конвертерам, слушателям или валидаторам. Вы можете использовать атрибут привязки тега f:validator, чтобы связать реализацию Validator со свойством Managed-бина.

Как правило, если данные не проходят валидацию, пользователю на странице отображаются соответствующие сообщения об ошибках. Необходимо хранить эти сообщения об ошибках в bundle-ресурсе.

После создания bundle-ресурса у вас есть два способа сделать сообщения доступными для приложения. Вы можете поместить сообщения об ошибках в FacesContext программно или зарегистрировать сообщения об ошибках в файле конфигурации приложения, как описано в Регистрация сообщений приложения.

Например, приложение электронной торговли может использовать кастомный валидатор общего назначения с именем FormatValidator.java для валидации введённых данных по шаблону формата, указанному в кастомном теге валидатора. Этот валидатор будет использоваться с полем Номер кредитной карты на странице Facelets. Вот кастомный тег валидатора:

<mystore:formatValidator
 formatPatterns="9999999999999999|9999 9999 9999 9999|9999-9999-9999-9999"/>

Согласно этому валидатору, данные, введённые в поле, должны быть одним из следующих:

  • 16-значный номер без пробелов

  • 16-значный номер с пробелами между каждыми четырьмя цифрами

  • 16-значный номер с дефисами между каждыми четырьмя цифрами

Тег f:validateRegex делает ненужным кастомный валидатор в этой ситуации. Однако в оставшейся части этого раздела описывается, как этот валидатор будет реализован и как указать кастомный тег, чтобы автор страницы мог зарегистрировать валидатор в компоненте.

Реализация интерфейса валидатора

Реализация Validator должна содержать конструктор, набор методов доступа для любых атрибутов тега и метод validate, который переопределяет метод validate интерфейса Validator.

Гипотетический класс FormatValidator также определяет методы доступа для установки атрибута formatPatterns, который указывает приемлемые шаблоны формата для ввода в поля. Set-метод вызывает метод parseFormatPatterns, который разделяет компоненты строки шаблона в строковый массив formatPatternsList.

public String getFormatPatterns() {
    return (this.formatPatterns);
}
public void setFormatPatterns(String formatPatterns) {
    this.formatPatterns = formatPatterns;
    parseFormatPatterns();
}

В дополнение к определению методов доступа для атрибутов, класс переопределяет метод validate интерфейса Validator. Этот метод проверяет ввод и также получает доступ к кастомным сообщениям об ошибках, которые отображаются, когда String невалидный.

Метод validate выполняет фактическую валидацию данных. Он принимает объект FacesContext, компонент, данные которого необходимо проверить, и значение, которое необходимо проверить. Валидатор имеет возможность проверять только данные компонента, который реализует javax.faces.component.EditableValueHolder.

Вот реализация метода validate:

@FacesValidator
public class FormatValidator implements Validator, StateHolder {
    ...
    public void validate(FacesContext context, UIComponent component,
                         Object toValidate) {

        boolean valid = false;
        String value = null;
        if ((context == null) || (component == null)) {
            throw new NullPointerException();
        }
        if (!(component instanceof UIInput)) {
            return;
        }
        if ( null == formatPatternsList || null == toValidate) {
            return;
        }
        value = toValidate.toString();
        // валидация значения по списку шаблонов.
        Iterator patternIt = formatPatternsList.iterator();
        while (patternIt.hasNext()) {
            valid = isFormatValid(
                ((String)patternIt.next()), value);
            if (valid) {
                break;
            }
        }
        if ( !valid ) {
            FacesMessage errMsg =
                new FacesMessage(FORMAT_INVALID_MESSAGE_ID);
            FacesContext.getCurrentInstance().addMessage(null, errMsg);
            throw new ValidatorException(errMsg);
        }
    }
}

Аннотация @FacesValidator регистрирует класс FormatValidator как валидатор с JavaServer Faces. Метод validate получает локальное значение компонента и преобразует его в String. Затем он перебирает список formatPatternsList, являющийся списком допустимых шаблонов, которые были проанализированы из атрибута formatPatterns кастомного тега валидатора.

Во время итерации по списку этот метод проверяет локальное значение компонента на соответствие шаблонам в списке. Если локальное значение не соответствует ни одному шаблону в списке, этот метод генерирует сообщение об ошибке. Затем он создаёт javax.faces.application.FacesMessage и помещает его в очередь на FacesContext для отображения, используя String, который представляет ключ в файле Properties:

public static final String FORMAT_INVALID_MESSAGE_ID =
     "FormatInvalid";
}

Наконец, метод передаёт сообщение в конструктор javax.faces.validator.ValidatorException.

Когда отображается сообщение об ошибке, {0} будет заменён на шаблон формата в сообщении об ошибке, которое выглядит следующим образом:

Входные данные должны соответствовать одному из следующих шаблонов: {0}

Вы можете сохранить и восстановить состояние вашего валидатора, хотя сохранение состояния обычно не требуется. Для этого необходимо реализовать интерфейс StateHolder, а также интерфейс Validator. Чтобы реализовать StateHolder, вам нужно реализовать четыре метода: saveState(FacesContext), restoreState(FacesContext, Object), isTransient и setTransient(boolean). Смотрите Сохранение и восстановление состояния для получения дополнительной информации.

Указание кастомного тега

Если вы реализовали интерфейс Validator, а не метод Managed-бина, который выполняет валидацию, вам нужно выполнить одно из следующих действий.

  • Разрешите автору страницы указывать реализацию Validator для использования с тегом f:validator. В этом случае реализация Validator должна определять свои собственные свойства. Использование кастомного валидатора объясняет, как использовать тег f:validator.

  • Укажите кастомный тег, который предоставляет атрибуты для настройки свойств валидатора со страницы.

Чтобы создать кастомный тег, необходимо добавить тег в дескриптор библиотеки тегов приложения, bookstore.taglib.xml:

<tag>
    <tag-name>validator</tag-name>
    <validator>
        <validator-id>formatValidator</validator-id>
        <validator-class>
            dukesbookstore.validators.FormatValidator
        </validator-class>
    </validator>
</tag>

Элемент tag-name определяет имя тега, так как он должен использоваться на странице Facelets. Элемент validator-id идентифицирует кастомный валидатор. Элемент validator-class связывает кастомный тег с его классом реализации.

Использование кастомного валидатора объясняет, как использовать кастомный тег валидатора на странице.

Использование кастомного валидатора

Чтобы зарегистрировать кастомный валидатор в компоненте, необходимо выполнить одно из следующих действий.

  • Вложите кастомный тег валидатора в тег компонента, значение которого вы хотите проверить.

  • Вложите стандартный тег f:validator в тег компонента и укажите ссылку на реализацию кастомного Validator из тега f:validator.

Вот гипотетический кастомный тег formatValidator для поля Credit Card Number, вложенный в тег h:inputText:

<h:inputText id="ccno" size="19"
  ...
  required="true">
  <mystore:formatValidator
  formatPatterns="9999999999999999|9999 9999 9999 9999|9999-9999-9999-9999"/>
</h:inputText>
<h:message styleClass="validationMessage" for="ccno"/>

Этот тег проверяет ввод поля ccno по шаблонам, определённым автором страницы в атрибуте formatPatterns.

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

Если разработчик приложения, создавший кастомный валидатор, предпочитает настраивать атрибуты в реализации Validator, а не разрешать автору страницы настраивать атрибуты со страницы, разработчик не будет создавать кастомный тег для использования с валидатором.

В этом случае автор страницы должен вложить тег f:validator в тег компонента, данные которого необходимо валидировать. Затем автору страницы необходимо выполнить одно из следующих действий.

Следующий тег регистрирует гипотетический валидатор в компоненте с помощью тега f:validator и ссылается на идентификатор валидатора:

<h:inputText id="name" value="#{CustomerBean.name}"
            size="10" ...>
    <f:validator validatorId="customValidator" />
    ...
</h:inputText>

Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)