Tomcat中用EntityManager持久化对象遇DAO空指针及驱动问题求助
Tomcat中使用EntityManager持久化User对象的两类问题及解决方法
问题1:Servlet中@Inject注入的UserDao为空,触发NullPointerException
相关代码
User.java
package ma.ac.iga.jee_with_spring.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class User { @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private int id; private String firstName; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } }
UserServlet.java
package ma.ac.iga.jee_with_spring.servlet; import ma.ac.iga.jee_with_spring.dao.UserDao; import ma.ac.iga.jee_with_spring.entity.User; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/user") public class UserServlet extends HttpServlet { @Inject UserDao userDao; // 注入实例为空,触发空指针 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { User user = new User(); user.setFirstName("achraf"); userDao.save(user); } }
UserDao.java
package ma.ac.iga.jee_with_spring.dao; import ma.ac.iga.jee_with_spring.entity.User; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; // 看到有些示例用@Stateless,但这里无法引用 public class UserDao { @PersistenceContext(unitName = "default") private EntityManager entityManager; public void save(User user) { entityManager.persist(user); } }
persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="default"> <class>ma.ac.iga.jee_with_spring.entity.User</class> <properties> <property name="javax.persistence.jdbc.Driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/projetjee"/> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="1341"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/> <property name="hibernate.hbm2ddl.auto" value="create"/> </properties> </persistence-unit> </persistence>
pom.xml(关键依赖部分)
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.6.15.Final</version> </dependency> <dependency> <groupId>org.jboss.weld.se</groupId> <artifactId>weld-se-core</artifactId> <version>3.1.9.Final</version> </dependency> <!-- 其他依赖省略 --> </dependencies>
错误信息
Type Exception Report Message Cannot invoke "ma.ac.iga.jee_with_spring.dao.UserDao.save(ma.ac.iga.jee_with_spring.entity.User)" because "this.userDao" is null Description The server encountered an unexpected condition that prevented it from fulfilling the request. Exception java.lang.NullPointerException: Cannot invoke "ma.ac.iga.jee_with_spring.dao.UserDao.save(ma.ac.iga.jee_with_spring.entity.User)" because "this.userDao" is null ma.ac.iga.jee_with_spring.servlet.UserServlet.doPost(UserServlet.java:24) javax.servlet.http.HttpServlet.service(HttpServlet.java:555) javax.servlet.http.HttpServlet.service(HttpServlet.java:623) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
解决方法
- 为UserDao添加CDI管理注解
CDI容器只会管理带有特定注解的类,给UserDao添加@ApplicationScoped或@Named注解,让它成为可被注入的CDI Bean:
import javax.enterprise.context.ApplicationScoped; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @ApplicationScoped public class UserDao { @PersistenceContext(unitName = "default") private EntityManager entityManager; public void save(User user) { entityManager.persist(user); } }
- 替换CDI依赖为Servlet环境适配包
当前使用的weld-se-core是SE环境的CDI实现,Tomcat作为Servlet容器需要适配的weld-servlet-core,修改pom.xml中的依赖:
<dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-core</artifactId> <version>3.1.9.Final</version> </dependency>
同时移除原有的weld-se-core依赖。
- 添加beans.xml文件
在WEB-INF目录下创建beans.xml文件,告知CDI容器启动并扫描Bean:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd" version="2.0" bean-discovery-mode="all"> </beans>
bean-discovery-mode="all"会扫描项目中所有带CDI注解的类。
问题2:Servlet中直接创建EntityManagerFactory提示"no suitable driver for mysql"
相关代码
EntityManagerFactory emf = Persistence.createEntityManagerFactory("default"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); User user = new User(); user.setFirstName("achraf"); em.persist(user); em.getTransaction().commit();
解决方法
- 添加MySQL JDBC驱动依赖
pom.xml中缺少MySQL驱动,添加以下依赖:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <scope>runtime</scope> </dependency>
如果使用MySQL 8.0+版本,需同步修改persistence.xml中的驱动类名和URL(添加时区参数避免时区错误):
<property name="javax.persistence.jdbc.Driver" value="com.mysql.cj.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/projetjee?serverTimezone=UTC"/>
- 确保驱动被打包到WAR中
检查maven-war-plugin配置,确认依赖被正确打包到WAR的WEB-INF/lib目录下,默认配置会自动打包,若有特殊配置需手动验证。
内容的提问来源于stack exchange,提问作者achraf
相关产品推荐
相关产品推荐

