Spring Batch CSV到XML


在本章中,我們將建立一個使用CSV Reader和XML Writer的簡單Spring Batch應用程式。

閱讀器 - 在應用程式中使用的閱讀器是FlatFileItemReader,用於從CSV檔案中讀取資料。

以下是在此應用程式中使用的輸入CSV檔案。 本文件包含指定詳細資訊的資料記錄,如教學編號,教學作者,教學標題,提交日期,教學圖示和教學說明。

完整的專案目錄結構如下:

建立一個Maven專案,使用以下組態檔案(pom.xml):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
   http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.yiibai</groupId>
    <artifactId>SpringBatchCSV2XML</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringBatch CSV to XML</name>
    <url>http://maven.apache.org</url>

    <properties>
        <jdk.version>1.8</jdk.version>
        <spring.version>4.3.8.RELEASE</spring.version>
        <spring.batch.version>3.0.7.RELEASE</spring.batch.version>
        <mysql.driver.version>5.1.25</mysql.driver.version>
        <junit.version>4.11</junit.version>
    </properties>

    <dependencies>
        <!-- Spring Core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/pdfbox/pdfbox -->
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.0</version>
        </dependency>


        <!-- Spring jdbc, for database -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring XML to/back object -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- MySQL database driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.driver.version}</version>
        </dependency>

        <!-- Spring Batch dependencies -->
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
            <version>${spring.batch.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-infrastructure</artifactId>
            <version>${spring.batch.version}</version>
        </dependency>

        <!-- Spring Batch unit test -->
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <version>${spring.batch.version}</version>
        </dependency>

        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>spring-batch</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>false</downloadJavadocs>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                </configuration>
            </plugin>
        </plugins>
        <defaultGoal>compile</defaultGoal>
    </build>
</project>

檔案:report.csv -

1001, "Sansu", "Learn Java", 16/12/2017 
1002, "Leejas", "Learn MySQL", 19/04/2017 
1003, "Kobe", "Learn JavaFX", 16/07/2018
  • Writer - 在應用程式中使用的WriterStaxEventItemWriter,用於將資料寫入XML檔案。
  • Processor - 在應用程式中使用的處理器是一個自定義處理器,它只是列印從CSV檔案中讀取的記錄。

 jobconfig.xml

以下是Spring Batch應用程式範例的組態檔案。 在這個檔案中,我們將定義Job和Step。 除此之外,還為ItemReaderItemProcessorItemWriter定義了bean。 (在這裡,我們將它們與相應的類相關聯,並傳遞所需屬性的值來組態它們。)

檔案:jobconfig.xml -

<beans xmlns = "http://www.springframework.org/schema/beans" 
   xmlns:batch = "http://www.springframework.org/schema/batch" 
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:util = "http://www.springframework.org/schema/util" 
   xsi:schemaLocation = "http://www.springframework.org/schema/batch 
      http://www.springframework.org/schema/batch/spring-batch-2.2.xsd 
      http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
      http://www.springframework.org/schema/util     
      http://www.springframework.org/schema/util/spring-util-3.0.xsd ">  

    <import resource="context.xml" />

    <bean id="report" class="Report" scope="prototype" />
    <bean id="itemProcessor" class="com.yiibai.CustomItemProcessor" />

    <batch:job id="helloWorldJob">

        <batch:step id="step1">

            <batch:tasklet>
                <batch:chunk reader="cvsFileItemReader" writer="xmlItemWriter"
                    processor="itemProcessor" commit-interval="10">
                </batch:chunk>
            </batch:tasklet>
        </batch:step>
    </batch:job>

    <bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
        <property name="resource" value="classpath:report.csv" />
        <property name="lineMapper">
            <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <property name="lineTokenizer">
                    <bean
                        class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
                        <property name="names"
                            value="tutorial_id, 
                     tutorial_author, Tutorial_title, submission_date" />
                    </bean>
                </property>

                <property name="fieldSetMapper">
                    <bean class="com.yiibai.TutorialFieldSetMapper" />
                </property>
            </bean>
        </property>
    </bean>

    <bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
        <property name="resource" value="file:xml/tutorials.xml" />
        <property name="marshaller" ref="reportMarshaller" />
        <property name="rootTagName" value="tutorials" />
    </bean>

    <bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="classesToBeBound">
            <list>
                <value>com.yiibai.Tutorial</value>
            </list>
        </property>
    </bean>
</beans>

context.xml

以下是Spring Batch應用程式的context.xml。 在這個檔案中,我們將定義bean,如作業儲存庫,作業啟動器和事務管理器。

<beans xmlns = "http://www.springframework.org/schema/beans" 
   xmlns:jdbc = "http://www.springframework.org/schema/jdbc" 
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation = "http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
      http://www.springframework.org/schema/jdbc 
      http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd">  
   <!-- stored job-meta in database --> 
   <bean id = "jobRepository" 
      class = "org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"> 
      <property name = "dataSource" ref = "dataSource" /> 
      <property name = "transactionManager" ref = "transactionManager" /> 
      <property name = "databaseType" value = "mysql" /> 
   </bean>  

   <bean id = "transactionManager" 
      class = "org.springframework.batch.support.transaction.ResourcelessTransactionManager" />  
   <bean id = "jobLauncher" 
      class = "org.springframework.batch.core.launch.support.SimpleJobLauncher"> 
      <property name = "jobRepository" ref = "jobRepository" /> 
   </bean>  

   <bean id = "dataSource" class = "org.springframework.jdbc.datasource.DriverManagerDataSource"> 
      <property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> 
      <property name = "url" value = "jdbc:mysql://localhost:3306/testdb" />
      <property name = "username" value = "root" /> 
      <property name = "password" value = "123456" /> 
   </bean> 

   <!-- create job-meta tables automatically --> 
   <jdbc:initialize-database data-source = "dataSource">   
      <jdbc:script location = "org/springframework/batch/core/schema-drop-mysql.sql" /> 
      <jdbc:script location = "org/springframework/batch/core/schema-mysql.sql" /> 
   </jdbc:initialize-database> 
</beans>

CustomItemProcessor.java

以下是處理器類。 在這個類中,在應用程式中編寫處理程式碼。 在這裡,列印每條記錄的內容。

import org.springframework.batch.item.ItemProcessor;  

public class CustomItemProcessor implements ItemProcessor<Tutorial, Tutorial> {  

   public Tutorial process(Tutorial item) throws Exception {  
      System.out.println("Processing..." + item); 
      return item; 
   } 
}

 TutorialFieldSetMapper.java

以下是TutorialFieldSetMapper類,它將資料設定為Tutorial類。

import org.springframework.batch.item.file.mapping.FieldSetMapper; 
import org.springframework.batch.item.file.transform.FieldSet; 
import org.springframework.validation.BindException;  

public class TutorialFieldSetMapper implements FieldSetMapper<Tutorial> {  


   public Tutorial mapFieldSet(FieldSet fieldSet) throws BindException {  

      //Instantiating the report object  
      Tutorial tutorial = new Tutorial(); 

      //Setting the fields  
      tutorial.setTutorial_id(fieldSet.readInt(0)); 
      tutorial.setTutorial_author(fieldSet.readString(1)); 
      tutorial.setTutorial_title(fieldSet.readString(2)); 
      tutorial.setSubmission_date(fieldSet.readString(3)); 

      return tutorial; 
   } 
}

Tutorial.java類

以下是Tutorial類。 它是一個簡單的帶有settergetter方法的Java類。 在這個類中,我們使用注釋來將這個類的方法與XML檔案的標籤關聯起來。

import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement;  

@XmlRootElement(name = "tutorial") 
public class Tutorial {  
   private int tutorial_id; 
   private String tutorial_author; 
   private String tutorial_title;
   private String submission_date;  

   @XmlAttribute(name = "tutorial_id") 
   public int getTutorial_id() { 
      return tutorial_id; 
   }  

   public void setTutorial_id(int tutorial_id) { 
      this.tutorial_id = tutorial_id; 
   }  

   @XmlElement(name = "tutorial_author") 
   public String getTutorial_author() { 
      return tutorial_author; 
   }  
   public void setTutorial_author(String tutorial_author) { 
      this.tutorial_author = tutorial_author; 
   }  

   @XmlElement(name = "tutorial_title") 
   public String getTutorial_title() { 
      return tutorial_title; 
   }  

   public void setTutorial_title(String tutorial_title) { 
      this.tutorial_title = tutorial_title; 
   }  

   @XmlElement(name = "submission_date") 
   public String getSubmission_date() { 
      return submission_date; 
   }  

   public void setSubmission_date(String submission_date) { 
      this.submission_date = submission_date; 
   } 

   @Override 
   public String toString() { 
      return "  [Tutorial id=" + tutorial_id + ", 
         Tutorial Author=" + tutorial_author  + ", 
         Tutorial Title=" + tutorial_title + ", 
         Submission Date=" + submission_date + "]"; 
   } 
}

