Skip to content

Commit 5c09968

Browse files
committed
Refactored spring batch example
1 parent c8d77a4 commit 5c09968

11 files changed

+199
-77
lines changed

spring-batch-demo/src/main/java/com/stacktips/app/SpringBatchDemoApplication.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
@SpringBootApplication
77
public class SpringBatchDemoApplication {
88

9-
public static void main(String[] args) {
10-
SpringApplication.run(SpringBatchDemoApplication.class, args);
11-
}
9+
public static void main(String[] args) {
10+
SpringApplication.run(SpringBatchDemoApplication.class, args);
11+
}
1212

1313
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.stacktips.app.config;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.springframework.batch.core.Job;
5+
import org.springframework.batch.core.JobExecutionException;
6+
import org.springframework.batch.core.JobParametersBuilder;
7+
import org.springframework.batch.core.launch.JobLauncher;
8+
import org.springframework.boot.context.event.ApplicationReadyEvent;
9+
import org.springframework.context.event.EventListener;
10+
import org.springframework.stereotype.Component;
11+
12+
@Component
13+
@RequiredArgsConstructor
14+
public class ApplicationEvent {
15+
16+
private final JobLauncher jobLauncher;
17+
private final Job csvImporterJob;
18+
19+
@EventListener(ApplicationReadyEvent.class)
20+
public void applicationEvent() throws JobExecutionException {
21+
jobLauncher.run(csvImporterJob, new JobParametersBuilder()
22+
.addString("ignoreCountry", "India")
23+
.toJobParameters());
24+
25+
}
26+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.stacktips.app.config;
2+
3+
import com.stacktips.app.model.Customer;
4+
import com.stacktips.app.utils.DateUtils;
5+
import jakarta.persistence.EntityManagerFactory;
6+
import org.springframework.batch.core.*;
7+
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
8+
import org.springframework.batch.core.job.builder.JobBuilder;
9+
import org.springframework.batch.core.launch.support.RunIdIncrementer;
10+
import org.springframework.batch.core.repository.JobRepository;
11+
import org.springframework.batch.core.step.builder.StepBuilder;
12+
import org.springframework.batch.item.ItemReader;
13+
import org.springframework.batch.item.ItemWriter;
14+
import org.springframework.batch.item.database.JpaItemWriter;
15+
import org.springframework.batch.item.database.builder.JpaItemWriterBuilder;
16+
import org.springframework.batch.item.file.FlatFileItemReader;
17+
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
18+
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
19+
import org.springframework.context.annotation.Bean;
20+
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.core.io.ClassPathResource;
22+
import org.springframework.transaction.PlatformTransactionManager;
23+
24+
@Configuration
25+
@EnableBatchProcessing
26+
public class BatchConfig {
27+
28+
@Bean
29+
public FlatFileItemReader<Customer> reader() {
30+
return new FlatFileItemReaderBuilder<Customer>()
31+
.linesToSkip(1)
32+
.name("csvItemReader")
33+
.resource(new ClassPathResource("customers.csv"))
34+
.delimited()
35+
.delimiter(",")
36+
.names("index", "customerId", "firstName", "lastName", "company",
37+
"city", "country", "phone1",
38+
"phone2", "email", "subscriptionDate", "website")
39+
.fieldSetMapper(fieldSet -> {
40+
return Customer.builder()
41+
.customerId(fieldSet.readString("customerId"))
42+
.firstName(fieldSet.readString("firstName"))
43+
.lastName(fieldSet.readString("lastName"))
44+
.company(fieldSet.readString("company"))
45+
.city(fieldSet.readString("city"))
46+
.country(fieldSet.readString("country"))
47+
.phone1(fieldSet.readString("phone1"))
48+
.phone2(fieldSet.readString("phone2"))
49+
.email(fieldSet.readString("email"))
50+
.website(fieldSet.readString("website"))
51+
.subscriptionDate(DateUtils.parseDate(fieldSet.readString("subscriptionDate")))
52+
.build();
53+
})
54+
.build();
55+
56+
}
57+
58+
59+
@Bean
60+
public JpaItemWriter<Customer> writer(EntityManagerFactory entityManagerFactory) {
61+
return new JpaItemWriterBuilder<Customer>()
62+
.entityManagerFactory(entityManagerFactory)
63+
.build();
64+
}
65+
66+
@Bean
67+
public Step csvImporterStep(ItemReader<Customer> reader, ItemWriter<Customer> writer,
68+
JobRepository jobRepository, PlatformTransactionManager transactionManager,
69+
CustomJobProcessor processor) {
70+
return new StepBuilder("csvImporterStep", jobRepository)
71+
.<Customer, Customer>chunk(50, transactionManager)
72+
.reader(reader)
73+
.processor(processor)
74+
.writer(writer)
75+
.allowStartIfComplete(true)
76+
.build();
77+
}
78+
79+
@Bean
80+
public Job csvImporterJob(Step csvImporterStep, JobRepository jobRepository, ImportJobListener listener) {
81+
return new JobBuilder("csvImporterJob", jobRepository)
82+
.incrementer(new RunIdIncrementer())
83+
.validator(new JobParametersValidator() {
84+
@Override
85+
public void validate(JobParameters parameters) throws JobParametersInvalidException {
86+
if ("Costa Rica".equals(parameters.getString("ignoreCountry"))) {
87+
throw new JobParametersInvalidException("Invalid configuration");
88+
}
89+
}
90+
})
91+
.listener(listener)
92+
.flow(csvImporterStep)
93+
.end()
94+
.build();
95+
}
96+
97+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.stacktips.app.config;
2+
3+
import com.stacktips.app.model.Customer;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.batch.core.configuration.annotation.JobScope;
6+
import org.springframework.batch.item.ItemProcessor;
7+
import org.springframework.beans.factory.annotation.Value;
8+
import org.springframework.stereotype.Component;
9+
10+
@Slf4j
11+
@JobScope
12+
@Component
13+
public class CustomJobProcessor implements ItemProcessor<Customer, Customer> {
14+
15+
private final String ignoreCountry;
16+
17+
public CustomJobProcessor(@Value("#{jobParameters['ignoreCountry']}") String ignoreCountry) {
18+
this.ignoreCountry = ignoreCountry;
19+
}
20+
21+
@Override
22+
public Customer process(Customer item) throws Exception {
23+
if (item.getCountry().equals(ignoreCountry)) {
24+
log.info("Customer ignored: {}", item.toString());
25+
}
26+
return item;
27+
}
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.stacktips.app.config;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.springframework.batch.core.BatchStatus;
5+
import org.springframework.batch.core.JobExecution;
6+
import org.springframework.batch.core.JobExecutionListener;
7+
import org.springframework.stereotype.Component;
8+
9+
@Slf4j
10+
@Component
11+
public class ImportJobListener implements JobExecutionListener {
12+
13+
@Override
14+
public void beforeJob(JobExecution jobExecution) {
15+
log.info("Job {} started", jobExecution.getJobInstance().getJobName());
16+
}
17+
18+
@Override
19+
public void afterJob(JobExecution jobExecution) {
20+
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
21+
log.info("Job {} completed", jobExecution.getJobInstance().getJobName());
22+
} else if (jobExecution.getStatus() == BatchStatus.FAILED) {
23+
log.info("Job {} failed", jobExecution.getJobInstance().getJobName());
24+
}
25+
}
26+
}

spring-batch-demo/src/main/java/com/stacktips/app/config/SpringBatchConfig.java

Lines changed: 0 additions & 53 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.stacktips.app.models;
1+
package com.stacktips.app.model;
22

33
import jakarta.persistence.Entity;
44
import jakarta.persistence.Id;
@@ -19,15 +19,15 @@
1919
public class Customer {
2020

2121
@Id
22-
private String customerId;
23-
private String firstName;
24-
private String lastName;
25-
private String company;
26-
private String city;
27-
private String country;
28-
private String phone1;
29-
private String phone2;
30-
private String email;
31-
private LocalDate subscriptionDate;
32-
private String website;
33-
}
22+
String customerId;
23+
String firstName;
24+
String lastName;
25+
String company;
26+
String city;
27+
String country;
28+
String phone1;
29+
String phone2;
30+
String email;
31+
LocalDate subscriptionDate;
32+
String website;
33+
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package com.stacktips.app.repository;
22

3-
import com.stacktips.app.models.Customer;
3+
import com.stacktips.app.model.Customer;
44
import org.springframework.data.jpa.repository.JpaRepository;
5-
import org.springframework.stereotype.Repository;
6-
7-
@Repository
8-
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
95

6+
public interface CustomerRepository extends JpaRepository<Customer, String> {
107
}

spring-batch-demo/src/main/java/com/stacktips/app/utils/DateUtils.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
@UtilityClass
99
public class DateUtils {
1010

11-
public static LocalDate convertDate(String subscriptionDate) {
12-
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
13-
return LocalDate.parse(subscriptionDate, dateFormat);
11+
public static LocalDate parseDate(String dateStr){
12+
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
13+
return LocalDate.parse(dateStr, formatter);
1414
}
15+
1516
}

0 commit comments

Comments
 (0)