【EasyExcel】复杂导出操作-自界说颜色样式等(版本3.1.x) ...

打印 上一主题 下一主题

主题 1707|帖子 1707|积分 5121


前言

   本文简单先容阿里的EasyExcel的复杂导出操作,包括自界说样式,根据数据合并单元格等。
  点击查看EasyExcel官方文档

一、自界说拦截器

要实现复杂导出,靠现有的拦截器怕是不大够用,EasyExcel 已经有提供部分像是 自界说样式的策略HorizontalCellStyleStrategy


通过源码,我们不难发现其原理正是实现了拦截器接口,使用了afterCellDispose方法,在数据写入单元格后会调用该方法,因此,需要举行复杂操作,我们需要自界说拦截器,在afterCellDispose方法举行逻辑处置惩罚,此中我们可以通过context参数获取到表,行,列及单元格数据等信息:

二、自界说操作

1.自界说颜色

   由于WriteCellStyle 及CellStyle接口的设置单元格配景颜色方法setFillForegroundColor不支持自界说颜色,我在网上找了半天,以及询问阿里自家ai助手通义得到的答案都是往里塞一个XSSFColor这样的答案,但这个方法传参是一个short类型的index呀,是预设好的颜色,内里也没有找到其他重载方法。(这里针对的是导出xlsx文件)
  

而真正可以自界说颜色的是XSSFCellStyle类,XSSFCellStyle实现CellStyle接口,并重载了该方法,于是我们只需要在workbook.createCellStyle()的时间将其强转为XSSFCellStyle:
  1. // 将背景设置成浅蓝色
  2. XSSFColor customColor = new XSSFColor(new java.awt.Color(181, 198, 234), null);
  3. XSSFCellStyle style = (XSSFCellStyle)workbook.createCellStyle();
  4. style.setFillForegroundColor(customColor);
  5. style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  6. cell.setCellStyle(style);
复制代码
  在idea我们可以使用 ctrl + alt + 鼠标点击接口,来查看接口的全部实现类(HSSF是针对xls的):
  

然而在我们自界说的拦截器中,操作当前单元格样式时会无法见效,这是由于在3.1.x版本后有一个FillStyleCellWriteHandler拦截器,他会把OriginCellStyle和WriteCellStyle合并,会已WriteCellStyle样式为主,他的order是50000,而我们自界说的拦截器默认是0,因此我们修改的样式会被覆盖。


解决方法很简单,我们可以在我们的自界说拦截器重写order方法,将其值设置大于50000即可
  1.   @Override
  2.   public int order() {
  3.       return 50001;
  4.   }
复制代码
如果你没有使用自界说拦截器(如HorizontalCellStyleStrategy )以及没有设置WriteCellStyle 样式,则还可以将ignoreFillStyle置为true,
  1. @Override
  2. public void afterCellDispose(CellWriteHandlerContext context) {
  3.          context.setIgnoreFillStyle(true);
  4.          // 做其他样式操作
  5. }
