【问题标题】:How to perform validation in JSF, how to create a custom validator in JSF如何在 JSF 中执行验证,如何在 JSF 中创建自定义验证器
【发布时间】:2011-08-28 05:15:24
【问题描述】:

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

【问题讨论】:

    标签: validation jsf jsf-2 javabeans


    【解决方案1】:

    标准方式是实现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,其消息就会显示在与输入字段关联的&lt;h:message&gt; 中。

    您还可以在任何 &lt;h:inputXxx&gt;/&lt;h:selectXxx&gt; 组件的 validator 属性中使用 EL,其中您引用的托管 bean 方法具有与 Validator#validate() 完全相同的方法签名(相同的方法参数)。 IE。按此顺序获取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 接口的自己的类。

    您也可以使用&lt;f:validator&gt; taghandler,如果您打算在同一个组件上附加多个验证器,这是唯一的方法:

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

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

    您还可以使用&lt;f:validator binding&gt; 来引用 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。另见How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired

    或者这种方式,反过来可以很容易地作为 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 进行持久性,默认情况下,此验证器也将在数据库中插入/更新期间执行。由于这将是一个完整的故事,这里只是一些开始的链接:

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

    另见:

    【讨论】:

      猜你喜欢
      • 2013-02-04
      • 1970-01-01
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 2012-05-11
      • 2015-10-30
      相关资源
      最近更新 更多