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