Как выполнить проверку в JSF, как создать собственный валидатор в JSF

Я хотел бы выполнить проверку в некоторых из моих входных компонентов, таких как <h:inputText>, используя какой-либо метод Java bean. Должен ли я использовать <f:validator> или <f:validateBean> для этого? Где я могу прочитать об этом подробнее?


person Aram Gevorgyan    schedule 18.05.2011    source источник


Ответы (1)


Стандартным способом является реализация интерфейса Validator.

@FacesValidator("fooValidator")
public class FooValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        // ...

        if (valueIsInvalid) {
            throw new ValidatorException(new FacesMessage("Value is invalid!"));
        }
    }

}

@FacesValidator зарегистрирует его в JSF с идентификатором валидатора. myValidator, чтобы вы могли сослаться на него в атрибуте validator любого компонента <h:inputXxx>/<h:selectXxx> следующим образом:

<h:inputText id="foo" value="#{bean.foo}" validator="fooValidator" />
<h:message for="foo" />

Всякий раз, когда валидатор выдает ValidatorException, его сообщение будет отображаться в <h:message>, связанном с полем ввода.

Вы также можете использовать EL в атрибуте validator любого компонента <h:inputXxx>/<h:selectXxx>, в котором вы ссылаетесь на метод управляемого компонента, имеющий точно такую ​​же сигнатуру метода (те же аргументы метода), что и Validator#validate(). т.е. принимая аргументы FacesContext, UIComponent и Object в указанном порядке.

<h:inputText id="foo" value="#{bean.foo}" validator="#{bean.validateFoo}" />
<h:message for="foo" />
public void validateFoo(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    // ...

    if (valueIsInvalid) {
        throw new ValidatorException(new FacesMessage("Value is invalid!"));
    }
}

Это полезно только в том случае, если валидатору требуется доступ к другому свойству, присутствующему в том же управляемом компоненте. Если в этом нет необходимости, то этот подход считается тесно связанным (таким образом, плохой практикой), и вы должны разделить валидатор на отдельный класс, реализующий интерфейс Validator.

Вы также можете использовать <f:validator> taghandler, что будет единственным способом, если вы собираетесь прикрепить несколько валидаторов к одному и тому же компоненту:

<h:inputText id="foo" value="#{bean.foo}">
    <f:validator validatorId="fooValidator" />
</h:inputText>
<h:message for="foo" />

Это выполнит @FacesValidator("fooValidator"), показанное выше.

Вы также можете использовать <f:validator binding> для ссылки на конкретный экземпляр валидатора где-то в области EL, который может быть указан и предоставлен следующим образом:

<h:inputText id="foo" value="#{bean.foo}">
    <f:validator binding="#{fooValidator}" />
</h:inputText>
<h:message for="foo" />
@Named("fooValidator")
public class FooValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        // ...

        if (valueIsInvalid) {
            throw new ValidatorException(new FacesMessage("Value is invalid!"));
        }
    }

}

Обратите внимание, что таким образом вместо @FacesValidator используется @Named. Здесь также поддерживается старый @ManagedBean вместо @Named. Исторически это был трюк, чтобы иметь возможность использовать @EJB и @Inject в валидаторе. См. также Как внедрить в @FacesValidator с помощью @EJB, @PersistenceContext, @Inject, @Autowired

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

<h:inputText id="foo" value="#{bean.foo}">
    <f:validator binding="#{bean.fooValidator}" />
</h:inputText>
<h:message for="foo" />
public Validator getFooValidator() {
    return (context, component, value) -> {
        // ...

        if (valueIsInvalid) {
            throw new ValidatorException(new FacesMessage("Value is invalid!"));
        }
    };
}

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

Чтобы сделать еще один шаг, вы можете использовать проверку бина JSR303. Это проверяет поля на основе аннотаций. Таким образом, вы можете иметь только

@Foo
private String foo;

Без необходимости явно регистрировать какой-либо валидатор на стороне XHTML. Если вы используете JPA для сохраняемости, по умолчанию этот валидатор также будет выполняться во время вставки/обновления в БД. Поскольку это будет целая история, вот несколько ссылок для начала:

Также есть тег <f:validateBean>, но он полезен только в том случае, если вы собираетесь отключить проверку бина JSR303. Затем вы помещаете компоненты ввода (или даже всю форму) внутрь <f:validateBean disabled="true">.

Смотрите также:

person BalusC    schedule 18.05.2011