如何在actionListener或action方法中执行JSF验证?

Far*_*san 14 validation jsf bean-validation

我的Bean验证在我的应用程序中运行良好.现在我想检查新用户是否选择了已经选择的用户名.

在actionlistener中,我有检查数据库的代码,但如果用户选择已存在的用户名,如何强制用户被发送回他们所在的页面?

Bal*_*usC 18

介绍

可以这样做,但JSF ajax/action/listener方法在语义上是错误的验证位置.如果表单中的输入值错误,您实际上不希望在JSF生命周期中达到那么远.您希望JSF生命周期在JSF验证阶段后停止.

你想用一个JSR303 Bean验证注解(@NotNull和朋友)和/或约束验证,或者使用JSF Validator(required="true",<f:validateXxx>,等)为代替.它将在JSF验证阶段正确调用.这样,当验证失败时,不会更新模型值,也不会调用业务操作,并且您将保持在同一页面/视图中.

由于没有标准的Bean Validation批注或JSF Validator来检查给定的输入值是否根据数据库是唯一的,因此您需要为此自定义验证器.

我将以两种方式展示如何创建一个自定义验证器来检查用户名的唯一性.

自定义JSR303 Bean验证注释

首先创建自定义@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 {};
}
Run Code Online (Sandbox Code Playgroud)

在此约束验证器(注:@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);
    }

}
Run Code Online (Sandbox Code Playgroud)

最后在模型中使用如下:

@Username
private String username;
Run Code Online (Sandbox Code Playgroud)

自定义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"));
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

最后在视图中使用如下:

<h:inputText id="username" ... validator="#{usernameValidator}" />
<h:message for="username" />
Run Code Online (Sandbox Code Playgroud)

请注意,您通常@FacesValidatorValidator类上使用注释,但在即将推出的JSF 2.3之前,它不支持@EJB@Inject.另请参见如何使用@EJB,@ PersistenceContext,@ Inject,@ Autowired注入@FacesValidator.

  • 在Bean验证之前执行JSF验证.但是如果值为"null"或为空,那么除了"required"之外的JSF验证将不会被执行.所以,如果你有一个没有'required ="true"`的`@NotNull`,那么它将首先被执行.但是如果它不是空的并且你有一个`@ Pattern`,那么将首先调用JSF验证器. (2认同)