Académique Documents
Professionnel Documents
Culture Documents
Achref El Mouelhi
elmouelhi.achref@gmail.com
1 Introduction
Spring Batch
Spring Batch
H I ©
Framework open-source (unique) pour le traitement par lots
U
Fournissant des fonctions réutilisables pour L grands volumes
Edes
de données
L MO
r e
Fonctionnement principalf E= { lecture de données ⇒ traitement de
données ⇒ A ch de données }
écriture
©
Configurable par XML ou classes Java
Spring Batch
Spring Batch
H I ©
U EL
O
f E LM
ch r e
©A
Source : documentation officielle
Spring Batch
Explication
Spring Batch
Exemple avec chunk(2)
H I ©
U EL
O
f E LM
ch r e
©A
Spring Batch
Création de projet Spring Boot
Chercher Spring, dans Spring Boot sélectionner Spring Starter Project et cli-
quer sur Next >
H I ©
EL
Saisir
OU
first-spring-batch dans Name,
M
E L
com.example dans Group,
f
c e
hr dans Artifact
firstspringbatch
© A
com.example.demo dans Package
Cliquer sur Next
Chercher et cocher les cases correspondantes aux Spring Data JPA, MySQL Driver,
Spring Web, Spring Boot DevTools, Lombok et Spring Batch
Spring Batch
Explication
I ©
Tous les autres packages dao, model... doivent être dans le package
H
demo.
UEL
O
f E LM
ch r e
©A
Spring Batch
Explication
I ©
Tous les autres packages dao, model... doivent être dans le package
H
demo.
U EL
O
f
Pour la suite, nous considérons E LM
r e
ch à définir dans com.example.demo.model
A
une entité Personne
©
une interface DAO PersonneRepository à définir dans
com.example.demo.dao
Spring Batch
@NoArgsConstructor
@AllArgsConstructor
@Data
H I ©
@Entity
UEL
public class Personne {
O
@Id
f E LM
private Long num;
ch r e
@GeneratedValue(strategy = GenerationType.IDENTITY)
©A
private String nom;
private String prenom;
private Long salaire;
}
Spring Batch
import org.springframework.data.jpa.repository. H I ©
EL
OU
JpaRepository;
L M
f E
import com.example.demo.model.Personne;
r e
A chPersonneRepository
©
public interface
JpaRepository<Personne, Long> {
extends
Spring Batch
Spring Batch
Contexte et objectif
H I ©
La RH de notre entreprise nous fournit régulièrement un fichier
EL
.csv contenant les noms et prénoms des nouvelles recrues ainsi
que les salaires négociés.
M OU
À partir de ce fichier, nousE
f L
souhaitons ajouter ces personnes dans
chr
la base de données. e
© A
Nous souhaitons aussi que le nom et la première lettre du prénom
soient écrits en majuscule.
model.naming.PhysicalNamingStrategyStandardImpl
O U
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.
f E LM
ch r e
©A
model.naming.PhysicalNamingStrategyStandardImpl
O U
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.
f E LM
r e
Indiquons également l’emplacement de notre fichier CSV
ch
©A
inputFile=classpath:/data.csv
model.naming.PhysicalNamingStrategyStandardImpl
O U
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.
f E LM
r e
Indiquons également l’emplacement de notre fichier CSV
ch
©A
inputFile=classpath:/data.csv
model.naming.PhysicalNamingStrategyStandardImpl
O U
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.
f E LM
r e
Indiquons également l’emplacement de notre fichier CSV
ch
©A
inputFile=classpath:/data.csv
Autorisons Spring Batch à générer ses tables nécessaires pour la gestion de lots
spring.batch.initialize-schema=always
Spring Batch
import org.springframework.batch.core.configuration.
H I ©
annotation.EnableBatchProcessing;
UEL
O
LM
import org.springframework.context.annotation.
Configuration;
r e f E
@Configuration
ch
©A
@EnableBatchProcessing
public class SpringBatchConfig {
Spring Batch
Dans la classe SpringBatchConfig, nous commençons par injecter les 5 éléments
indispensable pour le lancement d’un job
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
@Autowired private StepBuilderFactory stepBuilderFactory;
H I ©
@Autowired private ItemReader<Personne> itemReader;
UEL
@Autowired private ItemWriter<Personne> itemWriter;
O
LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
}
r e f E
ch
©A
Spring Batch
Dans la classe SpringBatchConfig, nous commençons par injecter les 5 éléments
indispensable pour le lancement d’un job
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
@Autowired private StepBuilderFactory stepBuilderFactory;
H I ©
@Autowired private ItemReader<Personne> itemReader;
UEL
@Autowired private ItemWriter<Personne> itemWriter;
O
LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
}
r e f E
ch
©A
Les imports nécessaires
import org.springframework.batch.core.configuration.annotation.
JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.
StepBuilderFactory;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
Spring Batch
Définissons un Bean pour le Job (dans SpringBatchConfig)
@Bean
public Job job(Step step1) {
return jobBuilderFactory.get("Recrutement") // le nom de notre job
.start(step1)
}
.build();
H I ©
UEL
O
f E LM
ch r e
©A
Spring Batch
Définissons un Bean pour le Job (dans SpringBatchConfig)
@Bean
public Job job(Step step1) {
return jobBuilderFactory.get("Recrutement") // le nom de notre job
.start(step1)
}
.build();
H I ©
UEL
O
f E LM
Nous devons donner à Spring plus de détail sur le Step
@Bean
ch r e
©A
public Step step1() {
return stepBuilderFactory.get("première étape: chargement de fichier"
)
.<Personne, Personne>chunk(2)
.reader(itemReader)
.processor(itemProcessor)
.writer(itemWriter)
.build();
}
setTargetType(Personne.class);
O U
.fieldSetMapper(new BeanWrapperFieldSetMapper<Personne>() {{
}})
.build();
f E LM
}
ch r e
©A
setTargetType(Personne.class);
O U
.fieldSetMapper(new BeanWrapperFieldSetMapper<Personne>() {{
}})
.build();
f E LM
}
ch r e
©A
Les imports nécessaires
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.
FlatFileItemReaderBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
Spring Batch
Explication
©A
names() : pour spécifier les noms des attributs de la classe Personne
présents dans le fichier
package com.example.demo.batch;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;
import com.example.demo.model.Personne;
@Component
H I ©
EL
public class PersonneItemProcessor implements ItemProcessor<Personne,
Personne> {
O U
@Override
f E LM
Exception {
ch r e
public Personne process(final Personne personne) throws
©A
var nom = personne.getNom().toUpperCase();
personne.setNom(nom);
var prenom = personne.getPrenom();
prenom = prenom.substring(0, 1).toUpperCase() + prenom.
substring(1).toLowerCase();
personne.setPrenom(prenom);
return personne;
}
}
package com.example.demo.batch;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
H I ©
EL
import com.example.demo.dao.PersonneRepository;
import com.example.demo.model.Personne;
O U
@Component
f E LM
@Autowired
ch r e
public class PersonneItemWriter implements ItemWriter<Personne> {
©A
private PersonneRepository personneRepository;
@Override
public void write(List<? extends Personne> items) throws
Exception {
System.out.println(items);
personneRepository.saveAll(items);
}
}
Spring Batch
Créons un contrôleur (qui nous permettra de lancer le Job) et commençons par injecter le
Job et JobLauncher
package com.example.demo.controller;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
H I ©
EL
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import
O U
org.springframework.web.bind.annotation.RequestMapping;
import
LM
org.springframework.web.bind.annotation.RestController;
f E
@RestController
ch r e
©A
public class JobInvokerController {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job processJob;
package com.example.demo.controller;
@RestController
public class JobInvokerController {
@Autowired
private JobLauncher jobLauncher;
H I ©
@Autowired
U EL
private Job processJob;
O
@RequestMapping("/loadData")
f E LM
r e
public String handle() throws Exception {
ch
©A
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(processJob, jobParameters);
Spring Batch
Objectif
H I ©
U
Supprimer le fichier data.csv après ajout L la base de
Edans
données
L MO
Utiliser un Tasklet e
r f
apr Ele premier Step pour supprimer le
ès
fichier A ch
©
Spring Batch
Tasklet
Comme un Step
H I ©
sans ItemWriter
UEL
O
généralement sans valeur de retour
f E LM
Utilisé souvent pour
ch r e
©A
appeler une procédure stockée
exécuter un script
Spring Batch
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
H I ©
EL
@Autowired private StepBuilderFactory stepBuilderFactory;
@Autowired private ItemReader<Personne> itemReader;
@Autowired private ItemWriter<Personne> itemWriter;
O U
f
@Autowired private Tasklet tasklet;
E LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
ch r e
©A
// ...
Spring Batch
@Configuration
@EnableBatchProcessing
public class SpringBatchConfig {
@Autowired private JobBuilderFactory jobBuilderFactory;
H I ©
EL
@Autowired private StepBuilderFactory stepBuilderFactory;
@Autowired private ItemReader<Personne> itemReader;
@Autowired private ItemWriter<Personne> itemWriter;
O U
f
@Autowired private Tasklet tasklet;
E LM
@Autowired private ItemProcessor<Personne, Personne> itemProcessor;
ch r e
©A
// ...
L’import nécessaire
import org.springframework.batch.core.step.tasklet.Tasklet;
Spring Batch
Modifions le Job précédent pour lancer le Tasklet après step1
@Bean
public Job job(@Qualifier("step1") Step step1, @Qualifier("deleteFile")
Step deleteFile) {
return jobBuilderFactory.get("Recrutement")
.start(step1)
H I ©
EL
.next(deleteFile)
}
.build();
O U
f E LM
ch r e
©A
Spring Batch
Modifions le Job précédent pour lancer le Tasklet après step1
@Bean
public Job job(@Qualifier("step1") Step step1, @Qualifier("deleteFile")
Step deleteFile) {
return jobBuilderFactory.get("Recrutement")
.start(step1)
H I ©
EL
.next(deleteFile)
}
.build();
O U
f E LM
ch r e
Définissons le Tasklet défini dans le Job
@Bean ©A
public Step deleteFile() {
return this.stepBuilderFactory.get("deuxième étape : suppression
du fichier CSV")
.tasklet(tasklet)
.build();
}
package com.example.demo.batch;
import java.io.File;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import
import
org.springframework.beans.factory.annotation.Value;
org.springframework.core.io.Resource;
H I ©
EL
import org.springframework.stereotype.Component;
@Component
O U
LM
public class FileDeletingTasklet implements Tasklet {
@Value("${inputFile}")
r e
private Resource resource;
f E
ch
©A
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)
throws Exception {
File file = resource.getFile();
boolean deleted = file.delete();
if (!deleted) {
throw new UnexpectedJobExecutionException("Impossible de supprimer le
fichier " + file.getPath());
}
System.out.println("Fichier supprimé : " + file.getPath());
return RepeatStatus.FINISHED;
}
}
Spring Batch
Rien à changer dans le contrôleur précédent
@RestController
public class JobInvokerController {
@Autowired
private JobLauncher jobLauncher;
H I ©
@Autowired
U EL
private Job processJob;
O
@RequestMapping("/loadData")
f E LM
r e
public String handle() throws Exception {
ch
©A
JobParameters jobParameters = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(processJob, jobParameters);
Spring Batch
....
H I ©
EL
Executing step: [deuxième étape : suppression du fichier CSV]
U
O
Fichier supprimé : C:\Users\elmou\eclipse-workspace\first-spring-batch\
LM
target\classes\data.csv
r e E
Step: [deuxième étape : suppression du fichier CSV] executed in 368ms
f
Job: [SimpleJob: [name=Recrutement]] completed with the following
ch
parameters: [{time=1600800074441}] and the following status: [
©A
COMPLETED] in 2s114ms
....
Spring Batch
Explication
ch r e
first-spring-batch/target/classes
©A
En effet, Spring a déplacé data.csv qu’on a créé dans
src/main/resources dans target/classes/
Faites un clic droit sur le projet et cliquez sur Refresh et allez
vérifiez que Spring a de nouveau déplacé data.csv dans
first-spring-batch/target/classes
Spring Batch
Question
Pourquoi Spring Boot a t-il redémarré l’application après suppression
de fichier ? H I ©
UEL
O
f E LM
ch r e
©A
Spring Batch
Question
Pourquoi Spring Boot a t-il redémarré l’application après suppression
de fichier ? H I ©
UEL
O
f E LM
Réponse
ch r e
©A
Devtools a détecté un changement (suppression de fichier) et par
conséquence a redémarré l’application.