
該圖片由宅-KEN在Pixabay上發布
你好,我是看山,
前文 說了寫操作,可以實作簡單的串列匯出,還能 定義樣式,有時候,我們還需要匯出的一個大表單,或者是表單+串列的形式,這個時候,我們就需要填充功能,
內容比較多,文內只會列出關鍵代碼,想要完整原始碼,可以關注公號「看山的小屋」回復“easyexcel”獲取,
在 EasyExcel 中,寫操作可以完成大部分作業,填充的優勢在于,可以實作自定義樣式的,只要在模板中設定好樣式,填充的資料就能夠帶著樣式,
先寫個表單
既然是使用模板,寫來定義一個模板,

在 EasyExcel 的模板填充定義中,使用{}來表示你要用的變數,如果本來就有"{","}“特殊字符,需要對其進行轉義,用”{","}"代替,
寫物件
既然是寫物件,先定義一下物件結構,
@Data
public class Item {
private String name;
private double number;
}
然后開始填充:
private static void fillUseObject() {
String fileName = defaultFileName("fillUseObject");
String templateFile = getPath() + File.separator + "template_fill_sample.xlsx";
Item item = new Item();
item.setName("法外狂徒張三");
item.setNumber(89757);
EasyExcelFactory.write(fileName)
.withTemplate(templateFile)
.sheet()
.doFill(item);
}
在寫操作中我們也使用過模板寫串列,這里填充模板,使用的是同樣的方法:com.alibaba.excel.write.builder.ExcelWriterBuilder#withTemplate(java.lang.String)指定模板檔案路徑,這里再重復一遍,withTemplate 方法有幾個多載實作:
- 指定模板檔案路徑
ExcelWriterBuilder#withTemplate(java.lang.String) - 指定模板檔案物件
ExcelWriterBuilder#withTemplate(java.io.File) - 指定模板檔案輸入流
ExcelWriterBuilder#withTemplate(java.io.InputStream)
指定模板檔案和模板檔案物件都是操作檔案的,需要有檔案資訊,
指定模板檔案輸入流是只要檔案流,這個可操作性空間就比較大了,比如,模板檔案是可變的,我們可以基于一個帶變數的模板檔案,使用填充寫入的方式初始化模板檔案,然后再用模板寫入的方式,寫入串列,
結果為:

寫 Map
我們也可以不用非得創建類,用 Map 也能實作相同的功能,
private static void fillUseMap() {
String fileName = defaultFileName("fillUseMap");
String templateFile = getPath() + File.separator + "template_fill_sample.xlsx";
Map<String, Object> data = new HashMap<>();
data.put("name", "法外狂徒張三");
data.put("number", 89757);
EasyExcelFactory.write(fileName)
.withTemplate(templateFile)
.sheet()
.doFill(data);
}
雖然 Map 能夠功能相同,不過還是建議定義具體的類,因為類是可校驗的,Map 是弱檢測機制,純靠約定或者測驗,不是很安全,
結果為:

從效果上看,結果是相同的,
再寫個串列
先定義模板:

可以看到,填充串列的引數定義,與填充物件的有些差別,模板中{.}多了個點,
對于表格的場景,從大體上會分為少量資料和大量資料,對于少量資料,直接在記憶體中操作即可,對于大量資料,可以使用分批寫入,借助檔案快取的方式節省記憶體,
少量寫
上代碼:
private static void fillListInMemory() {
String fileName = defaultFileName("fillListInMemory");
String templateFile = getPath() + File.separator + "template_fill_list.xlsx";
EasyExcelFactory.write(fileName)
.withTemplate(templateFile)
.sheet()
.doFill(sampleItems());
}
可以看到,填充串列與前文說到的寫檔案操作在代碼實作上沒有太大差異,這也是 EasyExcel 架構設計上的強悍,通過建造器模式的 fluent 寫法,屏蔽啰嗦的寫入,同時也屏蔽不同業務實作引數的差異,只在doFill的時候,根據不同引數實作不同邏輯,
結果為:

