Exemple de lot de printemps - Fichier XML dans la base de données MongoDB

Exemple de lot de printemps - Fichier XML vers la base de données MongoDB

Dans ce didacticiel, nous allons vous montrer comment configurer une tâche Spring Batch pour lire les données d'un fichier XML (bibliothèqueXStream) dans une base de données sans SQL (MongoDB). De plus, créez un scénario de test unitaire pour lancer et tester les travaux par lots.

Outils et bibliothèques utilisés

  1. Maven 3

  2. Eclipse 4.2

  3. JDK 1.6

  4. Spring Core 3.2.2.RELEASE

  5. Spring Batch 2.2.0.RELEASE

  6. Spring Batch Test 2.2.0.RELEASE

  7. Spring OXM 3.2.2.RELEASE

  8. MongoDB Java Driver 2.11.2

  9. MongoDB 2.2.3

  10. jUnit 4.11

  11. TestNG 6.8.5

P.S This example – XML file (reader) – MongoDB (writer).

1. Projet Java simple

1. Créez un projet Java de démarrage rapide avec Maven, convertissez et importez dans Eclipse IDE.

$ mvn archetype:generate -DgroupId=com.example -DartifactId=SpringBatchExample2
  -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
$ cd SpringBatchExample/
$ mvn eclipse:eclipse

2. Dépendances du projet

Déclare toutes les dépendances de projet dans lespom.xml

pom.xml


    4.0.0
    com.example
    SpringBatchExample
    jar
    1.0-SNAPSHOT
    SpringBatchExample
    http://maven.apache.org

    
        1.6
        3.2.2.RELEASE
        2.2.0.RELEASE
        1.2.1.RELEASE
        2.11.2
    

    

        
        
            org.springframework
            spring-core
            ${spring.version}
        

        
        
            org.springframework
            spring-oxm
            ${spring.version}
        

        
        
            org.springframework.batch
            spring-batch-core
            ${spring.batch.version}
        
        
            org.springframework.batch
            spring-batch-infrastructure
            ${spring.batch.version}
        

        
        
            org.springframework.batch
            spring-batch-test
            ${spring.batch.version}
        

        
        
            org.mongodb
            mongo-java-driver
            ${mongodb.driver.version}
        

        
        
            org.springframework.data
            spring-data-mongodb
            ${spring.data.version}
        

        
        
            junit
            junit
            4.11
            test
        

        
        
            org.testng
            testng
            6.8.5
            test
        

    
    
        spring-batch
        
        
            org.apache.maven.plugins
            maven-eclipse-plugin
            2.9
            
                true
                false
            
        
        
            org.apache.maven.plugins
            maven-compiler-plugin
            2.3.2
            
                ${jdk.version}
                ${jdk.version}
            
        
        
    

3. Structure du répertoire du projet

Passez en revue la structure finale du projet, obtenez un aperçu de ce qui se passera ensuite.

spring batch - xml to mongodb

4. Fichier XML

Il s'agit du fichier XML dans le dossier de ressources.

resources/xml/report.xml


    
        6/1/2013
        139,237
        40
        220.90
    
    
        6/2/2013
        339,100
        60
        320.88
    
    
        6/3/2013
        431,436
        76
        270.80
    

5. Lire le fichier XML

Dans Spring batch, nous pouvons utiliserStaxEventItemReader pour lire des fichiers XML etXStreamMarshaller pour mapper des valeurs et des attributs XML à un objet.

resources/spring/batch/jobs/job-report.xml

    
    
    
    
    
    

    

    
        
        
        
    
    
        
        
        
    

    

    

Report.java

package com.example.model;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Report {

    private int id;
    private Date date;
    private long impression;
    private int clicks;
    private BigDecimal earning;

    //getter and setter methods

}

Pour mapper une valeur XML à un type de données «complexe» commeDate etBigDecimal, vous devez attacher unconverter personnalisé pour convertir et mapper la valeur manuellement.

ReportConverter.java

