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>

自定义验证器

@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));
        }
    }
}

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

4

1 回答 1

5

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

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

<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>

带背豆:

@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;
    }

    ...
}

评论回复:

  • 这是一个普通的 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"));
        }
    }
}

并且应该像这样使用:

<h:inputText value="#{someBean.username}" validator="usernameValidator" />

所以:

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

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

如果您需要验证一个必须为非空大于 1970 年 1 月 1 日的组件值(即日期),您将需要两个专门的验证器。

于 2016-05-03T08:54:46.107 回答