06.バッチ処理の実際のサンプル
(チャンク処理:ファイル読み込み)
概要
今までは概要について説明してきました。
ここでは具体的にどのようにバッチ処理を記述するか、サンプル見てみます。
目標
まず、以下のサンプルの目標(ゴール)を示します。
SpringBatchでは、いくつか部品が用意されています。
自作することもできますが、面倒になりますので、既存の部品をいくつか使用してできる動作をさせます。
サンプルのゴールは、CSVファイルを読み込んで、他のファイルに書き込むことです。
このとき、列を入れ替えて出力します。
SpringBatchでは読み込んだファイルのデータを、FieldSetというクラスに保存します。
FieldSetからPOJOのクラスに値を設定することを「マップする」という言い方をします。
このサンプルではPOJOにはMemberクラスを使用します。
そして、マップされたMemberクラスをItemWriterで、nameプロパティ、numプロパティの順番に出力させます。
使用サンプル
<バッチ処理設定サンプル: /job-context.xml>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
">
<!-- SpringBatchの基盤部分に関する設定のインポート -->
<import resource="classpath:/back-context.xml" />
<!-- ジョブの設定 -->
<job id="job1" xmlns="http://www.springframework.org/schema/batch"
incrementer="jobParametersIncrementer">
<step id="step1" parent="simpleStep">
<tasklet>
<chunk reader="fileItemReader" writer="fileItemWriter" />
</tasklet>
</step>
</job>
<!-- enables the functionality of JobOperator.startNextInstance(jobName) -->
<bean id="jobParametersIncrementer"
class="org.springframework.batch.core.launch.support.RunIdIncrementer" />
<bean id="simpleStep"
class="org.springframework.batch.core.step.item.SimpleStepFactoryBean"
abstract="true">
<property name="jobRepository" ref="jobRepository" />
<property name="commitInterval" value="1" />
</bean>
<bean id="fileItemReader"
class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource" value="file:c:/test/data.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="num,name" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="test.batch.item.MemberFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<!-- 列を入れ替えてファイルに出力するWriter -->
<bean id="fileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:c:/test/test.txt" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor" >
<property name="names" value="name,num" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
各部品について簡単に記述して見ます。
【fileItemReader】
FlatFileItemReaderクラスを設定しています。
このクラスは、ファイルに記述されたデータを読み込むことができます。
<FlatFileItemReaderのプロパティ>
lineMapperプロパティを書き替えることで区切り文字を変更したり、固定文字列にも対応できます。
DelimitedLineTokenizer, FixedLengthTokenizer, PatternMatchingCompositeLineTokenizerあたりのjavadocを参照ください。
また、複数行で1つのデータになっている場合も読み込むことができるようです。
固定文字列を読み込むためのtokenizerの例
<bean id="fixedLengthLineTokenizer"
class="org.springframework.batch.io.file.transform.FixedLengthTokenizer">
<property name="names" value="num,name,age" />
<property name="columns" value="1-7, 7-18, 19-21" />
</bean>
【fileItemWriter】
FlatFileItemWriterクラスを設定しています。
このクラスは、ファイルにデータ書き込みをします。
lineAggregatorプロパティに設定しているのは区切り文字によるデータのファイル書き込みクラスです。
もちろん、区切り文字は自由に変更できます。
また、FormatterLineAggregatorを使用すれば位置を自由に変更することも、書式変換することもできます。
<FlatFileItemWriterのプロパティ>
<バッチ基盤に関する設定ファイル: /back-context.xml>
以下の記事の「Spring設定ファイルの記述例」の設定ファイルをコピーしてください。
※DBの設定については、同じページの「オンメモリのリポジトリを使用する方法」の項を参考に書き換えてください。
<POJOのクラス: test.batch.item.Member.java>
public class Member {
private int num;
private String name;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<POJOへの値設定マッパークラス: test.batch.item.MemberFieldSetMapper.java>
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class MemberFieldSetMapper implements FieldSetMapper<Member> {
@Override
public Member mapFieldSet(FieldSet fs) throws BindException {
Member member = new Member();
member.setNum(fs.readInt("num", 0));
member.setName(fs.readString("name"));
return member;
}
}
POJOへのマップは、FieldSetMapperをimplementsしたクラスで行います。
メソッドではFieldSetが渡ってくるので、readXxx()を使用して値を取得して、POJOのsetterで設定をします。
readXxx()の仕様は、第一引数で名称もしくは要素番号を指定します。
第二引数はオプションで、指定した場合は、値が存在しなかったときに返すデフォルト値になっています。
readDate()については第三引数まで存在します。
3つ目の引数は、日付のフォーマット(例: yyyy/MM/dd)を指定します。
<読み込みファイルのサンプル: c:/test/data.csv>
1,太郎
2,華子
<実行方法>
実行方法は、主に以下のような方法があります。
【コマンドラインからの起動方法】
コマンドラインから、以下のコマンドを実行すれば動作します。
java org.springframework.batch.core.launch.support.CommandLineJobRunner
classpath:/example/launch-context.xml job1
【eclipse上での起動方法】
eclipse上から起動する場合は、以下のようにすれば起動します。
①プロジェクトを右クリック ⇒ 実行 ⇒ 実行の構成 を選択します。
②左側の「Javaアプリケーション」を選択し、新規ボタンを押します。
③右側に以下の画面が表示されますので、以下のようにクラスを選択します。
④引数タブを押すと、以下のような画面が表示されますので、以下のように起動引数を記述します。
⑤ここまで記述しましたら、「実行」ボタンを押せば動作します。
ジョブの実行結果
上記のような設定を記述し、実行すれば以下のファイルが作成されます。
【実行結果ファイル】
太郎,1
華子,2
今回のサンプルでは、チャンクによるステップ処理を記述しました。
詳しくは他の「基本概念」の記事をご覧いただければと思います。
最後に
このサンプルをご覧になって、「マッパーを作成するのが少し面倒だな」と感じたかもしれません。
確かにそのとおりです。
実は、POJOのプロパティを設定するマッパーがSpringBatchには用意されています。
BeanWrapperFieldSetMapperクラスです。これが使用できるようであれば使用して楽をしましょう。
また、POJOのクラスを作るのがわずらわしいと感じた方もいらっしゃるでしょうか?
SpringBatchでは、データのやり取りはすべてPOJOを使用するのが基本思想になっているようです。
この基本思想は正しいと思っています。
しかし、一時的にしか使用しないようなデータまでクラスを作成しないといけないのは、つらいときがあります。
1回しか使用しないクラスであふれてしまうと、返ってそのプログラムの理解が難しくなることもあります。
soracaneではこれを回避するために、LinkedHashMapにマップする部品を用意しています。
こちらを使用することを検討されると良いかと思います。
ユーザーガイドをご覧ください。
Created Date: 2010/01/12