Spring Data JPA中TicketRepository空指针异常排查求助
空指针异常原因分析及解决办法
问题描述
应用运行时抛出NullPointerException:无法调用com.Practice.PracticeProject.Repositories.TicketRepository.findAllByEmployeeID(int),因为ticketRepository为null,报错位置在Login.java第80行的AllMyTickets方法中。期望通过Spring JPA返回工单列表,但多次尝试注入TicketRepository均失败,运行时始终出现空指针异常。
相关代码
Login类代码
package com.Practice.PracticeProject.Service; import com.Practice.PracticeProject.Model.Tickets; import com.Practice.PracticeProject.Repositories.TicketRepository; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Service; import java.security.Principal; import java.util.List; @Service public class Login { Authentication currentUser; public Login() { } public Login(Authentication currentUser) { this.currentUser = currentUser; } public String loggInUser(Principal principal, UserDetailsService userDetailsService) { UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName()); if (userDetails != null) { System.out.println("Andre the current user is " + userDetails.getUsername()); return userDetails.getUsername(); } else { System.out.println("No current user"); return "No Current User"; } } public String currentUserInfo(Principal principal, UserDetailsService userDetailsService) { UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName()); if (userDetails != null) { return userDetails.toString(); } else { return "No Current User"; } } public List<Tickets> AllMyTickets(int id, TicketRepository ticketRepository ) { List<Tickets> myTickets = ticketRepository.findAllByEmployeeID(id); if(myTickets.isEmpty()) { System.out.println("Did not find any Tickets for given empoyeeid"); System.exit(0); } return myTickets; } }
TicketRepository类代码
package com.Practice.PracticeProject.Repositories; import com.Practice.PracticeProject.Model.Tickets; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface TicketRepository extends JpaRepository<Tickets, Integer> { @Query(nativeQuery = true, value = "SELECT * FROM tickets WHERE ticketid = :ticketid") List<Tickets> findAllByEmployeeID(@Param("ticketid") int ticketid); }
异常原因
- 依赖注入方式错误:
Login类的AllMyTickets方法通过参数接收ticketRepository,而非让Spring容器自动注入。调用该方法时若未传入有效的TicketRepository实例,必然导致空指针。Spring管理的Bean依赖应该通过类成员变量注入,而非方法参数传递。 - 构造器设计问题:
Login类同时存在无参和带Authentication参数的构造器,Spring默认优先使用无参构造器创建实例,若未正确配置构造器注入,会影响其他依赖的初始化。 - Repository查询逻辑语义不符:
findAllByEmployeeID方法名指向“按员工ID查询”,但原生SQL实际过滤的是ticketid字段,不仅逻辑混淆,还可能导致查询结果不符合预期。
解决办法
1. 修正依赖注入方式
将TicketRepository改为Login类的成员变量,通过构造器注入让Spring管理:
package com.Practice.PracticeProject.Service; import com.Practice.PracticeProject.Model.Tickets; import com.Practice.PracticeProject.Repositories.TicketRepository; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Service; import java.security.Principal; import java.util.List; @Service public class Login { private final Authentication currentUser; private final TicketRepository ticketRepository; // 构造器注入所有依赖,移除无参构造器(或保留但确保Spring能正确处理) public Login(Authentication currentUser, TicketRepository ticketRepository) { this.currentUser = currentUser; this.ticketRepository = ticketRepository; } public String loggInUser(Principal principal, UserDetailsService userDetailsService) { UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName()); if (userDetails != null) { System.out.println("Andre the current user is " + userDetails.getUsername()); return userDetails.getUsername(); } else { System.out.println("No current user"); return "No Current User"; } } public String currentUserInfo(Principal principal, UserDetailsService userDetailsService) { UserDetails userDetails = userDetailsService.loadUserByUsername(principal.getName()); if (userDetails != null) { return userDetails.toString(); } else { return "No Current User"; } } public List<Tickets> AllMyTickets(int id) { List<Tickets> myTickets = ticketRepository.findAllByEmployeeID(id); if(myTickets.isEmpty()) { System.out.println("Did not find any Tickets for given empoyeeid"); // 替换System.exit(0),避免直接终止应用 throw new RuntimeException("No tickets found for employee ID: " + id); } return myTickets; } }
2. 修正Repository查询逻辑
让方法名与SQL过滤字段一致,若按员工ID查询,修改SQL为:
package com.Practice.PracticeProject.Repositories; import com.Practice.PracticeProject.Model.Tickets; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface TicketRepository extends JpaRepository<Tickets, Integer> { // 修正SQL,过滤employeeid字段 @Query(nativeQuery = true, value = "SELECT * FROM tickets WHERE employeeid = :employeeId") List<Tickets> findAllByEmployeeID(@Param("employeeId") int employeeId); // 可选:使用Spring Data JPA方法命名规则,无需原生SQL // List<Tickets> findByEmployeeId(int employeeId); }
3. 确认组件扫描范围
确保Spring配置的组件扫描路径包含com.Practice.PracticeProject包,这样@Service和@Repository注解的类才能被正确识别并纳入Spring容器管理。
内容的提问来源于stack exchange,提问作者user13288376
相关产品推荐
相关产品推荐

