
因为easyexcel做写入都是使用list作为数据,而这个账单则使用一个实体就够了,所以这里使用二维数组保存数据,而实体中的值使用一个自定义的注解来标记位置和单元格总的内容,反射获取注解中的位置,进行二维数组中的赋值,最后转为list传入easyexcel提供的生成代码里
0准备
准备一个自定义的注解,用来标记静态数据的位置、单元格内容
一个男子汉罢了
关注
关于easyexcel的不规则写入 原创
2022-01-26 17:00:46
1点赞
一个男子汉罢了
码龄2年
关注
最近在做一个项目时遇到了从数据库取数据生成一个账单的功能,其中一个excel中有多个sheet,有的是不规则的表格,有的则是比较规则的表格
做写入时发现了easyexcel这个开源的api,它在做大量数据的时候还可以保证内存不溢出,这点是比poi要好的,但是网上针对不规则的写入这个功能记录的比较少,这里写一下使用的过程
楼主也是小白一个,希望大家多指教,谢谢
这里先说一下思路:因为easyexcel做写入都是使用list作为数据,而这个账单则使用一个实体就够了,所以这里使用二维数组保存数据,而实体中的值使用一个自定义的注解来标记位置和单元格总的内容,反射获取注解中的位置,进行二维数组中的赋值,最后转为list传入easyexcel提供的生成代码里
0准备
准备一个自定义的注解,用来标记静态数据的位置、单元格内容
@Target({ElementTypeFIELD})
@Retention(RetentionPolicyRUNTIME)
@Documented
public @interface Sheet1RecordTemplate {
//excel中的行号
int rowNo();
//excel中的列号
int columnNo();
//单元格内容
String name();
}
实体:
这里说一下,这个实体是用来标记sheet中的静态内容的,与数据库无关
//静态单元格数据
public class ExcelEntity {
@Sheet1RecordTemplate(rowNo=1,columnNo = 1,name = "xxx有限公司")
//这里就代表第一行的第一列,内容为"xxx有限公司"
String value1;
@Sheet1RecordTemplate(rowNo=3,columnNo = 1,name = "结 算 单")
String value2;
@Sheet1RecordTemplate(rowNo=5,columnNo = 1,name = "客户名称")
String value3;
}
1首先是controller,这里具体调数据库的过程就不写了,总之得到了一个实体对象
//easyexcel生成
@RequestMapping("download")
public String downLoad(WriteDTO writeDTO) {
WriteVO writeVO = new WriteVO();
BeanUtilscopyProperties(writeDTO, writeVO); //将dto转换为vo
WriteVO excel = writeServicegetExcel(writeVOgetId()); //id传service
WriteDTO writeDTO1 = new WriteDTO();
BeanUtilscopyProperties(excel, writeDTO1); //将取出的数据再转dto,使用dto进行生成
try {
EasyexcelUtilrun(writeDTO1,""); //调一个工具类,完成生成
} catch (Exception e) {
eprintStackTrace();
return "生成成功";
}
2工具类,进行excel的生成
public class EasyexcelUtil {
public static void run(WriteDTO writeDTO, String filepath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//创建二维数组保存账单格式,反射赋值
Class<> clazz = ClassforName(ExcelEntityclassgetName());
Field[] declaredFields = clazzgetDeclaredFields();
String[][] cellNums = new String[17][10]; //二维数组的格式,按你们自己的表格来写
for (Field field : declaredFields) {
fieldsetAccessible(true);
//isAnnotationPresent如果指定类型的注释存在于此元素上,返回true
if (fieldisAnnotationPresent(Sheet1RecordTemplateclass)) {
Sheet1RecordTemplate annotation = fieldgetAnnotation(Sheet1RecordTemplateclass);
int rowNo = annotationrowNo();
int columnNo = annotationcolumnNo();
String name = annotationname();
cellNums[rowNo-1][columnNo-1]=name; //从0开始,所以减1
}
}
//从数据库中取出赋值给表格(二维数组),这里是动态单元格的数据
cellNums[4][1]=writeDTOgetUser();
//二维数组转list
List<List<String>> excelList = new ArrayList<>();
for (int i = 0; i < cellNumslength; i++) {
List<String> columnList = new ArrayList<String>();
for (int j = 0; j < cellNums[i]length; j++) {
columnListadd(j, cellNums[i][j]);
}
excelListadd(i, columnList);
}
String fileName = "D://file/账单模版xls";
//生成
WriteSheet sheet = EasyExcelwriterSheet(0, "结算单")
registerWriteHandler(new MyMergeStrategy())//合并单元格策略
registerWriteHandler(new CellSytle())//样式策略
build();
ExcelWriter excelWriter = EasyExcelwrite(fileName)
excelType(ExcelTypeEnumXLS)
autoCloseStream(true)
// inMemory(true) //文件放在内存还是磁盘
build();
excelWriterwrite(excelList, sheet);//生成Excel
excelWriterfinish();
}
}
3样式策略
这里说明一下,样式尽量需要复用,创建大量样式对象是很消耗性能的,我这里定义了6个,这个样式最好自己总结一下
public class CellSytle implements CellWriteHandler {
//样式进行复用
private CellStyle cellStyle1= null;
private CellStyle cellStyle2= null;
private CellStyle cellStyle3= null;
private CellStyle cellStyle4= null;
private CellStyle cellStyle5= null;
private CellStyle cellStyle6= null;
@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 afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
//不懂的小伙伴这里可以多看看参数可以调用的方法,能获取到很多对象使用
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//全局行列格式
//默认的行高,列宽
writeSheetHoldergetSheet()setDefaultRowHeight((short) 264);
writeSheetHoldergetSheet()setDefaultColumnWidth(11);
//单元格当前行数
int rowIndex = cellgetRowIndex();
//单元格当前列数
int columnIndex = cellgetColumnIndex();
//当前行
Row row = cellgetRow();
//样式进行复用
if (cellStyle1==null){
cellStyle1=createTitleCellStyle(cellgetSheet()getWorkbook()createCellStyle(), writeSheetHolder, 0);
}
if (cellStyle2==null){
cellStyle2=createHeadCellStyle(cellgetSheet()getWorkbook()createCellStyle(), writeSheetHolder, 0);
}
if (cellStyle3==null){
cellStyle3=createContentCellStyle(cellgetSheet()getWorkbook()createCellStyle(), writeSheetHolder, 1);
}
if (cellStyle4==null){
cellStyle4=createContentCellStyle(cellgetSheet()getWorkbook()createCellStyle(), writeSheetHolder, 2);
}
if (cellStyle5==null){
cellStyle5=createContentCellStyle(cellgetSheet()getWorkbook()createCellStyle(), writeSheetHolder, 3);
}
if (cellStyle6==null){
cellStyle6=createContentCellStyle(cellgetSheet()getWorkbook()createCellStyle(), writeSheetHolder, 4);
}
//按行设置样式的策略
switch (rowIndex){
case 0:
if (columnIndex>10){
break;
}
rowsetHeight((short) 600);
cellsetCellStyle(cellStyle1);
break;
case 1:
break;
case 2:
if (columnIndex>10){
break;
}
rowsetHeight((short) 400);
cellsetCellStyle(cellStyle2);
break;
case 3:
break;
case 4:
if (columnIndex>10){
break;
}
cellsetCellStyle(cellStyle3);
//这行的第8个单元格样式不一样
if (columnIndex==8){
cellsetCellStyle(cellStyle4);
}
break;
default:
break;
}
}
/
创建样式
这里的样式是自定义的,方法差不多就行,参数的rowStyle命名不严谨,应该是cellStyle
/
private static CellStyle createTitleCellStyle(CellStyle rowStyle,WriteSheetHolder writeSheetHolder, int sheetNo) {
rowStylesetAlignment(HorizontalAlignmentCENTER);//水平居中
rowStylesetVerticalAlignment(VerticalAlignmentCENTER);//垂直对齐
Font font = writeSheetHoldergetSheet()getWorkbook()createFont(); // 创建字体样式
fontsetBold(true); //字体加粗
fontsetFontName("宋体"); // 设置字体类型
if (sheetNo == 0) {
fontsetFontHeightInPoints((short) 16); // 设置字体大小
} else if (sheetNo == 1) {
rowStylesetBorderBottom(BorderStyleTHIN); //下边框
rowStylesetBorderLeft(BorderStyleTHIN); //左边框
rowStylesetBorderRight(BorderStyleTHIN); //右边框
rowStylesetBorderTop(BorderStyleTHIN); //上边框
fontsetFontHeightInPoints((short) 22); // 设置字体大小
}
rowStylesetFont(font); // 为标题样式设置字体样式
return rowStyle;
}
/
创建样式
/
private static CellStyle createHeadCellStyle(CellStyle rowStyle, WriteSheetHolder writeSheetHolder,int sheetNo) {
rowStylesetAlignment(HorizontalAlignmentCENTER); //水平居中
rowStylesetVerticalAlignment(VerticalAlignmentCENTER); //垂直对齐
Font font = writeSheetHoldergetSheet()getWorkbook()createFont(); // 创建字体样式
fontsetFontName("宋体"); // 设置字体类型
if (sheetNo == 0) {
fontsetFontHeightInPoints((short) 12); // 设置字体大小
} else if (sheetNo == 1) {
rowStylesetBorderBottom(BorderStyleTHIN); //下边框
rowStylesetBorderLeft(BorderStyleTHIN); //左边框
rowStylesetBorderRight(BorderStyleTHIN); //右边框
rowStylesetBorderTop(BorderStyleTHIN); //上边框
fontsetFontHeightInPoints((short) 15); // 设置字体大小
}
rowStylesetFont(font); // 为标题样式设置字体样式
return rowStyle;
}
/
创建内容样式
/
private static CellStyle createContentCellStyle(CellStyle rowStyle, WriteSheetHolder writeSheetHolder,int contentType) {
rowStylesetVerticalAlignment(VerticalAlignmentCENTER);// 垂直居中
Font font = writeSheetHoldergetSheet()getWorkbook()createFont(); // 创建字体样式
fontsetFontName("宋体"); // 设置字体类型
fontsetFontHeightInPoints((short) 10);
rowStylesetFont(font);
switch (contentType) {
case 1:
rowStylesetAlignment(HorizontalAlignmentLEFT);// 从左边对齐
rowStylesetBorderBottom(BorderStyleTHIN); //下边框
rowStylesetBorderLeft(BorderStyleTHIN); //左边框
rowStylesetBorderRight(BorderStyleTHIN); //右边框
rowStylesetBorderTop(BorderStyleTHIN); //上边框
break;
case 2:
rowStylesetWrapText(true);// 设置自动换行
rowStylesetAlignment(HorizontalAlignmentCENTER);// 居中对齐
rowStylesetBorderBottom(BorderStyleTHIN); //下边框
rowStylesetBorderLeft(BorderStyleTHIN); //左边框
rowStylesetBorderRight(BorderStyleTHIN); //右边框
rowStylesetBorderTop(BorderStyleTHIN); //上边框
break;
case 3:
rowStylesetAlignment(HorizontalAlignmentCENTER);// 居中对齐;
rowStylesetBorderBottom(BorderStyleTHIN); //下边框
break;
case 4:
rowStylesetAlignment(HorizontalAlignmentLEFT);// 从左边对齐
break;
}
return rowStyle;
}
}
4合并单元格策略
EasyExcel 适用于简单数据的导入导出,现阶段EasyExcel 不支持读取,对导出Excel样式、 读写规则要求严格的请使用POI!!!
参考:
>
1、在VBA中环境中
获取最后一行有数据的单元格的行号的代码如下
dim i as long
i=sheet1range("a65536")end(xlup)row
获取最后一列有数据的单元格的列号的代码如下
dim i as long
i=sheet1range("iv1")end(xlleft)column
2、想知道表格最多有多少行,在a1单元格输入公式
=countblack(b:b)
想知道表格最多有多少列,在a1单元格输入公式
=countblack(2:2)
3、在工作表中,想取得一列或一行中最后一个有数据的单元格的行号或列号
如果单元格是连续的,中间没有空单元格,可以输入公式=counta(a:a)或=counta(1:1)
如果单元格区域中间有空单元格,可以输入公式,然后按下Ctrl+Shift+Enter键结束公
式编辑
=max(if(a1:a20000="",0,row(a1:a20000))
=max(if(1:1="",0,column(1:1))
1userModel模式
一种是使用最多的,像用的HSSFWorkBook、XSSFWorkBook、SXSSFWorkBook,这里我们称它为(也是内存消耗较大的模式)。为什么内存占用大呢?直接看读取源码,拿XSSFWorkbook加载为例,最终会调用这个方法:
这里就可以看到,会一直读流,每行都会生成一个对象,加载到zipEntries中去,这就是内存占用大的根本原因。
2eventModel模式
也就是SAX模式,easyexcel就是重写了poi的这个方法,达到更小的内存占用。通过将流一行行的读取,加载到内存,达到节约内存的目的。
XlsxSaxAnalyser将数据读取成inputStream流,缓存到了sheetMap
拿到一行数据后,会去调用dealData方法,dealData方法会去调用之初始化的监听器,执行业务处理,readListenerinvoke方法。
apache
pomxml
优点:可以写非常大的数据量,比如100w或者更多,写数据更快,占用内存更少
原理:
API文档 >
不会。EasyExcel在写入文件时不会锁住文件,也不会限制其他程序读取或写入该文件。EasyExcel在写入文件时不会锁定文件。它能够在写入期间打开文件,写入数据后关闭文件。因此,在文件在打开的情况下,可以通过EasyExcel向其写入数据。但需要注意,如果在进行数据写入时另一个程序正尝试打开相同的文件,则可能会出现冲突,可能造成数据丢失或文件损坏。
easyexcel合并单元格导出内存溢出是一个比较常见的问题,主要是因为在合并单元格的时候,由于数据量太大,导致内存溢出。解决这个问题的方法有:1、减少合并单元格的数量;2、优化excel文件,减少数据量;3、更换更高配置的电脑,提高内存容量;4、使用更高版本的excel,支持更大的数据量。总之,您可以根据自己的实际情况,选择合适的解决方案来解决这个问题。
以上就是关于easyexcel横竖不固定如何写入全部的内容,包括:easyexcel横竖不固定如何写入、EasyExcel 官方文档总结、Excel 如何获取EXCEL 有数据区域的最大行数等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)