EasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートします

リリース: 2023-07-26 16:32:18
転載
2117 人が閲覧しました

まえがき

最近、読者の方から easypoi についての質問をいただきましたので、記事にまとめてみました。

#Text

EasyPOI 関数は Easy という名前の通り、メイン関数は easy なので、POI に触れたことのない人でも簡単に Excel エクスポートを作成できます。 Excel テンプレートのエクスポート、Excel インポート、Word テンプレートのエクスポート。単純な注釈とテンプレート言語 (使い慣れた式構文) を通じて、これまで複雑だった記述方法を完成させることができます。

この記事では主に簡単な分析を使用して、Excel テンプレートの作成方法と、EasyPOI を使用してニーズに合った Excel データをエクスポートする方法を読者に知らせ、それによってコーディングを簡素化します。同時に、この記事では、読者が落とし穴を回避できるように、画像エクスポート機能などの珍しい機能についても説明します。

バージョンと依存関係の説明

EasyPOI4.0.0 以降のバージョンは、将来の Apache POI 4.0.0 以降に依存します。バージョン。したがって、Maven 構成では、2 つのバージョン番号が一致する必要があります。

Apache POI 4.0.0 は以前のバージョンと比較して大幅な変更が加えられていることに注意してください。以前のコードの Excel 操作部分が古いバージョンに依存している場合、4.0.0 とバージョン。もちろん、以前のコードに WorkBook の作成の詳細が含まれていない、またはほとんど含まれていない場合は、新しいバージョンを使用しても問題ありません。

書き直す必要があるプロジェクトは、JEECG バージョン 3.7 に基づいており、Apache POI のバージョン 3.9 に依存しています。JEECG によって維持されている jeasypoi の最高バージョンは 2.2.0 のみで、このバージョンはテンプレートのエクスポートをサポートしていません画像機能。そういえば、次の JEECG チームに文句を言いたいのですが、私は jeasypoi をメンテナンスするつもりはないので、プロジェクト内で公式の EasyPOI を直接使用するのはどうでしょうか? jeasypoi の 2.2.0 バージョンは開発者のためにどれだけの穴を掘ったことでしょう? ?

旧バージョンとの互換性を保つため、EasyPOI の画像エクスポート機能を使用したいため、最終的に採用した EasyPOI のバージョンは 3.3.0 で、対応する Apache POI の依存関係は 3.15 です。

Maven の構成は次のとおりです。

<properties>
    <poi.version>3.15</poi.version>
    <easypoi.version>3.3.0</easypoi.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-scratchpad</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>cn.afterturn</groupId>
        <artifactId>easypoi-web</artifactId>
        <version>${easypoi.version}</version>
    </dependency>
</dependencies>
ログイン後にコピー

Excel テンプレートの設計

EasyPOI を使用します。テンプレートのエクスポート機能は、コーディングを通じて Excel レポートのスタイルをデザインすることを望まないため、最初のステップは Excel テンプレートをデザインし、どの部分が修正され、どの部分がループで入力される必要があるかを区別することです。 EasyPOI には独自の式言語があり、各式の詳細な紹介については、以下の参考リンクを参照してください。

単純な Excel レポート テンプレート

いくつかの単純なテンプレートについては、ここでは詳しく説明しません。レンダリングとテンプレート構成の内容についてのみ説明します。 。読者が複雑なテンプレートの作成方法と値の入力方法を理解すれば、単純なものもすぐに理解できるでしょう。

まず、レポートのレンダリングを確認します:

EasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートします

次に、実際のテンプレートを確認します:

EasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートします

上の 2 つの写真を見て、テンプレートのエクスポート機能の威力をすでに感じましたか?

複雑な Excel レポート テンプレート

以下に紹介するテンプレートはより複雑であり、ここで紹介するテンプレートほど一般的ではありません。その場合、1 行が 1 レコードとなるため、テンプレートの構成を詳しく紹介し、EasyPOI のいくつかの表現を簡単に紹介します。

まずレンダリングを見てみましょう:

EasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートします

次にテンプレートを見てみましょう:

EasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートします

これら写真 1 を比較して、知識があなたの運命を変えると感じますか?

複雑なテンプレート設計の分析

テンプレートの画像と製品情報のレンダリングから、テンプレート全体は実際には上下に分かれています。上部は変更されていないヘッダー情報、下部は循環的に挿入される商品詳細情報です。したがって、後半の文法に焦点を当てます。

下部の最初の列は完全には表示されていませんが、実際には {{!fe: list t.id.

ここには }} 記号がないことに注意してください。 EasyPOIの公式ドキュメントによると、{{}}は式を表しており、中の値は式に基づいて取得されます。画像を注意深く見ると、式の終了記号 {{}} が画像の右下隅に表示されていることがわかります。つまり、最初の列 {{ から始まり、右下隅}} までの間のすべてが式の一部になります。

テンプレート情報全体が式の一部であるため、通常の文字列であっても特別にマークする必要があります。以下、式内の部分式について 1 つずつ説明します。

