青岛的网站设计公司,南宁网站设计建设,推广运营公司哪家好,南郊网站建设报价文章目录 前言一、自定义拦截器二、自定义操作1.自定义颜色2.合并单元格 三、复杂操作示例1.实体(使用了注解式样式)#xff1a;2.自定义拦截器3.代码4.最终效果 前言 本文简单介绍阿里的EasyExcel的复杂导出操作#xff0c;包括自定义样式#xff0c;根据数据合并单元格等。… 文章目录 前言一、自定义拦截器二、自定义操作1.自定义颜色2.合并单元格 三、复杂操作示例1.实体(使用了注解式样式)2.自定义拦截器3.代码4.最终效果 前言 本文简单介绍阿里的EasyExcel的复杂导出操作包括自定义样式根据数据合并单元格等。 点击查看EasyExcel官方文档 一、自定义拦截器
要实现复杂导出靠现有的拦截器怕是不大够用EasyExcel 已经有提供部分像是 自定义样式的策略HorizontalCellStyleStrategy 通过源码我们不难发现其原理正是实现了拦截器接口使用了afterCellDispose方法在数据写入单元格后会调用该方法因此需要进行复杂操作我们需要自定义拦截器在afterCellDispose方法进行逻辑处理其中我们可以通过context参数获取到表行列及单元格数据等信息
二、自定义操作
1.自定义颜色 由于WriteCellStyle 及CellStyle接口的设置单元格背景颜色方法setFillForegroundColor不支持自定义颜色我在网上找了半天以及询问阿里自家ai助手通义得到的答案都是往里塞一个XSSFColor这样的答案但这个方法传参是一个short类型的index呀是预设好的颜色里面也没有找到其他重载方法。这里针对的是导出xlsx文件 而真正可以自定义颜色的是XSSFCellStyle类XSSFCellStyle实现CellStyle接口并重载了该方法于是我们只需要在workbook.createCellStyle()的时候将其强转为XSSFCellStyle
// 将背景设置成浅蓝色
XSSFColor customColor new XSSFColor(new java.awt.Color(181, 198, 234), null);
XSSFCellStyle style (XSSFCellStyle)workbook.createCellStyle();
style.setFillForegroundColor(customColor);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cell.setCellStyle(style); 在idea我们可以使用 ctrl alt 鼠标点击接口来查看接口的所有实现类HSSF是针对xls的 然而在我们自定义的拦截器中操作当前单元格样式时会无法生效这是因为在3.1.x版本后有一个FillStyleCellWriteHandler拦截器他会把OriginCellStyle和WriteCellStyle合并会已WriteCellStyle样式为主他的order是50000而我们自定义的拦截器默认是0因此我们修改的样式会被覆盖。 解决方法很简单我们可以在我们的自定义拦截器重写order方法将其值设置大于50000即可 Overridepublic int order() {return 50001;}如果你没有使用自定义拦截器如HorizontalCellStyleStrategy 以及没有设置WriteCellStyle 样式则还可以将ignoreFillStyle置为true Overridepublic void afterCellDispose(CellWriteHandlerContext context) {context.setIgnoreFillStyle(true);// 做其他样式操作}
2.合并单元格 javaOverridepublic void afterCellDispose(CellWriteHandlerContext context) {// 判断当前为表头不执行操作if (isHead) {log.info(\r\n当前为表头, 不执行操作);return;}// 获取当前单元格context.getCell()// 当前 SheetSheet sheet cell.getSheet();// 当前单元格所在行索引int rowIndexCurr cell.getRowIndex();// 当前单元格所在列索引int columnIndex cell.getColumnIndex();// 当前单元格所在行的上一行索引int rowIndexPrev rowIndexCurr - 1;// 当前单元格所在行的 Row 对象Row rowCurr cell.getRow();// 当前单元格所在行的上一行 Row 对象Row rowPrev sheet.getRow(rowIndexPrev);// 当前单元格的上一行同列单元格Cell cellPrev rowPrev.getCell(columnIndex);// 合并同列不同行的相邻两个单元格sheet.addMergedRegion(new CellRangeAddress(rowIndexPrev, rowIndexCurr,columnIndex, columnIndex));}
需要注意的是如果要合并的单元格已经被其他单元格合并过则不能直接使用这个合并方法需要先解除合并再进行组合合并 // 从 Sheet 中获取所有合并区域ListCellRangeAddress mergedRegions sheet.getMergedRegions();// 判断是否合并过boolean merged false;// 遍历合并区域集合for (int i 0; i mergedRegions.size(); i) {CellRangeAddress cellAddresses mergedRegions.get(i);// 判断 cellAddress 的范围是否是从 rowIndexPrev 到 cell.getColumnIndex()if (cellAddresses.isInRange(rowIndexPrev, cell.getColumnIndex())) {// 解除合并sheet.removeMergedRegion(i);// 设置范围最后一行为当前行cellAddresses.setLastRow(rowIndexCurr);// 重新进行合并sheet.addMergedRegion(cellAddresses);merged true;break;}}// mergedfalse表示当前单元格为第一次合并if (!merged) {CellRangeAddress cellAddresses new CellRangeAddress(rowIndexPrev, rowIndexCurr, cell.getColumnIndex(), cell.getColumnIndex());sheet.addMergedRegion(cellAddresses);}
三、复杂操作示例
自定义拦截器代码如下示例
1.实体(使用了注解式样式)
package com.mhqs.demo.tool.easyExcel.entity;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentFontStyle;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;
import lombok.EqualsAndHashCode;import java.math.BigDecimal;/*** 账单实体类* author 棉花* */
Data
EqualsAndHashCode(callSuper false)
HeadFontStyle(fontHeightInPoints 10)
HeadRowHeight(27)
ColumnWidth(13)
ContentFontStyle(fontName 宋体,fontHeightInPoints 11)
public class DemoEntity extends EasyExcelEntity {ExcelProperty({账期})private String settlePeriod;ExcelProperty({服务商})private String stockCreatorMchid;ExcelProperty({地区})private String place;ExcelProperty({金额元})private BigDecimal consumeAmount;public DemoEntity(String settlePeriod, String stockCreatorMchid,String place, BigDecimal consumeAmount){this.settlePeriod settlePeriod;this.stockCreatorMchid stockCreatorMchid;this.place place;this.consumeAmount consumeAmount;}}
2.自定义拦截器
package com.mhqs.demo.tool.easyExcel.handler;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.mhqs.demo.tool.easyExcel.entity.DemoEntity;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;import java.math.BigDecimal;
import java.util.*;/*** author bcb* 账单导出样式处理*/
public class CustomCellWriteHandler implements CellWriteHandler {/*** 自定义颜色*/private final java.awt.Color color;/*** 自定义颜色样式*/private CellStyle colorfulCellStyle;/*** 自定义特殊金额样式*/private CellStyle specialCellStyle;/*** 头样式*/private final WriteCellStyle headWriteCellStyle;/*** 内容样式*/private final WriteCellStyle contentWriteCellStyle;/*** 头样式(可自定义颜色)*/private CellStyle headCellStyle;/*** 内容样式(可自定义颜色)*/private CellStyle contentCellStyle;public CustomCellWriteHandler(WriteCellStyle headWriteCellStyle,WriteCellStyle contentWriteCellStyle, java.awt.Color color) {this.headWriteCellStyle headWriteCellStyle;this.contentWriteCellStyle contentWriteCellStyle;this.color color;}Overridepublic void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {// 在创建单元格之前的操作如果需要Workbook workbook writeSheetHolder.getSheet().getWorkbook();if (colorfulCellStyle null) {colorfulCellStyle createColorfulCellStyle(workbook);}// 合并样式以WriteCellStyle为主headCellStyle StyleUtil.buildCellStyle(workbook, colorfulCellStyle, headWriteCellStyle);contentCellStyle StyleUtil.buildCellStyle(workbook, workbook.createCellStyle(), contentWriteCellStyle);}/** 创建自定义颜色样式*/private CellStyle createColorfulCellStyle(Workbook workbook) {XSSFColor customColor new XSSFColor(color, null);XSSFCellStyle style (XSSFCellStyle)workbook.createCellStyle();// 设置自定义颜色style.setFillForegroundColor(customColor);style.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 设置边框style.setBorderTop(BorderStyle.THIN);style.setBorderBottom(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);// 设置垂直对齐方式style.setVerticalAlignment(VerticalAlignment.CENTER);// 设置水平对齐方式style.setAlignment(HorizontalAlignment.CENTER);return style;}/** 创建自定义特殊金额样式*/private CellStyle createSpecialCellStyle(Workbook workbook) {if (specialCellStyle null) {XSSFCellStyle style (XSSFCellStyle)createColorfulCellStyle(workbook);Font font workbook.createFont();// 字体加粗font.setBold(true);style.setFont(font);specialCellStyle style;}return specialCellStyle;}/*** 在 Cell 写入后处理** param writeSheetHolder* param writeTableHolder* param cellDataList* param cell 当前 Cell* param head* param relativeRowIndex 表格内容行索引从除表头的第一行开始索引为0* param isHead 是否是表头true表头false非表头*/Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,ListWriteCellData? cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 当前 SheetSheet sheet cell.getSheet();// 判断当前为表头执行对应样式操作if (isHead) {cell.setCellStyle(headCellStyle);} else {cell.setCellStyle(contentCellStyle);}// 判断当前为表头不执行操作if (isHead || relativeRowIndex 0) {return;}int columnIndex cell.getColumnIndex();// 当前 Cell 所在行索引int rowIndexCurr cell.getRowIndex();// 当前 Cell 所在行的上一行索引int rowIndexPrev rowIndexCurr - 1;// 当前 Cell 所在行的 Row 对象Row rowCurr cell.getRow();// 当前 Cell 所在行的上一行 Row 对象Row rowPrev sheet.getRow(rowIndexPrev);// 当前单元格的上一行同列单元格Cell cellPrev rowPrev.getCell(columnIndex);// 当前单元格的值Object cellValueCurr cell.getCellType() CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();if (columnIndex 3 cellValueCurr ! null (double)cellValueCurr 200) {// 判断金额大于200就设置特定颜色并加粗并将上一列同一行的数据也设置特定颜色CellStyle cellStyle createSpecialCellStyle(sheet.getWorkbook());cell.setCellStyle(cellStyle);// 当前单元格的同行上一列单元格Cell cellPreC rowCurr.getCell(columnIndex - 1);cellPreC.setCellStyle(colorfulCellStyle);}// 上面单元格的值Object cellValuePrev cellPrev.getCellType() CellType.STRING ? cellPrev.getStringCellValue() : cellPrev.getNumericCellValue();/** 只判断前两列相同行数据*/if (columnIndex ! 0 columnIndex ! 1) {return;}// 判断当前单元格与上面单元格是否相等不相等不执行操作if (!cellValueCurr.equals(cellValuePrev)) {return;}/** 当第一列上下两个单元格不一样时说明不是一个账期数据*/if (!rowPrev.getCell(0).getStringCellValue().equals(rowCurr.getCell(0).getStringCellValue())) {return;}// 从 Sheet 中获取所有合并区域ListCellRangeAddress mergedRegions sheet.getMergedRegions();// 是否合并过boolean merged false;// 遍历合并区域集合for (int i 0; i mergedRegions.size(); i) {CellRangeAddress cellAddresses mergedRegions.get(i);//判断 cellAddress 的范围是否是从 rowIndexPrev 到 cell.getColumnIndex()if (cellAddresses.isInRange(rowIndexPrev, columnIndex)) {// 从集合中移除sheet.removeMergedRegion(i);// 设置范围最后一行为当前行cellAddresses.setLastRow(rowIndexCurr);// 重新添加到 Sheet 中sheet.addMergedRegion(cellAddresses);// 已完成合并merged true;break;}}// mergedfalse表示当前单元格为第一次合并if (!merged) {CellRangeAddress cellAddresses new CellRangeAddress(rowIndexPrev, rowIndexCurr, columnIndex, columnIndex);sheet.addMergedRegion(cellAddresses);}}/*** 获取当前处理器优先级*/Overridepublic int order() {return 50001;}}
3.代码
public static void main(String[] args) {String fileName D:\\temp\\账单.xlsx;// 设置 Cell 样式WriteCellStyle writeCellStyle new WriteCellStyle();// 设置垂直对齐方式writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 设置水平对齐方式writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);// 设置边框writeCellStyle.setBorderTop(BorderStyle.THIN);writeCellStyle.setBorderBottom(BorderStyle.THIN);writeCellStyle.setBorderLeft(BorderStyle.THIN);writeCellStyle.setBorderRight(BorderStyle.THIN);// 自定义颜色java.awt.Color color new java.awt.Color(181, 198, 234);ListDemoEntity dataList new ArrayList();for (int i 0; i 5; i) {dataList.add(new DemoEntity(202301,服务商 i%2,地区 i,new BigDecimal(i * 100)));}dataList.sort(Comparator.comparing(DemoEntity::getSettlePeriod).thenComparing(DemoEntity::getStockCreatorMchid));ExcelWriter excelWriter EasyExcel.write(fileName, DemoEntity.class).build();WriteSheet writeSheet EasyExcel.writerSheet(0, 账单).registerWriteHandler(new CustomCellWriteHandler(null,writeCellStyle,color)).build();excelWriter.write(dataList, writeSheet);// 需要多sheet则可以继续// WriteSheet writeSheet2 EasyExcel.writerSheet(1, 第二个sheet)excelWriter.finish();}
4.最终效果 待续… 参考文章 easyexcel 3.1.0设置RBG背景颜色 EasyExcel导出多sheet并设置单元格样式 EasyExcel的CellWriteHandler注入CellStyle不生效