
一. Apache POI概述这段整理AI的让大家对Apache POI有个大概的概念 Apache POI 是一个开源的 Java 库用于处理 Microsoft Office 格式文件如 Excel、Word、PowerPoint 等。它提供了丰富的 API允许开发者通过 Java 代码读取、写入和操作 Office 文档无需依赖 Microsoft Office 软件。我们常用的EasyExcel是阿里对Apache POI进行的上层封装库针对POI在处理大数据量容易内存溢出OOM和API繁琐的痛点进行了深度优化和重构。但本文面向的场景主要是面向少量关系数据的模块化存储因此不对EasyExcel做过多介绍二.背景介绍场景是需要将某个列表页面存档转成pdf由于是关系型数据且格式相对固定因此博主使用Apache POI先将数据填充至excel再转换成pdf。写在前面博主对Apache POI也只是初次使用本文仅是一次记录并非教程。三.Excel模板、行和单元格获取首先我们读取写好的模板模板就要自己准备了里面填充静态的不需要动态填充的内容当然你也可以把静态内容放到代码里填充//获取模板 org.springframework.core.io.Resource resource new ClassPathResource(); InputStream template resource.getInputStream(); Workbook workbook WorkbookFactory.create(template); //获取工作簿中的第x个工作表 Sheet sheet workbook.getSheetAt(x);WorkbookFactory这是 Apache POI 提供的一个工厂类。它的最大特点是自动识别文件格式。如果template流中是旧版的.xls(BIFF8) 格式它会自动创建HSSFWorkbook对象如果template流中是新版的.xlsx(OOXML) 格式它会自动创建XSSFWorkbook对象如果是宏启用文件.xlsm它也能正确处理注意workbook类是一整个Excel文件对象只有sheet才是我们真正处理的工作表。//获取rowIndex行 Row row sheet.getRow(rowIndex); //创建rowIndex行注意如果rowIndex处已经有一行旧行会被销毁 Row row sheet.createRow(rowIndex); //获取单元格 Cell cell sheet.getRow(rowIndex).getCell(colIndex); //单元格填充数据 cell.setCellValue(data);Row和Cell分别是apache poi中的行类和单元格类内置了很多功能强大的方法本文只会涉及其中最常用的有兴趣的读者可以自行查看。值得一提的是这里的索引都是从0开始的也即A1单元格的rowIndex和colIndex都是[0]且针对合并的单元格需要选中时应以其最左上角的单元格作为索引。最后是Cell.setCellValue()方法虽然内置了适配多种数据填充方法但是博主建议统一转成String填充这可以让获取单元格内容长度比较简单在后面适应行高时较为方便。四.行移动、单元格合并及内容填充//将startRow至endRow移动n行n0下移n0上移 void shiftRows(int startRow, int endRow, int n)当我们填充excel时我们可能会遇到列表填充这时候如果不是最下层的数据填充就需要根据listDataVO长度下移静态内容当然你喜欢从下往上填充也不是不行这时候就需要用shiftRows()方法。shiftRows()方法还有一个五参数版本的重构主要区别在于是否清空源数据以及是否保留列宽。当然也有类似的shiftColumns()方法。//动态合并单元格 sheet.addMergedRegion(new CellRangeAddress(rowIndex1, rowIndex2, colIndex1, colIndex2));如果需要填充的位置相对固定那么可以使用Mapint[], FunctionDataVO, String类简化对数据进行填充五.单元格格式//单元格格式 CellStyle style workbook.createCellStyle(); //字体格式 Font font workbook.createFont(); targetFont.setFontHeightInPoints(FONT_SIZE); //字号 style.setFont(targetFont); targetFont.setBold(true); //加粗 style.setWrapText(true); //开启自动换行 style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中 style.setAlignment(HorizontalAlignment.LEFT); // 左对齐 //边框 style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); cell.setCellStyle(style);六. 行高自适应/手动计算根据需求可以选择单元格是否自动换行。如果需要自动换行那么我们就需要设置行高这里提到一个excel的知识点如果一行内没有合并单元格那么当你双击内容明显超出列宽的单元格的时候excel底层会自动计算行高并固定我们也可以在代码中这样做//让excel自适应行高 row.setHeightInPoints(-1);但是一旦有合并单元格那么excel的自动计算行高就会失效这时候我们就需要手动计算行高并进行适配。//单元格内容长 float wordLen row.getCell(wordColIdx).getRichStringCellValue().length(); // 列宽这里只给了单单元格的计算方式如果是合并单元格则需要多个列共同算除以512是为了适配中文 float wordCellWidthLen (float) sheet.getColumnWidth(wordColIdx) / 512; //如果文本内容没超过一行设置为默认高度 if (wordCellWidthLen wordLen) { row.setHeightInPoints(DEFAULT_HEIGH); return; } //可以根据效果传入修正参数param float wordWrappedLines wordLen / wordCellWidthLen * correctionFactor * param; float rowHeightForOneLine row.getHeightInPoints(); row.setHeightInPoints(rowHeightForOneLine * wordWrappedLines);七.在excle中插入图形主要使用XSSFDrawing配合XSSFClientAnchor、XSSFSimpleShape完成