mcpField
E
easyexcel-fill

easyexcel-fill

github.com/full-stack-skillsドキュメント771 回インストール4 週間前に更新
リポジトリ

easyexcel-fill について

easyexcel-fill は、EasyExcel で用意済みの .xlsx テンプレートにオブジェクトやリストのデータを入力する Java 開発者向けスキルです。複雑・横方向・複数リストの入力方法に加え、メモリや大量データの制約も扱います。

主な機能

  1. 01単一オブジェクトとリストの入力
  2. 02複雑な入力と横方向の入力
  3. 03複数リストの組み合わせ
  4. 04Spring Boot との連携
  5. 05テンプレート構文とデータ量の制約

活用シーン

  1. 01給与明細や契約書のテンプレートへのデータ入力
  2. 02明細と合計行を含む照合書の作成
  3. 03横方向のレイアウトを使ったレポート入力

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/full-stack-skills/java-skills --skill easyexcel-fill

インストール後、Claude Code で/easyexcel-fillを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
examples/business/
11-salary.md
12-contract.md
13-reconciliation.md
14-finance-report.md
15-invoice.md
examples/complex-large/
05-complex-with-table.md
examples/complex/
04-complex-fill.md
examples/composite/
07-composite.md
examples/error-handling/
18-fail-json.md
19-validation.md
examples/horizontal/
06-horizontal.md
examples/list/
02-list-once.md
03-list-multi-fill.md
examples/multi-list/
08-mixed-direction.md
examples/optimization/
20-batch.md
21-memory.md
22-03-vs-07.md
examples/simple/
01-simple-object.md
examples/spring-boot/
09-controller.md
10-service.md
examples/template-style/
23-escape.md
24-formula.md
25-image.md
examples/web/
16-stream-output.md
17-async-export.md
references/annotations/
template-syntax.md
references/api/
api-reference.md
references/comparison/
fill-vs-write.md
references/design/
template-design.md

詳細

EasyExcel テンプレートへのデータ入力(Fill)

公式ドキュメント:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill 公式サンプル:https://github.com/alibaba/easyexcel/blob/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java 現在のバージョン:com.alibaba:easyexcel:4.0.3(Apache-2.0、リポジトリはアーカイブ済みで、バグ修正のみ)

このスキルは、**「事前に用意したテンプレートへのデータ入力」**のシナリオに特化しています。ユーザーがスタイル設定済みの .xlsx テンプレートを渡し、データベースや API のデータを入力するよう求めている場合(給与明細、契約書、請求書、レポート、集計表など)は、このスキルを使用してください。

対応範囲

✅ 得意なこと
  1. 単純なオブジェクトへの入力(Map / 単一 DTO)
  2. リストへの入力(テンプレートの {.} 構文、縦方向のみ)
  3. 複雑な入力(リストの後に内容がある場合 → forceNewRow=true)
  4. 大量データの複雑な入力(リストは必ず最終行に配置し、後続の集計行は write で追加)
  5. 複数列への横方向の入力(WriteDirectionEnum.HORIZONTAL + FillWrapper)
  6. テンプレートのエスケープ文字の処理(\{ \})
  7. Spring Boot との統合(テンプレートファイルは resources/ または OSS から取得可能)
⚠️ 制限事項
  1. .xlsx(07 形式)のみサポートします。03 形式(.xls)では複雑な入力や大量データの入力はサポートされません
  2. forceNewRow=true はデータをすべてメモリに保持するため、データ量が多い場合は注意して使用してください
  3. withTemplate はテンプレートをすべてメモリに読み込むため、テンプレートファイルが大きすぎる(数十 MB 超)と OOM が発生します
  4. Map でリストに入力する場合、リストのすべての key を含める必要があります。含まれていない場合は NPE が発生します
❌ 対象外(このスキルを使わないシナリオ。ほかのスキルを使用してください)
  1. テンプレートを使わないプログラムによる Excel の生成(事前に用意したテンプレートがない場合)→ このスキルは対象外です。easyexcel-write を使用してください
  2. Excel データの読み取り → このスキルは対象外です。easyexcel-read を使用してください
  3. CSV ファイルの処理 → このスキルは対象外です。commons-csv / OpenCSV を使用してください
  4. Word/PPT → このスキルは対象外です。Apache POI / Apache POI-XML を使用してください

データプライバシー

このスキルは、ユーザーデータを収集、保存、送信しません。すべてのコード例は、ローカル開発での参考用です。

