当前位置: 首页 > news >正文

使用springboot+easyexcel实现导出excel并合并指定单元格

1:准备一个单元格合并策略类代码:

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.List;public class ExcelMergeHandler implements CellWriteHandler {// 要合并的列索引数组private final int[] mergeColumnIndex;// 合并开始的行索引private final int mergeRowIndex;/*** 构造函数** @param mergeRowIndex     合并开始的行索引* @param mergeColumnIndex  要合并的列索引数组*/public ExcelMergeHandler(int mergeRowIndex, int[] mergeColumnIndex) {this.mergeRowIndex = mergeRowIndex;this.mergeColumnIndex = mergeColumnIndex;}@Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {// 单元格创建前的处理(这里不需要处理)}@Overridepublic void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 单元格创建后的处理(这里不需要处理)}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 当前行索引int curRowIndex = cell.getRowIndex();// 当前列索引int curColIndex = cell.getColumnIndex();// 如果当前行大于合并开始行且当前列在需要合并的列中if (curRowIndex > mergeRowIndex && isMergeColumn(curColIndex)) {// 进行合并操作mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);}}/*** 检查当前列是否在需要合并的列中** @param curColIndex 当前列索引* @return 如果是需要合并的列返回true,否则返回false*/private boolean isMergeColumn(int curColIndex) {for (int columnIndex : mergeColumnIndex) {if (curColIndex == columnIndex) {return true;}}return false;}/*** 当前单元格向上合并** @param writeSheetHolder 当前工作表持有者* @param cell             当前单元格* @param curRowIndex      当前行索引* @param curColIndex      当前列索引*/private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {// 获取当前单元格的数据Object curData = getCellData(cell);// 获取前一个单元格的数据Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);Object preData = getCellData(preCell);// 判断当前单元格和前一个单元格的数据以及主键是否相同if (curData.equals(preData) && isSamePrimaryKey(cell, curRowIndex)) {// 获取工作表Sheet sheet = writeSheetHolder.getSheet();// 合并单元格mergeCells(sheet, curRowIndex, curColIndex);}}/*** 获取单元格的数据** @param cell 单元格* @return 单元格数据*/private Object getCellData(Cell cell) {return cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();}/*** 判断当前单元格和前一个单元格的主键是否相同** @param cell         当前单元格* @param curRowIndex  当前行索引* @return 如果主键相同返回true,否则返回false*/private boolean isSamePrimaryKey(Cell cell, int curRowIndex) {String currentPrimaryKey = cell.getRow().getCell(0).getStringCellValue();String previousPrimaryKey = cell.getSheet().getRow(curRowIndex - 1).getCell(0).getStringCellValue();return currentPrimaryKey.equals(previousPrimaryKey);}/*** 合并单元格** @param sheet        工作表* @param curRowIndex  当前行索引* @param curColIndex  当前列索引*/private void mergeCells(Sheet sheet, int curRowIndex, int curColIndex) {// 获取已合并的区域List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();boolean isMerged = false;// 检查前一个单元格是否已经被合并for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {CellRangeAddress cellRangeAddr = mergeRegions.get(i);if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {sheet.removeMergedRegion(i);cellRangeAddr.setLastRow(curRowIndex);sheet.addMergedRegion(cellRangeAddr);isMerged = true;}}// 如果前一个单元格未被合并,则新增合并区域if (!isMerged) {CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);sheet.addMergedRegion(cellRangeAddress);}}
}


2:业务类实现代码:
 

    //从第2行开始合并private static final int mergeRowIndex=1;//需要合并的单元格列private static final int[] mergeCols={0,1,2,3,4,5,6,7,8,9,10,11,12};@Overridepublic void exportBillOfQuantity(BillOfQuantityExportDto exportDto, HttpServletResponse response) {// 设置响应参数setResponseHeader(response, "export-bill-quantities.xlsx_");// 整理需要导出的数据List<ExportBillQuantitiesVo> exportBillQuantitiesVoList = getExportBillQuantitiesVoList(exportDto);try {// 获取模板文件输入流InputStream templateStream = new ClassPathResource(GlobalConstants.TEMPLATE_PATH + File.separator + GlobalConstants.EXPORT_BILL_QUANTITIES_FILE_NAME).getInputStream();// 使用EasyExcel写入数据到HttpServletResponseEasyExcel.write(response.getOutputStream()).registerWriteHandler(setStyle()).registerWriteHandler(new ExcelMergeHandler(mergeRowIndex, mergeCols)).withTemplate(templateStream).sheet().doWrite(exportBillQuantitiesVoList);} catch (IOException e) {log.error("export productCoreParamList data is filed", e);throw new BusinessException(StatusCode.FAILED);}}// 设置响应头通用方法private void setResponseHeader(HttpServletResponse response, String fileName) {try {String fileNameStr = fileName + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".xls";String encodedFileName = URLEncoder.encode(fileNameStr, StandardCharsets.UTF_8.toString());response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("UTF-8");response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);} catch (Exception e) {log.error("set response header error", e);throw new BusinessException(StatusCode.SYSTEM_ERROR);}}// 设置导出excel文件部分内容样式private HorizontalCellStyleStrategy setStyle() {// 定义样式:自动换行WriteCellStyle contentWriteCellStyle = new WriteCellStyle();contentWriteCellStyle.setWrapped(true); // 关键:开启自动换行WriteFont writeFont = new WriteFont();writeFont.setFontName("Microsoft YaHei"); // 字体writeFont.setFontHeightInPoints((short) 12); // 字体大小contentWriteCellStyle.setWriteFont(writeFont);// 注册样式策略(全局生效)HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(null, // 头样式(默认)contentWriteCellStyle // 内容样式(自动换行));return styleStrategy;}

http://www.xdnf.cn/news/133777.html

相关文章:

  • VuePress可以做什么?
  • Keras中Lambda层的常用方法
  • 告别默认配置!Xray自定义POC开发指南
  • Linux字符设备驱动开发的详细步骤
  • ubuntu22.04 命令行修改静态ip
  • 贝叶斯优化GAM回归(matlab代码)
  • 牛客小白月赛115-B题:签到题
  • Python Cookbook-6.9 快速复制对象
  • 代码随想录算法训练营第60期第十七天打卡
  • 小白如何使用Cursor运行python程序(含环境配置教程)
  • 隐形革命:环境智能如何重构“人-机-境“共生新秩序
  • 关于循环缓冲区
  • 【java源码】AI智能导诊系统,基于H5、小程序、app等多端,引导患者自助就诊挂号,实现科学就诊
  • 4G卡的DTU固件TCP通讯
  • 【Rust】Rust中的枚举与模式匹配,原理解析与应用实战
  • 秒级到毫秒:BFD的速度革命
  • Swift闭包(Closure)深入解析与底层原理
  • SAM 2 (Segment Anything ):图像与视频通用分割模型
  • Vue里面elementUi-aside 和el-main不垂直排列
  • 知识蒸馏和迁移学习的区别
  • 在项目中使用 Sonar:提升代码质量的利器
  • 深入理解机器学习:人工智能的核心驱动力
  • AI之FastAPI+ollama调用嵌入模型OllamaBgeEmbeddings
  • SQL笛卡尔积运用-为每个用户初始化数据
  • [Windows] 卡巴斯基Kaspersky 21.21.7.384 免费版
  • 基于Axure的动态甘特图设计:实现任务增删改与时间拖拽交互
  • 打工人必看:Word中姓名对齐的高效方法
  • 计算器(WEB)
  • PWNOS:2.0(vulnhub靶机)
  • Java知识日常巩固(五)