需求背景:需要将数据导出成excel格式,但是表头信息不确定和表头格式复杂,基于代码也可以实现,但是代码实现复杂,且后续需要改动时成本较大,所以选择依赖模板的形式进行数据导出,将提前准备好的模板放置在指定路径下,数据导出的时候依赖指定模板即可
依赖包导入:此处使用的版本是2.2.3,相关版本可以根据具体的项目要求进行依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.3</version>
</dependency>
具体实现:模板中需要设置一些数据导出的时候需要替换的文字
(1)依赖模板单sheet数据导出
代码实现:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
/**
* @author:xhwang
* @date:2022年12月9日
* @description:依赖模板数据导出,单个sheet页面
* @version:1.0
* @param:sheetName:每个sheet页面名称 data:每个sheet页面填充的数据 templatePath:模板路径 filePath:生成文件路径 map:替换模板中的正则表达式 fileName:文件名称
*/
public static void export(List<List<Object>> data,String templatePath,String filePath,Map<String, Object> map,String fileName){
ExcelWriter excelWriter = null;
try{
excelWriter = EasyExcel.write(filePath).withTemplate(templatePath).registerWriteHandler(new ColumnStyle()).build();
//map中存储需要替换模板中item的数据,例如表格表头需要显示2013级,那么map中需要传入的数据为("item",2013)
WriteSheet writeSheet = EasyExcel.writerSheet(0,map.get("item") != null ? map.get("item").toString(): fileName).build();
excelWriter.write(data, writeSheet);
excelWriter.fill(map, writeSheet);
} catch (Exception e) {
e.printStackTrace();
}finally{
excelWriter.finish();
}
}
(2)依赖多模板的多sheet页面数据导出,具体的需求为,导出的数据中有50家单位的数据,需要将每家单位的数据导出为一个sheet页,其中一家单位的表头和其余49家单位的表头不一样,所以我们的模板需要设置两个sheet,两个sheet的表头不一样,第一家使用模板的第一个sheet,其余49家使用第二个sheet,所以在数据导出的时候就需要对模板中第二个sheet进行拷贝
模板中第一个sheet如下:
第二个sheet如下:
代码实现:
/**
* @author:xhwang
* @date:2022年12月9日
* @description: 利用模板导入多个Sheet,需要克隆模板Sheet,此处为特殊需求,模板中有两个sheet,导出的excel有很多sheet,导出的excel第一个sheet用模板里面第一个sheet,其余的sheet用模板里面第二个sheet
* @version:1.0
* @param:sheetName:每个sheet页面名称 data:每个sheet页面填充的数据 templatePath:模板路径 filePath:生成文件路径
*/
public static void exportMoreSheet(List<String> sheetName,List<List<List<Object>>> data,String templatePath,String filePath){
FileInputStream fileInputStream= null;ExcelWriter excelWriter = null;ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
fileInputStream = new FileInputStream(templatePath);
XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
for (int i = 0; i < sheetName.size(); i++) {
if(i<=1){
workbook.setSheetName(i, sheetName.get(i));
}else{
workbook.cloneSheet(1, sheetName.get(i));//导出的文件自第二个sheet页开始使用模板中的第二个sheet,需要按照数据对模板中的第二个sheet进行制定长度的克隆
}
}
//写到流里
workbook.write(bos);
byte[] bArray = bos.toByteArray();
InputStream is = new ByteArrayInputStream(bArray);
//输出文件路径
excelWriter = EasyExcel.write(filePath).withTemplate(is).build();
Map<String,Object> map = new HashMap<String, Object>();
for (int i = 0; i < sheetName.size(); i++) {
WriteSheet writeSheet = EasyExcel.writerSheet(i,sheetName.get(i)).registerWriteHandler(new MoreSheetStyle()).build();
excelWriter.write(data.get(i), writeSheet);
map.put("item", sheetName.get(i));
excelWriter.fill(map, writeSheet);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
excelWriter.finish();
}
}
代码中涉及到的CloumnStyle.java和MoreSheetStyle.java两个类都是对导出数据样式的一些自定义细微调整,可以根据自己的实际需要进行设置
import java.util.List;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
@SuppressWarnings("rawtypes")
public class ColumnStyle implements CellWriteHandler {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
cellStyle.setBorderBottom(BorderStyle.THIN);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cell.setCellStyle(cellStyle);
font.setFontHeightInPoints((short) 16);
font.setFontName("宋体");
font.setBold(true);
cellStyle.setFont(font);
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
}
easyexcel做的比较灵活,可以根据自己实际要进行数据导出