@EJB inside utility class 为空

@EJB inside utility class is null

我的应用程序中有一个表单,我正在尝试验证用户名 and/or 电子邮件是否已在数据库中。

这是服务 class:

@Stateless
public class CustomerFacade extends AbstractFacade<Customer> {

  @PersistenceContext(unitName = "OnlineStorePU")
  private EntityManager em;

  @Override
  protected EntityManager getEntityManager() {
    return em;
  }

  public CustomerFacade() {
    super(Customer.class);
  }

}

这是实体 class:

@Entity
@Table(name = "customer")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Customer.findAll", query = "SELECT c FROM Customer c"),
    @NamedQuery(name = "Customer.findById", query = "SELECT c FROM Customer c WHERE c.id = :id"),
    @NamedQuery(name = "Customer.findByName", query = "SELECT c FROM Customer c WHERE c.name = :name"),
    @NamedQuery(name = "Customer.findByMobile", query = "SELECT c FROM Customer c WHERE c.mobile = :mobile"),
    @NamedQuery(name = "Customer.findByEmail", query = "SELECT c FROM Customer c WHERE c.email = :email"),
    @NamedQuery(name = "Customer.findByAddress", query = "SELECT c FROM Customer c WHERE c.address = :address"),
    @NamedQuery(name = "Customer.findByFax", query = "SELECT c FROM Customer c WHERE c.fax = :fax"),
    @NamedQuery(name = "Customer.findByTelephone", query = "SELECT c FROM Customer c WHERE c.telephone = :telephone"),
    @NamedQuery(name = "Customer.findByUsername", query = "SELECT c FROM Customer c WHERE c.username = :username")})
public class Customer implements Serializable {

//ALL GETTERS AND SETTERS + CONSTRUCTOR

}

这是class检查表格:

public class ErrorUtils {

  @EJB
  private CustomerFacade customerFacade;

  //**the arg String uName is the username input from the form**
  private boolean isUserNameInDBOK(String uName) {
    boolean OKBD = true;
    //            Checking UserName is not in the DB
    for (Customer customer : customerFacade.findAll()) {
        if (customer.getUsername().equals(uName)) {
            OKBD = false;
            break;
        }
    }
    return OKBD;
  }
}

我得到的错误是 customerFacadenull:

Warning:   StandardWrapperValve[ControllerServlet]: Servlet.service()     
for servlet ControllerServlet threw exception java.lang.NullPointerException

这是怎么造成的,我该如何解决?

通过 @EJB 注入仅适用于容器管理的工件。 IE。 classes 的实例由容器本身创建,因此不是您通过 new 运算符创建的。

例如一个 servlet:

@WebServlet("/your-servlet")
public class YourServlet extends HttpServlet {

    @EJB
    private YourService yourService;

}

容器本身 new YourServlet()。容器负责执行依赖注入。容器负责调用 init()。容器负责调用适当的 doXxx() 方法。等等,这是一个容器管理的神器。

但是,您试图将其注入某些实用程序 class:

public class ErrorUtils {

    @EJB
    private CustomerFacade customerFacade;

}

这看起来不像是容器管理的工件。鉴于 class 上完全没有任何与容器管理相关的注释,例如 @Stateless@ApplicationScoped@WebServlet 等,您很可能只是手动创建了一个你自己的实例如下:

ErrorUtils errorUtils = new ErrorUtils();

然后你期望 @EJB 神奇地被注入。

错了。

您使用 new 关键字手动创建了 ErrorUtils class 的实例。您正在手动管理它。所以您基本上还需要手动获取并设置该 EJB。通常,您为此使用 JNDI,另请参阅

errorUtils.customerFacade = (CustomerFacade) new InitialContext().lookup("java:/.../CustomerFacade");

但是,更好的方法是将 class 变成容器管理的工件。例如。一个 CDI 托管 bean:

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class ErrorUtils {

然后将其注入您的 servlet 而不是手动制作它:

@WebServlet("/your-servlet")
public class YourServlet extends HttpServlet {

    @Inject
    private ErrorUtils errorUtils;

}

它会注意它的所有依赖项,如 @EJB 也被正确注入。


与具体问题无关,以下没有意义:

private boolean isUserNameInDBOK(String uName) {
    boolean OKBD = true;
    //            Checking UserName is not in the DB
    for (Customer customer : customerFacade.findAll()) {
        if (customer.getUsername().equals(uName)) {
            OKBD = false;
            break;
        }
    }
    return OKBD;
}

您基本上违背了关系数据库系统的目的,低估了结构化查询语言的能力 SQL。您基本上是将整个数据库 table 完全复制到 Java 的内存中,然后手动探索每条记录是否符合给定条件。

这显然效率低下。您应该以这样的方式与数据库进行交互,即return完全您需要的信息,仅此而已。您可以为此使用 WHERE 子句。看来您的 IDE 足够聪明,可以为您自动生成这样一个命名查询:Customer.findByName。好好利用吧。

private boolean isUserNameInDBOK(String uName) {
    return customerFacade.findByName(name) != null;
}

这样数据库将 return 1 或 0 条记录匹配给定条件。您只需要检查它是否 return 记录了。然而更有效的是添加一个命名查询,它执行 COUNT(*) returning longboolean 而不是整个 Customer。即使那样,整个 ErrorUtils class 在这个结构中也是多余的。直接调用服务方法即可。