JSF 2.3中的f:validateWholeBean

Pet*_*zov 3 jsf jsf-2.3

我想f:validateWholeBean用JSF 2.3 实施。我尝试使用Mojarra 2.3.0-m05Tomcat 8 实现此示例:

<h:form>
    <h:panelGroup>
        <h:inputSecret id="passwd" value="#{bean.dataList['passwd']}">
            <f:ajax event="blur" render="passwdvalidator" />
        </h:inputSecret>
        <h:message id="passwdvalidator" for="passwd" />
    </h:panelGroup>

    <h:panelGroup>Confirm Password</h:panelGroup>
    <h:panelGroup>
        <h:inputSecret id="confurmpasswd" value="#{bean.dataList['passwd']}">
            <f:ajax event="blur" render="confurmpasswdvalidator" />
        </h:inputSecret>
        <h:message id="confurmpasswdvalidator" for="confurmpasswd" />
    </h:panelGroup>
    <h:commandButton action="#{bean.submit}">
        <f:ajax render="@form" execute="@form"></f:ajax>
    </h:commandButton>                          

    <f:validateWholeBean  value="#{contactBean}" validationGroups="validateBean.ContactGroup" />
</h:form>
Run Code Online (Sandbox Code Playgroud)

自定义验证器

@Named
@ViewScoped
public class NewAccountValidator implements Validator, Serializable
{
    @Override
    public void validate(FacesContext fc, UIComponent uic, Object o) throws ValidatorException
    {
        // not used
    }

    public void validatePasswords(FacesContext context, UIComponent component, Object value)
    {
        String l;
        String s = value.toString().trim();

        if (s != null)
        {
            // compare passwords
        }
        else
        {
            throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO,
                s.isEmpty() ? "  This field cannot be empty!" : "  '" + s + "' is not a number!", null));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用f:validateWholeBean自定义JSF验证程序实现解决方案的正确方法是什么?

Mic*_*tti 5

您不应实现“标准”验证器,而应实现ConstraintValidator

您可以在Arjan Tijms Weblog上找到一个示例:

<h:form>
    <h:inputText value="#{indexBean.foo}">
        <f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/>
    </h:inputText>
    <h:inputText value="#{indexBean.bar}">
        <f:validateBean validationGroups="javax.validation.groups.Default,java.util.RandomAccess"/>
    </h:inputText>

    <f:validateWholeBean value="#{indexBean}" validationGroups="java.util.RandomAccess"/>

    <h:commandButton value="submit"/>
</h:form>
Run Code Online (Sandbox Code Playgroud)

与支持豆:

@Named
@RequestScoped
@ValidIndexBean(groups = java.util.RandomAccess.class)
public class IndexBean implements ConstraintValidator<ValidIndexBean, IndexBean> {

    @Constraint(validatedBy = IndexBean.class)
    @Documented
    @Target(TYPE)
    @Retention(RUNTIME)
    public @interface ValidIndexBean {
        String message() default "Invalid Bean";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }

    @Inject // @EJB
    private PersistenceService service;

    @NotNull
    private String foo;

    @NotNull
    private String bar;

    @Override
    public void initialize(ValidIndexBean constraintAnnotation) {
        //
    }

    @Override
    public boolean isValid(IndexBean other, ConstraintValidatorContext context) {
        // return other.getFoo().equals(other.getBar());

        return service.query("select count(p) from Person p where p.foo like ?1 and p.bar like ?2", other.getFoo(), other.getBar()) == 0;
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

回答评论:

  • 这是一个普通的bean,所以可以,它可以是@ViewScoped。
  • 那么您应该创建多个验证器:让单个验证器执行多个逻辑是一种不好的做法。

无关:

从发布的代码中可以看到,您误解了“经典”验证器的使用,使其成为ManagedBean(带有CDI风格),但这不是 JSF验证器/转换器的“普通”用法。

我想您不是在使用验证器,而是在使用验证方法

“经典”验证器应如下所示(请参见此处):

@FacesValidator("usernameValidator")
public class UsernameValidator implements Validator, Serializable
{
    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException
    {
        // you should use THIS method to validate a single Component's Value

        if(query("select count(*) from user where username = '?'", String.valueOf(value)) > 0)
        {
            throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "invalid username"));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并应按以下方式使用:

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

所以:

  1. “经典”的Faces Validator很难验证一个组件的价值
  2. 他们不应该是@ManagedBean或@Named
  3. 它们应按名称引用(validator="usernameValidator"不使用EL表达式validator="#{usernameValidator}"

但是,“验证器/转换器”被“专业化”是最佳实践:它们应该执行单个验证逻辑。

如果您需要验证必须为非空大于01/01/1970 的组件值(即Date),则需要两个专门的验证器。