大量寫
接下來就是大量資料填充了,與上面的差異在于需要手動創建ExcelWriter和WriteSheet物件,然后使用com.alibaba.excel.ExcelWriter.fill方法多次寫入資料,
fill方法支持直接寫入串列和使用 lambda 函式方式,注意是fill,不是doFill,doFill會呼叫finish方法自動關閉流,fill方法只做資料填充,需要手動關閉流,
代碼為:
private static void fillListSegment() {
String fileName = defaultFileName("fillListSegment");
String templateFile = getPath() + File.separator + "template_fill_list.xlsx";
final ExcelWriter excelWriter = EasyExcelFactory.write(fileName).withTemplate(templateFile).build();
try {
final WriteSheet writeSheet = EasyExcelFactory.writerSheet().build();
excelWriter.fill(BaseFill::sampleItems, writeSheet);
excelWriter.fill(sampleItems(), writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
結果為:

最后寫個表單+串列
最后來個表單與串列的形式,比如銷售統計,表頭需要填寫引數資訊,比如店鋪資訊、時間等,然后是銷售記錄,最后需要增加類似合計之類的資訊,
這種的話,可以實作的方式也挺多,這里介紹固定串列的實作,在技巧篇中會再介紹一種動態串列的實作,
填充物件+串列
先定義模板:

從模板中可以看到,開頭是時間資訊,結尾有統計資訊,中間是一個串列,
上代碼:
/**
* 填充物件+串列,因為串列之后還有一個欄位,所以需要將{@link FillConfigBuilder#forceNewRow(Boolean)}設定為 TRUE 才行,
* <p>
* 這樣會有一個副作用:所有資料會在記憶體中,即資料量大的時候特別耗記憶體,
* <p>
* 想要解決有兩種方式:
*
* <ul>
* <li>list 之后沒有資料了,{@link FillConfigBuilder#forceNewRow(Boolean)}設定為 FALSE</li>
* <li>list 寫完之后,手動寫后面的資料</li>
* </ul>
*/
private static void fillObjectAndListInMemory() {
String fileName = defaultFileName("fillObjectAndListInMemory");
String templateFile = getPath() + File.separator + "template_fill_object_and_list.xlsx";
final ExcelWriter excelWriter = EasyExcelFactory.write(fileName).withTemplate(templateFile).build();
try {
final WriteSheet writeSheet = EasyExcelFactory.writerSheet().build();
Map<String, Object> map = new HashMap<>();
map.put("date", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));
map.put("total", System.currentTimeMillis());
excelWriter.fill(map, writeSheet);
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(BaseFill::sampleItems, fillConfig, writeSheet);
excelWriter.fill(sampleItems(), fillConfig, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
這里有一個新增的配置類:FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(),這個是用來定義寫入時的配置資訊,配置為 true,代表在寫入串列的時候,不管下面有沒有空行,都會創建一行,然后下面的資料往后移動,如果不定義或者設定為 false,最后那行的統計資訊會被覆寫,
但是只要設定為 true 了,整個填充操作將都在記憶體中操作,比較耗費記憶體,
結果為:

填充物件+串列(大資料量)
如果串列資料比較大,還在記憶體中操作就比較容易記憶體溢位了,所以需要特殊的操作:
- 串列之后沒有表單填充了,這種最容易實作,一句話實作不了,改需求,
- 只能在串列之后手動寫資料
代碼如下:
private static void fillObjectAndListManual() {
String fileName = defaultFileName("fillObjectAndListManual");
String templateFile = getPath() + File.separator + "template_fill_object_and_list_manual.xlsx";
final ExcelWriter excelWriter = EasyExcelFactory.write(fileName).withTemplate(templateFile).build();
try {
final WriteSheet writeSheet = EasyExcelFactory.writerSheet().build();
Map<String, Object> map = new HashMap<>();
map.put("date", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));
excelWriter.fill(map, writeSheet);
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(BaseFill::sampleItems, fillConfig, writeSheet);
excelWriter.fill(sampleItems(), fillConfig, writeSheet);
// 下面是純手工寫資料
List<List<String>> totalListList = new ArrayList<>();
List<String> totalList = new ArrayList<>();
totalListList.add(totalList);
totalList.add(null);
totalList.add("統計:1000");
excelWriter.write(totalListList, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
結果為:

橫向填充資料
先定義模板:

private static void fillObjectAndListHorizontal() {
String fileName = defaultFileName("fillObjectAndListHorizontal");
String templateFile = getPath() + File.separator + "template_fill_list_horizontal.xlsx";
final ExcelWriter excelWriter = EasyExcelFactory.write(fileName).withTemplate(templateFile).build();
try {
final WriteSheet writeSheet = EasyExcelFactory.writerSheet().build();
Map<String, Object> map = new HashMap<>();
map.put("date", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));
excelWriter.fill(map, writeSheet);
FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
excelWriter.fill(BaseFill::sampleItems, fillConfig, writeSheet);
excelWriter.fill(sampleItems(), fillConfig, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
這里配置FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(),用于定義寫入方向,
結果為:

填充多個表格
與寫操作相同,填充操作也可以實作多表格的寫入,

對于多表格寫入,定義模板時,必須有{前綴,},
private static void fillMultiList() {
String fileName = defaultFileName("fillMultiList");
String templateFile = getPath() + File.separator + "template_fill_multi_list.xlsx";
final ExcelWriter excelWriter = EasyExcelFactory.write(fileName).withTemplate(templateFile).build();
try {
final WriteSheet writeSheet = EasyExcelFactory.writerSheet().build();
Map<String, Object> map = new HashMap<>();
map.put("date", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));
excelWriter.fill(map, writeSheet);
FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
excelWriter.fill(new FillWrapper("data1", sampleItems()), fillConfig, writeSheet);
// data2 分批寫入
excelWriter.fill(new FillWrapper("data2", sampleItems()), writeSheet);
excelWriter.fill(new FillWrapper("data3", sampleItems()), writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
這里用到了FillWrapper,用來包裝前綴,
結果為:

至此,寫操作和填充操作全部介紹完成,
文末總結
本文從實戰角度說了一下 EasyExcel 如果實作填充模板匯出表格,有了模板填充邏輯,再加上寫邏輯,我們會有更多的玩法,接下來就會說一下這些好玩的騷操作,
推薦閱讀
- 阿里開源的這個庫,讓 Excel 匯出不再復雜(簡簡單單的寫)
- 阿里開源的這個庫,讓 Excel 匯出不再復雜(既要能寫,還要寫的好看)
- 阿里開源的這個庫,讓 Excel 匯出不再復雜(填充模板的使用指南)
你好,我是看山,游于碼界,戲享人生,如果文章對您有幫助,請點贊、收藏、關注,
個人主頁:https://www.howardliu.cn
個人博文:阿里開源的這個庫,讓 Excel 匯出不再復雜(填充模板的使用指南)
CSDN 主頁:https://kanshan.blog.csdn.net/
CSDN 博文:阿里開源的這個庫,讓 Excel 匯出不再復雜(填充模板的使用指南)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/308747.html
標籤:java
