opticyclic
opticyclic

Reputation: 8116

How Do I Add A CommandLine Application To My Spring Boot Rest Application

I have a REST application that reads from a database repository.

I want to add a command line application that reads a CSV and imports the data to the database.

If I add another @SpringBootApplication class that implements CommandLineRunner to the project/jar, Spring starts it at the same time as my main server.

If I add a class that initialises the spring context itself, the jdbc url on the JPARepository uses the defaults instead of those from the spring boot properies

spring.datasource.url=jdbc:h2:file:./test;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE

@ComponentScan(basePackages = "com.test")
public class CsvImport {

@Autowired
private Repository repository;

public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CsvImport.class);
    context.start();

    CsvImport csvImport = context.getBean(CsvImport.class);
    File file = new File(args[0]);
    if (file.isFile()) {
        csvImport.importCsv(file);
    }
    context.stop();
}

private void importCsv(File file) {
....
....

Is there a better way to do this?

Upvotes: 0

Views: 742

Answers (1)

opticyclic
opticyclic

Reputation: 8116

There are several steps required to get this working.

The first thing is that @SpringBootApplication auto-scans any packages below it and will auto-start any CommandLineRunner that it finds so the command line application needs to be in a parallel package.

e.g.

- com
    - test
        - rest
            - model
            - repository
            - controller
          #RestSpringBoot.java
        - Commands
          #ImportCsv.java

The next thing is that since the command line application is in a parallel package you need to specify the scanning yourself.

There are 3 parts to this:

  • @ComponentScan
  • @EntityScan
  • @EnableJpaRepositories

The first ensures the beans are created, the second ensures that the hibernate entities are created and the third ensures that the JPA classes are generated correctly.

The last part is to disable the start of the spring boot webserver otherwise you will have port conflicts.

This ends up with:

@SpringBootApplication
@ComponentScan(basePackageClasses = {Repository.class})
@EntityScan(basePackageClasses = {MyEntity.class})
@EnableJpaRepositories(basePackageClasses = {Repository.class})
public class CsvImport {

@Autowired
private RiskRepository repository;

public static void main(String[] args) {
    SpringApplication app = new SpringApplication(CsvImport.class);
    app.setBannerMode(Banner.Mode.OFF);
    app.setWebApplicationType(WebApplicationType.NONE);
    app.run(args);
}

@Override
public void run(String... args) throws Exception {
    File file = new File(args[0]);
    if (file.isFile()) {
        importCsv(file);
    }
}

private void importCsv(File file) {
....
....

Upvotes: 1

Related Questions