文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

EasyExcel代码层面设置写出的Excel样式、以及拦截器策略的使用、自动列宽设置、EasyExcel默认设置详解

2023-10-10 21:35

关注

一、概述

虽然EasyExcel已经提供了一系列注解方式去设置样式。

但是如果没有实体类,或者想要更精确的去设置导出文件的Excel样式的时候就需要在代码层面去控制样式了。

二、使用已有拦截器自定义样式

主要步骤:

第一步是否需要创建Excel实体对象,得根据实际需求而定,如果导出字段不固定则使用无模型的方式即可

不使用实体类时可以直接传入ListString>>类型的数据来作为表头和数据内容。

2.1 定义一个Excel实体类

@Getter@Setter@EqualsAndHashCodepublic class DemoData {    @ExcelProperty("字符串")    private String string;    @ExcelProperty("日期")    private Date date;    @ExcelProperty("数字")    private Double doubleData;        @ExcelIgnore    private String ignore;}

2.2 设置表头样式

// 创建一个写出的单元格样式对象WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为红色headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());// 创建写出Excel的字体对象WriteFont headWriteFont = new WriteFont(); headWriteFont.setFontHeightInPoints((short)20);// 设置字体大小为20headWriteFont.setItalic(BooleanEnum.TRUE.getBooleanValue());// 设置字体斜体headWriteCellStyle.setWriteFont(headWriteFont);// 把字体对象设置到单元格样式对象中

2.3 设置内容样式

// 创建一个写出的单元格样式对象WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND// 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);// 设置内容背景色为绿色contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());// 边框设置contentWriteCellStyle.setBorderTop(BorderStyle.THIN); // 设置单元格上边框为细线contentWriteCellStyle.setBorderBottom(BorderStyle.THICK); // 设置单元格下边框为粗线contentWriteCellStyle.setBorderLeft(BorderStyle.MEDIUM);     // 设置单元格左边框为中线contentWriteCellStyle.setBorderRight(BorderStyle.MEDIUM_DASHED); // 设置单元格右边框为中虚线// 创建写出Excel的字体对象WriteFont contentWriteFont = new WriteFont();contentWriteFont.setFontHeightInPoints((short)20);  //设置字体大小contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); //设置文字居中contentWriteCellStyle.setWriteFont(contentWriteFont);  // 把字体对象设置到单元格样式对象中

2.4 使用EasyExcel默认的拦截器策略自定义样式

常见的策略有两种:

2.5 使用默认的拦截器HorizontalCellStyleStrategy自定义样式

// 完整代码@Testpublic void handlerStyleWrite() {    // 创建一个写出的单元格样式对象    WriteCellStyle headWriteCellStyle = new WriteCellStyle();    // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND    // 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定    contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);    // 设置内容背景色为绿色    contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());    // 边框设置    contentWriteCellStyle.setBorderTop(BorderStyle.THIN);// 设置单元格上边框为细线    contentWriteCellStyle.setBorderBottom(BorderStyle.THICK);// 设置单元格下边框为粗线    contentWriteCellStyle.setBorderLeft(BorderStyle.MEDIUM);    // 设置单元格左边框为中线    contentWriteCellStyle.setBorderRight(BorderStyle.MEDIUM_DASHED);//设置单元格右边框为中虚线    // 创建写出Excel的字体对象    WriteFont contentWriteFont = new WriteFont();    contentWriteFont.setFontHeightInPoints((short)20); //设置字体大小    contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);//设置文字居中    contentWriteCellStyle.setWriteFont(contentWriteFont);  // 把字体对象设置到单元格样式对象中        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现    HorizontalCellStyleStrategy horizontalCellStyleStrategy =        new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭    EasyExcel.write(fileName, DemoData.class)        .registerWriteHandler(horizontalCellStyleStrategy)        .sheet("horizontalCellStyleStrategy拦截器设置样式")        .doWrite(data());}

2.5 使用默认的拦截器AbstractVerticalCellStyleStrategy自定义样式

1)创建一个类实现AbstractVerticalCellStyleStrategy

public class CustomVerticalCellStyleStrategy extends AbstractVerticalCellStyleStrategy {    // 重写定义表头样式的方法    @Override    protected WriteCellStyle headCellStyle(Head head) {        WriteCellStyle writeCellStyle = new WriteCellStyle();        writeCellStyle.setFillBackgroundColor(IndexedColors.RED.getIndex());        WriteFont writeFont = new WriteFont();        writeFont.setColor(IndexedColors.RED.getIndex());        writeFont.setBold(false);        writeFont.setFontHeightInPoints(Short.valueOf((short)15));        writeCellStyle.setWriteFont(writeFont);        return writeCellStyle;    }    // 重写定义内容部分样式的方法    @Override    protected WriteCellStyle contentCellStyle(Head head) {        WriteCellStyle writeCellStyle = new WriteCellStyle();        writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);        writeCellStyle.setFillBackgroundColor(IndexedColors.GREEN.getIndex());        writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);        return writeCellStyle;    }}

这个方式在背景色设置方面存在问题,不知道是不是bug,这种方式还是慎用吧

2)具体使用

