diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/util/CellUtils.java b/easyexcel-core/src/main/java/com/alibaba/excel/util/CellUtils.java new file mode 100644 index 00000000..33496f6b --- /dev/null +++ b/easyexcel-core/src/main/java/com/alibaba/excel/util/CellUtils.java @@ -0,0 +1,36 @@ +package com.alibaba.excel.util; + +import org.apache.poi.ss.usermodel.Cell; + +/** + * @author gxz gongxuanzhang@foxmail.com + **/ +public class CellUtils { + + private CellUtils() { + throw new UnsupportedOperationException("utils class can't invoke construction"); + } + + /** + * get cell value; + * + * @return maybe null when cell style is not in + **/ + public static Object getCellValue(Cell cell) { + if (cell == null) { + throw new NullPointerException("cell must be not null"); + } + switch (cell.getCellType()) { + case NUMERIC: + return cell.getNumericCellValue(); + case STRING: + return cell.getStringCellValue(); + case BOOLEAN: + return cell.getBooleanCellValue(); + default: + return null; + } + } + + +} diff --git a/easyexcel-core/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java b/easyexcel-core/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java index 79db35b7..2a2ab203 100644 --- a/easyexcel-core/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java +++ b/easyexcel-core/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java @@ -1,9 +1,15 @@ package com.alibaba.excel.write.merge; import com.alibaba.excel.metadata.property.LoopMergeProperty; +import com.alibaba.excel.util.CellUtils; import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; import com.alibaba.excel.write.handler.context.RowWriteHandlerContext; - +import com.alibaba.excel.write.handler.context.WorkbookWriteHandlerContext; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; /** @@ -11,7 +17,7 @@ import org.apache.poi.ss.util.CellRangeAddress; * * @author Jiaju Zhuang */ -public class LoopMergeStrategy implements RowWriteHandler { +public class LoopMergeStrategy implements RowWriteHandler, WorkbookWriteHandler { /** * Each row */ @@ -25,6 +31,22 @@ public class LoopMergeStrategy implements RowWriteHandler { */ private final int columnIndex; + // custom merge field + + /** + * custom merge strategy + **/ + private ValueSetting valueSetting; + /** + * current merged value cache. + **/ + private Object[][] currentMergedValue; + + /** + * support the last merged when excel row can't divisible by eachRow + **/ + private int lastRowIndexStart; + public LoopMergeStrategy(int eachRow, int columnIndex) { this(eachRow, 1, columnIndex); } @@ -51,17 +73,89 @@ public class LoopMergeStrategy implements RowWriteHandler { this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex); } + + /** + * setting you custom value when the cell merge. + * but if the data row can't divisible by eachRow. + * the last merge cell can't call the setting + * + * @param valueSetting setting value strategy + **/ + public void setValueSetting(ValueSetting valueSetting) { + this.valueSetting = valueSetting; + } + + @Override public void afterRowDispose(RowWriteHandlerContext context) { if (context.getHead() || context.getRelativeRowIndex() == null) { return; } + if (this.valueSetting == null) { + doSimpleMerge(context); + } else { + doCustomMerge(context); + } + } + + @Override + public void afterWorkbookDispose(WorkbookWriteHandlerContext context) { + if (this.currentMergedValue != null) { + WriteSheetHolder writeSheetHolder = context.getWriteContext().writeSheetHolder(); + Sheet sheet = writeSheetHolder.getSheet(); + CellRangeAddress cellRangeAddress = new CellRangeAddress(lastRowIndexStart, + lastRowIndexStart + eachRow - 1, + columnIndex, columnIndex + columnExtend - 1); + sheet.addMergedRegionUnsafe(cellRangeAddress); + this.currentMergedValue = null; + } + } + + + private void doCustomMerge(RowWriteHandlerContext context) { + int indexMod = context.getRelativeRowIndex() % eachRow; + if (indexMod == 0) { + this.currentMergedValue = new String[eachRow][columnExtend]; + this.lastRowIndexStart = context.getRowIndex(); + } + Row row = context.getRow(); + for (int i = 0; i < columnExtend; i++) { + Cell cell = row.getCell(i + columnIndex); + Object cellValue = CellUtils.getCellValue(cell); + currentMergedValue[indexMod][i] = cellValue; + } + if (indexMod == eachRow - 1) { + CellRangeAddress cellRangeAddress = new CellRangeAddress(lastRowIndexStart, + lastRowIndexStart + eachRow - 1, + columnIndex, columnIndex + columnExtend - 1); + Sheet sheet = context.getWriteSheetHolder().getSheet(); + sheet.addMergedRegionUnsafe(cellRangeAddress); + int mergedRowIndex = context.getRowIndex() - eachRow + 1; + Cell mergedCell = sheet.getRow(mergedRowIndex).getCell(columnIndex); + this.valueSetting.settingMergedCell(mergedCell, this.currentMergedValue); + this.currentMergedValue = null; + } + } + + private void doSimpleMerge(RowWriteHandlerContext context) { if (context.getRelativeRowIndex() % eachRow == 0) { CellRangeAddress cellRangeAddress = new CellRangeAddress(context.getRowIndex(), context.getRowIndex() + eachRow - 1, columnIndex, columnIndex + columnExtend - 1); - context.getWriteSheetHolder().getSheet().addMergedRegionUnsafe(cellRangeAddress); + Sheet sheet = context.getWriteSheetHolder().getSheet(); + sheet.addMergedRegionUnsafe(cellRangeAddress); } } + @FunctionalInterface + public interface ValueSetting { + + /** + * setting merged cell value + * + * @param merged merged cell + * @param beforeMergedValue the value of the cell to be merged + **/ + void settingMergedCell(Cell merged, Object[][] beforeMergedValue); + } } diff --git a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 607a91be..54f6e332 100644 --- a/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -1,14 +1,5 @@ package com.alibaba.easyexcel.test.demo.write; -import java.io.File; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; @@ -39,7 +30,6 @@ import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; - import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.FillPatternType; @@ -49,6 +39,15 @@ import org.apache.poi.xssf.streaming.SXSSFSheet; import org.junit.Ignore; import org.junit.Test; +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** * 写的常见写法 * @@ -452,7 +451,7 @@ public class WriteTest { // 背景设置为红色 headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); WriteFont headWriteFont = new WriteFont(); - headWriteFont.setFontHeightInPoints((short)20); + headWriteFont.setFontHeightInPoints((short) 20); headWriteCellStyle.setWriteFont(headWriteFont); // 内容的策略 WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); @@ -462,7 +461,7 @@ public class WriteTest { contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); WriteFont contentWriteFont = new WriteFont(); // 字体大小 - contentWriteFont.setFontHeightInPoints((short)20); + contentWriteFont.setFontHeightInPoints((short) 20); contentWriteCellStyle.setWriteFont(contentWriteFont); // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 HorizontalCellStyleStrategy horizontalCellStyleStrategy = @@ -563,6 +562,33 @@ public class WriteTest { EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data()); } + /** + * 自定义合并单元格 + **/ + @Test + public void customWrite() { + String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; + // 每隔两行会合并 同mergeWrite的例子 + LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); + // 这里设置合并之后单元格的值 此例子表示把单元格所有的字符串的值拼接起来 给合并之后的单元格. + // mergedCell 是合并之后的单元格 我们可以直接进行操作,但是注意如果操作了这个单元格,如果再想拆分可能会和原数据不一样 + // values是一个二维数组 假如我们每两行合并一次,一次合并两列 + // 那二维数组会把两行两列的数据提供给你 + loopMergeStrategy.setValueSetting((mergedCell, values) -> { + StringBuilder mergedValue = new StringBuilder(); + for (Object[] rowValues : values) { + for (Object cellValue : rowValues) { + if (cellValue != null) { + mergedValue.append(cellValue); + } + } + } + mergedCell.setCellValue(mergedValue.toString()); + }); + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data()); + } + /** * 使用table去写入 *