SpringバッチHello Worldの例

Spring Batchは一連のジョブの実行 - バッチ処理用のフレームワークです。 Spring Batchでは、ジョブは多くのステップで構成され、各ステップは READ-PROCESS-WRITE`タスクまたは single operation`タスク(タスクレット)で構成されます。

  1. 「READ-PROCESS-WRITE」プロセスの場合、それは、

リソース(csv、xml、データベース)、それを "処理"し、他のリソース(csv、xml、データベース)に "書き込む"ことができます。たとえば、あるステップは、CSVファイルからデータを読み取り、処理してデータベースに書き込むことができます。 Spring Batchは、CSV、XML、およびデータベースを読み書きするために作られた多くのクラスを提供します。

  1. 「シングル」操作タスク(タスクレット)の場合は、単一のタスクを実行することを意味します

ステップが開始または完了する前または完了する前にリソースをクリーンアップするような場合のみです。

  1. そして、ステップは一緒に連鎖して仕事として走ることができます.

1 Job = Many Steps.
1 Step = 1 READ-PROCESS-WRITE or 1 Tasklet.
Job = {Step 1 -> Step 2 -> Step 3} (Chained together)

春のバッチの例

次のバッチジョブを検討してください。

  1. ステップ1 - フォルダAからCSVファイルを読み取り、処理して、フォルダBに書き込みます.

"READ-PROCESS-WRITE" 。ステップ2 - フォルダBからCSVファイルを読み込んで処理し、

データベース。 "READ-PROCESS-WRITE" 。ステップ3 - フォルダBからCSBファイルを削除します。 "タスクレット"

  1. ステップ4 - データベースからデータを読み取り、統計を生成して生成する

XML形式でレポートし、フォルダCに書き込みます。 "READ-PROCESS-WRITE" 。ステップ5 - レポートを読んでマネージャのEメールに送信します。 "タスクレット"

Spring Batchでは、次のように宣言できます。

  <job id="abcJob" xmlns="http://www.springframework.org/schema/batch">
    <step id="step1" next="step2">
      <tasklet>
        <chunk reader="cvsItemReader" writer="cvsItemWriter"
                    processor="itemProcesser" commit-interval="1"/>
      </tasklet>
    </step>
    <step id="step2" next="step3">
      <tasklet>
        <chunk reader="cvsItemReader" writer="databaseItemWriter"
                    processor="itemProcesser" commit-interval="1"/>
      </tasklet>
    </step>
    <step id="step3" next="step4">
      <tasklet ref="fileDeletingTasklet"/>
    </step>
    <step id="step4" next="step5">
      <tasklet>
        <chunk reader="databaseItemReader" writer="xmlItemWriter"
                    processor="itemProcesser" commit-interval="1"/>
      </tasklet>
    </step>
    <step id="step5">
        <tasklet ref="sendingEmailTasklet"/>
    </step>
  </job>

ジョブとステップの実行全体がデータベースに格納され、失敗したステップが失敗した場所で再起動できるようになり、ジョブ全体を開始する必要はありません。

1.チュートリアル

このSpring Batchチュートリアルでは、ジョブの作成方法、CSVファイルの読み込み方法、処理方法、出力をXMLファイルに書き込む方法について説明します。

使用されるツールとライブラリ

  1. Maven 3

  2. Eclipse 4.2

  3. JDK 1.6

  4. Spring Core 3.2.2.RELEASE

  5. Spring OXM 3.2.2.RELEASE

  6. Spring JDBC 3.2.2.RELEASE

  7. Spring Batch 2.2.0.RELEASE

2.プロジェクトディレクトリ

標準のMavenプロジェクトである最終プロジェクトディレクトリを確認します。

spring-batch-hello-world-directory、width = 408、height = 537

3.プロジェクトの依存関係

Spring Core、Spring Batch、JDK 1.5だけの依存関係が必要です。コメントは読んでください。

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.mkyong</groupId>
    <artifactId>SpringBatchExample</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringBatchExample</name>
    <url>http://maven.apache.org</url>

    <properties>
        <jdk.version>1.6</jdk.version>
        <spring.version>3.2.2.RELEASE</spring.version>
        <spring.batch.version>2.2.0.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>

        <!-- 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>
    </build>
</project>

4.春バッチジョブ

CSVファイル。

report.csv

1001,"213,100",980,"mkyong", 29/7/2013
1002,"320,200",1080,"staff 1", 30/7/2013
1003,"342,197",1200,"staff 2", 31/7/2013

FlatFileItemReader`でcsvファイルを読み込むSpringバッチジョブは itemProcessor`でデータを処理し、 `StaxEventItemWriter`でXMLファイルに書き込みます。

job-hello-world.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"
    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
    ">

    <import resource="../config/context.xml"/>
    <import resource="../config/database.xml"/>

    <bean id="report" class="com.mkyong.model.Report" scope="prototype"/>
    <bean id="itemProcessor" class="com.mkyong.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:cvs/input/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="id,sales,qty,staffName,date"/>
                </bean>
            </property>
            <property name="fieldSetMapper">
                <bean class="com.mkyong.ReportFieldSetMapper"/>

                 <!-- if no data type conversion, use BeanWrapperFieldSetMapper to map by name
                <bean
                    class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
                    <property name="prototypeBeanName" value="report"/>
                </bean>
                 -->
            </property>
            </bean>
        </property>

    </bean>

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

    <bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
       <property name="classesToBeBound">
        <list>
            <value>com.mkyong.model.Report</value>
        </list>
        </property>
    </bean>

