如何在 JSF 中执行验证,如何在 JSF 中创建自定义验证器



我想在我的一些输入组件中执行验证,例如使用一些Java bean方法进行<h:inputText>。我应该为此使用<f:validator>还是<f:validateBean>?我在哪里可以阅读更多关于它的信息?

标准方法是实现Validator接口。

@FacesValidator("fooValidator")
public class FooValidator implements Validator {
    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        // ...
        if (valueIsInvalid) {
            throw new ValidatorException(new FacesMessage("Value is invalid!"));
        }
    }
}

@FacesValidator将使用验证器ID myValidator将其注册到JSF,以便您可以在任何<h:inputXxx>/<h:selectXxx>组件的validator属性中引用它,如下所示:

<h:inputText id="foo" value="#{bean.foo}" validator="fooValidator" />
<h:message for="foo" />

每当验证器抛出ValidatorException,那么它的消息将显示在与输入字段关联的<h:message>中。

您还可以在任何<h:inputXxx>/<h:selectXxx>组件的validator属性中使用EL,其中您引用的托管Bean方法与Validator#validate()具有完全相同的方法签名(相同的方法参数),即按此顺序获取FacesContextUIComponentObject参数。

<h:inputText id="foo" value="#{bean.foo}" validator="#{bean.validateFoo}" />
<h:message for="foo" />
public void validateFoo(FacesContext context, UIComponent component, Object value) throws ValidatorException {
    // ...
    if (valueIsInvalid) {
        throw new ValidatorException(new FacesMessage("Value is invalid!"));
    }
}

仅当验证器需要访问同一受管 Bean 中存在的另一个属性时,这才有用。如果不需要,那么这种方法被认为是紧密耦合的(因此做法很差),你应该将验证器拆分到它自己的类中,实现Validator接口。

您还可以使用<f:validator>标记处理程序,如果您打算在同一组件上附加多个验证器,这将是唯一的方法:

<h:inputText id="foo" value="#{bean.foo}">
    <f:validator validatorId="fooValidator" />
</h:inputText>
<h:message for="foo" />

这将执行上面显示的@FacesValidator("fooValidator")

您还可以使用 <f:validator binding> 引用 EL 作用域中某处的具体验证程序实例,可以通过以下方式指定和提供该实例:

<h:inputText id="foo" value="#{bean.foo}">
    <f:validator binding="#{fooValidator}" />
</h:inputText>
<h:message for="foo" />
@Named("fooValidator")
public class FooValidator implements Validator {
    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        // ...
        if (valueIsInvalid) {
            throw new ValidatorException(new FacesMessage("Value is invalid!"));
        }
    }
}

请注意,因此使用的是@Named而不是@FacesValidator。这里也支持旧@ManagedBean而不是@Named。从历史上看,这是一个技巧,以便能够在验证器中使用@EJB@Inject。另请参阅如何使用@EJB、@PersistenceContext、@Inject@Autowired注入@FacesValidator

或者这样,反过来可以很容易地作为lambda提供:

<h:inputText id="foo" value="#{bean.foo}">
    <f:validator binding="#{bean.fooValidator}" />
</h:inputText>
<h:message for="foo" />
public Validator getFooValidator() {
    return (context, component, value) -> {
        // ...
        if (valueIsInvalid) {
            throw new ValidatorException(new FacesMessage("Value is invalid!"));
        }
    };
}

当这个验证器不需要来自同一 bean 的任何其他属性时,这里也应用了相同的紧密耦合问题。

为了更进一步,您可以使用 JSR303 Bean 验证。这将根据批注验证字段。所以你可以只有一个

@Foo
private String foo;

无需在 XHTML 端显式注册任何验证器。如果您使用 JPA 进行持久性,则默认情况下,此验证器也将在数据库中插入/更新期间执行。由于这将是一个完整的故事,因此这里只是一些开始的链接:

  • 休眠验证器 - 入门
  • JSF 2.0 教程 - 微调验证

还有一个<f:validateBean>标记,但这仅在您打算禁用 JSR303 Bean 验证时才有用。然后,您将输入组件(甚至整个表单)放入<f:validateBean disabled="true"> 中。

另请参阅:

  • JSF 不支持跨字段验证,有解决方法吗?
  • 如何在 actionListener 或 action Method 中执行 JSF 验证?

相关内容

  • 没有找到相关文章

最新更新