33

如何在 a 中注入像@EJB, @PersistenceContext, @Inject,@AutoWired等这样的依赖项@FacesValidator?在我的特定情况下,我需要通过以下方式注入 Spring 托管 bean @AutoWired

@FacesValidator("emailExistValidator")
public class EmailExistValidator implements Validator {

    @Autowired
    private UserDao userDao;

    // ...
}

但是,它没有被注入,它仍然存在null,导致java.lang.NullPointerException. 似乎@EJB@PersistenceContext并且@Inject也不起作用。

如何在我的验证器中注入服务依赖项以便我可以访问数据库?

4

2 回答 2

68

JSF 2.3+

如果您已经在 J​​SF 2.3 或更新版本上,并且想通过例如@EJB@PersistenceContext或 注入 CDI 支持的工件@Inject,那么只需添加managed=true@FacesValidator注释以使其由 CDI 管理。

@FacesValidator(value="emailExistValidator", managed=true)

JSF 2.2-

如果您还没有使用 JSF 2.3 或更新版本,那么您基本上需要将其设为托管 bean。使用 Spring's @Component、 CDI's@Named或 JSF's@ManagedBean而不是@FacesValidator为了使其成为托管 bean,从而有资格进行依赖注入。

例如,假设您想使用 CDI @Named

@Named
@ApplicationScoped
public class EmailExistValidator implements Validator {
    // ...
}

您还需要在 EL 中将其作为托管 bean 引用,#{name}而不是作为硬编码字符串中的验证器 ID。因此,所以

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

代替

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

或者

<f:validator binding="#{emailExistValidator}" />

代替

<f:validator validatorId="emailExistValidator" />

对于 EJB,有一种解决方法是从 JNDI 中手动获取它,另请参阅在 @FacesConverter 和 @FacesValidator 中获取 @EJB

如果您碰巧使用 JSF 实用程序库OmniFaces ,从 1.6 版开始,它添加了对在类中使用@Inject和的透明支持,而无需任何额外的配置或注释。另请参阅CDI展示示例@EJB@FacesValidator@FacesValidator

也可以看看:


于 2011-09-27T16:21:11.507 回答
2

如果您使用的是 Java EE 8 和/或 JSF 2.3,您现在可以注入 JSF 验证器。

在 Payara Server 5.192 #badassfish 上使用 Mojarra 2.3.9.payara-p2 进行了测试。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:body>
        Hello from Facelets
        <h:form>
            <h:messages/>
            <h:inputText value="#{someBean.txtField}" validator="someValidator"/>
        </h:form>
    </h:body>
</html>
import javax.inject.Named;
import javax.enterprise.context.Dependent;

@Named(value = "someBean")
@Dependent
public class SomeBean {

  private String txtField;

  public String getTxtField() {
    return txtField;
  }

  public void setTxtField(String txtField) {
    this.txtField = txtField;
  }
}
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.inject.Inject;

@FacesValidator(value = "someValidator", managed = true)
public class CustomValidator implements Validator<String> {

  @Inject
  NewClass newClass;

  @Override
  public void validate(FacesContext context, UIComponent component, String value)
      throws ValidatorException {

    System.out.println("validator running");
    System.out.println("injected bean: " + newClass);

    if (value != null && value.equals("badvalue")) {
      throw new ValidatorException(new FacesMessage(newClass.getMessage()));
    }
  }
}
public class NewClass {

  public String getMessage() {
    return "secret message";
  }
}
import javax.faces.annotation.FacesConfig;

// WITHOUT THIS INJECTION WILL NOT WORK!
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class ConfigurationBean {
}

应该呈现如下内容:

在此处输入图像描述

在意识到需要ConfigurationBean. 从文档中:

FacesConfig.Version.JSF_2_3 此值指示 CDI 应用于 EL 解析以及启用 JSF CDI 注入,如第 5.6.3 节“用于 EL 解析的 CDI”和第 5.9 节“CDI 集成”中所述

从这个 GitHub 问题,https ://github.com/eclipse-ee4j/glassfish/issues/22094 :

默认情况下,JSF 2.3 以与 JSF 先前版本兼容的模式运行,除非应用程序中包含 CDI 托管 bean,并带有注释 @javax.faces.annotation.FacesConfig。要切换到 JSF 2.3 模式,您将需要如下配置 bean:(显示 ConfigurationBean

...

JSF 需要切换到“当前版本”这一事实引起了极大的争议。几乎整个 EG 都投了反对票,但最终我们无法绕过 JCP 为 Java EE 设置的向后兼容性要求以及规范负责人强制执行的要求。

于 2019-12-27T19:32:37.050 回答