このチュートリアルでは、XMLファイル(

JAXB2`ライブラリ)を

csv`ファイルに読み込み、 `ItemProcessor`で書き込む前にレコードをフィルタするようにSpringバッチジョブを設定する方法を説明します。

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

  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 OXM 3.2.2.RELEASE


P.Sこの例 – XMLファイル(リーダー) – フィルタリング(itemProcessor) – CSV(ライター).

1.シンプルなJavaプロジェクト

{空} 1。 MavenでクイックスタートJavaプロジェクトを作成し、Eclipse IDEに変換してインポートします。

$ mvn archetype:generate -DgroupId=com.mkyong -DartifactId=SpringBatchExample3
  -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

$ cd SpringBatchExample3/$ mvn eclipse:eclipse

プロジェクトの依存関係

`pom.xml`のすべてのプロジェクト依存関係を宣言します。

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>
    </properties>

    <dependencies>

        <!-- Spring Core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</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>

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

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

3.プロジェクトのディレクトリ構造

最終的なプロジェクトの構造を見直し、次に何が起こるかを概観する。


spring batch xml to csv、width = 454、height = 557

4. XMLファイル

resources/xml/report.xml

<?xml version="1.0" encoding="UTF-8" ?>
<company>
    <record refId="1001">
        <name>mkyong</name>
        <age>31</age>
        <dob>31/8/1982</dob>
        <income>200,000</income>
    </record>
    <record refId="1002">
        <name>kkwong</name>
        <age>30</age>
        <dob>26/7/1983</dob>
        <income>100,999</income>
    </record>
    <record refId="1003">
        <name>joel</name>
        <age>29</age>
        <dob>21/8/1984</dob>
        <income>1,000,000</income>
    </record>
    <record refId="1004">
        <name>leeyy</name>
        <age>29</age>
        <dob>21/3/1984</dob>
        <income>80,000.89</income>
    </record>
</company>

5. XMLファイルを読む

この例では、XML値と属性をオブジェクトにマップするために `Jaxb2Marshaller`を使用します。

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

    <!-- ...... -->
    <bean id="xmlItemReader"
        class="org.springframework.batch.item.xml.StaxEventItemReader">
    <property name="fragmentRootElementName" value="record"/>
    <property name="resource" value="classpath:xml/report.xml"/>
    <property name="unmarshaller" ref="reportUnmarshaller"/>
    </bean>

    <!-- Read and map values to object, via jaxb2 -->
    <bean id="reportUnmarshaller"
        class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
      <list>
        <value>com.mkyong.model.Report</value>
      </list>
    </property>
    </bean>

どのXML値がどのフィールドにマップされているかを知るために `Report`に注釈を付けます。

Report.java

package com.mkyong.model;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import com.mkyong.adapter.JaxbBigDecimalAdapter;
import com.mkyong.adapter.JaxbDateAdapter;

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

    private int refId;
    private String name;
    private int age;
    private Date dob;
    private BigDecimal income;

    @XmlAttribute(name = "refId")
    public int getRefId() {
        return refId;
    }

    public void setRefId(int refId) {
        this.refId = refId;
    }

    @XmlElement(name = "age")
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @XmlElement
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlJavaTypeAdapter(JaxbDateAdapter.class)
    @XmlElement
    public Date getDob() {
        return dob;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }

    @XmlJavaTypeAdapter(JaxbBigDecimalAdapter.class)
    @XmlElement
    public BigDecimal getIncome() {
        return income;
    }

    public void setIncome(BigDecimal income) {
        this.income = income;
    }

   //for csv file only
    public String getCsvDob() {

        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        return dateFormat.format(getDob());

    }

}

JAXB2では、

Date`や

BigDecimal`のような複雑なデータ型は、注釈がついていてもフィールドに自動的にはマッピングされません。

JAXB2が

Date`変換をサポートするようにするには、

Date format`を手動で処理するカスタムアダプタを作成し、 `@ XmlJavaTypeAdapter`を介してアダプタをアタッチする必要があります。

JaxbDateAdapter.java

package com.mkyong.adapter;

import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;


public class JaxbDateAdapter extends XmlAdapter<String, Date> {

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

