BAEL-4706 - Spring Boot with Spring Batch (#10292)
Co-authored-by: Jonathan Cook <jcook@sciops.esa.int>
This commit is contained in:
parent
eed264e2e4
commit
06bebff4cb
3
pom.xml
3
pom.xml
@ -617,7 +617,8 @@
|
||||
<module>spring-aop</module>
|
||||
<module>spring-apache-camel</module>
|
||||
|
||||
<module>spring-batch</module>
|
||||
<module>spring-batch</module>
|
||||
<module>spring-batch-2</module>
|
||||
<module>spring-bom</module>
|
||||
<module>spring-boot-modules</module>
|
||||
<module>spring-boot-rest</module>
|
||||
|
57
spring-batch-2/pom.xml
Normal file
57
spring-batch-2/pom.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-batch-2</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<name>spring-batch-2</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-batch</artifactId>
|
||||
<version>2.3.6.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>${hsqldb.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring.boot.batch.version}</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.batch</groupId>
|
||||
<artifactId>spring-batch-test</artifactId>
|
||||
<version>${spring.batch.test.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring.boot.batch.version>2.3.6.RELEASE</spring.boot.batch.version>
|
||||
<spring.batch.test.version>4.2.4.RELEASE</spring.batch.test.version>
|
||||
<hsqldb.version>2.5.1</hsqldb.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,81 @@
|
||||
package com.baeldung.batch;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
|
||||
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
|
||||
import org.springframework.batch.core.launch.support.RunIdIncrementer;
|
||||
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
|
||||
import org.springframework.batch.item.database.JdbcBatchItemWriter;
|
||||
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
|
||||
import org.springframework.batch.item.file.FlatFileItemReader;
|
||||
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
|
||||
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
public class BatchConfiguration {
|
||||
|
||||
@Autowired
|
||||
public JobBuilderFactory jobBuilderFactory;
|
||||
|
||||
@Autowired
|
||||
public StepBuilderFactory stepBuilderFactory;
|
||||
|
||||
@Value("${file.input}")
|
||||
private String fileInput;
|
||||
|
||||
@Bean
|
||||
public FlatFileItemReader<Coffee> reader() {
|
||||
return new FlatFileItemReaderBuilder<Coffee>().name("coffeeItemReader")
|
||||
.resource(new ClassPathResource(fileInput))
|
||||
.delimited()
|
||||
.names(new String[] { "brand", "origin", "characteristics" })
|
||||
.fieldSetMapper(new BeanWrapperFieldSetMapper<Coffee>() {{
|
||||
setTargetType(Coffee.class);
|
||||
}})
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CoffeeItemProcessor processor() {
|
||||
return new CoffeeItemProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JdbcBatchItemWriter<Coffee> writer(DataSource dataSource) {
|
||||
return new JdbcBatchItemWriterBuilder<Coffee>().itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
|
||||
.sql("INSERT INTO coffee (brand, origin, characteristics) VALUES (:brand, :origin, :characteristics)")
|
||||
.dataSource(dataSource)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
|
||||
return jobBuilderFactory.get("importUserJob")
|
||||
.incrementer(new RunIdIncrementer())
|
||||
.listener(listener)
|
||||
.flow(step1)
|
||||
.end()
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Step step1(JdbcBatchItemWriter<Coffee> writer) {
|
||||
return stepBuilderFactory.get("step1")
|
||||
.<Coffee, Coffee> chunk(10)
|
||||
.reader(reader())
|
||||
.processor(processor())
|
||||
.writer(writer)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
47
spring-batch-2/src/main/java/com/baeldung/batch/Coffee.java
Normal file
47
spring-batch-2/src/main/java/com/baeldung/batch/Coffee.java
Normal file
@ -0,0 +1,47 @@
|
||||
package com.baeldung.batch;
|
||||
|
||||
public class Coffee {
|
||||
|
||||
private String brand;
|
||||
private String origin;
|
||||
private String characteristics;
|
||||
|
||||
public Coffee() {
|
||||
}
|
||||
|
||||
public Coffee(String brand, String origin, String characteristics) {
|
||||
this.brand = brand;
|
||||
this.origin = origin;
|
||||
this.characteristics = characteristics;
|
||||
}
|
||||
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
public void setBrand(String brand) {
|
||||
this.brand = brand;
|
||||
}
|
||||
|
||||
public String getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
public void setOrigin(String origin) {
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
public String getCharacteristics() {
|
||||
return characteristics;
|
||||
}
|
||||
|
||||
public void setCharacteristics(String characteristics) {
|
||||
this.characteristics = characteristics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Coffee [brand=" + getBrand() + ", origin=" + getOrigin() + ", characteristics=" + getCharacteristics() + "]";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.baeldung.batch;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
|
||||
public class CoffeeItemProcessor implements ItemProcessor<Coffee, Coffee> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CoffeeItemProcessor.class);
|
||||
|
||||
@Override
|
||||
public Coffee process(final Coffee coffee) throws Exception {
|
||||
String brand = coffee.getBrand().toUpperCase();
|
||||
String origin = coffee.getOrigin().toUpperCase();
|
||||
String chracteristics = coffee.getCharacteristics().toUpperCase();
|
||||
|
||||
Coffee transformedCoffee = new Coffee(brand, origin, chracteristics);
|
||||
LOGGER.info("Converting ( {} ) into ( {} )", coffee, transformedCoffee);
|
||||
|
||||
return transformedCoffee;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.baeldung.batch;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class JobCompletionNotificationListener extends JobExecutionListenerSupport {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JobCompletionNotificationListener.class);
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterJob(JobExecution jobExecution) {
|
||||
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
|
||||
LOGGER.info("!!! JOB FINISHED! Time to verify the results");
|
||||
|
||||
String query = "SELECT brand, origin, characteristics FROM coffee";
|
||||
jdbcTemplate.query(query, (rs, row) -> new Coffee(rs.getString(1), rs.getString(2), rs.getString(3)))
|
||||
.forEach(coffee -> LOGGER.info("Found < {} > in the database.", coffee));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.batch;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringBootBatchProcessingApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootBatchProcessingApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
1
spring-batch-2/src/main/resources/application.properties
Normal file
1
spring-batch-2/src/main/resources/application.properties
Normal file
@ -0,0 +1 @@
|
||||
file.input=coffee-list.csv
|
3
spring-batch-2/src/main/resources/coffee-list.csv
Normal file
3
spring-batch-2/src/main/resources/coffee-list.csv
Normal file
@ -0,0 +1,3 @@
|
||||
Blue Mountain,Jamaica,Fruity
|
||||
Lavazza,Colombia,Strong
|
||||
Folgers,America,Smokey
|
|
13
spring-batch-2/src/main/resources/logback.xml
Normal file
13
spring-batch-2/src/main/resources/logback.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
8
spring-batch-2/src/main/resources/schema-all.sql
Normal file
8
spring-batch-2/src/main/resources/schema-all.sql
Normal file
@ -0,0 +1,8 @@
|
||||
DROP TABLE coffee IF EXISTS;
|
||||
|
||||
CREATE TABLE coffee (
|
||||
coffee_id BIGINT IDENTITY NOT NULL PRIMARY KEY,
|
||||
brand VARCHAR(20),
|
||||
origin VARCHAR(20),
|
||||
characteristics VARCHAR(30)
|
||||
);
|
@ -0,0 +1,49 @@
|
||||
package com.baeldung.batch;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.test.JobLauncherTestUtils;
|
||||
import org.springframework.batch.test.JobRepositoryTestUtils;
|
||||
import org.springframework.batch.test.context.SpringBatchTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@SpringBatchTest
|
||||
@SpringBootTest
|
||||
@DirtiesContext
|
||||
@PropertySource("classpath:application.properties")
|
||||
@RunWith(SpringRunner.class)
|
||||
public class SpringBootBatchIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private JobLauncherTestUtils jobLauncherTestUtils;
|
||||
|
||||
@Autowired
|
||||
private JobRepositoryTestUtils jobRepositoryTestUtils;
|
||||
|
||||
@After
|
||||
public void cleanUp() {
|
||||
jobRepositoryTestUtils.removeJobExecutions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCoffeeList_whenJobExecuted_thenSuccess() throws Exception {
|
||||
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
|
||||
JobInstance jobInstance = jobExecution.getJobInstance();
|
||||
ExitStatus jobExitStatus = jobExecution.getExitStatus();
|
||||
|
||||
assertThat(jobInstance.getJobName(), is("importUserJob"));
|
||||
assertThat(jobExitStatus.getExitCode(), is("COMPLETED"));
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user