【问题标题】:Custom Validator class not working自定义验证器类不起作用
【发布时间】:2025-12-09 03:15:01
【问题描述】:

我有一个问题:

场景: 我有一个 JSF-2,Spring(Beans 布线)应用程序。我编写了一个自定义验证器,我想执行它。

@FacesValidator("com.test.vali")
@Named("com.test.vali")
public class TestValidator implements Validator {

    @Override
    public void validate(FacesContext arg0, UIComponent arg1, Object arg2) throws ValidatorException {
        System.out.println("dhkdfkbhdfbkdfksdfdfk");

    }

}

我尝试使用以下方式注入验证器:

方式#1:

  <h:inputText value="#{helloWorld.name}">
      <f:validator binding="#{com.test.vali}" />
  </h:inputText>

输出

当试图渲染页面时,它抛出了一个异常。

javax.servlet.ServletException: /testRichFaces.xhtml @17,48 <f:validator> A validator id was not specified. Typically the validator id is set in the constructor ValidateHandler(ValidatorConfig)

对此进行了很多搜索,并验证了以下几种方法:

  1. Java 文件位于包中。

方式#2

 <f:validator validatorId="com.test.vali" />

输出

javax.servlet.ServletException: Expression Error: Named Object: com.test.vali not found.

因此,从方式#1 和方式#2 来看,我可以解释没有任何注释对我有用。

然后,我尝试转向最后一种方法:

方式#3:在 faces-config.xml 中添加验证器,只是为了表明我使用的是 2.0 合规性:

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">

验证器配置为:

 <validator>
       <validator-id>com.test.vali</validator-id>
       <validator-class>teet.TestValidator</validator-class>
 </validator>

输出

作品

现在问题来了,即使使用 JSF-2.0,我也不得不求助于 faces-config.xml。

我做错了什么?

如果需要更多配置,请告知。

【问题讨论】:

  • @Named 注释不是必需的。你是如何管理你的 backing bean 的。如果它们使用 Spring 注释进行注释,那么您必须在 faces-config.xml 中配置 org.springframework.web.jsf.el.SpringBeanFacesELResolver。

标签: java jsf-2 cdi


【解决方案1】:

首先,您基本上混合了两种注册验证器实例的方法,它们完全独立工作:通过@FacesValidator 注册为面部验证器,或通过@Named 注册为CDI 托管bean。那些注解彼此不认识,也不考虑彼此。你基本上会得到两个完全不同的实例,它们不共享彼此的数据。因此,为避免将来出现混淆,强烈建议删除其中一个注释,这样您就可以保证始终使用同一个实例。

至于方式一失败的原因:

@Named("com.test.vali")
public class TestValidator implements Validator {
    // ...
}
<f:validator binding="#{com.test.vali}" />

这是因为句点. 是EL 中的一个特殊运算符,表示bean 属性访问或bean 方法调用。使用#{com.test.vali} 只会查找一个bean #{com},然后是它的test 属性,然后是它的vali 属性。换句话说,它基本上是试图通过com.getTest().getVali() 获取验证器,其中com 是一个CDI 托管bean,就像@Named("com") 一样。

这不是您的本意。摆脱名称中的那些句点。更好的是,只需使用默认实例名称 testValidator。这是最明智的选择,如果你给你的类起一个合理的名字,那是肯定的。

@Named
public class TestValidator implements Validator {
    // ...
}
<f:validator binding="#{testValidator}" />

至于方式2失败的原因:

@FacesValidator("com.test.vali")
public class TestValidator implements Validator {
    // ...
}
<f:validator validatorId="com.test.vali" />

@FacesValidator 在启动期间没有被正确拾取时,可能会发生这种情况。当所讨论的类不在 WAR 内部,而是在例如内部时,这可能反过来发生。 EAR 或 EJB。在这种情况下,您需要在faces-config.xml 中显式注册验证器。但最好将类放在 WAR 中,即绝对没有在项目的 EAR 或 EJB 部分中有任何 JSF 工件。它将模型/服务逻辑(JPA、EJB 等)与视图(JSF)紧密耦合,并使它们不再可用于其他视图(前端),例如 JAX-RS、Spring MVC、Struts2 等。

【讨论】:

  • +1 用于捕获两个注释和“。” EL 表达式中的操作符事实。我完全没有想到“。”
  • 我删除了 FacesValidator 并继续使用 @Named 以保持一致性,但有一件事我不清楚。我制作了一个扩展 UIInput 的自定义控件,并为它制作了一个验证器。使用 ,我尝试注册验证器。但是在测试时我无法执行它。在调试时,我可以看到带有自定义组件的验证器。但由于某种原因,它没有执行。然后我重写组件的 validate 方法,获取验证器并执行每个绑定的验证器的 validate 方法。方法对吗?
  • 验证器在默认情况下或配置为空时不会被调用。为此,应使用required 属性,或者应将javax.faces.VALIDATE_EMPTY_FIELDS 上下文参数设置为true
  • @BalusC 我尝试了您的 CDI 托管验证器,但它仅在我使用 f:validateBean 而不是 f:validator 时才有效。