package com.example.converter;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import com.example.model.Report;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class ReportConverter implements Converter {

    @Override
    public boolean canConvert(Class type) {
        //we only need "Report" object
        return type.equals(Report.class);
    }

    @Override
    public void marshal(Object source,
            HierarchicalStreamWriter writer, MarshallingContext context) {
        //do nothing
    }

    @Override
    public Object unmarshal(
            HierarchicalStreamReader reader, UnmarshallingContext context) {

        Report obj = new Report();

        //get attribute
        obj.setId(Integer.valueOf(reader.getAttribute("id")));
        reader.moveDown(); //get date

        Date date = null;
        try {
            date = new SimpleDateFormat("M/d/yyyy").parse(reader.getValue());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        obj.setDate(date);
        reader.moveUp();

        reader.moveDown(); //get impression

        String impression = reader.getValue();
        NumberFormat format = NumberFormat.getInstance(Locale.US);
                Number number = 0;
        try {
            number = format.parse(impression);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        obj.setImpression(number.longValue());

        reader.moveUp();

        reader.moveDown(); //get click
        obj.setClicks(Integer.valueOf(reader.getValue()));
        reader.moveUp();

        reader.moveDown(); //get earning
        obj.setEarning(new BigDecimal(reader.getValue()));
                reader.moveUp();

                return obj;

    }
}

6. Base de données MongoDB

Définissez une instance mongodb, ainsi qu'unmongoTemplate.

resources/spring/batch/config/database.xml



        
    
    

    
        
    

7. Réglage de base du lot de printemps

DéfinissezjobRepository etjobLauncher.

resources/spring/batch/config/context.xml



    
    
    
    

    


    
    
    

8. Emplois Spring Batch

Une tâche Spring batch, lisez le fichierreport.xml, mappez sur un objetReport et écrivez-le dans leMongoDB. Lisez le commentaire, il devrait être explicite.

resources/spring/batch/jobs/job-report.xml



    
    
      
        
        
      
    
    

    
    
    
    
    
    

    
    
    
      
        
      
    

        
    
      
        
      
    

    

    

    //write it to MongoDB, 'report' collection (table)
    
    
    
    

9. Test de l'unité

Testez-le à l'unité avec les frameworks jUnit ou TestNG. Tout d'abord, vous devez déclarer lesJobLauncherTestUtils manuellement.

test/resources/spring/batch/config/test-context.xml



    
    

Exemple jUnit

AppTest.java

package com.example;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:spring/batch/jobs/job-report.xml",
    "classpath:spring/batch/config/context.xml",
    "classpath:spring/batch/config/database.xml",
    "classpath:spring/batch/config/test-context.xml"})
public class AppTest {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Test
    public void launchJob() throws Exception {

        //JobExecution jobExecution = jobLauncherTestUtils.launchJob();

        JobExecution jobExecution = jobLauncherTestUtils.launchStep("step1");

        assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());

    }
}

Exemple de testNG

AppTest2.java

package com.example;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.Assert;
import org.testng.annotations.Test;

@ContextConfiguration(locations = {
    "classpath:spring/batch/jobs/job-report.xml",
    "classpath:spring/batch/config/context.xml",
    "classpath:spring/batch/config/database.xml",
    "classpath:spring/batch/config/test-context.xml"})
public class AppTest2 extends AbstractTestNGSpringContextTests {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Test
    public void launchJob() throws Exception {

        JobExecution jobExecution = jobLauncherTestUtils.launchJob();
        Assert.assertEquals(jobExecution.getStatus(), BatchStatus.COMPLETED);

    }
}

Production. Les valeurs XML sont insérées dans MongoDB.

mongo
MongoDB shell version: 2.2.3
connecting to: test

> use yourdb
switched to db yourdb
> show collections
report
system.indexes

> db.report.find()
{ "_id" : 1, "_class" : "com.example.model.Report",
"date" : ISODate("2013-05-31T16:00:00Z"), "impression" : NumberLong(139237),
"clicks" : 40, "earning" : "220.90" }

{ "_id" : 2, "_class" : "com.example.model.Report",
"date" : ISODate("2013-06-01T16:00:00Z"), "impression" : NumberLong(339100),
"clicks" : 60, "earning" : "320.88" }

{ "_id" : 3, "_class" : "com.example.model.Report",
"date" : ISODate("2013-06-02T16:00:00Z"), "impression" : NumberLong(431436),
"clicks" : 76, "earning" : "270.80" }
>

10. Et les métadonnées du travail?

Désolé, je n'ai pas encore de solution pour cela. Comme je le sais, la base de données relationnelle est nécessaire pour les métadonnées de travail, afin d'assurer la possibilité de redémarrage et les restaurations des travaux. Le MongoDB n'a pas de gestion des transactions «solide», par conception.

Solution 1: Créez une autre base de données relationnelle pour stocker les métadonnées du travail, hmm… Cela semble stupide, mais fonctionne. Avez-vous de meilleures idées?

Solution 2: attendez que l'équipe de Spring trouve une solution à ce problème.

Télécharger le code source

Téléchargez-le -SpringBatch-XML-MongoDB-Example.zip (81 kb)