まえがき
最近、読者の方から easypoi についての質問をいただきましたので、記事にまとめてみました。
#Text
EasyPOI 関数は Easy という名前の通り、メイン関数は easy なので、POI に触れたことのない人でも簡単に Excel エクスポートを作成できます。 Excel テンプレートのエクスポート、Excel インポート、Word テンプレートのエクスポート。単純な注釈とテンプレート言語 (使い慣れた式構文) を通じて、これまで複雑だった記述方法を完成させることができます。 この記事では主に簡単な分析を使用して、Excel テンプレートの作成方法と、EasyPOI を使用してニーズに合った Excel データをエクスポートする方法を読者に知らせ、それによってコーディングを簡素化します。同時に、この記事では、読者が落とし穴を回避できるように、画像エクスポート機能などの珍しい機能についても説明します。<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>
いくつかの単純なテンプレートについては、ここでは詳しく説明しません。レンダリングとテンプレート構成の内容についてのみ説明します。 。読者が複雑なテンプレートの作成方法と値の入力方法を理解すれば、単純なものもすぐに理解できるでしょう。
まず、レポートのレンダリングを確認します:
次に、実際のテンプレートを確認します:
上の 2 つの写真を見て、テンプレートのエクスポート機能の威力をすでに感じましたか?
以下に紹介するテンプレートはより複雑であり、ここで紹介するテンプレートほど一般的ではありません。その場合、1 行が 1 レコードとなるため、テンプレートの構成を詳しく紹介し、EasyPOI のいくつかの表現を簡単に紹介します。
まずレンダリングを見てみましょう:
次にテンプレートを見てみましょう:
これら写真 1 を比較して、知識があなたの運命を変えると感じますか?
テンプレートの画像と製品情報のレンダリングから、テンプレート全体は実際には上下に分かれています。上部は変更されていないヘッダー情報、下部は循環的に挿入される商品詳細情報です。したがって、後半の文法に焦点を当てます。
下部の最初の列は完全には表示されていませんが、実際には {{!fe: list t.id.
ここには }} 記号がないことに注意してください。 EasyPOIの公式ドキュメントによると、{{}}は式を表しており、中の値は式に基づいて取得されます。画像を注意深く見ると、式の終了記号 {{}} が画像の右下隅に表示されていることがわかります。つまり、最初の列 {{ から始まり、右下隅}} までの間のすべてが式の一部になります。
テンプレート情報全体が式の一部であるため、通常の文字列であっても特別にマークする必要があります。以下、式内の部分式について 1 つずつ説明します。
#!fe: 行を作成せずにデータを走査します。
公式ドキュメントのこの文は、誰にとっても理解しにくいかもしれません。行を作成しないとはどういう意味ですか?実際、行を作成しないことは行の作成に関連しており、行を作成するための式は fe: です。 データベース内の各レコードがエンティティ オブジェクトに対応するのと同様に、行を作成するということは、各行がエンティティ オブジェクトであることを意味します。このエンティティ オブジェクトの属性は、{{}} 式でラップされます。 行を作成しないということは、式全体にエンティティ オブジェクト Object が 1 つしかないことを意味しますが、このオブジェクトは特別であり、リスト内の N 個のエンティティによって結合されます。各エンティティはモデル自体を参照するだけでなく、それが占めるセルの数、セルの座標、配置順序などの Excel スタイルも含みます。list 式内のデータ コレクションを表すカスタム名。コードでは、リストをキーとして使用して、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
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官方文档
EasyPOI测试项目
近日有网友求助我解决EasyPOI的复杂模板配置问题,通过解决该网友的问题发现了EasyPOI中的几个坑点,补充说明几个问题。
EasyPOI でサポートされる複雑なテンプレートを構成する方法については、「複雑なテンプレート設計の分析」セクションで説明されています。このテンプレートの構成はまったく正しいのですが、明確に記載されていない点が 3 つあります。ひょうたんをコピーするときに誰でも間違いやすいのです。リストは列内で別個に指定する必要があります。 EasyPOI ソース コードでは、リスト内の各要素に必要な行数は、セルの行と列の範囲に基づいて決定されます。たとえば、上の図では、セルのスパンは 5 行 1 列です。つまり、リスト内の各要素は将来 5 行を占めることになります。この列がカスタム テンプレートのスタイルに準拠していないと思われる場合は、列の列幅を 0 に設定できますが、{{!fe: list.
以上がEasyPOI を使用して Excel テンプレート データ (画像を含む) をエレガントにエクスポートしますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。