我正在尝试使用Spring Data JPA保存对象。不幸的是我总是得到一个NullPointerException。但我不明白为什么。我遵循了这个教程:https://www.callicoder.com/spring-boot-jpa-hibernate-postgresql-restful-crud-api-example/我不需要CRUD API,因此我遗漏了属于它的东西。
我收到以下错误:
java.lang.NullPointerException
at com.niclas.elitedangerousapi.handler.SystemPopulatedHandler.insertIntoDB(SystemPopulatedHandler.java:39)
at com.niclas.elitedangerousapi.Main.main(Main.java:19)
[main] ERROR c.n.e.h.SystemPopulatedHandler - null
更新我想填充我的数据库,但随后我想要。最后应该是每天晚上下载文件然后存储在数据库中。后来我想通过API访问数据。我想在开始和每x个小时执行这个方法(systemPopulatedHandler.insertIntoDB())。
SystemPopulated.class
@Data
@Entity
@Table(name = "systems_populated")
@JsonIgnoreProperties(ignoreUnknown = true)
public class SystemPopulated {
@Id
@Column(name = "id")
private int id;
@Column(name = "edsm_id")
private long edsm_id;
@Column(name = "name")
private String name;
@Column(name = "x")
private double x;
@Column(name = "y")
private double y;
@Column(name = "z")
private double z;
@Column(name = "population")
private long population;
@Column(name = "is_populated")
private boolean is_populated;
@Column(name = "government_id")
private long government_id;
@Column(name = "government")
private String government;
@Column(name = "allegiance_id")
private int allegiance_id;
@Column(name = "allegiance")
private String allegiance;
@Column(name = "security_id")
private int security_id;
@Column(name = "security")
private String security;
@Column(name = "primary_economy_id")
private int primary_economy_id;
@Column(name = "primary_economy")
private String primary_economy;
@Column(name = "power")
private String power;
@Column(name = "power_state")
private String power_state;
@Column(name = "power_state_id")
private int power_state_id;
@Column(name = "needs_permit")
private boolean needs_permit;
@Column(name = "updated_at")
private long updated_at;
@Column(name = "controlling_minor_faction_id")
private int controlling_minor_faction_id;
@Column(name = "controlling_minor_faction")
private String controlling_minor_faction;
@Column(name = "reserve_type_id")
private int reserve_type_id;
@Column(name = "reserve_type")
private String reserve_type;
}
我的SystemPopulatedReposetory.class
@Repository
public interface SystemPopulatedRepository extends JpaRepository<SystemPopulated, Integer> {
}
我的类我想要InsertIntoDB SystemPopulatedHandler.class
@Slf4j
public class SystemPopulatedHandler {
@Autowired
private SystemPopulatedRepository systemPopulatedRepository;
public void insertIntoDB() {
BufferedReader reader;
try {
reader = new BufferedReader( new FileReader(DOWNLOAD_SAVE_PATH + FILE_NAME_SYSTEMS_POPULATED) );
String line = reader.readLine();
while( line != null ){
ObjectMapper mapper = new ObjectMapper();
systemPopulatedRepository.save( mapper.readValue( line, SystemPopulated.class ) );
line = reader.readLine();
}
reader.close();
}
catch( Exception e ) {
e.printStackTrace();
log.error( e.getLocalizedMessage() );
}
}
}
我的Main.class
@SpringBootApplication
@EnableJpaRepositories
public class Main {
public static void main( String[] args ) {
SpringApplication.run( Main.class, args );
SystemPopulatedHandler systemPopulatedHandler = new SystemPopulatedHandler();
systemPopulatedHandler.insertIntoDB();
}
}
问题是你自己创建SystemPopulatedHandler
SystemPopulatedHandler systemPopulatedHandler = new SystemPopulatedHandler();
这样Spring就不会将存储库注入到您的类中,因为只有在spring创建类时它才有效。
但是如果你想在启动时填充一个数据库(至少看起来你试图这样做)你应该检查flyway(或者在本文档中为85.5:https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html)
如果由于某种原因无法使用flyway,可以将以下代码添加到主类:
@Bean
public SystemPopulatedHandler systemPopulatedHandler(SystemPopulatedRepository repository) {
SystemPopulatedHandler systemPopulatedHandler = new SystemPopulatedHandler(repository);
systemPopulatedHandler.insertIntoDB()
return systemPopulatedHandler;
}
然后将构造函数添加到SystemPopulatedHandler
类:
public SystemPopulatedHandler(SystemPopulatedRepository systemPopulatedRepository) {
this.systemPopulatedRepository = systemPopulatedRepository;
}
并删除@Autowired
注释。
更新
您还需要添加此答案中提到的缺失注释:https://stackoverflow.com/a/55767393/2248239
更新2
如果你想定期做这个动作你可以使用调度(就像在本指南中https://spring.io/guides/gs/scheduling-tasks/)实际上这很简单:
除了添加缺少的注释之外,不要执行上面提到的更改,只需执行以下操作:
将@Component
添加到SystemPopulatedHandler
将@Scheduled
添加到insertIntoDB()
的SystemPopulatedHandler
并将@EnableScheduling
添加到主类
对于@Scheduled
,只需阅读指南,它描述了您可以使用注释做什么。
这是因为你自动连接的存储库没有连接bean。
请使用@Repository注释您的存储库并在主类中指定@EnableJpaRepository。
有关更多详细信息,请参阅spring数据JPA文档
问题是您在不使用ApplicationContext或BeanFactory的情况下实例化SystemPopulatedHandler bean,因此它不是由IOC容器维护的。
要在SpringBoot应用程序中使用DI,只需在控制器或服务中自动连接SystemPopulatedHandler,然后就可以调用insert Into DB()方法。
由于您使用的是Spring引导,并且示例非常简单,因此您无需为bean单独配置。
@Controller
public class SystemPopulatedController {
@Autowired
private SystemPopulatedHandler systemPopulatedHandler;
@RequestMapping("/")
public void insertIntoDB() {
systemPopulatedHandler.insertIntoDB();
}
}
非常感谢你们所有人。我已经解决了以下问题:
SystemPopulatedReposetory.class
@Repository
public interface SystemPopulatedRepository extends JpaRepository<SystemPopulated, Integer> {
}
´´´
SystemPopulatedHandler.class
@Slf4j
@Component
public class SystemPopulatedHandler {
@Autowired
private SystemPopulatedRepository systemPopulatedRepository;
@PostConstruct
@Scheduled(cron = "0 0 0 * * *")
public void insertIntoDB() {
BufferedReader reader;
try {
reader = new BufferedReader( new FileReader(DOWNLOAD_SAVE_PATH + FILE_NAME_SYSTEMS_POPULATED) );
String line = reader.readLine();
while( line != null ){
ObjectMapper mapper = new ObjectMapper();
systemPopulatedRepository.save( mapper.readValue( line, SystemPopulated.class ) );
line = reader.readLine();
}
reader.close();
}
catch( Exception e ) {
e.printStackTrace();
log.error( e.getLocalizedMessage() );
}
}
}
´´´
Main.class
@SpringBootApplication
@EnableJpaRepositories
@EnableScheduling
public class Main {
public static void main( String[] args ) {
SpringApplication.run( Main.class, args );
FileHandler fileHandler = new FileHandler();
}
}