App.java

以下是啟動批次處理過程的程式碼。 在這個類中,通過執行JobLauncher來啟動批次處理應用程式。

package com.yiibai;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) throws Exception {

        String[] springConfig = {"context.xml", "jobconfig.xml" };

        // Creating the application context object
        ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);

        // Creating the job launcher
        JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");

        // Creating the job
        Job job = (Job) context.getBean("helloWorldJob");

        // Executing the JOB
        JobExecution execution = jobLauncher.run(job, new JobParameters());
        System.out.println("Exit Status : " + execution.getStatus());
    }
}

在執行這個應用程式時,它將產生以下輸出。

資訊: Executed SQL script from class path resource [org/springframework/batch/core/schema-mysql.sql] in 7040 ms.
四月 28, 2018 2:32:15 下午 org.springframework.oxm.jaxb.Jaxb2Marshaller createJaxbContextFromClasses
資訊: Creating JAXBContext with classes to be bound [class com.yiibai.Tutorial]
四月 28, 2018 2:32:17 下午 org.springframework.batch.core.launch.support.SimpleJobLauncher run
資訊: Job: [FlowJob: [name=helloWorldJob]] launched with the following parameters: [{}]
四月 28, 2018 2:32:17 下午 org.springframework.batch.core.job.SimpleStepHandler handleStep
資訊: Executing step: [step1]
Processing...  [Tutorial id=1001, Tutorial Author=Sansu, Tutorial Title=Learn Java, Submission Date=16/12/2017]
Processing...  [Tutorial id=1002, Tutorial Author=Leejas, Tutorial Title=Learn MySQL, Submission Date=19/04/2017]
Processing...  [Tutorial id=1003, Tutorial Author=Kobe, Tutorial Title=Learn JavaFX, Submission Date=16/07/2018]
四月 28, 2018 2:32:18 下午 org.springframework.batch.core.launch.support.SimpleJobLauncher run
資訊: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
Exit Status : COMPLETED

這將生成一個包含以下內容的XML檔案。