本記事では、EasyExcelライブラリを活用したデータインポート機能の実装方法を解説します。特に1000行ごとにバッチ処理を行う設計と、抽象化されたリスナークラスに焦点を当てます。
コアコンポーネントの設計
- DataImportListener:インポート処理を統括する抽象リスナークラス
- RowRecord:各行データを保持するエンティティクラス
- BatchProcessor:バッチ処理を定義する関数型インターフェース
実装コード
1. DataImportListener
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public abstract class DataImportListener extends AnalysisEventListener<RowRecord> implements BatchProcessor<Void> {
private final int skipRows;
private static final int BATCH_SIZE = 1000;
private final List<RowRecord> batchCache = new ArrayList<>();
public DataImportListener(int skipRows) {
if (skipRows < 0) {
throw new IllegalArgumentException("スキップ行数は0以上である必要があります");
}
this.skipRows = skipRows;
}
public DataImportListener() {
this(0);
}
@Override
public void invoke(RowRecord record, AnalysisContext context) {
int currentRowIndex = context.readRowHolder().getRowIndex();
if (currentRowIndex < skipRows) {
return;
}
batchCache.add(record);
if (batchCache.size() >= BATCH_SIZE) {
flush();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
flush();
}
@Override
public Void accept() {
return processBatch();
}
private void flush() {
if (!batchCache.isEmpty()) {
accept();
batchCache.clear();
}
}
}
DataImportListenerはEasyExcelのAnalysisEventListenerを継承し、行単位の読み取りとバッチ処理を自動化します。BATCH_SIZEで指定した件数(デフォルト1000行)ごとにflush()が呼ばれ、accept()メソッドが実行されます。全てのデータ読み取り完了後もflush()が呼ばれるため、端数のデータも漏れなく処理されます。
2. RowRecord
import lombok.Data;
@Data
public class RowRecord {
private String field01;
private String field02;
private String field03;
private String field04;
private String field05;
private String field06;
private String field07;
private String field08;
private String field09;
private String field10;
private String field11;
private String field12;
private String field13;
private String field14;
private String field15;
private String field16;
private String field17;
private String field18;
private String field19;
private String field20;
}
RowRecordはExcelの各行データをマッピングするPOJOです。20フィールドまでサポートしていますが、プロジェクトの要件に応じて拡張可能です。フィールド名はcol1からfield01に変更し、より意味的な命名としました。
3. BatchProcessor
public interface BatchProcessor<T> {
T processBatch();
T accept();
}
この関数型インターフェースにより、バッチ処理の実装をリスナークラスに委譲しつつ、呼び出し元からはaccept()メソッドを通じて処理を実行できます。processBatch()が実際のビジネスロジックを定義する抽象メソッドです。
使用例
public class UserImportListener extends DataImportListener {
public UserImportListener() {
super(1); // ヘッダー行をスキップ
}
@Override
public Void processBatch() {
// バッチデータをDBに保存するなどの処理
System.out.println("バッチ処理実行: " + batchCache.size() + "件");
return null;
}
}
この設計により、実際のインポート処理はprocessBatch()メソッドをオーバーライドするだけで実装可能です。EasyExcelのイベント駆動型APIと組み合わせることで、大規模なExcelデータを効率的かつメモリフレンドリーに処理できます。