このスキルを使う場面

  • ユーザーが「テンプレートから Excel を生成」「Excel テンプレートに入力」「給与明細/契約書/請求書をエクスポート」と依頼した場合
  • ユーザーが .xlsx テンプレートファイルを提供し、変数プレースホルダーにデータを書き込むよう求めた場合
  • レポートの形式が固定されており、スタイル/結合セル/関数/グラフを保持する必要がある場合
  • 業務上、「まずリストを fill し、その後に合計行/集計行を追加する」要件がある場合

クイックスタート

一般的な呼び出し方法(ファイルサイズの小さい順に 4 つから選択):

// 方案 A:最简单的对象填充(since 2.1.1)
String fileName = "output_simple.xlsx";
EasyExcel.write(fileName).withTemplate("templates/simple.xlsx")
    .sheet().doFill(fillData);

// 方案 B:列表填充(一次放入内存)
EasyExcel.write(fileName).withTemplate("templates/list.xlsx")
    .sheet().doFill(list);

// 方案 C:列表分次填充(文件缓存,省内存)
try (ExcelWriter excelWriter = EasyExcel.write(fileName)
        .withTemplate("templates/list.xlsx").build()) {
    WriteSheet writeSheet = EasyExcel.writerSheet().build();
    excelWriter.fill(list, writeSheet);  // 多次 fill,自动文件缓存
    excelWriter.fill(list, writeSheet);
}

// 方案 D:先 fill 列表 + 后 write 追加合计行(推荐:复杂报表 + 大数据量)
try (ExcelWriter excelWriter = EasyExcel.write(fileName)
        .withTemplate("templates/complex.xlsx").build()) {
    WriteSheet writeSheet = EasyExcel.writerSheet().build();
    excelWriter.fill(list, writeSheet);          // 1. 填列表
    excelWriter.fill(headerMap, writeSheet);     // 2. 填头部变量
    excelWriter.write(totalListList, writeSheet);// 3. 手动追加合计行
}

ワークフロー

Step 1. シナリオを確認する — ユーザーは .xlsx テンプレートを提供していますか? テンプレートには {var} {.} {prefix.} のプレースホルダーがありますか? Step 2. データ量を評価する — 1 万行未満:方案 A/B。1 万行超:方案 C/D(リストは必ず最終行に配置) Step 3. 入力モードを選択する — 単一オブジェクト/リスト/複雑な入力/複数列への横方向の入力 Step 4. データを構築する — Map / DTO / List。Map でリストに入力する場合は、すべての key を含める必要があります Step 5. 入力を実行する — try-with-resources で ExcelWriter を閉じます Step 6. 出力を検証する — 生成された .xlsx を開き、プレースホルダーが置換されているか、{.} {} が残っていないか確認します

重要:テンプレート構文の早見表

テンプレートのプレースホルダー意味Java データ構造
{name} {number} {date}単一値のプレースホルダーMap.put("name", value) または DTO フィールド
{.}リストのプレースホルダー(デフォルトは縦方向)List<DTO> 全体を fill の最初の引数として指定
{data1.} {data2.}プレフィックス付きリスト(複数のリストを区別)new FillWrapper("data1", list)
\{ \}エスケープ:テンプレートに { } の文字をそのまま含める場合——

