本文共 8906 字,大约阅读时间需要 29 分钟。
一、情景描述
最近在项目中客户提到一个新的需求,具体要求是在列表查询时导出多个Excel表格,并将这些表格合并到一个Sheet中,实现多个表内容在一个Sheet内展示。以下是两种操作的对比图示:一开始:
合并后:
二、实现思路
为了实现上述需求,可以按照以下步骤操作:Workbook sourceWorkbook,然后再创建一个Workbook targetWorkbook。targetWorkbook中新建一个Sheet targetSheet工作表。sourceWorkbook中第一个Sheet sheet1的内容复制到targetSheet中。sourceWorkbook中的第二个Sheet sheet2的内容复制到targetSheet中,依此类推。sourceWorkbook中全部五张表后,目标Sheet即为多个表合并到一个Sheet的结果。三、示例代码
1. POIUtil工具类package com.cdtye.itps.jjxt.model.util; import com.cdtye.itps.jjxt.model.excel.CellRangeAddressExcelVo; import org.apache.poi.ss.usermodel.*; import org.springframework.util.CollectionUtils; import java.util.List; public class POIUtil { /** * 拷贝sheet(表) * @param targetSheet 目标表 * @param sourceSheet 源表 * @param targetWork 目标工作簿 * @param sourceWork 源工作簿 * @param startRow 开始行号 * @param cellRangeAddressExcelVoList 需要合并的单元格坐标信息 */ public static void copySheet(Sheet targetSheet, Sheet sourceSheet, Workbook targetWork, Workbook sourceWork, int startRow, List cellRangeAddressExcelVoList) { if (targetSheet == null || sourceSheet == null || targetWork == null || sourceWork == null) { throw new IllegalArgumentException("调用PoiUtil.copySheet()方法时,targetSheet、sourceSheet、targetWork、sourceWork都不能为空,故抛出该异常!"); } // 设置单元格默认宽度 targetSheet.setDefaultColumnWidth(25); // 复制源表中的行 for (int i = sourceSheet.getFirstRowNum(); i <= sourceSheet.getLastRowNum(); i++) { Row sourceRow = sourceSheet.getRow(i); Row targetRow = targetSheet.createRow(i + startRow); if (sourceRow != null) { copyRow(targetRow, sourceRow, targetWork, sourceWork); } } // 自定义合并单元格样式(若不需要进行单元格合并操作,将cellRangeAddressExcelVoList赋值为null即可) if (!CollectionUtils.isEmpty(cellRangeAddressExcelVoList)) { // 合并单元格 for (CellRangeAddressExcelVo model : cellRangeAddressExcelVoList) { targetSheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(model.getFirstRow(), model.getLastRow(), model.getFirstCol(), model.getLastCol())); } } } /** * 拷贝row(行) * @param targetRow 目标行 * @param sourceRow 源行 * @param targetWork 目标工作簿 * @param sourceWork 源工作簿 */ public static void copyRow(Row targetRow, Row sourceRow, Workbook targetWork, Workbook sourceWork) { if (targetRow == null || sourceRow == null || targetWork == null || sourceWork == null) { throw new IllegalArgumentException("调用PoiUtil.copyRow()方法时,targetRow、sourceRow、targetWork、sourceWork都不能为空,故抛出该异常!"); } // 设置行高 targetRow.setHeight(sourceRow.getHeight()); for (int i = sourceRow.getFirstCellNum(); i < sourceRow.getLastCellNum(); i++) { Cell sourceCell = sourceRow.getCell(i); Cell targetCell = null; if (sourceCell != null && sourceCell.getStringCellValue() != "") { if (targetCell == null) { targetCell = targetRow.createCell(i); } // 拷贝单元格,包括内容和样式 copyCell(targetCell, sourceCell, targetWork, sourceWork); } } } /** * 拷贝cell(单元格) * @param targetCell 目标单元格 * @param sourceCell 源单元格 * @param targetWork 目标工作簿 * @param sourceWork 源工作簿 */ public static void copyCell(Cell targetCell, Cell sourceCell, Workbook targetWork, Workbook sourceWork) { if (targetCell == null || sourceCell == null || targetWork == null || sourceWork == null) { throw new IllegalArgumentException("调用PoiUtil.copyCell()方法时,targetCell、sourceCell、targetWork、sourceWork都不能为空,故抛出该异常!"); } CellStyle targetCellStyle = targetWork.createCellStyle(); targetCellStyle.cloneStyleFrom(sourceCell.getCellStyle()); targetCell.setCellStyle(targetCellStyle); targetCell.setCellValue(sourceCell.getStringCellValue()); } } **2. 需要合并的单元格位置信息实体** ```java package com.cdtye.itps.jjxt.model.excel; import lombok.AllArgsConstructor; import lombok.Data; import lombok.experimental.Accessors; @Data @Accessors(chain = true) @AllArgsConstructor public class CellRangeAddressExcelVo { // 起始行号 private int firstRow; // 终止行号 private int lastRow; // 起始列号 private int firstCol; // 终止列号 private int lastCol; } 该实体类用于存储需要合并的单元格位置信息,主要用于在Excel表中进行单元格合并操作。
3. Service层代码
public void export(BureauDayShiftVo bureauDayShiftVo, HttpServletResponse response) { try { // 设置下载的Excel名称,以当前时间为文件后缀 String dateTime = DateUtil.formatDateString(new Date(), DateUtil.DATE_FORMAT); String fileName = "供电安全质量日交班表" + dateTime + ".xlsx"; // 设置响应输出的头类型 response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + fileName); // excel信息部分 // 供电处重点信息追踪表信息 bureauDayShiftVo.setTrackFlag(1); Map trackSafeQualityMap = this.getTrackSafeQualityMap(bureauDayShiftVo); // 日安全质量信息表信息 bureauDayShiftVo.setTrackFlag(0); Map safeQualityParamsMap = this.getTrackSafeQualityMap(bureauDayShiftVo); // 天窗兑现统计表 Map skylightCashStatisticsMap = this.getSkylightCashStatisticsMap(); // 其他安全质量信息表 Map otherSafeQualityInfoMap = this.getOtherSafeQualityInfoMap(bureauDayShiftVo); // 安全质量考核表 Map safeQualityAssessmentMap = this.getSafeQualityAssessmentMap(); // 添加表 List 4. 合并sheet逻辑
public static Workbook mergeWorkSheet(Workbook targetWorkbook, Workbook sourceWorkbook) { try { // 获取源工作簿的各个Sheet Sheet firstSourceSheet = sourceWorkbook.getSheetAt(0); Sheet secondSourceSheet = sourceWorkbook.getSheetAt(1); Sheet thirdSourceSheet = sourceWorkbook.getSheetAt(2); Sheet fourSourceSheet = sourceWorkbook.getSheetAt(3); Sheet fiveSourceSheet = sourceWorkbook.getSheetAt(4); // 创建目标Sheet并命名 Sheet targetSheet = targetWorkbook.createSheet("安全质量信息日交班表"); // 按照顺序将源Sheet复制到目标Sheet中,并处理单元格合并 // 第一张表:直接复制,startRow=0 POIUtil.copySheet(targetSheet, firstSourceSheet, targetWorkbook, sourceWorkbook, 0, null); // 第二张表:在第一张表末尾开始,startRow=firstSourceSheet.getPhysicalNumberOfRows() +1 POIUtil.copySheet(targetSheet, secondSourceSheet, targetWorkbook, sourceWorkbook, firstSourceSheet.getPhysicalNumberOfRows() +1, null); // 第三张表:设置单元格合并信息 List cellRangeAddressExcelVoList = getCellRangeAddressExcelVoList( firstSourceSheet.getPhysicalNumberOfRows() + secondSourceSheet.getPhysicalNumberOfRows() +2, thirdSourceSheet.getRow(0).getPhysicalNumberOfCells() ); POIUtil.copySheet(targetSheet, thirdSourceSheet, targetWorkbook, sourceWorkbook, firstSourceSheet.getPhysicalNumberOfRows() + secondSourceSheet.getPhysicalNumberOfRows() +2, cellRangeAddressExcelVoList); // 第四张表:直接复制,startRow=上述总行数+1 POIUtil.copySheet(targetSheet, fourSourceSheet, targetWorkbook, sourceWorkbook, firstSourceSheet.getPhysicalNumberOfRows() + secondSourceSheet.getPhysicalNumberOfRows() + thirdSourceSheet.getPhysicalNumberOfRows() +3, null); // 第五张表:直接复制,startRow=上述总行数+1 POIUtil.copySheet(targetSheet, fiveSourceSheet, targetWorkbook, sourceWorkbook, firstSourceSheet.getPhysicalNumberOfRows() + secondSourceSheet.getPhysicalNumberOfRows() + thirdSourceSheet.getPhysicalNumberOfRows() + fourSourceSheet.getPhysicalNumberOfRows() +4, null); return targetWorkbook; } catch (Exception e) { log.error("Workbook合并出错", e); return null; } } // 其他方法类似,涉及多个Map数据的导出和Sheet合并操作 转载地址:http://jdhfk.baihongyu.com/