@Testpublic void handlerStyleWrite() {// 创建拦截器对象    CustomVerticalCellStyleStrategy customVerticalCellStyleStrategy         = new CustomVerticalCellStyleStrategy();    // 写出Excel    EasyExcel.write(fileName, DemoData.class)        .registerWriteHandler(customVerticalCellStyleStrategy)        .sheet("horizontalCellStyleStrategy拦截器设置样式")        .doWrite(data());}

三、自定义拦截器设置Excel样式

3.1 为什么不使用AbstractCellWriteHandler

老版本中自定义拦截器主要是继承 Easyexcel 的抽象类AbstractCellWriteHandler 控制器。

重写beforeCellCreate前置处理方法和afterCellDispose后置处理方法完成对应的方法达到控制单个单元格

样式的效果。但是AbstractCellWriteHandler这个抽象类在3.x版本已经被弃用,所以现在不推荐使用它。

3.2 实现CellWriteHandler接口

前面的两种方式,都只能在代码层面批量设置样式,而不能设置导出Excel中的一部分单元格样式。

实现这个接口后可以重写afterCellDispose方法来对单个单元格的样式进行设置。

每个单元格处理完毕之后都会调用它。

虽然文档中说不太推荐,可能是这里代码多了会影响性能,但是这是目前设置单个单元格最好的方式了。

3.1 基础使用

1)定义类实现CellWriteHandler接口,并重写afterCellDispose方法

public class CustomCellWriteStrategy implements CellWriteHandler {    // 在单元格处理之后执行    @Override    public void afterCellDispose(CellWriteHandlerContext context) {        // 当前事件会在 数据设置到poi的cell里面才会回调        // 判断不是头的情况 如果是fill 的情况 这里会==null 所以用not true        if (BooleanUtils.isNotTrue(context.getHead())) {            // 获取第一个单元格对象            // 只要不是头 一定会有数据 当然fill(填充)的情况 可能要context.getCellDataList()             // 这个需要看模板,因为一个单元格会有多个 WriteCellData            WriteCellData<?> cellData = context.getFirstCellData();                        // cellData 可以获取样式/数据,也可以直接设置样式/数据,设置后会立即生效            // 这里也需要用cellData去获取样式            // 很重要的一个原因是 WriteCellStyle 和 dataFormatData绑定的             // 简单的说 比如你加了 DateTimeFormat,已经将writeCellStyle里面的dataFormatData改了   // 如果你自己new了一个WriteCellStyle,可能注解的样式就失效了            // 然后getOrCreateStyle 用于返回一个样式,如果为空,则创建一个后返回            // (总之记住用这个方法获取样式即可)            WriteCellStyle writeCellStyle = cellData.getOrCreateStyle();            writeCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());            // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND            // 要不然背景色不会生效            writeCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);                        // 获取当前单元格的数据,必要的时候可以根据数据来设置单元格的颜色            // 比如当前列为状态列,数据为1是正常,背景色为绿色,反正不正常,背景色设置为红            // 这种需求的实现将变得可能            Object data = cellData.getStringValue();            System.out.println("data: " + data);                        // 这样样式就设置好了 后面有个FillStyleCellWriteHandler 默认会将 WriteCellStyle 设置 到 cell里面去 所以可以不用管了        }    }}

2)写出Excel时注册处理策略

@Testpublic void handlerStyleWrite() {// 创建处理器策略对象    CustomCellWriteStrategy customCellWriteStrategy = new CustomCellWriteStrategy();    // 写出Excel    EasyExcel.write(fileName, DemoData.class)        .registerWriteHandler(customCellWriteStrategy)        .sheet("自定义单个单元格样式演示")        .doWrite(data());}

四、设置列宽

有实体类的时候,可以使用注解去设置列宽,但是如果是那种无模型的,又该怎么去设置列宽呢。

官方提供的LongestMatchColumnWidthStyleStrategy

4.1 AbstractColumnWidthStyleStrategy

1)基础写法

定义一个类,去继承AbstractColumnWidthStyleStrategy这个抽象类,并且重写里面的setColumnWidth方法

