1. 사업 배경
最近公司有一个业务就是要求导出一个excel,虽说这个excel的表头只有一行,但是这一行的表头是由两部分组成,
一部分是固定部分,一部分是动态部分。要求导出的表头如下图所示,该表中前五列是固定表头,后面的列数不固定,
有可能是五个月,六个月或者八个月,九个月都有可能。
2. 솔루션
因为笔者目前只掌握了Easyexcel的固定表头(也就是固定列)的导出,所以这里没有像用easy excel一样把该
excel每一行的数据抽象成一个对象去处理。所以这里用到的技术是poi,然后主要是通过哪一行哪一列来确定一个
单元格,比如一行一列确定了一个单元格,然后把该行该列的数据作为条件去查对应单元格里面的数据。
3. 솔루션
3.1 종속성 소개
//因为easyexcel底层用的也是poi,所以引入这个类就等于引入了poi
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.3</version>
</dependency>
3.2 세부 시행
public void dateConvertDemoFour(HttpServletResponse response) throws IOException {
//经过查阅相关资料,从HSSFWorkbook和XSSFWorkbook还有SXSSFWorkbook中选出了SXSSFWorkbook作为适合笔者需求的实现类
int rowAccess = 100;
SXSSFWorkbook wb = new SXSSFWorkbook(rowAccess);
//设置表头样式
CellStyle cellStyleHeader = getCellStyle(wb);
//创建第一个sheet
SXSSFSheet sheetOne = wb.createSheet();
wb.setSheetName(0, "第一个sheet页");
//创建第二个sheet
Sheet sheetTwo = wb.createSheet();
wb.setSheetName(1, "第二个sheet页");
/**
* 一、确定第一个sheet表头(第二个sheet类似)
*/
List<String> headList = getHeaderData(cellStyleHeader, sheetOne);
/**
* 二、填充第一个sheet数据(第二个sheet类似)
*/
getContentData(sheetOne, headList);
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" +
URLEncoder.encode("demo" + "." + "xlsx", "UTF-8"));
// 输出
wb.write(response.getOutputStream());
}
/**
* 设置表头数据
*
* @param wb
* @return
*/
private CellStyle getCellStyle(SXSSFWorkbook wb) {
CellStyle cellStyleHeader = wb.createCellStyle();
// 标题水平居中
cellStyleHeader.setAlignment(HorizontalAlignment.CENTER);
// 标题垂直居中
cellStyleHeader.setVerticalAlignment(VerticalAlignment.CENTER);
// 字体加粗
Font font = wb.createFont();
font.setBold(true);
// 字体大小
font.setFontHeight((short) 300);
font.setFontName("宋体");
cellStyleHeader.setFont(font);
return cellStyleHeader;
}
/**
* 一、确定第一个sheet表头(第二个sheet类似)
*/
private List<String> getHeaderData(CellStyle cellStyleHeader, SXSSFSheet sheetOne) {
//确定行:假如第一个sheet有4行(其中有一行是表头行),其余需要从库中查出数据
//确定列:假如第一个sheet有8列,需要从库中查出数据
//假如有3行,8列,其中8是固定的5列加上时间的列数3(当然这里3是动态的,可以是7或者8或者9,这里是演示,所以写为3)
int timeCount = 5;
Row row = sheetOne.createRow(0);
List<String> headList = new ArrayList<>();
//确定首行中的固定列,也就是表头固定列(excel中列是从第0列开始的)
for (int j = 0; j < timeCount; j++) {
Cell cell = row.createCell(j);
//设置表头样式
cell.setCellStyle(cellStyleHeader);
sheetOne.setColumnWidth(j, 25 * 140);
if (j == 0) {
cell.setCellValue("固定列名1");
} else if (j == 1) {
cell.setCellValue("固定列名2");
} else if (j == 2) {
cell.setCellValue("固定列名3");
} else if (j == 3) {
cell.setCellValue("固定列名4");
} else {
cell.setCellValue("固定列名5");
}
}
//确定首行中的动态列,也就是表头动态列,模拟动态月份的表头(假如有3个月)
int trendsCount = 3;
for (int a = 5; a < 5 + trendsCount; a++) {
Cell cell = row.createCell(a);
//设置表头样式
cell.setCellStyle(cellStyleHeader);
//设置每一列的宽度(每列的宽度只需要在首行中设置就行)
sheetOne.setColumnWidth(a, 25 * 140);
String value = "2022-" + a;
cell.setCellValue(value);
//注意此处会在填充数据时会用到
headList.add(value);
}
return headList;
}
/**
* 二、填充第一个sheet数据(第二个sheet类似)
*/
private void getContentData(SXSSFSheet sheetOne, List<String> headList) {
//开始填充数据
for (int rowNum = 1; rowNum < 4; rowNum++) {
Row dataRow = sheetOne.createRow(rowNum);
//1.填充固定列数据(固定列数据可以抽象为一个对象),此处为造的假数据
ExcelTable excelTableOne = new ExcelTable("第一列数据", "第二列数据", "第三列数据", "第四列数据", "第五列数据");
ExcelTable excelTableTwo = new ExcelTable("第一列数据", "第二列数据", "第三列数据", "第四列数据", "第五列数据");
ExcelTable excelTableThree = new ExcelTable("第一列数据", "第二列数据", "第三列数据", "第四列数据", "第五列数据");
List<ExcelTable> list = new ArrayList<>();
list.add(excelTableOne);
list.add(excelTableTwo);
list.add(excelTableThree);
for (int i = 0; i < 5; i++) {
Cell cell = dataRow.createCell(i);
if (i == 0) {
cell.setCellValue(list.get(rowNum - 1).getFixedColOne());
} else if (i == 1) {
cell.setCellValue(list.get(rowNum - 1).getFixedColTwo());
} else if (i == 2) {
cell.setCellValue(list.get(rowNum - 1).getFixedColThree());
} else if (i == 3) {
cell.setCellValue(list.get(rowNum - 1).getFixedColFour());
} else {
cell.setCellValue(list.get(rowNum - 1).getFixedColFive());
}
}
//2.填充动态列数据(注意这里的起始列是固定列的最后一行加1)
for (int i = 5; i < headList.size() + 5; i++) {
Cell cell = dataRow.createCell(i);
//此时需要把这一行的第一个元素:(String fixedColOne = list.get(rowNum).getFixedColOne();)
//和这一列的元素:i = 5....都拿出来作为条件去数据库中查到这行这列确定的单元格的内容,然后进行填充
//查db
// cell.setCellValue("库中查到的数据");
cell.setCellValue("第" + ((i + 1) + "列数据"));
}
}
}
3.3 결과 테스트
- 1 고정 헤더 + 동적 헤더 실현
- 2 고정 테이블 헤더에 해당하는 고정 열 데이터 채우기 실현
- 3 동적 테이블 헤더에 해당하는 동적 열 데이터 채우기 실현
4. 강점과 약점 분석
장점 : 형식의 다양성에 구애받지 않고 데이터 채움을 동적으로 실현할 수 있습니다. 이 방법은 각 셀에서 작동하기 때문입니다.
단점 : 데이터 양이 많으면 내보내기 속도에 영향을 주어 내보내기 속도가 느려집니다. 여담: 내보낼 때 작성자가 게이트웨이의 응답 시간을 특별히 조정했습니다. 그렇지 않으면 응답 시간이 초과되므로 이 방법을 신중하게 선택하십시오. 또는 누군가 이것을 최적화할 수 있다면 지적하는 것을 환영합니다. 대단히 감사합니다.
일반 헤더만 사용하여 Excel을 내보내는 경우 여기를 클릭하십시오 https://blog.csdn.net/qq_41774102/article/details/128252059
https://www.jb51.net/article/264793.htm 기사에 거물들의 아이디어에 대한 참조가 있습니다.
설명 : 이 글의 내용은 작성자가 테스트한 내용이며 타당한 내용이며, 부적절할 수 있는 부분이 있다면 주저하지 마시고 말씀해 주시면 작성자가 겸허히 받아들이고 수정하도록 하겠습니다.