Как выполнить проверку 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>