#!fe: 行を作成せずにデータを走査します。

公式ドキュメントのこの文は、誰にとっても理解しにくいかもしれません。行を作成しないとはどういう意味ですか?実際、行を作成しないことは行の作成に関連しており、行を作成するための式は fe: です。

データベース内の各レコードがエンティティ オブジェクトに対応するのと同様に、行を作成するということは、各行がエンティティ オブジェクトであることを意味します。このエンティティ オブジェクトの属性は、{{}} 式でラップされます。

行を作成しないということは、式全体にエンティティ オブジェクト Object が 1 つしかないことを意味しますが、このオブジェクトは特別であり、リスト内の N 個のエンティティによって結合されます。各エンティティはモデル自体を参照するだけでなく、それが占めるセルの数、セルの座標、配置順序などの Excel スタイルも含みます。

list 式内のデータ コレクションを表すカスタム名。コードでは、リストをキーとして使用して、Map から値のコレクションを取得します。

list という名前はわかりやすく、単なるプレースホルダーなので気軽に選択できます。 EasyPOI がリストを解析すると、Map にキーの値のセットがあることがわかり、後でデータを解析するときに、そのセットから値を取得するだけで済みます。

Java Zhiyin 公式アカウントを検索し、「バックエンド インタビュー」と返信すると、Java インタビューの質問ガイドをお送りします .pdf

# t は、コレクション内の任意のオブジェクトを表す事前定義された値です。

テンプレートから、リスト内の各オブジェクトは t と呼ばれ、t.name は t の name 属性を表すため、t という名前を気軽に呼ぶことができることが大まかにわかります。 list. と同じで、プレースホルダーとして機能します。

しかし、実際には、これは大きな落とし穴です。 t を g などの別の値に置き換えたり、テンプレート内の別の場所に g.name g.code などを書いたりすると、最終的には解析されなくなります。公式文書ではこの点は強調されていませんでしたが、著者は実際に罠を踏んで初めてそのことに気づきました。

]] 改行文字 複数行のトラバーサル エクスポート。

この記号の公式の説明も不可解です 改行文字と複数行のトラバーサル エクスポートとは何ですか?実際、これが意味するのは、式にこの記号が含まれている場合、背後に他のコンテンツやスタイルがあるかどうかに関係なく、その行以降のコンテンツは解析されないということです。

このシンボルは各行の最後の列に記述する必要があります。そうしないと、行と列の数が異なり、EasyPOI が内部割り当てを実行するときに NULL ポインタ例外が報告されます。

'' 一重引用符は定数値を表します '' たとえば、「1」の場合、出力は 1

公式ドキュメントのここでの紹介にもあります。落とし穴。 '' は定数値を表しますが、実際にはこれを Excel だけで使用するのは間違いです。Excel はセル内で ' に遭遇すると、以下はすべて文字列であると判断するため、「 ライブラリ タイプ: 」と記述する必要があります。セル内に . が表示されるため、文字列ライブラリ タイプ:' ではなく、'ライブラリ タイプ:' が表示されます。

上記の分析後、画像のテンプレートは実際には次のようになります:

{{!fe: list t.id ‘库别:’ t.bin 换行 ‘商品名称:’ t.name 换行 ‘商品编号:’ t.code t.barcode 换行 ‘生产日期:’ t.proDate 换行 ‘进货日期:’ t.recvDate}}

如果list中有多条记录,上述字符串就再循环拼接一些内容,最终都在一个{{}}表达式中。

至此,模板的设计已剖析完毕,读者可根据自己的需求结合官方文档自行设计模板。下面将对模板赋值进行介绍。

准备模板数据

从上节的描述中可知,只需要准备一个Map的对象即可,其中键为list,值为一个List数组,数组中元素类型为Map。代码如下:

Map<String, Object> total = new HashMap<>();
List<Map<String, Object>> mapList = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
    Map<String, Object> map = new HashMap<>();
    map.put("id", i + "");
    map.put("bin", "001 1000千克");
    map.put("name", "商品" + i);
    map.put("code", "goods" + i);
    map.put("proDate", "2019-05-30");
    map.put("recvDate", "2019-07-07");

    // 插入图片
    ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
    BufferedImage bufferImg = ImageIO.read(BarcodeUtil.generateToStream("001"));
    ImageIO.write(bufferImg, "jpg", byteArrayOut);
    ImageEntity imageEntity = new ImageEntity(byteArrayOut.toByteArray(), 200, 1000);
    map.put("barcode", imageEntity);

    mapList.add(map);
}
total.put("list", mapList);
ログイン後にコピー

图片数据导出

上述代码中需要特殊关注的是图片导出部分。EasyPOI导出图片有两种方式,一种是通过图片的Url,还有一种是获取图片的byte[],毕竟图片的本质就是byte[]。因为笔者的项目中图片不是存放在数据库之中,而是需要根据查询结果动态生成条码,所以通过byte[]导出图片。