    @Override
    public String marshal(Date date) throws Exception {
        return dateFormat.format(date);
    }

    @Override
    public Date unmarshal(String date) throws Exception {
        return dateFormat.parse(date);
    }

}

`BigDecimal`と同じ、コンマ”、 “XMLの収入要素が変換の問題を引き起こしているので、それを扱うカスタムアダプタも必要です。

JaxbBigDecimalAdapter.java

package com.mkyong.adapter;

import java.math.BigDecimal;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class JaxbBigDecimalAdapter extends XmlAdapter<String, BigDecimal> {

    @Override
    public String marshal(BigDecimal obj) throws Exception {
        return obj.toString();
    }

    @Override
    public BigDecimal unmarshal(String obj) throws Exception {
        return new BigDecimal(obj.replaceAll(",", ""));
    }

}

6.バネバッチコア設定


jobRepository`と

jobLauncher`を定義してください。

resources/spring/batch/config/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>

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

7.バッチバッチジョブ

Springバッチジョブで

report.xml`ファイルを読み込み、

Report`オブジェクトにマップし、csvファイルに書き込みます。コメントを読んで、それは自明であるべきです。

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

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:batch="http://www.springframework.org/schema/batch"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:util="http://www.springframework.org/schema/util"
    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
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-3.2.xsd">

  <batch:job id="reportJob">
    <batch:step id="step1">
    <batch:tasklet>
        <batch:chunk reader="xmlItemReader"
            writer="cvsFileItemWriter" processor="filterReportProcessor"
            commit-interval="1">
        </batch:chunk>
    </batch:tasklet>
    </batch:step>
  </batch:job>

  <!-- Filtering process -->
  <bean id="filterReportProcessor" class="com.mkyong.processor.FilterReportProcessor"/>

  <bean id="xmlItemReader"
        class="org.springframework.batch.item.xml.StaxEventItemReader">
    <property name="fragmentRootElementName" value="record"/>
    <property name="resource" value="classpath:xml/report.xml"/>
    <property name="unmarshaller" ref="reportUnmarshaller"/>
  </bean>

  <!-- Read and map values to object, via jaxb2 -->
  <bean id="reportUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
    <list>
        <value>com.mkyong.model.Report</value>
    </list>
    </property>
  </bean>

  <bean id="cvsFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
    <!-- write to this csv file -->
    <property name="resource" value="file:cvs/report.csv"/>
    <property name="shouldDeleteIfExists" value="true"/>

    <property name="lineAggregator">
      <bean
        class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
        <property name="delimiter" value=","/>
        <property name="fieldExtractor">
          <bean
            class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
            <property name="names" value="refId, name, age, csvDob, income"/>
           </bean>
        </property>
       </bean>
    </property>
  </bean>

</beans>

8. Springバッチ – ItemProcessor

Springバッチでは、有線の

Processor`がリソースに書き込む前に起動されるので、これは変換、フィルタリング、ビジネスロジックを処理するのに最適な場所です。この例では、 `

age`が30の場合、 `Report`オブジェクトは無視されます(csvファイルへの書き込みではありません)。

FilterReportProcessor.java

package com.mkyong.processor;

import org.springframework.batch.item.ItemProcessor;
import com.mkyong.model.Report;
//run before writing
public class FilterReportProcessor implements ItemProcessor<Report, Report> {

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

       //filter object which age = 30
        if(item.getAge()==30){
            return null;//null = ignore this object
        }
        return item;
    }

}

9.それを実行する

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

App.java

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/config/context.xml",
        "spring/batch/jobs/job-report.xml"
    };

    ApplicationContext context =
        new ClassPathXmlApplicationContext(springConfig);

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

    try {

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

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

    System.out.println("Done");

  }
}

出力。 XML値はcsvファイルに挿入されます。

csv/report.csv

1001,mkyong,31,31/08/1982,200000
1003,joel,29,21/08/1984,1000000
1004,leeyy,29,21/03/1984,80000.89


出力、幅= 611、高さ= 290

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

ダウンロードする –

SpringBatch-XML-CSV-Example.zip

(81 kb)