</beans>

CSV値を `Report`オブジェクトにマップし、XMLファイルに書き出します(jaxbアノテーションを介して)。

Report.java

package com.mkyong.model;

import java.math.BigDecimal;
import java.util.Date;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "record")
public class Report {

    private int id;
    private BigDecimal sales;
    private int qty;
    private String staffName;
    private Date date;

    @XmlAttribute(name = "id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @XmlElement(name = "sales")
    public BigDecimal getSales() {
        return sales;
    }

    public void setSales(BigDecimal sales) {
        this.sales = sales;
    }

    @XmlElement(name = "qty")
    public int getQty() {
        return qty;
    }

    public void setQty(int qty) {
        this.qty = qty;
    }

    @XmlElement(name = "staffName")
    public String getStaffName() {
        return staffName;
    }

    public void setStaffName(String staffName) {
        this.staffName = staffName;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Report[id=" + id + ", sales=" + sales
                    + ", qty=" + qty + ", staffName=" + staffName + "]";
    }

}

Date`を変換するには、カスタム FieldSetMapper`が必要です。データ型変換がない場合は、BeanWrapperFieldSetMapperを使用して値を自動的に名前でマップします。

ReportFieldSetMapper.java

package com.mkyong;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;

import com.mkyong.model.Report;

public class ReportFieldSetMapper implements FieldSetMapper<Report> {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

    @Override
    public Report mapFieldSet(FieldSet fieldSet) throws BindException {

        Report report = new Report();
        report.setId(fieldSet.readInt(0));
        report.setSales(fieldSet.readBigDecimal(1));
        report.setQty(fieldSet.readInt(2));
        report.setStaffName(fieldSet.readString(3));

       //default format yyyy-MM-dd
       //fieldSet.readDate(4);
        String date = fieldSet.readString(4);
        try {
            report.setDate(dateFormat.parse(date));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return report;

    }

}

itemProcessorはitemWriterの前に起動されます。

CustomItemProcessor.java

package com.mkyong;

import org.springframework.batch.item.ItemProcessor;
import com.mkyong.model.Report;

public class CustomItemProcessor implements ItemProcessor<Report, Report> {

    @Override
    public Report process(Report item) throws Exception {

        System.out.println("Processing..." + item);
        return item;
    }

}

Springのコンテキストとデータベースの設定。

context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    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">

    <!-- stored job-meta in memory -->
    <!--
    <bean id="jobRepository"
        class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
     -->

     <!-- 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>

</beans>

database.xml

<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">

        <!-- connect to MySQL database -->
    <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/test"/>
        <property name="username" value="root"/>
        <property name="password" value=""/>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>

    <!-- 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>
5.それを実行する

バッチジョブを実行する最も簡単な方法。

package com.mkyong;

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) {

    String[]springConfig  =
        {
            "spring/batch/jobs/job-hello-world.xml"
        };

    ApplicationContext context =
            new ClassPathXmlApplicationContext(springConfig);

    JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
    Job job = (Job) context.getBean("helloWorldJob");

    try {

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

    } catch (Exception e) {
        e.printStackTrace();
    }

    System.out.println("Done");

  }
}

出力

report.xml

<?xml version="1.0" encoding="UTF-8"?>
<report>
    <record id="1001">
        <date>2013-07-29T00:00:00+08:00</date>
        <qty>980</qty>
        <sales>213100</sales>
        <staffName>mkyong</staffName>
    </record>
    <record id="1002">
        <date>2013-07-30T00:00:00+08:00</date>
        <qty>1080</qty>
        <sales>320200</sales>
        <staffName>staff 1</staffName>
    </record>
    <record id="1003">
        <date>2013-07-31T00:00:00+08:00</date>
        <qty>1200</qty>
        <sales>342197</sales>
        <staffName>staff 2</staffName>
    </record>
</report>

コンソール

Jul 30, 2013 11:52:00 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job:[FlowJob:[name=helloWorldJob]]launched with the following parameters:[{}]Jul 30, 2013 11:52:00 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step:[step1]Processing...Report[id=1001, sales=213100, qty=980, staffName=mkyong]Processing...Report[id=1002, sales=320200, qty=1080, staffName=staff 1]Processing...Report[id=1003, sales=342197, qty=1200, staffName=staff 2]Jul 30, 2013 11:52:00 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job:[FlowJob:[name=helloWorldJob]]completed with the following parameters:[{}]and the following status:[COMPLETED]Exit Status : COMPLETED
Done

ソースコードをダウンロードする

ダウンロードする - SpringBatch-Hello-World-Example.zip (27 kb)

参考文献

バッチ - リファレンスドキュメント]

hello world リンク://タグ/spring-batch/[spring バッチ]

次の投稿:Java - 文字列に別の文字列が含まれているかどうかを確認する