ImageEntity是EasyPOI内置的一个JavaBean,用于设定图片的宽度和高度、导出方式、RowSpan和ColumnSpan等。调试EasyPOI的源码可知,当设置了RowSpan或者ColumnSpan之后,图片的高度设置就失效了,图片大小会自动填充图片所在的单元格。

图片导出的坑点在于导出图片的大小。假设我们将四个单元格合成为一个,希望导出的图片能填充合并之后的单元格,但是对不起,EasyPOI暂时做不到,它只会填充合并之前左上角的单元格,具体原因如下源码所示:

//BaseExportService.java
ClientAnchor anchor;
if (type.equals(ExcelType.HSSF)) {
    anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
            cell.getRow().getRowNum() + 1);
} else {
    anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
            cell.getRow().getRowNum() + 1);
}
ログイン後にコピー

可以看到,在创建图片插入位置的时候已经指定了图片的跨度为1行1列,即左上角的单元格。如果之前又设置了RowSpan或者ColumnSpan,那么图片高度的设置也会失效,最终导致导出的图片非常小。

搜索Java知音公众号,回复“后端面试”,送你一份Java面试题宝典.pdf

个人认为ImageEntity提供的RowSpan或者ColumnSpan的set方法并没有什么用,因为我们动态创建的合并单元格并不能被赋值。所以,导出图片的最好方式就是直接指定它的高度,因为宽度会自动填充单元格,模板中单元格的宽度要合适。

//ExcelExportOfTemplateUtil.java
if (img.getRowspan()>1 || img.getColspan() > 1){
    img.setHeight(0);
    PoiMergeCellUtil.addMergedRegion(cell.getSheet(),cell.getRowIndex(),
            cell.getRowIndex() + img.getRowspan() - 1, cell.getColumnIndex(), cell.getColumnIndex() + img.getColspan() -1);
}
ログイン後にコピー

将数据导出至模板

以上准备工作全部完成后就可以将模板和数据进行组装了,或者说是渲染,代码如下所示:

public static void exportByTemplate(String templateName, Map<String, Object> data, OutputStream fileOut) {
    TemplateExportParams params = new TemplateExportParams("export/template/" + templateName, true);
    try {
        Workbook workbook = ExcelExportUtil.exportExcel(params, data);
        workbook.write(fileOut);
    } catch (Exception e) {
        LogUtil.error("", e);
    }
}
ログイン後にコピー

总结

网上针对EasyPOI的介绍多限于最基本的行插入功能,但实际上Excel模板的需求可能各式各样。本文只是抛砖引玉,对EasyPOI中的部分概念做了详细介绍,希望帮助大家少踩坑。

如果想详细了解EasyPOI的各种功能,参考链接中的文档说明及测试项目源码就是最好的学习资料。希望大家都能得心应手地使用EasyPOI,大大提升开发效率!

参考链接

EasyPOI官方文档

  • https://opensource.afterturn.cn/doc/easypoi.html

EasyPOI测试项目

  • https://gitee.com/lemur/easypoi-test

一些坑

近日有网友求助我解决EasyPOI的复杂模板配置问题,通过解决该网友的问题发现了EasyPOI中的几个坑点,补充说明几个问题。

EasyPOI でサポートされる複雑なテンプレートを構成する方法については、「複雑なテンプレート設計の分析」セクションで説明されています。このテンプレートの構成はまったく正しいのですが、明確に記載されていない点が 3 つあります。ひょうたんをコピーするときに誰でも間違いやすいのです。リストは列内で別個に指定する必要があります。 EasyPOI ソース コードでは、リスト内の各要素に必要な行数は、セルの行と列の範囲に基づいて決定されます。たとえば、上の図では、セルのスパンは 5 行 1 列です。つまり、リスト内の各要素は将来 5 行を占めることになります。この列がカスタム テンプレートのスタイルに準拠していないと思われる場合は、列の列幅を 0 に設定できますが、{{!fe: list.

  1. オブジェクトの開始記号と終了記号 {{}} の間に空のセルがあってはなりません。コードは、セルが空であることを解析するときに直接例外をスローします。セルを空にしたい場合は、空の文字列 '''' を記述する必要があります。
  2. 改行文字]] は、各行の最後のセルを占有する必要があります。たとえば、最初の行に 10 個のセルがあり、最初の 5 個だけが 2 行目に使用されている場合、5 番目の行の末尾に改行文字 ]] を直接記述することはできず、代わりに 6 個のセルを結合する必要があります。 -10 セルを入力し、Enter]] と入力します。上の図の製造日の行の最後の列を参照してください。この設定の理由は、EasyPOI では、各セルの列スパンがソース コードで決定されるため、各行のセルの数がまったく同じである必要があるためです。事前に ]] 改行文字が使用されている場合、その数は列の数が他の行と異なる場合、値を割り当てるときに混乱が生じ、インデックス例外が発生します。

以上がEasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートしますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:Java学习指南
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!