Как выполнить проверку JSF в actionListener или методе действия?
У меня есть проверка бобов, хорошо работающая в моем приложении. Теперь я хочу проверить, что новый пользователь не выбирает имя пользователя, которое уже было выбрано.
в actionlistener у меня есть код, который проверяет базу данных, но как заставить пользователя вернуться на страницу, на которой они были, если они выбирают уже существующее имя пользователя?
4 ответов
введение
вы can сделайте это, но методы JSF ajax/action/listener семантически являются неправильно место для проверки. На самом деле вы не хотите заходить так далеко в жизненном цикле JSF, если у вас неправильные входные значения в форме. Вы хотите, чтобы жизненный цикл JSF остановился после фазы проверки JSF.
вы хотите использовать аннотацию проверки Jsr303 Bean (@NotNull
и друзья) и / или валидатор ограничений, или используйте JSF Validator
(required="true"
, <f:validateXxx>
и т. д.) Для этого вместо. Он будет правильно вызван на этапе проверки JSF. Таким образом, при сбое проверки значения модели не обновляются, бизнес-действие не вызывается, и вы остаетесь на той же странице/представлении.
поскольку нет стандартной аннотации проверки бобов или валидатора JSF для проверки того, является ли данное входное значение уникальным в соответствии с базой данных, вам нужно будет создать пользовательский валидатор для этого.
я для обе стороны показывают, как создать пользовательский валидатор, который проверяет уникальность имени пользователя.
пользовательские Jsr303 Bean Validation Аннотация
создаем Custom @Username
ограничения аннотация:
@Constraint(validatedBy = UsernameValidator.class)
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Username {
String message() default "Username already exists";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
С этим валидатором ограничений (Примечание:@EJB
или @Inject
внутри ConstraintValidator
работает только с CDI 1.1; поэтому, если вы все еще на CDI 1.0, вам нужно будет вручную захватить его из JNDI):
public class UsernameValidator implements ConstraintValidator<Username, String> {
@EJB
private UserService service;
@Override
public void initialize(Username constraintAnnotation) {
// If not on CDI 1.1 yet, then you need to manually grab EJB from JNDI here.
}
Override
public boolean isValid(String username, ConstraintValidatorContext context) {
return !service.exist(username);
}
}
наконец, использовать его следующим образом модель:
@Username
private String username;
пользовательский валидатор JSF
альтернативой является использование пользовательского валидатора JSF. Просто реализуйте JSF Validator
интерфейс:
@ManagedBean
@RequestScoped
public class UsernameValidator implements Validator {
@EJB
private UserService userService;
@Override
public void validate(FacesContext context, UIComponent component, Object submittedAndConvertedValue) throws ValidatorException {
String username = (String) submittedAndConvertedValue;
if (username == null || username.isEmpty()) {
return; // Let required="true" or @NotNull handle it.
}
if (userService.exist(username)) {
throw new ValidatorException(new FacesMessage("Username already in use, choose another"));
}
}
}
наконец, используйте его следующим образом:
<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
обратите внимание, что вы обычно используете @FacesValidator
аннотация Validator
класс, но до предстоящего JSF 2.3 он не поддерживает @EJB
или @Inject
. См. также как впрыснуть в @FacesValidator с @EJB, @PersistenceContext, @Inject, @Autowired.
Да, вы можете. Вы можете выполнить проверку в методе прослушивателя действий, добавить сообщения лиц, если пользовательская проверка не удалась, а затем вызвать FacesContext.validationFailed()
просто перед возвращением.
единственная проблема с этим решением заключается в том, что это происходит после проверки JSF и проверки bean. То есть, это после этапа проверки. Если у вас есть несколько прослушивателей действий, скажите listener1 и listener2: если ваша пользовательская проверка в listener1 не удалась, она продолжит выполнение listener2. Но в конце концов, вы получите validationFailed в ответе AJAX.
для этой цели лучше использовать метод действия вместо actionListener. Тогда вы можете вернуться null
(перезагружает страницу, которая вызвала действие) из этого метода, если имя пользователя существует. Вот пример:
В экземпляры facelet:
<h:commandButton action="#{testBean.doAction}" value="and... Action"/>
в зернах:
public String doAction() {
if (userExists) {
return null;
} else {
// go on processing ...
}
}
вы можете определить случай навигации в faces-config.XML-файл. Это позволит вам перенаправить пользователя на заданную страницу в зависимости от возвращаемого значения компонента.
в приведенном ниже примере suer перенаправляется на одну из двух страниц в зависимости от возвращаемого значения "myMethod()".
<navigation-rule>
<from-view-id>/index.xhtml</from-view-id>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>true</from-outcome>
<to-view-id>/correct.xhtml</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{myBean.myMethod()}</from-action>
<from-outcome>false</from-outcome>
<to-view-id>/error.xhtml</to-view-id>
</navigation-case>
</navigation-rule>