public class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {        @Override    protected void setColumnWidth(WriteSheetHolder writeSheetHolder,      List<WriteCellData<?>> cellDataList,      Cell cell,      Head head,      Integer relativeRowIndex,      Boolean isHead) {        // 使用sheet对象 简单设置 index所对应的列的列宽        Sheet sheet = writeSheetHolder.getSheet();        sheet.setColumnWidth(cell.getColumnIndex(), 5000);    }}

每处理一个单元格都会调用一次setColumnWidth方法,这个方法有两种重载,重写哪一个都行。

2)自适应列宽写法

public class ExcelWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {     // 单元格的最大宽度    private static final int MAX_COLUMN_WIDTH = 50;                       // 缓存(第一个Map的键是sheet的index, 第二个Map的键是列的index, 值是数据长度)    private  Map<Integer, Map<Integer, Integer>> CACHE = new HashMap(8);        // 重写设置列宽的方法    @Override    protected void setColumnWidth(WriteSheetHolder writeSheetHolder,       List<WriteCellData<?>> cellDataList,       Cell cell,       Head head,       Integer relativeRowIndex,       Boolean isHead) {        boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList);        // 当时表头或者单元格数据列表有数据时才进行处理        if (needSetWidth) {            Map<Integer, Integer> maxColumnWidthMap =                 CACHE.get(writeSheetHolder.getSheetNo());                        if (maxColumnWidthMap == null) {                maxColumnWidthMap = new HashMap(16);                CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);            }            // 获取数据长度            Integer columnWidth = this.getLength(cellDataList, cell, isHead);            if (columnWidth >= 0) {                if (columnWidth > MAX_COLUMN_WIDTH) {                    columnWidth = MAX_COLUMN_WIDTH;                }                // 确保一个列的列宽以表头为主,如果表头已经设置了列宽,单元格将会跟随表头的列宽                Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex());    if (maxColumnWidth == null || columnWidth > maxColumnWidth) {                    maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);                    // 如果使用EasyExcel默认表头,那么使用columnWidth * 512                    // 如果不使用EasyExcel默认表头,那么使用columnWidth * 256                    // 如果是自己定义的字体大小,可以再去测试这个参数常量                    writeSheetHolder                        .getSheet()                        .setColumnWidth(cell.getColumnIndex(), columnWidth * 512);                }            }        }    }        private Integer dataLength(List<WriteCellData<?>> cellDataList,    Cell cell,    Boolean isHead) {        if (isHead) {            return cell.getStringCellValue().getBytes().length;        } else {            WriteCellData cellData = cellDataList.get(0);            CellDataTypeEnum type = cellData.getType();            if (type == null) {                return -1;            } else {                switch(type) {                    case STRING:                        return cellData.getStringValue().getBytes().length;                    case BOOLEAN:                        return cellData.getBooleanValue().toString().getBytes().length;                    case NUMBER:                        return cellData.getNumberValue().toString().getBytes().length;                    default:                        return -1;                }            }        }    }}

可以根据自己的需求自行改造

4.2 写出Excel时注册处理策略

@Testpublic void handlerStyleWrite() {// 创建处理器策略对象    ExcelWidthStyleStrategy excelWidthStyleStrategy = new ExcelWidthStyleStrategy();    // 写出Excel    EasyExcel.write(fileName, DemoData.class)        .registerWriteHandler(excelWidthStyleStrategy)        .sheet("单个单元格列宽设置")        .doWrite(data());}

五、EasyExcel其它默认设置

5.1 表头自动合并

EasyExcel.write(response.getOutputStream(), DemoData.class)            .automaticMergeHead(false) // 自动合并表头            .sheet("模板")            .doWrite(demoData);

automaticMergeHead设置为true,那么对于相邻表格中存在相同内容单元格,easyexcel会自动将其合并。

它的默认值也是true

如果不想使用表头自动合并,就设置为false即可。

5.2 取消导出Excel的默认风格

EasyExcel.write(response.getOutputStream(), DemoData.class)            .useDefaultStyle(false) // 取消导出Excel的默认风格            .sheet("模板")            .doWrite(demoData);

easyexcel的默认风格是最明显的体现,对于表头会显示灰色背景,并且字体会加粗和放大。

在这里插入图片描述

如果不想使用这个默认风格,把useDefaultStyle设置为false即可。

5.3 是否使用1904日期窗口

EasyExcel.write(response.getOutputStream(), DemoData.class)            .use1904windowing(true) // 设置使用1904的时间格式            .sheet("模板")            .doWrite(demoData);

EasyExcel中时间是存储1900年起的一个双精度浮点数。一般也是使用1900的时间格式就可以了。

如果有业务想把开始日期改为1904,就可以设置use1904windowingtrue即可。

来源地址:https://blog.csdn.net/qq_44749491/article/details/127917454

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