背景
因为项目需要,需要生成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页复制/克隆的无效文章后,为了不误导读者及浪费读者的时间决定还记录一下