POI를 사용하여 동적 헤더로 Excel 내보내기

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 기사에 거물들의 아이디어에 대한 참조가 있습니다.

설명 : 이 글의 내용은 작성자가 테스트한 내용이며 타당한 내용이며, 부적절할 수 있는 부분이 있다면 주저하지 마시고 말씀해 주시면 작성자가 겸허히 받아들이고 수정하도록 하겠습니다.

추천

출처blog.csdn.net/qq_41774102/article/details/129296699