背景
因爲項目需要,需要生成EXCEL,爲了開發的方便,使用了阿里的EasyExcel,並使用了模板excel進行填充。
但由於需要根據數據動態填充多個sheet,所以便決定用代碼先動態生成excel模板,在動態生成excel模板時需要將原始的模板sheet進行復制
爲了實現sheet的複製在快速瀏覽了EasyExcel的API後發現在EasyExcel中並沒有相關的複製Sheet的api,所以打算用原生的POI去實現,於是我像往常一樣在百度和谷歌中搜索關鍵字:poi sheet複製,poi sheet克隆
結果發現了很多個搜索結果,於是我把搜索結果中的代碼粘貼到我的項目中時卻發現要麼代碼找不到包,要麼就是不生效,也不知道給出答案的人在他們的項目中是怎麼實現出來的,文章也是抄來抄去。
解決方法
後面我仔細看了下poi的api,發現有一個cloneSheet的方法:
/**
* create an HSSFSheet from an existing sheet in the HSSFWorkbook.
*
* @return HSSFSheet representing the cloned sheet.
*/
@Override
public HSSFSheet cloneSheet(int sheetIndex) {
validateSheetIndex(sheetIndex);
HSSFSheet srcSheet = _sheets.get(sheetIndex);
String srcName = workbook.getSheetName(sheetIndex);
HSSFSheet clonedSheet = srcSheet.cloneSheet(this);
clonedSheet.setSelected(false);
clonedSheet.setActive(false);
String name = getUniqueSheetName(srcName);
int newSheetIndex = _sheets.size();
_sheets.add(clonedSheet);
workbook.setSheetName(newSheetIndex, name);
// Check this sheet has an autofilter, (which has a built-in NameRecord at workbook level)
int filterDbNameIndex = findExistingBuiltinNameRecordIdx(sheetIndex, NameRecord.BUILTIN_FILTER_DB);
if (filterDbNameIndex != -1) {
NameRecord newNameRecord = workbook.cloneFilter(filterDbNameIndex, newSheetIndex);
HSSFName newName = new HSSFName(this, newNameRecord);
names.add(newName);
}
// TODO - maybe same logic required for other/all built-in name records
// workbook.cloneDrawings(clonedSheet.getSheet());
return clonedSheet;
}
看上面的代碼可以看出,cloneSheet方法會將索引爲sheetIndex(下標從0開始)的sheet頁進行拷貝生成一個新的sheet,並添加到原始excel的工作薄的末尾sheet中並根據原始sheet的名稱後加下標來命名
那麼對於克隆/複製sheet頁的實現就比較方便了:
/**
* POI Excel工具類
* created on 2020/5/28 10:08
* @author puhaiyang
*/
public class POIExcelUtil {
public static void cloneSheet(File excelFile, String srcSheetName, String destSheetName) {
Workbook sheets = readExcelFromFile(excelFile);
int index = sheets.getSheetIndex(srcSheetName);
cloneSheet(excelFile, index, destSheetName);
}
public static void cloneSheet(File excelFile, Integer index, String destSheetName) {
Workbook sheets = readExcelFromFile(excelFile);
//克隆一個新的sheet
Sheet newSheet = sheets.cloneSheet(index);
int sheetIndex = sheets.getSheetIndex(newSheet);
sheets.setSheetName(sheetIndex, destSheetName);
try {
FileOutputStream out = new FileOutputStream(excelFile);
out.flush();
sheets.write(out);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//讀取excel
public static Workbook readExcelFromFile(File file) {
if (file == null) {
return null;
}
try {
return new XSSFWorkbook(new FileInputStream(file));
} catch (IOException e) {
throw new RuntimeException("文件解析失敗");
}
}
}
EasyExcel使用注意點
另外再記錄一點,EasyExcel的實現也是基於poi的,如果導入到EasyExcel的包的話,是不需要再引入poi的包的(自己導poi的包可能由於版本代碼原因導致EasyExcel不能正常使用 )
如果是springBoot/springCloud的項目,根據項目需要,記得將其他的可能衝突的包排除掉,如我這裏的,具體情況看自己項目而定
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.3</version>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
最後想說
本文無技術含量,在看到了網上還有那麼一大堆關於poi的sheet頁複製/克隆的無效文章後,爲了不誤導讀者及浪費讀者的時間決定還記錄一下