Springの掲示板を読んでいたら、面白い記事がありましたので触れてみたいと思います。
まさに、この記事のタイトルの内容です。
http://forum.springsource.org/showthread.php?t=48530
それほど難しくないので、まずはサンプルを見てみましょう!
※ここではItemWriterだけを記述します。
ItemReaderなどの設定は他の記事を参照してください。
※あと、ライブラリとしてmail.jarとactivation.jarが必要になるので、ダウンロードして配置してください。
ちなみに、Java1.6以降ではactivation.jarは必要ないようです。
【メール送信ItemWriterクラス】
package sample;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.transform.LineAggregator;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
public class MailItemWriter<T> implements ItemWriter<T> {
private static final String DEFAULT_LINE_SEPARATOR = System.getProperty("line.separator");
protected static final Log log = LogFactory.getLog(MailItemWriter.class);
private int maxSendCount = 10;
private int sendedCount = 0;
private LineAggregator<T> lineAggregator;
private String lineSeparator = DEFAULT_LINE_SEPARATOR;
private MailSender mailSender;
private String mailSubject;
private String mailFrom;
private String[] mailTo;
public int getMaxSendCount() {
return maxSendCount;
}
public void setMaxSendCount(int maxSendCount) {
this.maxSendCount = maxSendCount;
}
public LineAggregator<T> getLineAggregator() {
return lineAggregator;
}
public void setLineAggregator(LineAggregator<T> lineAggregator) {
this.lineAggregator = lineAggregator;
}
public String getLineSeparator() {
return lineSeparator;
}
public void setLineSeparator(String lineSeparator) {
this.lineSeparator = lineSeparator;
}
public MailSender getMailSender() {
return mailSender;
}
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public String getMailSubject() {
return mailSubject;
}
public void setMailSubject(String mailSubject) {
this.mailSubject = mailSubject;
}
public String getMailFrom() {
return mailFrom;
}
public void setMailFrom(String mailFrom) {
this.mailFrom = mailFrom;
}
public String[] getMailTo() {
return mailTo;
}
public void setMailTo(String[] mailTo) {
this.mailTo = mailTo;
}
@Override
public void write(List<? extends T> items) throws Exception {
StringBuilder buf = new StringBuilder();
if(this.sendedCount > this.maxSendCount)
throw new IndexOutOfBoundsException("送信数がmaxSendCountを超えました");
try{
for (T item : items) {
buf.append(this.lineAggregator.aggregate(item) + this.lineSeparator);
}
//
sendMail(buf.toString());
}catch(Exception e){
log.error("item書き込み&送信中にエラーが発生しました。", e);
throw e;
}
}
protected void sendMail(String text) throws Exception {
SimpleMailMessage msg = new SimpleMailMessage();
msg.setSubject(this.mailSubject + "[" + this.sendedCount + "]");
msg.setFrom(this.mailFrom);
msg.setTo(this.mailTo);
msg.setText(text);
try{
this.mailSender.send(msg);
++this.sendedCount;
}catch(Exception e){
log.error("エラー発生時メールの送信に失敗", e);
throw e;
}
}
}
【Springの設定ファイル一部抜粋】
<!-- メール送信テスト -->
<bean id="mailItemWriter" class="sample.MailItemWriter">
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.PassThroughFieldExtractor" >
</bean>
</property>
<property name="format" value="%2$s,%1$03d,%3$d" />
</bean>
</property>
<property name="mailSender" ref="mailSender" />
<property name="mailFrom" value="test@test.co.jp" />
<property name="mailTo" value="xxx@mail.co.jp" />
<property name="mailSubject" value="mailCsv" />
</bean>
<!-- メールセンダー -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="defaultEncoding" value="ISO-2022-JP" />
<property name="host" value="smtp.XXX.ne.jp" />
<property name="username" value="Xxxxx" />
</bean>
【説明】
メール送信のための機構もSpringは用意しています。
それがMailSenderです。
設定ファイルにそれを書くだけでOKです。
実際のデータ作成とメール送信する実装はItemWriterにあります。
再掲:ItemWriter
public void write(List<? extends T> items) throws Exception {
StringBuilder buf = new StringBuilder();
if(this.sendedCount > this.maxSendCount)
throw new IndexOutOfBoundsException("送信数がmaxSendCountを超えました");
try{
for (T item : items) {
buf.append(this.lineAggregator.aggregate(item) + this.lineSeparator);
}
//
sendMail(buf.toString());
}catch(Exception e){
log.error("item書き込み&送信中にエラーが発生しました。", e);
throw e;
}
}
データの作成は、FlatFileItemWriterクラスで使用していたlineAggregatorを流用しています。
これでFormatter変換も、区切り文字も自在にできます。
しかも、何も自作しなくていいですね!![]()
そして、作成したデータをmailSenderに送っているだけです。
ちなみに、メールを何回も送ると負荷がかかって危ないので、最大送信数を儲けています。
何かあっさりできましたね(笑)
Springがいろいろ用意してくれているのと、DIのおかげですね。
【拡張など】
もっと複数のデータ処理結果を送りたい場合、もしくは、ヘッダー・フッターなどを付けたい場合。
それほど難しくないです。
まずヘッダー・フッターについてはFlatFileItemWriterの真似をしましょう。
FlatFileItemWriterではheaderCallbackプロパティを持っていますよね。これをつけて、内部で処理の最初に
呼び出してあげればいいですよね。
また、複数のデータ処理結果を送りたい場合は、それぞれの処理結果をファイルに保存しましょう。
ItemReaderの中には複数のファイルをまとめて扱うクラスがあります。
MultiResourceItemReaderです。
readerにこのクラスを指定すれば、複数になってしまった処理結果ファイルをひとまとめにできます。
あとはwriterに上のメールItemWriterを指定すればよいでしょう。
結構、再利用でき、便利ですね!
【補足】
念のため補足しておきます。
上記のサンプルは簡単にするため、restartできるようには考えていません。
なぜならJobが終了したときにWriterクラス内部で持っているsendedCount も消えてしまうからです。
restartしたときにメールのタイトルが「mailCsv[0]」から始まってしまいます。
Javaが終了するので内部のインスタンスが消えてしまうので当たり前ですよね。
(このサンプルでは問題はメールタイトルだけですが、restartできるようにする方法は知っておきましょう)
しかし、値をを保持し、restartできるようにすることは簡単です。
StepExectutionの中に持っているExecutionContextに値を保存し、そこから値を取得してメールのタイトルに使用すればOKです。
もっと詳しいことは他の記事で書いてみようと思います。
参照:
・Spring Batchを使えるようにするには? (準備編)
・データの書き込み(コミット)タイミングを制御するには? (restart機能もついでに見る!)