設置合並豎行單元格,表頭設置
OutputStream outputStream = ExcelUtils.getResponseOutputStream(response, fileName); //根據數據組裝需要合並的單元格 Map<String, List<String>> strategyMap = addMerStrategy(importAssignExcelDemo()); ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(outputStream) .registerWriteHandler(new ReadCustomCellStyleStrategy(new WriteCellStyle(), new WriteCellStyle())) .registerWriteHandler(new DemoMergeStrategy(strategyMap))//添加的豎行內容一致時,合並單元格 .excelType(ExcelTypeEnum.XLSX); ExcelWriter excelWriter = excelWriterBuilder.build(); String customer = "***表頭名稱"; String dateStr = new SimpleDateFormat("yyyy年MM月dd日").format(new Date());
//getHeader()獲取自定義表頭 ExcelUtils.writeOnly(excelWriter, importAssignExcelDemo(), ImportDemoExcelDTO.class, 1, fileName + "數據", getHeader(customer, dateStr));
private List<List<String>> getHeader(String customer, String dateStr) { /** * 打算展示成如下樣子 * |客戶:xxx 公司 (這一行需要合並單元格) * |單號: SO22222222222222| 日期: 2020-01-01 (分別需要合並單元格) * |產品ID|產品名稱|價格|數量|總金額|備注| */ List<List<String>> list = new ArrayList<>(); //反射獲取excel表頭所有字段 List<String> attributeList = getExcelObjectAttribute(); //拼裝表頭 attributeList.forEach(excelName->{ List<String> head = new ArrayList<>(); head.add(customer); head.add(dateStr); head.add(excelName); list.add(head); }); return list;
/** * 反射獲取excel對象excel注解屬性坐表頭 */ public static List<String> getExcelObjectAttribute() { List<String> list = new ArrayList(); try { //獲取類名的包名地址 Class<?> clazz = Class.forName("com.。。。.importexcel.ImportExcelDTO"); // 得到所有定義字段 Field[] allFields = clazz.getDeclaredFields(); // 得到所有field並存放到一個list中. for (Field field : allFields) { //判斷並獲取excel注解信息 if (field.isAnnotationPresent(ExcelProperty.class)) { ExcelProperty excelProperty = field.getDeclaredAnnotation(ExcelProperty.class); list.add(excelProperty.value()[0]); } } } catch (Exception e) { e.printStackTrace(); } return list; }
/** * 重載:生成excel文件指定sheet頁方法 * * @param excelWriter * @param data * @param clazz * @param sheetNo * @param sheetName * @param <T> * @param head 重載添加表頭參數 */ public static <T> void writeOnly(ExcelWriter excelWriter, List<T> data, Class clazz, Integer sheetNo, String sheetName, List<List<String>> head) { ExcelWriterSheetBuilder excelWriterSheetBuilder; WriteSheet writeSheet = new WriteSheet(); excelWriterSheetBuilder = new ExcelWriterSheetBuilder(excelWriter); excelWriterSheetBuilder.sheetNo(sheetNo); excelWriterSheetBuilder.sheetName(sheetName); writeSheet.setSheetNo(sheetNo); writeSheet.setSheetName(sheetName); writeSheet.setClazz(clazz); writeSheet.setHead(head); excelWriter.write(data, writeSheet); }
/** * 合並豎行單元格 * @param excelDtoList * @return */ private Map<String, List<String>> addMerStrategy(List<ImportDemoExcelDTO> excelDtoList) { Map<String, List<String>> strategyMap = new HashMap<>(); ImportDemoExcelDTO preExcelDto = null; //是否合並 int startCol = 0; List<String> mapList = new ArrayList<>(); String mapTest = ""; for (int i = 0; i < excelDtoList.size(); i++) { ImportDemoExcelDTO importAssignExcelDTO = excelDtoList.get(i); if (preExcelDto != null) { //從第二行開始判斷是否需要合並 if (!preExcelDto.getLeaderName().equals(importAssignExcelDTO.getLeaderName())) { mapTest = startCol + "," + (i); //第0行是表頭 startCol = i + 1; if (i == excelDtoList.size() - 1) { mapList.add(mapTest); //最后一條清空不用合並 mapTest = ""; } } else if (i == excelDtoList.size() - 1) { mapTest = startCol + "," + (startCol+1);//豎行合並 } } else { startCol = i + 1; } preExcelDto = importAssignExcelDTO; if (StringUtils.isNotBlank(mapTest)) { mapList.add(mapTest); } } //1代表第一列,excel從0開始。(至合並第一列) strategyMap.put("1", mapList); return strategyMap; }
package com.****.write.style; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.write.merge.AbstractMergeStrategy; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import java.util.List; import java.util.Map; public class DemoMergeStrategy extends AbstractMergeStrategy {
//豎行合並,合並列:開始行,結束行 private Map<String, List<String>> strategyMap; private Sheet sheet; public DemoMergeStrategy(Map<String, List<String>> strategyMap) { this.strategyMap = strategyMap; } @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { this.sheet = sheet;
System.out.println(cell.getRowIndex()+",測試記錄行列,"+cell.getColumnIndex());
if (cell.getRowIndex() == 1 && cell.getColumnIndex() == 0) {
/** * 保證每個cell被合並一次,如果不加上面的判斷,因為是一個cell一個cell操作的, * 例如合並A2:A3,當cell為A2時,合並A2,A3,但是當cell為A3時,又是合並A2,A3, * 但此時A2,A3已經是合並的單元格了 */
for (Map.Entry<String, List<String>> entry : strategyMap.entrySet()) {
Integer columnIndex = Integer.valueOf(entry.getKey());
entry.getValue().forEach(rowRange -> {
//添加一個合並請求
String startRow = rowRange.split(",")[0];
String endRow = rowRange.split(",")[1];
sheet.addMergedRegionUnsafe(new CellRangeAddress(Integer.parseInt(startRow), Integer.parseInt(endRow), columnIndex, columnIndex));
});
}
}
}
}
效果實現

下面為參考內容:
調整內容:
OutputStream outputStream = ExcelUtils.getResponseOutputStream(response, excelName);
ExcelWriter excelWriter;
ExcelWriterBuilder excelWriterBuilder = EasyExcel.write(outputStream);
int lastCol = ExportCommentsTaskExcelDTO.class.getDeclaredFields().length-1;
//根據數據組裝需要合並的單元格
Map<String, List<String>> strategyMap = addMerStrategy(commentsTaskExcelDTOList);
excelWriterBuilder
.registerWriteHandler(new CommentsCustomExcelHeader(excelName, createTime, lastCol))//文檔名、時間、表頭合並結束列數
.registerWriteHandler(new CommentsExcelStyleStrategy(new WriteCellStyle(), new WriteCellStyle()))
.registerWriteHandler(new CommentsExcelMergeStrategy(strategyMap)).relativeHeadRowIndex(3)//真實數據從第三行開始
.excelType(ExcelTypeEnum.XLSX);
excelWriter = excelWriterBuilder.build();
ExcelUtils.writeOnly(excelWriter, commentsTaskExcelDTOList, ExportCommentsTaskExcelDTO.class, 1, excelName + "數據");
DetectionSheetWriteHandler 復雜表頭樣式整理
這個類繼承SheetWriteHandler 抽象類,實現afterSheetCreate方法,進行自定義表頭策略,傳入自定義的表頭信息,及自定義樣式。
public class DetectionSheetWriteHandler implements SheetWriteHandler {
private String dataTime;
public DetectionSheetWriteHandler(){}
public DetectionSheetWriteHandler(String dataTime){
this.dataTime = dataTime;
}
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
Workbook workbook = writeWorkbookHolder.getWorkbook();
Sheet sheet = workbook.getSheetAt(0);
//設置第一行標題
Row row1 = sheet.createRow(1);
row1.setHeight((short) 800);
Cell row1Cell1 = row1.createCell(0);
row1Cell1.setCellValue(" 統 計 表");
CellStyle row1CellStyle = workbook.createCellStyle();
row1CellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
row1CellStyle.setAlignment(HorizontalAlignment.CENTER);
Font row1Font = workbook.createFont();
row1Font.setBold(true);
row1Font.setFontName("宋體");
row1Font.setFontHeightInPoints((short) 18);
row1CellStyle.setFont(row1Font);
row1Cell1.setCellStyle(row1CellStyle);
//合並單元格,起始行,結束行,起始列,結束列
sheet.addMergedRegionUnsafe(new CellRangeAddress(1, 1, 0, 5));
// sheet.addMergedRegionUnsafe(new CellRangeAddress(1, 1, 22, 23));
// 設置第二行標題
Row row2 = sheet.createRow(2);
row2.setHeight((short) 400);
Cell row2Cell1 = row2.createCell(0);
row2Cell1.setCellValue("時間范圍:"+ dataTime);
CellStyle row2CellStyle = workbook.createCellStyle();
row2CellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
row2CellStyle.setAlignment(HorizontalAlignment.RIGHT);
Font row2Font = workbook.createFont();
row2Font.setFontName("宋體");
row2Font.setFontHeightInPoints((short) 10);
row2CellStyle.setFont(row2Font);
row2Cell1.setCellStyle(row2CellStyle);
sheet.addMergedRegionUnsafe(new CellRangeAddress(2, 2, 0, 5));
}
}
自定義excel內容格式
DetectionCellStyleStrategy 類 自定義excel內容的樣式
public class DetectionCellStyleStrategy {
/**
* 導出excel時的樣式配置
*
* @param headFont
* contentFont字體大小
* @return
*/
public static HorizontalCellStyleStrategy getStyleStrategy(short headFont, short contentFont) {
// 頭的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景設置為灰色
// headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints(headFont);
// 字體樣式
headWriteFont.setFontName("宋體");
headWriteCellStyle.setWriteFont(headWriteFont);
// 自動換行
headWriteCellStyle.setWrapped(true);
// 水平對齊方式
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 垂直對齊方式
headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
headWriteCellStyle.setBorderLeft(BorderStyle.THIN);// 左邊框
headWriteCellStyle.setBorderTop(BorderStyle.THIN);// 上邊框
headWriteCellStyle.setBorderRight(BorderStyle.THIN);// 右邊框
headWriteCellStyle.setBorderBottom(BorderStyle.THIN);// 下邊框
// 內容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 這里需要指定 FillPatternType 為FillPatternType.SOLID_FOREGROUND 不然無法顯示背景顏色.頭默認了
// FillPatternType所以可以不指定
// contentWriteCellStyle.setFillPatternType(FillPatternType.SQUARES);
// 背景白色
contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
// 字體策略
WriteFont contentWriteFont = new WriteFont();
// 字體大小
contentWriteFont.setFontHeightInPoints(contentFont);
// 字體樣式
contentWriteFont.setFontName("宋體");
contentWriteCellStyle.setWriteFont(contentWriteFont);
// 自動換行
contentWriteCellStyle.setWrapped(true);
// 水平對齊方式
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 垂直對齊方式
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
// 這個策略是 頭是頭的樣式 內容是內容的樣式 其他的策略可以自己實現
return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
}
}
效果:

————————————————
版權聲明:本文為CSDN博主「笑依」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
參考原文鏈接:https://blog.csdn.net/weixin_50539367/article/details/108530250
合並行:
excelWriterBuilder
.registerWriteHandler(new CommentsCustomExcelHeader(excelName, createTime, lastCol))
.registerWriteHandler(new CommentsExcelStyleStrategy(new WriteCellStyle(), new WriteCellStyle()))
.registerWriteHandler(new CommentsExcelMergeStrategy(strategyMap))
.relativeHeadRowIndex(2)
.excelType(ExcelTypeEnum.XLSX);
package com.****.excel.write.style;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
import java.util.Map;
public class CommentsExcelMergeStrategy extends AbstractMergeStrategy { //需要合並的行:合並的開始,結束列 private Map<String, String> strategyMap; private Sheet sheet; public CommentsExcelMergeStrategy(Map<String, String> strategyMap) { this.strategyMap = strategyMap; } @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { this.sheet = sheet; if (cell.getRowIndex() >= 3 && cell.getColumnIndex() == 0) { /** * 保證每個cell被合並一次,如果不加上面的判斷,因為是一個cell一個cell操作的, * 例如合並A2:A3,當cell為A2時,合並A2,A3,但是當cell為A3時,又是合並A2,A3, * 但此時A2,A3已經是合並的單元格了 */ for (Map.Entry<String, String> entry : strategyMap.entrySet()) { System.out.println(entry.getKey()+",內容,"+entry.getValue()); if(entry.getKey().equals(cell.getRowIndex()+"")){ Integer rowIndex = Integer.valueOf(entry.getKey()); //添加一個合並請求 String startCol = entry.getValue().split(",")[0]; String endCol = entry.getValue().split(",")[1]; sheet.addMergedRegionUnsafe(new CellRangeAddress(rowIndex, rowIndex, Integer.parseInt(startCol), Integer.parseInt(endCol))); //設置樣式,加粗,靠左 CellStyle cellStyle = sheet.getWorkbook().createCellStyle(); Font font = sheet.getWorkbook().createFont(); cellStyle.setAlignment(HorizontalAlignment.LEFT); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); font.setBold(true); cellStyle.setFont(font); cell.setCellStyle(cellStyle); } } } } }
/**
* 橫行領導名稱合並單元格
*
* @param excelDtoList
* @return
*/
private Map<String, String> addMerStrategy(List<Object> excelDtoList, int endCol) {
Map<String, String> strategyMap = new HashMap<>();
//第0行是表頭
int startCol = 3;
String mapTest = "";
for (int i = 0; i < excelDtoList.size(); i++) {
ExportCommentsTaskExcelDTO commentsTaskExcelDTO = (ExportCommentsTaskExcelDTO) excelDtoList.get(i);
//從第二行開始判斷是否需要合並
if (StringUtils.contains(commentsTaskExcelDTO.getSortNum(), "(") && Objects.isNull(strategyMap.get(startCol+i))) {
mapTest = 0 + "," + endCol;
strategyMap.put(startCol + i + "", mapTest);
}
}
return strategyMap;
}
效果:

