EasyExcel
Java解析、生成Excel比較有名的框架有Apache poi、jxl。但他們都存在一個嚴重的問題就是非常的耗內存,poi有一套SAX模式的API可以一定程度的解決一些內存溢出的問題,但POI還是有一些缺陷,比如07版Excel解壓縮以及解壓後存儲都是在內存中完成的,內存消耗依然很大。easyexcel重寫了poi對07版Excel的解析,能夠原本一個3M的excel用POI sax依然需要100M左右內存降低到幾M,並且再大的excel不會出現內存溢出。
阿里開源,github:https://github.com/alibaba/easyexcel
使用(有模型)
1. 引包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beta5</version>
</dependency>
<! --執行測試代碼是一直報.ClassNotFoundException,修改poi相關版本後解決 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2. 定義模型
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExcelEmployee extends BaseRowModel{
@ExcelProperty(value = {"員工信息","序號"} ,index = 0)
private String sortNo;
@ExcelProperty(value = {"員工信息","員工代碼","EMPCODE"},index = 1)
private String employeeCode;
@ExcelProperty(value = {"員工信息","用戶登錄名","USERNAME"},index = 2)
private String userName;
@ExcelProperty(value = {"員工信息","員工姓名","EMPNAME"},index = 3)
private String trueName;
。。。。。。。。。。。。。
}
3. 自定義工具類(有模型寫、有模型讀、自定義參數類)
@Component
public class ExcelUtil {
private static StyleExcelHandler styleExcelHandler;
@Autowired
public void setStyleExcelHandler(StyleExcelHandler styleExcelHandler){
ExcelUtil.styleExcelHandler = styleExcelHandler;
}
/**
* @param inputStream 輸入流
* @param sheetNo 工作表編號
* @param headLineMun 標題佔用行數
*/
public static List<Object> readJavaModel(InputStream inputStream, ExcelParameter excelParam, Class<? extends BaseRowModel> clazz) {
List<Object> data = null;
try {
data = EasyExcelFactory.read(inputStream, new Sheet(excelParam.getSheetNo(), excelParam.getHeadLineMun(), clazz));
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
/**
* 寫Excel文件
*
* @param excelTypeEnum excel版本
* @param fileName 包含文件路徑的文件名
* @param sheetName sheet名
* @param datas 文件數據(包含表頭)
*/
public static void writeExcel(OutputStream outputStream, List<ExcelParameter> excelParameterList,
List<List<? extends BaseRowModel>> employeeDateList) {
try {
ExcelWriter writer = new ExcelWriter(null, outputStream, ExcelTypeEnum.XLSX, true, styleExcelHandler);
// ExcelWriter writer = EasyExcelFactory.getWriter(outputStream);
for (int j = 0; j < excelParameterList.size(); j++) {
ExcelParameter parameter = excelParameterList.get(j);
List<? extends BaseRowModel> data = employeeDateList.get(j);
Class<? extends BaseRowModel> t;
if (data != null && data.size() > 0) {
t = data.get(0).getClass();
} else {
continue;
}
Sheet sheet = new Sheet(parameter.sheetNo, parameter.headLineMun, t, parameter.sheetName, null);
sheet.setStartRow(parameter.getStartRow());
//設置列寬 設置每列的寬度
if (parameter.columnWidth != null && parameter.columnWidth.size() > 0) {
sheet.setColumnWidthMap(parameter.columnWidth);
} else {
// 設置自適應寬度
sheet.setAutoWidth(Boolean.TRUE);
}
writer.write(data, sheet);
//合併單元格
if (parameter.getMergeParameterList() != null && parameter.getMergeParameterList().size() > 0) {
for (MergeParameter mergeParameter : parameter.getMergeParameterList()) {
writer.merge(mergeParameter.firstRow, mergeParameter.lastRow, mergeParameter.firstCol, mergeParameter.lastCol);
}
}
}
writer.finish();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Data
public static class ExcelParameter {
/**
* 工作表編號
*/
private Integer sheetNo;
/**
* 標題佔用行數
*/
private Integer headLineMun;
/**
* 工作表名稱
*/
private String sheetName;
/**
* 表頭
*/
private List<List<String>> listStringHead;
/**
* 寬度
*/
private Map<Integer, Integer> columnWidth;
/**
* 開始行號
*/
private Integer startRow;
/**
* 合併單元格參數
*/
private List<MergeParameter> mergeParameterList;
}
/**
* 單元格合併參數
*/
@Data
@AllArgsConstructor
public static class MergeParameter {
/**
* 起始行
*/
private Integer firstRow;
/**
* 結束行
*/
private Integer lastRow;
/**
* 起始列
*/
private Integer firstCol;
/**
* 結束列
*/
private Integer lastCol;
}
}
4. 實現WriteHandler,自定義單元格樣式
@Component
public class StyleExcelHandler implements WriteHandler {
@Override
public void sheet(int i, Sheet sheet) {
}
@Override
public void row(int i, Row row) {
}
@Override
public void cell(int i, Cell cell) {
Sheet sheet = cell.getSheet();
Workbook workbook = sheet.getWorkbook();
CellStyle cellStyle = createStyle(workbook);
Font font = workbook.createFont();
font.setFontName("黑體");
String sheetName = sheet.getSheetName();
if(sheetName.equals("員工信息")) {
if(cell.getRowIndex() <= 2) {
if (i == 5) {
cellStyle.setFillPattern(FillPatternType.LESS_DOTS);//設置前景填充樣式
cellStyle.setFillBackgroundColor((short)13);
cellStyle.setFillForegroundColor((short)13);
}
font.setFontHeightInPoints((short) 12);
}else{
font.setFontHeightInPoints((short) 8);
}
}else {
if(cell.getRowIndex() < 1) {
font.setFontHeightInPoints((short) 12);
}else {
font.setFontHeightInPoints((short) 8);
}
}
cellStyle.setFont(font);
cell.getRow().getCell(i).setCellStyle(cellStyle);
}
/**
* 實際中如果直接獲取原單元格的樣式進行修改, 最後發現是改了整行的樣式, 因此這裏是新建一個樣* 式
*/
private CellStyle createStyle(Workbook workbook) {
CellStyle cellStyle = workbook.createCellStyle();
// 下邊框
cellStyle.setBorderBottom(BorderStyle.THIN);
// 左邊框
cellStyle.setBorderLeft(BorderStyle.THIN);
// 上邊框
cellStyle.setBorderTop(BorderStyle.THIN);
// 右邊框
cellStyle.setBorderRight(BorderStyle.THIN);
// 水平對齊方式
cellStyle.setAlignment(HorizontalAlignment.CENTER);
// 垂直對齊方式
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
return cellStyle;
}
}
5. 測試
public static void main(String[] args) throws FileNotFoundException {
List<ExcelParameter> excelParameterList = new ArrayList<>();
ExcelParameter excelParam1 = new ExcelParameter();
excelParam1.setSheetNo(1);
excelParam1.setHeadLineMun(2);
excelParam1.setSheetName("員工信息");
excelParam1.setStartRow(0);
MergeParameter m1 = new MergeParameter(1,2,0,0);
List<MergeParameter> mergeParameterList1 = new ArrayList<>();
mergeParameterList1.add(m1);
excelParam1.setMergeParameterList(mergeParameterList1);
Map<Integer,Integer> columnWidth = new HashMap<>();
columnWidth.put(0, 2000);
columnWidth.put(1, 3000);
columnWidth.put(2, 4000);
columnWidth.put(3, 3000);
excelParam1.setColumnWidth(columnWidth);
excelParameterList.add(excelParam1);
OutputStream outputStream = new FileOutputStream(new File("E:\\test.xlsx"));
List<List<? extends BaseRowModel>> employeeDate = new ArrayList<>();
employeeDate.add(Arrays.asList(new ExcelEmployee()));
writeExcel(outputStream, excelParameterList, employeeDate);
}