公式の説明:「{} は通常の変数、{.} は list の変数です。もともと「{」「}」の特殊文字がある場合は、「\{」「\}」に置き換えます。{.前缀は異なる list を区別できます。」

重要:4 種類の入力シナリオの完全な例

シナリオ 1:単純なオブジェクトへの入力

DTO:

@Getter
@Setter
@EqualsAndHashCode
public class FillData {
    private String name;
    private double number;
    private Date date;
}

テンプレート(templates/simple.xlsx):セルに {name} {number} {date} を含めます

コード:

@Test
public void simpleFill() {
    String templateFileName = "templates/simple.xlsx";
    String fileName = "output_simpleFill_" + System.currentTimeMillis() + ".xlsx";

    // 方案 1:根据对象填充
    FillData fillData = new FillData();
    fillData.setName("张三");
    fillData.setNumber(5.2);
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(fillData);

    // 方案 2:根据 Map 填充
    Map<String, Object> map = new HashMap<>();
    map.put("name", "张三");
    map.put("number", 5.2);
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(map);
}
シナリオ 2:リストへの入力(テンプレートの {.} が 1 行を表す)

テンプレート(templates/list.xlsx):1 行のセルに {.} を含め、リストの開始位置を示します

コード:

@Test
public void listFill() {
    String templateFileName = "templates/list.xlsx";
    String fileName = "output_listFill_" + System.currentTimeMillis() + ".xlsx";

    // 方案 1:一次性放入内存
    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(data());

    // 方案 2:分次填充(文件缓存,省内存,推荐)
    try (ExcelWriter excelWriter = EasyExcel.write(fileName)
            .withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        excelWriter.fill(data(), writeSheet);
        excelWriter.fill(data(), writeSheet);
    }
}

公式のヒント:「複数回に分けて入力すると、ファイルキャッシュが使用されます」

シナリオ 3:複雑な入力(リストの後に合計行/総計行がある)

シナリオの特徴:テンプレート内の {.} のリスト行の下に、リスト以外の内容(「総計:xxx」など)があります。

@Test
public void complexFill() {
    String templateFileName = "templates/complex.xlsx";
    String fileName = "output_complexFill_" + System.currentTimeMillis() + ".xlsx";

    try (ExcelWriter excelWriter = EasyExcel.write(fileName)
            .withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        // ⚠️ 关键:forceNewRow=true 才能让 list 后面再追加内容
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();

        excelWriter.fill(data(), fillConfig, writeSheet);
        excelWriter.fill(data(), fillConfig, writeSheet);

        Map<String, Object> map = new HashMap<>();
        map.put("date", "2019年10月9日13:28:28");
        map.put("total", 1000);
        excelWriter.fill(map, writeSheet);
    }
}

公式の説明:「02 形式では、テンプレートの list が最終行ではなく、その下にデータがある場合は forceNewRow=true を設定する必要があります。ただし、すべてのデータがメモリに読み込まれるという欠点があるため、注意して使用してください」 公式の説明:「データ量が多く、list が最終行ではない場合は、次の例(complexFillWithTable)を参照してください」

シナリオ 4:大量データの複雑な入力(リストを最終行に配置 + write で追加)

推奨するテンプレート設計:テンプレート内のリストの後にある「合計行」のプレースホルダーを削除し、リストを最終行に配置します。後続の「集計行」は write で手動で追加します。

@Test
public void complexFillWithTable() {
    String templateFileName = "templates/complexFillWithTable.xlsx";
    String fileName = "output_complexFillWithTable_" + System.currentTimeMillis() + ".xlsx";

    try (ExcelWriter excelWriter = EasyExcel.write(fileName)
            .withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();

        // 1. 写入 list 数据
        excelWriter.fill(data(), writeSheet);
        excelWriter.fill(data(), writeSheet);

        // 2. 写入 list 之前的变量
        Map<String, Object> map = new HashMap<>();
        map.put("date", "2019年10月9日13:28:28");
        excelWriter.fill(map, writeSheet);

        // 3. list 后面手动 write 统计行
        List<List<String>> totalListList = new ArrayList<>();
        List<String> totalList = new ArrayList<>();
        totalListList.add(totalList);
        totalList.add(null);
        totalList.add(null);
        totalList.add(null);
        totalList.add("统计:1000");
        excelWriter.write(totalListList, writeSheet);
    }
}

公式の説明:「ここでは write を使います。fill と混同しないでください」

シナリオ 5:横方向の入力(複数列を横に並べて配置)
@Test
public void horizontalFill() {
    String templateFileName = "templates/horizontal.xlsx";
    String fileName = "output_horizontalFill_" + System.currentTimeMillis() + ".xlsx";

    try (ExcelWriter excelWriter = EasyExcel.write(fileName)
            .withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        // 横向:列方向展开
        FillConfig fillConfig = FillConfig.builder()
            .direction(WriteDirectionEnum.HORIZONTAL).build();
        excelWriter.fill(data(), fillConfig, writeSheet);
        excelWriter.fill(data(), fillConfig, writeSheet);

        Map<String, Object> map = new HashMap<>();
        map.put("date", "2019年10月9日13:28:28");
        excelWriter.fill(map, writeSheet);
    }
}
シナリオ 6:複数リストを組み合わせた入力(複数の list を同時に入力)

テンプレート:{data1.} {data2.} {data3.} の 3 種類のプレフィックス付きリストを含めます

@Test
public void compositeFill() {
    String templateFileName = "templates/composite.xlsx";
    String fileName = "output_compositeFill_" + System.currentTimeMillis() + ".xlsx";

    try (ExcelWriter excelWriter = EasyExcel.write(fileName)
            .withTemplate(templateFileName).build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        FillConfig fillConfig = FillConfig.builder()
            .direction(WriteDirectionEnum.HORIZONTAL).build();

        // ⚠️ 关键:多个 list 必须用 FillWrapper 包裹,prefix 必须与模板占位符前缀一致
        excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet);
        excelWriter.fill(new FillWrapper("data2", data()), writeSheet);  // data2 纵向
        excelWriter.fill(new FillWrapper("data3", data()), writeSheet);

        Map<String, Object> map = new HashMap<>();
        map.put("date", new Date());
        excelWriter.fill(map, writeSheet);
    }
}

