Я хотел бы выполнить проверку в некоторых из моих входных компонентов, таких как <h:inputText>
, используя какой-либо метод Java bean. Должен ли я использовать <f:validator>
или <f:validateBean>
для этого? Где я могу прочитать об этом подробнее?
Как выполнить проверку в JSF, как создать собственный валидатор в JSF
Ответы (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">
.
Смотрите также:
- JSF не поддерживает проверку между полями, есть ли обходной путь?
- Как выполнить проверку JSF в actionListener или методе действия?