L'objet de ce billet est de vous présenter les "best-practices" afin de lire les divers de formats de fichiers csv du simple à l'exotique.
Le reader de spring-batch doit être configuré (et uniquement si possible 🙂 ) pour gérer des formats particuliers de fichiers csv.
La démarche reste identique pour les autres formats de fichiers.
Comme il est difficile de traiter tous les cas pour un blog, la démo ci-après se focalise sur ce fichier csv:
A nommer ce fichier entreprises.csv sous src/main/resources.
D'où, en dehors de l'entête ignorée par le reader FlatFileItemReader, chaque bloc (ligne ou +) est préfixé avec le mot EOF_RECORD.
Merci de noter :
- le séparateur du fichier csv est la virgule,
- le bloc de données peut s'étendre sur plusieurs lignes ( c'est le cas du record avec id=1),
- les valeurs sont encadrées (quotées) avec le caractère guillement '"',
- la présence de la virgule dans certaines valeurs du champ nommé rs (pour raison sociale) par ex. ligne(s) ayant id=1,
- Enfin, l'avant dernière ligne ayant l'id=2 ne fournit pas de raison sociale!
Ces lignes vont être stockées en base de données en passant par la création d'une liste d'entités java de type Entreprise:
Ingrédients du blog: Spring 4, Spring-Batch 3, java 7+, JUnit
Les mots clés sont ceux de spring: RecordSeparatorPolicy, SuffixRecordSeparatorPolicy.
Voici les étapes de la démo :
Étape 1. Configurer le projet maven,
Étape 2. Configurer spring (java config minimale: seul le reader),
Étape 3. Configurer un policy (suffix policy) pour le reader,
Étape 4. Écrire un test unitaire du reader.
L'intérêt de tester unitairement le(s) reader(s) se confirme lorsque le métier présente des fichiers csv assez particuliers ou encore lorsqu'il exige un traitement spécifique au moment de les lire.
Il est bien évidemment possible de tester unitairement les tokenizer, lineMapper, beanWrapperFieldSetMapper.. mais là ça fera beaucoup de chose à tester séparément!!
Une fois le test TU du reader écrit, le(s) refactoring(s) et les évolutions (agilité oblige) deviennent des opérations plus sûres.
ETAPE 1. Créer le projet maven
Partons d'un projet spring-boot créé, from scratch, depuis la page initilzr en ayant sélectionné spring-batch & h2.
Note. Pour le test junit, la dépendance h2 n'est pas nécessaire mais comme rien n'est à configurer, laissons-la.
ETAPE 2. Configurer Spring
Cette étape est réduite à la création du reader et ce qui est nécessaire au lancement du test Junit ci-après.
Voici le code utile:
L'entête des imports est comme suit:
NOTE. Penser à remplacer les o.s.b. par org.springframework.batch.
ETAPE 3. Configurer SuffixRecordPolicy
A ce code, nous devons rajouter la configuration d'un SuffixRecordSeparatorPolicy pour le reader.
Cela permettra de lire facilement le format csv présenté ci-dessus ou les blocs des enregistrements (records) sont préfixés avec le mot 'EOF_RECORD'.
Voici exactement ce qu'il faudrait rajouter, à la fin de la méthode avant le return reader:
ETAPE 4. Test unitaire Junit
Maintenant que notre reader est configuré et le suffixRecordPolicy est défini, testons unitairement ce reader.
Voici le code simple du test JUnit:
La dernière ligne appelle la méthode qui effectue certaines assertions sur l'opération read du FlatFileItemReader:
L'exécution du test unitaire JUnit confirme que chaque bloc (et non pas ligne) lu correspond à un objet java de type Entreprise et que ses propriétés sont conformes et sont celles attendues.
CONCLUSION
L'intérêt de l'approche de définir un SuffixRecordSeparatorPolicy est triple:
- Suivre les best-practices tel le principe SOC (separation of concerns),
- Éliminer l'écriture de nouveau code inutile (code de plomberie) et ses conséquences (bugs!) sur la recette,
- Centrer dans un composant les adaptations nécessaires à la configuration de chaque reader.
Le SuffixRecordSeparatorPolicy permet aussi, via juste quelques adaptations des assertions junit, de gérer le cas suivant où certains enregistrements(records) sont répartis sur plusieurs lignes comme illustré ci-après:
Vous remarquez que les champs rs et date sont répartis sur deux lignes.
J'espère que cet article vous sera utile.
Hello Abderrazek,
Merci cet excellent blog , je m’en sert énormément durant mon stage ! pourriez-vous svp mettre partager le code source finale svp.
Je vous remercie d’avance.
Nacim