IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Spring Java Discussion :

[SPRINGBATCH] Lecture des enregistrements par client depuis un fichier [Batch]


Sujet :

Spring Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2016
    Messages : 19
    Par défaut [SPRINGBATCH] Lecture des enregistrements par client depuis un fichier
    Bonjour,

    Je souhaite lire les enregistrements d'un fichier csv, par Client afin de traiter, par la suite, les informations dans l'ItemProcessor avec l'Objet Client, pour ensuite écrire les données du client en base de données

    Versions :
    - java 1.8
    - springBatch : 3.0.7.RELEASE

    Ci-dessous le fichier client CSV
    client1;adresse;adresse1
    client1;telephone;telephone1;telephone1
    client1;facture;facture1
    client2;adresse;adresse1;adresse2
    client2;telephone;telephone1
    client2;facture;facture1
    client3;adresse;adresse1
    client3;telephone;telephone1
    client3;facture;facture1;facture2
    EndOfClients

    J'utilise RecordSeparatorPolicy pour récupérer les données par client
    Avec la méthode isEndOfRecord, j'indique le changement de client pour transmettre les données, via la méthode postProcess, au LineMapper ci dessous les enregistrements passés par la méthode :
    postProcess = client1;adresse;adresse1||client1;telephone;telephone1;telephone1||client1;facture;facture1
    postProcess = client2;adresse;adresse1;adresse2||client2;telephone;telephone1||client2;facture;facture1
    postProcess = client3;adresse;adresse1||client3;telephone;telephone1||client3;facture;facture1;facture2

    Avant la concaténation des enregistrements, j'insére un séparateur d'enregistrement "||" afin de pouvoir décomposer
    mes enregistrements et construire mon objet Client dans le LineMapper
    LineMapper : client1;adresse;adresse1||client1;telephone;telephone1;telephone1||client1;facture;facture1
    LineMapper : client2;adresse;adresse1;adresse2||client2;telephone;telephone1||client2;facture;facture1
    LineMapper : client3;adresse;adresse1||client3;telephone;telephone1||client3;facture;facture1;facture2

    Et écrire dans l'ItemWriter avec l'objet Client
    ItemWriter = le client1 a : 1 adresse, 2 numero de telephone, 1 facture
    ItemWriter = le client2 a : 2 adresse, 1 numero de telephone, 1 facture
    ItemWriter = le client3 a : 1 adresse, 1 numero de telephone, 2 facture

    Le soucis est que je suis obligé d'ajouter dans mon fichier csv un indicateur de fin de ligne : EndOfClients
    afin que le client3 soit transmis vers le LineMapper, sinon j'obtiens l'erreur suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    org.springframework.batch.item.file.FlatFileParseException: Unexpected end of file before record complete
    Tout d'abord, est-ce que j'utilise la bonne manière de faire ?
    Si la manière est bonne, comment puis-je détecter que je suis en fin de ligne afin de transmettre le dernier client3 au LineMapper, sans utiliser EndOfClients ?

    Ci-dessous le code du ClientRecordSeparatorPolicy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    public class ClientRecordSeparatorPolicy implements RecordSeparatorPolicy {
     
    	// Separateur de champ d'un enregistrement
    	private String fieldSeparator = ";";
    	// Separateur d'enregistrement
    	private String recordSeparator = "||";
    	private String END_OF_CLIENT = "EndOfClients";
     
    	private DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(fieldSeparator);
    	private String previousClient;
    	private List<String> listLineClient = new ArrayList<String>();
     
     
    	public boolean isEndOfRecord(String record) {
    		FieldSet fieldSet = tokenizer.tokenize(record);
    		String currentClient;
     
    		// Test si fin de fichier
    		if (END_OF_CLIENT.equalsIgnoreCase(record)) {
    			return true;
    		}	
     
    		// Test si init
    		currentClient = fieldSet.readString(0);
    		if (previousClient != null) {
     
    			// Test rupture
    			if (!currentClient.equalsIgnoreCase(previousClient)) {
    				previousClient = currentClient;
    				return true;
    			}
     
    		} else {
    			// Init 1ier record
    			previousClient = currentClient;
    		}
     
    //		System.out.println("isEndOfRecord = " + record);
    		return false;
    	}
     
    	public String postProcess(String record) {
    		String clientRecords = listLineClient.stream().collect(Collectors.joining(recordSeparator));
    		listLineClient.clear();
    		listLineClient.add(record);
    		System.out.println("postProcess = " + clientRecords);
    		return clientRecords;
    	}
     
    	public String preProcess(String record) {
    		listLineClient.add(record);
    //		System.out.println("preProcess = " + record);
    		return "";
    	}
    Sinon dois-je faire autrement ?
    Dois-je m'y prendre directement dans l'ItemReader ?
    Si oui, auriez vous un exemple ?

    Merci

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2007
    Messages
    697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2007
    Messages : 697
    Par défaut
    As-tu essayé d'ajouter un retour à la ligne à la fin de ton fichier ?

    Sinon ce que tu fais me parait très compliqué pour lire un simple fichier CSV, normalement tu devrait juste faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    csvReader.setDelimiter(";")//ou un truc du genre
    Enlève également "EndOfClients" de ton fichier.

  3. #3
    Membre averti
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2016
    Messages : 19
    Par défaut
    Oui il y a bien un retour à la ligne dans le fichier
    En retirant la ligne "EndOfClients", il est possible de mettre un blanc à la place comme ci dessous

    Nom : 2019-10-28 10_33_26-Window.png
Affichages : 2067
Taille : 5,7 Ko
    En contre partie, il me faut détecter la ligne vide comme si dessous

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    // Test si fin de fichier
    if (END_OF_CLIENT.equalsIgnoreCase(record) || "".equals(record)) {
    	return true;
    }
    Sinon j'ai toujours l'erreur

    Je pense qu'il y a bien une solution comme j'ai pu voir dans le doc de Spring
    https://docs.spring.io/spring-batch/...l#customReader

    Il faut, je pense, customiser la lecture des enregistrements à la manière de csvreader

  4. #4
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2007
    Messages
    697
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Calvados (Basse Normandie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Janvier 2007
    Messages : 697
    Par défaut
    Tu ne devrais pas avoir besoin d’utiliser un custom reader ou une custom policy pour ce type de fichier.
    Je pense que tu dois louper un truc. Normalement tu devrais avoir maximum 3, 4 lignes pour récupérer tout dans un tableau/writer. Ou alors l'API est mal foutue mais venant de Spring, ça serait étonnant.
    Tu as jeté un oeil à https://howtodoinjava.com/spring-bat...essor-example/ ?

  5. #5
    Membre averti
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2016
    Messages : 19
    Par défaut
    J'ai utilisé cette technique en retournant un null afin de poursuivre les enregistrements entre les clients mais le traitement s'arrêtait.
    De mémoire, je pense l'avoir fait dans l'ItemReader et non dans l'ItemProcessor comme dans l'exemple du lien que tu m'indiques

    Merci pour cette nouvelle piste. Je ferais un test.

  6. #6
    Membre averti
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Avril 2016
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Avril 2016
    Messages : 19
    Par défaut
    J'ai fait le test, et toujours le même problème
    En fait il me manque toujours l'instruction de dernier enregistrement pour transmettre de l'ItemProcessor, l'objet Client avec ses informations, vers l'ItemWriter

    Comme je ne sais pas si c'est le dernier enregistrement d'un client, je continue à lire le fichier


    Ci dessous le code de l'ItemProcessor

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    public class ClientProcessor implements ItemProcessor<BeanClient, BeanClient> {
     
    	BeanClient beanClientPrevious;
     
    	@Override
    	public BeanClient process(BeanClient item) throws Exception {
    		// Save le client precedent, complet ou non
    		BeanClient beanClientFull = beanClientPrevious;
     
    		if (beanClientPrevious == null) {
    			// 1ier Client
    			beanClientPrevious = item;
    			return null;
    		} else if (item.getClientName().equalsIgnoreCase(beanClientPrevious.getClientName())) {
    			// Enregistrement suivant pour le meme client
    			beanClientPrevious.addRecord(item);
    			return null;
    		} else if (item != null) {
    			/* Rupture client */
    				// Init nouveau client
    			beanClientPrevious = item;
    		}
     
    		// Dans tous les cas 
    		return beanClientFull;
    	}
    Ci dessous le code de LineMapper
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public class OneClientLineMapper implements LineMapper<BeanClient> {
     
    	@Override
    	public BeanClient mapLine(String line, int lineNumber) throws Exception {
    		BeanClient beanClient = new BeanClient(line);
    		return beanClient;
    	}
    ci dessous les traces sur la console
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ItemWriter = le client1 a : 1 adresse, 1 numero de telephone, 1 facture
    ItemWriter = le client2 a : 1 adresse, 1 numero de telephone, 1 facture
    Job ended with status: exitCode=FAILED;exitDescription=
    Il me manque les infos du client 3

    Je pense que je devrais commencer par lire le nombre d'enregistrement du fichier,
    puis comme dans le LineMapper j'ai le numéro de ligne je pourrais comparer et toper alors la dernier enregistrement comme fin de ligne dans mon objet client

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 10/09/2007, 12h05
  2. sélectionner le dernier élément enregistré par client
    Par sorlok dans le forum Langage SQL
    Réponses: 2
    Dernier message: 09/05/2007, 13h58
  3. TOTAL des enregistrements par table
    Par LDDL dans le forum Requêtes
    Réponses: 2
    Dernier message: 21/03/2007, 14h17
  4. Récupérer des enregistrements par tranche horaire
    Par olive_le_malin dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 19/05/2006, 16h53
  5. compter des enregistrement par SQL
    Par 973thom dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 22/11/2004, 18h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo