tohnamanブログ

東村山に生息するWindows好きな太っちょオヤジプログラマのブログ

Spring Batch その4

今回も前回から時間が経過していますが、Spring Batch の続きです。


完成したモノをGitHubここ に置いています。

今回は、やっとJob作成です。
作成するJobは、

  1. CSVファイルからデータを取得
  2. 取得したデータを編集
  3. データベースに登録

するJobです。
Spring Batchの場合、chunk(チャンク)という仕組みがあるので、この仕組みに沿って作成します。

ガワ作成

Jobを定義するクラスを作成します。

@EnableBatchProcessing
@Import({ BatchContext.class })
public class Csv2dbJob01Config {

}

@EnableBatchProcessingは、Spring Batchの設定クラスに必要なアノテーションです。
本来は@Configurationも必要なのですが、BatchContextをImportしていることで、無くても大丈夫なようです。
BatchContextは前回作成したBatch用のApplicationContextです。
このBatchContextをImportすることで、DataSource設定とMyBatis設定を取り込みます。

CSVファイル読み込み処理

使用するCSVファイルは、これ で、内容は

  • 東京都住所情報
  • 先頭行に項目名がある
  • Shift_JISのファイル

です。
CSVファイル読み込みは、Spring Batchが提供しているファイルを簡単に扱えるクラスを利用します。

/** CSVファイルパス */
private static final String CSV_FILE_PATH = "D:/CsvData/13tokyo.csv";

@Bean
public FlatFileItemReader<AddressDto> addressReader() {
    DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
    lineTokenizer.setNames(new String[] { "id", "prefCd", "cityCd", "townCd", "zip", "officeFlg", "deleteFlg",
            "prefName", "prefKana", "cityName", "cityKana", "townName", "townKana", "townMemo", "kyotoStreet",
            "azaName", "azaKana", "memo", "officeName", "officeKana", "officeAddress", "newId" });

    BeanWrapperFieldSetMapper<AddressDto> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
    fieldSetMapper.setTargetType(AddressDto.class);
    
    DefaultLineMapper<AddressDto> lineMapper = new DefaultLineMapper<>();
    lineMapper.setLineTokenizer(lineTokenizer);
    lineMapper.setFieldSetMapper(fieldSetMapper);

    FlatFileItemReader<AddressDto> reader = new FlatFileItemReader<>();
    reader.setResource(new FileSystemResource(CSV_FILE_PATH));
    reader.setLinesToSkip(1);
    reader.setEncoding("Shift_JIS");
    reader.setLineMapper(lineMapper);
    return reader;
}

このコードを実行すると、CSVファイルの1行がAddressDtoに設定されます。
コード内容は、
DelimitedLineTokenizerでは、行をカンマで区切り、各項目に名前を付けています。
(DelimitedLineTokenizerはデフォルトがカンマ区切りです)
BeanWrapperFieldSetMapperでは、AddressDtoのフィールド名にマッピングすることを定義しています。
これらをDefaultLineMapperで包んでFlatFileItemReaderに設定しています。
FlatFileItemReaderのsetLinesToSkipは、スキップする行数を指定しています。
今回使用するCSVは先頭行に項目名がある為、1行スキップする必要があります。

取得データの編集処理

以下のルールで取得データを編集する

  • 市区町村名が東村山市以外は無視
  • 郵便番号のハイフンを削除

データ編集処理では、Spring Batchが提供しているItemProcessorを実装したクラスを作成します。

package jp.tokyo.higashimurayama.tohnaman.batch.jobs.csv2db;

public class CsvToModelItemProcessor implements ItemProcessor<AddressDto, MstAddress> {
  @Override
  public MstAddress process(AddressDto item) throws Exception {
    String cityName = item.getCityName();
    if (cityName.equals("東村山市")) {
      MstAddress output = new MstAddress();
      BeanUtils.copyProperties(item, output);
      output.setZip(item.getZip().replace("-", ""));
      return output;
    }
    return null;
  }
}

引数はItemReaderから渡されるAddressDtoで、戻り値はItemWriterに渡すMstAddressです。

@Bean
public CsvToModelItemProcessor csvToModelItemProcessor() {
  return new CsvToModelItemProcessor();
}

作成したCsvToModelItemProcessorをCsv2dbJob01ConfigにBeanとして設定ファイルに追加する

データベース登録

データベース登録には、MyBatisが提供しているMyBatisBatchItemWriterを作成します。
Spring BatchでもIbatisBatchItemWriterを提供していますが、Deprecatedなので使用しません。

@Autowired
private SqlSessionFactory sqlSessionFactory;

@Bean
public MyBatisBatchItemWriter<MstAddress> addressWriter() {
  MyBatisBatchItemWriter<MstAddress> writer = new MyBatisBatchItemWriter<>();
  writer.setStatementId("jp.tokyo.higashimurayama.tohnaman.batch.mybatis.mapper.MstAddressMapper.insert");
  writer.setSqlSessionFactory(sqlSessionFactory);
  return writer;
}

setStatementIdで指定しているIDは、MyBatis Generatorを使用して自動生成したmapperのIDです。
これで、CsvToModelItemProcessor から渡されたMstAddress の内容をMST_ADDRESSにinsertします。