EasyExcelを用いた効率的なデータインポート実装

本記事では、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データを効率的かつメモリフレンドリーに処理できます。

タグ: EasyExcel Java データインポート バッチ処理 AnalysisEventListener

6月18日 18:43 投稿