公式の説明:「複数の list は FillWrapper でラップする必要があります。{前缀.} のプレフィックスで異なる list を区別できます。異なる list に異なる方向(HORIZONTAL/VERTICAL)を指定できます」

重要:Spring Boot との統合

1) テンプレートを resources/templates/ に配置する
@Service
public class SalaryFillService {

    public void fillSalary(String employeeId, OutputStream out) {
        InputStream templateIn = getClass()
            .getResourceAsStream("/templates/salary.xlsx");
        SalaryDTO data = salaryMapper.findByEmployee(employeeId);

        // 模板以流方式加载,避免临时文件
        try (ExcelWriter writer = EasyExcel.write(out)
                .withTemplate(templateIn).build()) {
            WriteSheet sheet = EasyExcel.writerSheet().build();
            writer.fill(data, sheet);
        }
    }
}
2) Controller の戻り値
@GetMapping("/export/salary/{employeeId}")
public void exportSalary(@PathVariable String employeeId,
                         HttpServletResponse response) throws IOException {
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setCharacterEncoding("utf-8");
    String fileName = URLEncoder.encode("工资条", "UTF-8").replaceAll("\\+", "%20");
    response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

    salaryFillService.fillSalary(employeeId, response.getOutputStream());
}
3) 複雑なシナリオ:給与明細の一括パッケージ化
public void batchExportSalary(List<String> employeeIds, OutputStream zipOut) {
    try (ZipOutputStream zos = new ZipOutputStream(zipOut);
         ExcelWriter writer = EasyExcel.write(/* unused */).build()) {  // 实际逐个写入临时文件
        for (String id : employeeIds) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            fillSalary(id, baos);
            ZipEntry entry = new ZipEntry("salary_" + id + ".xlsx");
            zos.putNextEntry(entry);
            zos.write(baos.toByteArray());
            zos.closeEntry();
        }
    }
}

重要:業務テンプレートの設計規則

業務シナリオ推奨するテンプレート設計重要なコード
給与明細単一オブジェクト {name} {base} {bonus} {total}単純な入力、方案 1
従業員契約書ヘッダー {company} {name} {id} + リスト {items.}単純な入力 + リスト
照合明細書ヘッダー {date} {account} + リスト {details.} + 下部に「合計」complexFillWithTable(先にリストを fill し、その後に合計行を write)
財務レポート複数列への横方向の入力 {months.} + 縦方向 {rows.}compositeFill(複数の FillWrapper)
請求書単一オブジェクト + 関数 =SUM()単純な入力(数式はテンプレートにあらかじめ設定)
商品リストリスト {products.} + 画像リスト + 画像(画像は byte[] として読み込む必要があります)
集計表(月別)ヘッダー {year} + リスト {data1.}(横方向に複数列へ展開)horizontalFill

Gotchas(常见错误)

#错误正确做法
1Map 填充 list 漏掉某些 keyMap 填充时必须 put 所有 list 的 key(可 value=null)
2模板有 { } 字符未转义用 \{ \} 转义
3复杂填充忘记 forceNewRow=truelist 下面还有内容时必须设置
4forceNewRow=true 用在百万级数据改用 complexFillWithTable(list 放最后一行)
503 版(.xls)做复杂填充改用 07 版(.xlsx)
6list 后追加合计行用 fill用 write("这里是write 别和fill 搞错了")
7横向多列忘了 FillWrapper多 list 必须用 new FillWrapper("prefix", list)
8横向多列方向忘了配必须 FillConfig.builder().direction(HORIZONTAL)
9模板文件 withTemplate(InputStream) 用完未关模板流是缓存的,try-with-resources 关闭
10关闭 ExcelWriter 时漏掉 finish()用 try-with-resources 让 ExcelWriter.close() 触发 finish
11模板文件 > 几十 MB改用多个小模板分批填充
12模板变量写错(大小写 / 漏 { })模板变量名必须与 Map key / DTO 字段完全一致

Key Classes / Methods

类型名称用途
入口EasyExcel.write(path).withTemplate(template)指定模板路径或流
入口EasyExcel.write(OutputStream).withTemplate(stream)Web 输出流场景
核心ExcelWriter多次 fill 的容器,需 try-with-resources
核心WriteSheet单个 sheet 配置
配置FillConfig.builder().forceNewRow(true)复杂填充(list 后还有内容)
配置FillConfig.builder().direction(HORIZONTAL)横向填充
包装FillWrapper("prefix", list)多列表分组,前缀匹配模板 {prefix.}
工具EasyExcel.writerSheet().build()创建默认 WriteSheet
工具EasyExcel.writerSheet(0, "sheet名").build()指定 sheetNo 和名称

References

コメント