Как выполнить проверку JSF в actionListener или методе действия? - PullRequest
14 голосов
/ 05 мая 2011

В моем приложении хорошо работает проверка Бинов.Теперь я хочу убедиться, что новый пользователь не выбирает имя пользователя, которое уже было выбрано.

В actionlistener у меня есть код, который проверяет базу данных, но как заставить пользователя отправить его обратно встраницу, на которой они были, если выбрали уже существующее имя пользователя?

Ответы [ 5 ]

18 голосов
/ 05 мая 2011

Введение

Вы можете сделать это, но методы JSF ajax / action / listener семантически являются неправильным местом для проверки. Вы на самом деле не хотите заходить так далеко в жизненном цикле JSF, если вы неправильно указали значения в форме. Вы хотите, чтобы жизненный цикл JSF остановился после фазы проверки JSF.

Вы хотите использовать аннотацию Bean Validation JSR303 (@NotNull и друзья) и / или валидатор ограничений или использовать для этого JSF Validator (required="true", <f:validateXxx> и т. Д.). Он будет правильно вызываться на этапе проверки JSF. Таким образом, при сбое проверки значения модели не обновляются, а бизнес-действие не вызывается, и вы остаетесь на той же странице / представлении.

Так как нет стандартной аннотации Bean Validation или JSF Validator для проверки того, является ли заданное входное значение уникальным в соответствии с базой данных, вам необходимо создать собственный валидатор для этого.

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

Пользовательская аннотация валидации бина JSR303

Сначала создайте пользовательскую аннотацию ограничения @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 Validator

Альтернативой является использование пользовательского валидатора 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 .

4 голосов
/ 09 февраля 2012

Да, вы можете.Вы можете выполнить проверку в методе прослушивателя действий, добавить сообщения лиц, если ваша пользовательская проверка не удалась, а затем вызвать FacesContext.validationFailed() непосредственно перед возвратом.

Единственная проблема с этим решением - это происходит после проверки JSF и проверки bean-компонента,То есть это после этапа проверки.Если у вас есть несколько слушателей действий, скажем, listener1 и listener2: если ваша пользовательская проверка в listener1 не удалась, она продолжит выполнение listener2.Но в конце концов вы получите validationFailed в ответе AJAX.

1 голос
/ 05 мая 2011

Для этой цели лучше использовать метод действия вместо actionListener. Затем вы можете вернуть null (перезагрузить страницу, которая запустила действие) из этого метода, если имя пользователя существует. Вот пример:

в лицевой стороне:

<h:commandButton action="#{testBean.doAction}" value="and... Action"/>

в бобе:

public String doAction() {
   if (userExists) {
     return null;
   } else {
     // go on processing ...
   }
}
0 голосов
/ 21 июня 2019

Если вы хотите предоставить отзыв конечному пользователю:

xhtml:

    <p:commandButton value="Go" process="@this" action="#{myBean.checkEntity()}" oncomplete="if(args.validationFailed){PF('widgetOldInfoNotice').show();}"/>

    <p:confirmDialog id="dialogOldInfoNotice" header="NOTICE" severity="alert" widgetVar="widgetOldInfoNotice">
    -- feedback message--
<p:button value="Ok" onclick="PF('widgetOldInfoNotice').hide();"/>
    </p:confirmDialog>

bean:

public String checkEntity() {
    if (!dao.whateverActionToValidateEntity(selectedEntity)) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.validationFailed();
        return "";
    }
    return "myPage.xhtml";
}
0 голосов
/ 05 мая 2011

Вы можете определить регистр навигации в файлеface-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>
...