/Registration.xhtml @19,81 validator="#{UsernameValidator}": Identity 'UsernameValidator' 为空,无法调用

/Registration.xhtml @19,81 validator="#{UsernameValidator}": Identity 'UsernameValidator' was null and was unable to invoke

这是我的项目结构:

这是在我的 XHTML 文件中:

<h:inputText id="username" value="#{user.username}" required="true"
 validator="#{UsernameValidator}" />
 <h:message for="username"/>

这里是 UsernameValidator class:

@FacesValidator("UsernameValidator")
public class UsernameValidator implements Validator {

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
        JOptionPane.showMessageDialog(null, "in validator class");
        if (String.valueOf(value).length() == 0 || String.valueOf(value).length() < 3) {
            FacesMessage message = new FacesMessage("Username Validation Failed", "Invalid Username");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
    }
}

但是当我在 username 字段中写东西时,会发生此错误:

/Registration.xhtml @19,81 validator="#{UsernameValidator}": Identity 'UsernameValidator' was null and was unable to invoke

您的 Registration.xhtml 文件似乎有问题。验证器需要在 标签内有一个单独的标签:

<h:inputText id="username" value="#{user.username}" required="true">
<f:validator validatorId="UsernameValidator" />
</h:inputText>

<h:message for="username" />

您遇到的错误似乎是由于 JSF 无法找到验证 bean 引起的。您的项目目录看起来不错,但请检查以确保 UsernameValidator 的 class 文件存在并且可以被您的应用服务器读取。

由于你的问题稍作修改,我在与你原问题相关的内容处添加了删除线:

首先,除了使用自定义组件之外,应用程序级别的验证还包括第 3 点和第 4 点(使用 Validator 接口和支持 bean 中的验证方法的自定义验证)。

您似乎混淆了使用 bean 方法的验证和实现自定义验证器 classes(最后两个),以您的代码为例快速回顾一下这两种方法:

使用 bean 方法验证:

这是最简单的一个,因为您只需要向您的 class 添加验证方法并使用 validator 属性通过方法表达式调用它,就像您的示例一样:

<h:inputText id="username" value="#{user.username}" required="true" validator="#{usernameValidator}" /> 
// I changed to usernameValidator to respect naming conventions

但是,在那种情况下,usernameValidatoruser @ManagedBean 中的一个方法,像这样:

@ManagedBean("user")
@SessionScoped
public class User implements Serializable{

    // Please notice that this method should have the same signature as the validate method of the interface Validator 
    public void usernameValidator(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
        JOptionPane.showMessageDialog(null, "in validator class");
        if (String.valueOf(value).length() == 0 || String.valueOf(value).length() < 3) {
            FacesMessage message = new FacesMessage("Username Validation Failed", "Invalid Username");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
    }
}

自定义验证器 Classes:

Class 的实现与您所做的相同,即实现 Validator 接口,并通过给它和 ID 、 [=73 来注册验证器=]我会复制你的确切代码以使答案干净:

// I just changed the ID from UsernameValidator to usernameValidator
@FacesValidator("usernameValidator") 
public class UsernameValidator implements Validator {

    @Override
    public void validate(FacesContext fc, UIComponent uic, Object value) throws ValidatorException {
        JOptionPane.showMessageDialog(null, "in validator class");
        if (String.valueOf(value).length() == 0 || String.valueOf(value).length() < 3) {
            FacesMessage message = new FacesMessage("Username Validation Failed", "Invalid Username");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ValidatorException(message);
        }
    }
}

您可以通过使用注释 @FacesValidator("usernameValidator")(您已经这样做了)将 IDID 提供给您的验证器,faces-config.xml通过添加以下内容:

<validator>
    <validator-id>usernameValidator</validator-id>
    <validator-class>yourpackage.UsernameValidator</validator-class>
</validator>

然后,您将在 f:validator 标签中使用相同的 ID,如下所示:

<h:inputText id="username" value="#{user.username}" required="true">
    <f:validator validatorId="usernameValidator" />
</h:inputText>

注意:这是不是JSF中的所有验证方法,但我认为这两个是自定义验证最简单的方法您可以在您的示例中使用 (它分别是您提供的 JSF 验证方式列表中的 4 和 3).

作为附加信息,我还将简要回顾一下 不适合 的内置验证组件代码示例:

内置验证组件:

JSF(我说的是 2.0,因为我不确定 JSF 2.2 中是否有一些新的)具有可用于验证的标准验证器:

  • String的长度使用f:validateLength
  • 一个double/long值在可选范围内分别使用f:validateDoubleRange/f:validateLongRange
  • A String 使用 f:validateRegex
  • 对抗正则表达式
  • 使用 f:validateRequired 或属性 required
  • 的必需值

还有另一种方法可以使用 f:validator 使用这些标签,您可以找到 good example here

另请参阅:

你的错误在这里:

<h:inputText ... validator="#{UsernameValidator}" />

您正在尝试将 @FacesValidator 引用为托管 bean。这行不通。 @FacesValidator 注释中的值代表应用程序范围的验证器 ID,它被指定为一个字符串,而不是托管 bean 名称。

所以,下面应该做:

<h:inputText ... validator="UsernameValidator" />

是的,您可能已经看到代码片段,其中通过 #{...} 将验证器(或转换器)引用为托管 bean。但在那些情况下,它们 实际上 也通过 @ManagedBean@Named 而不是 @FacesValidator(或 @FacesConverter)注册为托管 bean .

@ManagedBean
@RequestScoped
public class UsernameValidator implements Validator {}

通常这样做是为了能够将 EJB 注入其中,以便可以执行任何必要的 business/DB 逻辑。

另请参阅:

  • How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @Autowired

与具体问题无关:以下

JOptionPane.showMessageDialog(null, "in validator class");

web 应用程序中执行“日志记录”是一种非常、非常 糟糕的方法。请停止这样做。