Spring 如何使用@EJB、@PersistenceContext、@inject、@Autowired在@FacesValidator中注入

Spring 如何使用@EJB、@PersistenceContext、@inject、@Autowired在@FacesValidator中注入,spring,validation,jsf-2,dependency-injection,service-layer,Spring,Validation,Jsf 2,Dependency Injection,Service Layer,如何在@FacesValidator中注入像@EJB、@PersistenceContext、@inject、@AutoWired等依赖项?在我的特定情况下,我需要通过@AutoWired: 但是,它没有被注入,并且仍然为null,导致java.lang.NullPointerException。 似乎@EJB、@PersistenceContext和@Inject也不起作用 如何在验证器中注入服务依赖项以便访问DB?在JSF2.3之前,注入容器不管理服务依赖项。您需要使其成为托管bean。使用

如何在@FacesValidator中注入像@EJB、@PersistenceContext、@inject、@AutoWired等依赖项?在我的特定情况下,我需要通过@AutoWired:

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

如何在验证器中注入服务依赖项以便访问DB?

在JSF2.3之前,注入容器不管理服务依赖项。您需要使其成为托管bean。使用Spring的@Component、CDI或JSF代替,以使其成为托管bean,从而符合依赖注入的条件

例如,假设您想使用JSF的@ManagedBean:

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

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

而不是

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

这确实很尴尬。JSF的人已经证实了这一令人尴尬的疏忽,他们自JSF2.3以来就将@FacesValidator和@FacesConverter作为合格的注入目标,另请参见。对于EJB,可以通过从JNDI手动获取它来解决问题,另请参见。如果您碰巧使用了CDI扩展,那么还可以通过在类上添加@Advanced注释来解决它

另见:
如果您碰巧使用了JSF实用程序库,那么由于版本1.6是透明的,因此添加了对在@FacesValidator类中使用@Inject和@EJB的透明支持,而无需任何额外的配置或注释。另请参见。

如果您使用的是JavaEE8和/或JSF2.3,那么现在可以将其注入JSF验证器

在payara服务器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>
应该呈现如下内容:

在意识到配置Bean的必要性之前,我把头撞在墙上大约一个小时。从文件中:

FacesConfig.Version.JSF_2_3 该值表示应将CDI用于EL分辨率以及启用JSF CDI注入,如第5.6.3节“EL分辨率CDI”和第5.9节“CDI集成”所述

从这个GitHub问题来看:

默认情况下,JSF2.3以与JSF早期版本兼容的模式运行,除非应用程序中包含CDI管理的bean,并带有注释@javax.faces.annotation.FacesConfig。要切换到JSF2.3模式,您需要一个如下所示的配置bean:shows ConfigurationBean

JSF需要切换到当前版本这一事实引起了极大的争议。几乎整个EG都投了反对票,但最终我们无法绕过JCP为JavaEE设置的向后兼容性要求和spec lead强制执行的向后兼容性要求


对不起,我不做春季运动。我做EJB,对CDI有所了解。但我真的不能在春天的细节。2因为您不想在不同的请求之间共享DAO状态。3绑定要求EL范围中的任何位置都有一个具体实例,该实例由@ManagedBean或@Named准备。validatorId需要@FacesValidator id,但由于我们删除了它,它就不存在了。如果您的DAO类拥有一个状态,并且您将其设置为会话或应用程序范围,那么它将在多个请求或用户之间共享。这可能会导致不期望的结果/行为,即不安全。如果您的DAO类不包含任何状态,也不是来自您正在使用JPA的情况下的持久性上下文!,然后,您可以安全地将其设置为会话或应用程序范围。请举个小例子,您所说的保持状态是什么意思?一个对更改敏感的实例变量,被一个或多个方法使用。例如,公共类FooDAO{private Bar;}这里,Bar是FooDAO类的状态。如果它在会话或应用程序范围内,并且一个请求更改了它,那么它将反映回所有其他请求/会话。这可能是不可取的。在这种情况下,您应该将其保留在请求范围内,以便它不会被所有其他请求/会话共享。但是,如果DAO不保持状态,并且所有的工作都是基于同一个方法块中的变量完成的,那么您可以安全地将其放入会话/应用程序范围。如果DAO是无状态的,即没有任何字段/属性,那么您可以安全地将其保持在一个较宽的范围内。但如果它是有状态的,即有任何字段/属性对基于请求的更改敏感,那么您更愿意将其保留在请求范围内。有趣的是,注释@FacesConfigversion=FacesConfig.Version.JSF_2_3必须存在,即使faces-config.xml中已经设置了Version=2.3。这需要一些时间才能弄清楚。
<f:validator binding="#{emailExistValidator}" />
<h:inputText ... validator="emailExistValidator" />
<f:validator validatorId="emailExistValidator" />
<?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 {
}