复制代码
2.合并单元格

  1. ```java
  2. @Override
  3. public void afterCellDispose(CellWriteHandlerContext context) {
  4.          // 判断当前为表头,不执行操作
  5.      if (isHead) {
  6.             log.info("\r\n当前为表头, 不执行操作");
  7.             return;
  8.      }
  9.      // 获取当前单元格
  10.      context.getCell()
  11.      // 当前 Sheet
  12.      Sheet sheet = cell.getSheet();
  13.      // 当前单元格所在行索引
  14.      int rowIndexCurr = cell.getRowIndex();
  15.      // 当前单元格所在列索引
  16.      int columnIndex = cell.getColumnIndex();
  17.      // 当前单元格所在行的上一行索引
  18.      int rowIndexPrev = rowIndexCurr - 1;
  19.      // 当前单元格所在行的 Row 对象
  20.      Row rowCurr = cell.getRow();
  21.      // 当前单元格所在行的上一行 Row 对象
  22.      Row rowPrev = sheet.getRow(rowIndexPrev);
  23.      // 当前单元格的上一行同列单元格
  24.      Cell cellPrev = rowPrev.getCell(columnIndex);
  25.          // 合并同列不同行的相邻两个单元格
  26.      sheet.addMergedRegion(new CellRangeAddress(rowIndexPrev, rowIndexCurr,columnIndex, columnIndex));
  27.          
  28. }
复制代码
需要注意的是,如果要合并的单元格已经被其他单元格合并过,则不能直接使用这个合并方法,需要先解除合并,再举行组合合并:
  1. // 从 Sheet 中,获取所有合并区域
  2. List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
  3. // 判断是否合并过
  4. boolean merged = false;
  5. // 遍历合并区域集合
  6. for (int i = 0; i < mergedRegions.size(); i++) {
  7.      CellRangeAddress cellAddresses = mergedRegions.get(i);
  8.      // 判断 cellAddress 的范围是否是从 rowIndexPrev 到 cell.getColumnIndex()
  9.      if (cellAddresses.isInRange(rowIndexPrev, cell.getColumnIndex())) {
  10.          // 解除合并
  11.          sheet.removeMergedRegion(i);
  12.          // 设置范围最后一行,为当前行
  13.          cellAddresses.setLastRow(rowIndexCurr);
  14.          // 重新进行合并
  15.          sheet.addMergedRegion(cellAddresses);
  16.          merged = true;
  17.          break;
  18.      }
  19. }
  20. // merged=false,表示当前单元格为第一次合并
  21. if (!merged) {
  22.      CellRangeAddress cellAddresses = new CellRangeAddress(rowIndexPrev, rowIndexCurr, cell.getColumnIndex(), cell.getColumnIndex());
  23.      sheet.addMergedRegion(cellAddresses);
  24. }
复制代码
三、复杂操作示例

自界说拦截器代码如下(示例):
1.实体(使用了注解式样式):

  1. package com.mhqs.demo.tool.easyExcel.entity;
  2. import com.alibaba.excel.annotation.ExcelProperty;
  3. import com.alibaba.excel.annotation.write.style.ColumnWidth;
  4. import com.alibaba.excel.annotation.write.style.ContentFontStyle;
  5. import com.alibaba.excel.annotation.write.style.HeadFontStyle;
  6. import com.alibaba.excel.annotation.write.style.HeadRowHeight;
  7. import lombok.Data;
  8. import lombok.EqualsAndHashCode;
  9. import java.math.BigDecimal;
  10. /**
  11. * 账单实体类
  12. * @author 棉花
  13. * */
  14. @Data
  15. @EqualsAndHashCode(callSuper = false)
  16. @HeadFontStyle(fontHeightInPoints = 10)
  17. @HeadRowHeight(27)
  18. @ColumnWidth(13)
  19. @ContentFontStyle(fontName = "宋体",fontHeightInPoints = 11)
  20. public class DemoEntity extends EasyExcelEntity {
  21.     @ExcelProperty({"账期"})
  22.     private String settlePeriod;
  23.     @ExcelProperty({"服务商"})
  24.     private String stockCreatorMchid;
  25.     @ExcelProperty({"地区"})
  26.     private String place;
  27.     @ExcelProperty({"金额(元)"})
  28.     private BigDecimal consumeAmount;
  29.     public DemoEntity(String settlePeriod, String stockCreatorMchid,String place, BigDecimal consumeAmount){
  30.         this.settlePeriod = settlePeriod;
  31.         this.stockCreatorMchid = stockCreatorMchid;
  32.         this.place = place;
  33.         this.consumeAmount = consumeAmount;
  34.     }
  35. }
复制代码
2.自界说拦截器

  1. package com.mhqs.demo.tool.easyExcel.handler;
  2. import com.alibaba.excel.EasyExcel;
  3. import com.alibaba.excel.ExcelWriter;
  4. import com.alibaba.excel.metadata.Head;
  5. import com.alibaba.excel.metadata.data.WriteCellData;
  6. import com.alibaba.excel.util.StyleUtil;
  7. import com.alibaba.excel.write.handler.CellWriteHandler;
  8. import com.alibaba.excel.write.metadata.WriteSheet;
  9. import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
  10. import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
  11. import com.alibaba.excel.write.metadata.style.WriteCellStyle;
  12. import com.mhqs.demo.tool.easyExcel.entity.DemoEntity;
  13. import org.apache.poi.ss.usermodel.*;
  14. import org.apache.poi.ss.util.CellRangeAddress;
  15. import org.apache.poi.xssf.usermodel.XSSFCellStyle;
  16. import org.apache.poi.xssf.usermodel.XSSFColor;
  17. import java.math.BigDecimal;
  18. import java.util.*;
  19. /**
  20. * @author bcb
  21. * 账单导出样式处理
  22. */
  23. public class CustomCellWriteHandler implements CellWriteHandler {
  24.     /**
  25.      * 自定义颜色
  26.      */
  27.     private final java.awt.Color color;
  28.     /**
  29.      * 自定义颜色样式
  30.      */
  31.     private CellStyle colorfulCellStyle;
  32.     /**
  33.      * 自定义特殊金额样式
  34.      */
  35.     private CellStyle specialCellStyle;
  36.     /**
  37.      * 头样式
  38.      */
  39.     private final WriteCellStyle headWriteCellStyle;
  40.     /**
  41.      * 内容样式
  42.      */
  43.     private final WriteCellStyle contentWriteCellStyle;
  44.     /**
  45.      * 头样式(可自定义颜色)
  46.      */
  47.     private CellStyle headCellStyle;
  48.     /**
  49.      * 内容样式(可自定义颜色)
  50.      */
  51.     private CellStyle contentCellStyle;
  52.     public CustomCellWriteHandler(WriteCellStyle headWriteCellStyle,WriteCellStyle contentWriteCellStyle, java.awt.Color color) {
  53.         this.headWriteCellStyle = headWriteCellStyle;
  54.         this.contentWriteCellStyle = contentWriteCellStyle;
  55.         this.color = color;
  56.     }
  57.     @Override
  58.     public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
  59.         // 在创建单元格之前的操作(如果需要)
  60.         Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
  61.         if (colorfulCellStyle == null) {
  62.             colorfulCellStyle = createColorfulCellStyle(workbook);
  63.         }
  64.         // 合并样式(以WriteCellStyle为主)
  65.         headCellStyle = StyleUtil.buildCellStyle(workbook, colorfulCellStyle, headWriteCellStyle);
  66.         contentCellStyle = StyleUtil.buildCellStyle(workbook, workbook.createCellStyle(), contentWriteCellStyle);
  67.     }
  68.     /*
  69.     * 创建自定义颜色样式
  70.     */
  71.     private CellStyle createColorfulCellStyle(Workbook workbook) {
  72.         XSSFColor customColor = new XSSFColor(color, null);
  73.         XSSFCellStyle style = (XSSFCellStyle)workbook.createCellStyle();
  74.         // 设置自定义颜色
  75.         style.setFillForegroundColor(customColor);
  76.         style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
  77.         // 设置边框
  78.         style.setBorderTop(BorderStyle.THIN);
  79.         style.setBorderBottom(BorderStyle.THIN);
  80.         style.setBorderLeft(BorderStyle.THIN);
  81.         style.setBorderRight(BorderStyle.THIN);
  82.         // 设置垂直对齐方式
  83.         style.setVerticalAlignment(VerticalAlignment.CENTER);
  84.         // 设置水平对齐方式
  85.         style.setAlignment(HorizontalAlignment.CENTER);
  86.         return style;
  87.     }
  88.     /*
  89.      * 创建自定义特殊金额样式
  90.      */
  91.     private CellStyle createSpecialCellStyle(Workbook workbook) {
  92.         if (specialCellStyle == null) {
  93.             XSSFCellStyle style = (XSSFCellStyle)createColorfulCellStyle(workbook);
  94.             Font font = workbook.createFont();
  95.             // 字体加粗
  96.             font.setBold(true);
  97.             style.setFont(font);
  98.             specialCellStyle = style;
  99.         }
  100.         return specialCellStyle;
  101.     }
  102.     /**
  103.      * 在 Cell 写入后处理
  104.      *
  105.      * @param writeSheetHolder
  106.      * @param writeTableHolder
  107.      * @param cellDataList
  108.      * @param cell               当前 Cell
  109.      * @param head
  110.      * @param relativeRowIndex   表格内容行索引,从除表头的第一行开始,索引为0
  111.      * @param isHead             是否是表头,true表头,false非表头
  112.      */
  113.     @Override
  114.     public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
  115.                                  List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
  116.         // 当前 Sheet
  117.         Sheet sheet = cell.getSheet();
  118.         // 判断当前为表头,执行对应样式操作
  119.         if (isHead) {
  120.             cell.setCellStyle(headCellStyle);
  121.         } else {
  122.             cell.setCellStyle(contentCellStyle);
  123.         }
  124.         // 判断当前为表头,不执行操作
  125.         if (isHead || relativeRowIndex == 0) {
  126.             return;
  127.         }
  128.         int columnIndex = cell.getColumnIndex();
  129.         // 当前 Cell 所在行索引
  130.         int rowIndexCurr = cell.getRowIndex();
  131.         // 当前 Cell 所在行的上一行索引
  132.         int rowIndexPrev = rowIndexCurr - 1;
  133.         // 当前 Cell 所在行的 Row 对象
  134.         Row rowCurr = cell.getRow();
  135.         // 当前 Cell 所在行的上一行 Row 对象
  136.         Row rowPrev = sheet.getRow(rowIndexPrev);
  137.         // 当前单元格的上一行同列单元格
  138.         Cell cellPrev = rowPrev.getCell(columnIndex);
  139.         // 当前单元格的值
  140.         Object cellValueCurr = cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
  141.         if (columnIndex == 3 && cellValueCurr != null && (double)cellValueCurr > 200) {
  142.             // 判断金额大于200就设置特定颜色并加粗,并将上一列同一行的数据也设置特定颜色
  143.             CellStyle cellStyle = createSpecialCellStyle(sheet.getWorkbook());
  144.             cell.setCellStyle(cellStyle);
  145.             // 当前单元格的同行上一列单元格
  146.             Cell cellPreC = rowCurr.getCell(columnIndex - 1);
  147.             cellPreC.setCellStyle(colorfulCellStyle);
  148.         }
  149.         // 上面单元格的值
  150.         Object cellValuePrev = cellPrev.getCellType() == CellType.STRING ? cellPrev.getStringCellValue() : cellPrev.getNumericCellValue();
  151.         /*
  152.          * 只判断前两列相同行数据
  153.          */
  154.         if (columnIndex != 0 && columnIndex != 1) {
  155.             return;
  156.         }
  157.         // 判断当前单元格与上面单元格是否相等,不相等不执行操作
  158.         if (!cellValueCurr.equals(cellValuePrev)) {
  159.             return;
  160.         }
  161.         /*
  162.          * 当第一列上下两个单元格不一样时,说明不是一个账期数据
  163.          */
  164.         if (!rowPrev.getCell(0).getStringCellValue().equals(rowCurr.getCell(0).getStringCellValue())) {
  165.             return;
  166.         }
  167.         // 从 Sheet 中,获取所有合并区域
  168.         List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
  169.         // 是否合并过
  170.         boolean merged = false;
  171.         // 遍历合并区域集合
  172.         for (int i = 0; i < mergedRegions.size(); i++) {
  173.             CellRangeAddress cellAddresses = mergedRegions.get(i);
  174.             //判断 cellAddress 的范围是否是从 rowIndexPrev 到 cell.getColumnIndex()
  175.             if (cellAddresses.isInRange(rowIndexPrev, columnIndex)) {
  176.                 // 从集合中移除
  177.                 sheet.removeMergedRegion(i);
  178.                 // 设置范围最后一行,为当前行
  179.                 cellAddresses.setLastRow(rowIndexCurr);
  180.                 // 重新添加到 Sheet 中
  181.                 sheet.addMergedRegion(cellAddresses);
  182.                 // 已完成合并
  183.                 merged = true;
  184.                 break;
  185.             }
  186.         }
  187.         // merged=false,表示当前单元格为第一次合并
  188.         if (!merged) {
  189.             CellRangeAddress cellAddresses = new CellRangeAddress(rowIndexPrev, rowIndexCurr, columnIndex, columnIndex);
  190.             sheet.addMergedRegion(cellAddresses);
  191.         }
  192.     }
  193.     /**
  194.      * 获取当前处理器优先级
  195.      */
  196.     @Override
  197.     public int order() {
  198.         return 50001;
  199.     }
  200. }
复制代码
3.代码

  1.   public static void main(String[] args) {
  2.       String fileName = "D:\\temp\\账单.xlsx";
  3.       // 设置 Cell 样式
  4.       WriteCellStyle writeCellStyle = new WriteCellStyle();
  5.       // 设置垂直对齐方式
  6.       writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  7.       // 设置水平对齐方式
  8.       writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
  9.       // 设置边框
  10.       writeCellStyle.setBorderTop(BorderStyle.THIN);
  11.       writeCellStyle.setBorderBottom(BorderStyle.THIN);
  12.       writeCellStyle.setBorderLeft(BorderStyle.THIN);
  13.       writeCellStyle.setBorderRight(BorderStyle.THIN);
  14.       // 自定义颜色
  15.       java.awt.Color color = new java.awt.Color(181, 198, 234);
  16.       List<DemoEntity> dataList = new ArrayList<>();
  17.       for (int i = 0; i < 5; i++) {
  18.           dataList.add(new DemoEntity("202301","服务商" + i%2,"地区" + i,new BigDecimal(i * 100)));
  19.       }
  20.       dataList.sort(Comparator.comparing(DemoEntity::getSettlePeriod).thenComparing(DemoEntity::getStockCreatorMchid));
  21.       ExcelWriter excelWriter = EasyExcel.write(fileName, DemoEntity.class).build();
  22.       WriteSheet writeSheet = EasyExcel.writerSheet(0, "账单")
  23.               .registerWriteHandler(new CustomCellWriteHandler(null,writeCellStyle,color))
  24.               .build();
  25.       excelWriter.write(dataList, writeSheet);
  26.         // 需要多sheet则可以继续
  27.         // WriteSheet writeSheet2 = EasyExcel.writerSheet(1, "第二个sheet")
  28.       excelWriter.finish();
  29.   }
复制代码
4.终极效果


待续…

参考文章:
easyexcel 3.1.0+,设置RBG配景颜色
EasyExcel导出多sheet并设置单元格样式
EasyExcel的CellWriteHandler注入CellStyle不见效

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

何小豆儿在此

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表