easyExcel工具

news/2024/12/5 7:16:52/

注解格式

 

通过注解定义格式是 EasyExcel 封装的高级功能,可以让我们很方便的定义格式。

格式化内容

先定义一个使用注解格式化内容的实体类:

@Data
public class FormatContentItem {
    @ExcelProperty(value = "字符串标题", converter = TitleFormatConverter.class)
    private String string;
    @DateTimeFormat("yyyy 年 MM 月 dd 日 HH 时 mm 分 ss 秒")
    @ExcelProperty(value = "日期标题")
    private Date date;
    @NumberFormat("0.000%")
    @ExcelProperty("数字标题")
    private Double doubleData;
}

其中DateTimeFormat和NumberFormat两个注解都是自带的注解,用于格式化时间和数字。

DateTimeFormat注解有两个属性,一个属性是value,用来定义时间格式,可以参考java.text.SimpleDateFormat;另一个属性是use1904windowing,表示使用时间使用 1904 时间系统还是 1900 时间系统,默认是否。

NumberFormat注解有两个属性,一个属性是value,用来定义数字格式,可以参考java.text.DecimalFormat;另一个属性是roundingMode,用来定义保留小数的方式,使用的是java.math.RoundingMode枚举。

想要格式化字符串,可以借助ExcelProperty的 converter 属性,这个属性传入实现Converter的类。比如示例中的TitleFormatConverter,代码如下:

public class TitleFormatConverter implements Converter<String> {
    @Override
    public Class<?> supportJavaTypeKey() {
        return String.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
            GlobalConfiguration globalConfiguration) {
        return new WriteCellData<>(String.format("标题:%s(自定义)", value));
    }

}

结果为:

 定义行高、列宽
使用注解定义行高的话,可以使用HeadRowHeight定义表头高度,使用ContentRowHeight定义表体高度,这个注解定义之后,所有表体高度都是相同的。列宽可以使用ColumnWidth注解定义,这个注解可以定义在类上,表示整个表格的列都一样宽,也可以定义的属性上,表示指定列的宽度。
@Data
@HeadRowHeight(20)
@ContentRowHeight(10)
@ColumnWidth(25)
public class FormatCellItem {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ColumnWidth(50)
    @ExcelProperty("数字标题")
    private Double doubleData;
}
结果为:

单元格定义样式
控制单元格样式有四个注解:HeadStyle、HeadFontStyle、ContentStyle、ContentFontStyle,这四个注解可以定义在类上作为全局表格的样式,也可以定义在字段上,作为当前列的样式。下面分别说一下这几个注解中比较常用的配置。

*Style:分为HeadStyle和ContentStyle,分别定义表头和表体样式
dataFormat:表头格式化,short 格式,是org.apache.poi.ss.usermodel.BuiltinFormats类中已定义格式的小标
border*:分别是 borderLeft、borderRight、borderTop、borderBottom 四个属性,类型是com.alibaba.excel.enums.poi.BorderStyleEnum枚举,用来定义表头单元格边框样式。边框的颜色也可以定义,使用、*BorderColor 定义即可。
fillPatternType:填充类型,类型是com.alibaba.excel.enums.poi.FillPatternTypeEnum枚举,如果想要填充背景色,这个属性需要设置为SOLID_FOREGROUND。
fillForegroundColor:前景色,类型是 short,值却是使用的org.apache.poi.ss.usermodel.IndexedColors枚举的 idx 值,只不过,两个类型不一致,一个是 short,一个是 int,没有办法直接引用。可见 java 中的依赖之间,还是有很多坑的。
fillBackgroundColor:背景色,同fillForegroundColor。
rotation:内容旋转角度
*FontStyle:有HeadFontStyle和ContentFontStyle,分别定义表头和表体的字体样式。
fontName:定义字体名称,类型字符串
fontHeightInPoints:字号大小,类型是 short
italic:是否斜体,类型是com.alibaba.excel.enums.BooleanEnum
bold:是否加粗,类型是com.alibaba.excel.enums.BooleanEnum
strikeout:是否使用删除线(这个词本意是三振出局的意思,应该是与棒球有关)
color:文本颜色,值使用的是org.apache.poi.ss.usermodel.IndexedColors,依然有类型不一致的情况
underline:下划线,类型是 byte,可以直接使用Font.U_NONE、Font.U_SINGLE、Font.U_DOUBLE、Font.U_SINGLE_ACCOUNTING、Font.U_DOUBLE_ACCOUNTING。
我们可以这么定义:
@Data
// 头背景设置成红色 IndexedColors.RED.getIndex()
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 10)
// 头字体设置成 20
@HeadFontStyle(fontHeightInPoints = 20)
// 内容的背景设置成绿色 IndexedColors.GREEN.getIndex()
@ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 17)
// 内容字体设置成 20
@ContentFontStyle(fontHeightInPoints = 20)
public class FormatStyleCellItem {
    // 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()
    @HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 14)
    // 字符串的头字体设置成 20
    @HeadFontStyle(fontHeightInPoints = 30)
    // 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()
    @ContentStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, fillForegroundColor = 40)
    // 字符串的内容字体设置成 20
    @ContentFontStyle(fontHeightInPoints = 30)
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
}
结果为:

类对象定义格式
这种方式可以说是纯手工组装数据了,使用的是com.alibaba.excel.metadata.data.WriteCellData类,这个类相当于是单元格的定义,通过设置com.alibaba.excel.enums.CellDataTypeEnum枚举类型的 type 属性,可以指明当前单元格格式。

守恒定律一直存在。这种方式灵活度很高,可以精细到具体的单元格格式,但是繁琐程度也增加了。

超链接
超链接使用的是com.alibaba.excel.metadata.data.HyperlinkData类,需要设置地址、超链类型(com.alibaba.excel.metadata.data.HyperlinkData.HyperlinkType枚举),然后将值写入到WriteCellData对象的hyperlinkData属性即可。

// 设置超链接
HyperlinkData hyperlinkData = new HyperlinkData();
hyperlinkData.setAddress("https://www.howardliu.cn");
hyperlinkData.setHyperlinkType(HyperlinkType.URL);
WriteCellData<String> hyperlink = new WriteCellData<>("网站");
hyperlink.setHyperlinkData(hyperlinkData);
备注
备注使用的是com.alibaba.excel.metadata.data.CommentData类,需要设置作者、备注内容(com.alibaba.excel.metadata.data.RichTextStringData类型),因为备注的默认大小是单元格大小,如果感觉太小,还可以设置相对高度和宽度。
// 设置备注
CommentData commentData = new CommentData();
commentData.setAuthor("Howard Liu");
commentData.setRichTextStringData(new RichTextStringData("这是一个备注"));
// 备注的默认大小是按照单元格的大小 这里想调整到 4 个单元格那么大 所以向后 向下 各额外占用了一个单元格
commentData.setRelativeLastColumnIndex(1);
commentData.setRelativeLastRowIndex(1);
WriteCellData<String> comment = new WriteCellData<>("备注的单元格信息");
comment.setCommentData(commentData);
公式

公式使用的是com.alibaba.excel.metadata.data.FormulaData类,可以直接设置formulaValue公式,不过官方不太推荐使用公式。

// 设置公式
FormulaData formulaData = new FormulaData();
// 将 123456789 中的第一个数字替换成 2
// 这里只是例子 如果真的涉及到公式 能内存算好尽量内存算好 公式能不用尽量不用
formulaData.setFormulaValue("REPLACE(123456789,1,1,2)");
WriteCellData<String> formula = new WriteCellData<>();
formula.setFormulaData(formulaData);
单元格格式
通过类定义单元格格式,与通过注解定义本质是一样的。所以与注解HeadStyle、HeadFontStyle、ContentStyle、ContentFontStyle对应,设置单元格格式的类是WriteCellStyle,设置字体的类是WriteFont。其中这些类的属性与注解的也是类似,不再赘述太多,直接上例子。(其实我觉得使用类定义格式的场景不多,真的碰到了,看看类定义就明白了)

// 设置单个单元格的样式 当然样式 很多的话 也可以用注解等方式。
WriteCellStyle writeCellStyleData = new WriteCellStyle();
// 这里需要指定 FillPatternType 为 FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色。
writeCellStyleData.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 背景绿色
writeCellStyleData.setFillForegroundColor(IndexedColors.GREEN.getIndex());
WriteCellData<String> writeCellStyle = new WriteCellData<>("单元格样式");
writeCellStyle.setWriteCellStyle(writeCellStyleData);
writeCellStyle.setType(CellDataTypeEnum.STRING);

// 设置单个单元格多种样式
RichTextStringData richTextStringData = new RichTextStringData();
richTextStringData.setTextString("红色绿色默认");
// 前 2 个字红色
WriteFont writeFont = new WriteFont();
writeFont.setColor(IndexedColors.RED.getIndex());
richTextStringData.applyFont(0, 2, writeFont);
// 接下来 2 个字绿色
writeFont = new WriteFont();
writeFont.setColor(IndexedColors.GREEN.getIndex());
richTextStringData.applyFont(2, 4, writeFont);
WriteCellData<String> richTest = new WriteCellData<>();
richTest.setType(CellDataTypeEnum.RICH_TEXT_STRING);
richTest.setRichTextStringDataValue(richTextStringData);
结果为:

拦截器定义格式
除了直接使用类定义格式,我们还可以借助拦截器实现。(这里在名称上会有一些歧义,所用的类对象命名都是 xxxStrategy,翻译过来就是 xxx 策略,但是官方对其命名为拦截器)

已有拦截器
前面示例中使用WriteCellStyle、WriteFont可以实现单元格的样式,如果想要实现整行数据都是相同的格式,可以借助com.alibaba.excel.write.style.HorizontalCellStyleStrategy拦截器。

/**
 * 使用已有策略实现自定义样式
 *
 * <ul>
 *     <li>HorizontalCellStyleStrategy 每一行的样式都一样 或者隔行一样</li>
 *     <li>AbstractVerticalCellStyleStrategy 每一列的样式都一样 需要自己回调每一页</li>
 * </ul>
 */
private static void writeByCellStyleStrategy() {
    String fileName = defaultFileName("writeByCellStyleStrategy");

    // 表头策略
    WriteCellStyle headWriteCellStyle = new WriteCellStyle();
    // 背景设置为红色
    headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
    WriteFont headWriteFont = new WriteFont();
    headWriteFont.setFontHeightInPoints((short) 40);
    headWriteCellStyle.setWriteFont(headWriteFont);

    // 表体策略
    WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
    // 这里需要指定 FillPatternType 为 FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色。表头默认了 FillPatternType 所以可以不指定
    contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    // 背景绿色
    contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
    WriteFont contentWriteFont = new WriteFont();
    // 字体大小
    contentWriteFont.setFontHeightInPoints((short) 20);
    contentWriteCellStyle.setWriteFont(contentWriteFont);

    // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
    HorizontalCellStyleStrategy horizontalCellStyleStrategy =
            new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

    // 这里 需要指定写用哪个 class 去写,然后写到第一个 sheet,名字为模板 然后文件流会自动关闭
    EasyExcelFactory.write(fileName)
            .head(Item.class)
            .registerWriteHandler(horizontalCellStyleStrategy)
            .sheet()
            .doWrite(sampleItems());
}
结果为:

 正如上面的结果,如果我们某个单元格数据比较长,可能会有遮挡,这个时候我们可以使用com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy实现自动列宽调整。不过这个不太精确,但聊胜于无。

 private static void writeUseLongestMatchColumnWidthStyleStrategy() {
    String fileName = defaultFileName("writeUseLongestMatchColumnWidthStyleStrategy");
    EasyExcelFactory.write(fileName)
            .head(Item.class)
            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
            .sheet()
            .doWrite(sampleItems());
}

结果为:

可以看到,确实不够精确。

自定义拦截器
上面展示的拦截器,都是实现了com.alibaba.excel.write.handler.WriteHandler接口,然后使用com.alibaba.excel.write.builder.AbstractExcelWriterParameterBuilder.registerWriteHandler方法注册到写函数中。所以,我们也可能根据需要,自己定义需要的拦截器。
这种自定义拦截器属于低级功能,需要了解很多底层设计和 API,鉴于篇幅,本文没有办法覆盖,这里只给出例子。如果有需要,可以留言沟通。

比如,我们需要某些单元格设置数据验证,展现形式就是下拉菜单,我们可以这样写:

public class ColumnValidationWriteHandler implements SheetWriteHandler {
    @Override
    public void afterSheetCreate(SheetWriteHandlerContext context) {
        // 区间设置 第一列第一行和第二行的数据。由于第一行是头,所以第一、二行的数据实际上是第二三行
        CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 2, 0, 0);
        DataValidationHelper helper = context.getWriteSheetHolder().getSheet().getDataValidationHelper();
        DataValidationConstraint constraint = helper.createExplicitListConstraint(new String[] {"测试 1", "测试 2"});
        DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
        context.getWriteSheetHolder().getSheet().addValidationData(dataValidation);
    }
}


如果我们需要将某个单元格的格式设置为超链,也可以使用拦截器:

public class CellStyleWriteHandler implements CellWriteHandler {
    @Override
    public void afterCellDispose(CellWriteHandlerContext context) {
        Cell cell = context.getCell();
        // 这里可以对 cell 进行任何操作
        if (BooleanUtils.isTrue(context.getHead()) && cell.getColumnIndex() == 0) {
            CreationHelper createHelper = context.getWriteSheetHolder().getSheet().getWorkbook().getCreationHelper();
            Hyperlink hyperlink = createHelper.createHyperlink(HyperlinkType.URL);
            hyperlink.setAddress("https://www.howardliu.cn");
            cell.setHyperlink(hyperlink);
        }
    }
}
结果为:

合并单元格
EasyExcel 提供的合并单元格功能比较简单,有两种方式:基于注解的合并、基于拦截器的合并。

注解
基于注解的合并单元格提供了两个注解:

OnceAbsoluteMerge注解实现指定位置的合并
ContentLoopMerge这个是内容的循环合并,指定某一列每几行合并。
// 将第 6-7 行的 2-3 列合并成一个单元格
@OnceAbsoluteMerge(firstRowIndex = 5, lastRowIndex = 6, firstColumnIndex = 1, lastColumnIndex = 2)
@Data
public class MergeCellItem {
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
}
结果为:

拦截器

拦截器合并也是有两种,对应着注解:

  • OnceAbsoluteMergeStrategy,相对位置合并
  • LoopMergeStrategy循环合并

 private static void writeMergeCellCustom() {
    String fileName = defaultFileName("writeMergeCellCustom");
    // 每隔 2 行会合并
    // 把 eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写
    LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
    EasyExcelFactory.write(fileName)
            .head(Item.class)
            .registerWriteHandler(loopMergeStrategy)
            .sheet()
            .doWrite(sampleItems());
}

结果为:

文末总结

本文从实战角度说了一下 EasyExcel 如果实现写出好看的表格,EasyExcel中提供了很多用于格式化的注解、拦截器,可以时薪通用的格式化输出,如果还有更加个性化的格式要求,也可以自定义拦截器实现。接下来聊一下如何填充模板。


版权声明:本文为CSDN博主「看山」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liuxinghao/article/details/120637460

想要完整源码,可以关注公号「看山的小屋」回复“easyexcel”获取。


http://www.ppmy.cn/news/429782.html

相关文章

EasyExcel合并表头,控制文字大小及样式处理

引入jar <!--引入 阿里的 easyexcel 如果报错 需要引入 asm jar--> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</ve…

table可编辑表格写法(简单)

1、添加JS $(".table").find(".dbclicktd").bind("dblclick", function () {var input "<input typetext idtemp stylewidth:130px; value" $(this).text() " >";$(this).text("");$(this).append(inpu…

EasyExcel复杂表头的生成方法

一.简介 本篇使用阿里EasyExcel框架&#xff0c;官方文档&#xff1a; https://github.com/alibaba/easyexcel <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version></depen…

easyx文字输出汇总

文章目录 前言一、outtextxy()输出文字字符要修改字符集 二、文字特效1.setbkmode设置文字背景2.settextcolor();设置文字颜色用RGB三原色设置用颜色常量3.settextstyle()设置文字样式大小 总结标题最后附上文字动态变色渐变放大输出的代码&#xff1a; 前言 在前面的一系列文…

excel制表基础:规范的制表理念和思路让效率提升 下篇

在日常工作中我们会构建很多的表格&#xff0c;其实这些表格无论多少&#xff0c;都可以归结为三大类&#xff0c;分别为“源数据表”、“关系信息表”和“统计分析表”。上次我们提到了一套表格“统计的核心”——“源数据表”&#xff0c;今天继续为大家分享“关系信息表”和…

动态表格功能

这里写目录标题 需求实现原理代码效果展示 需求 表格由专业班级学号1-10号同学的信息组成&#xff0c;包括:学号、姓名、性别、二级学院、班级、专业、辅导员: 表格的奇数行字体为黑色&#xff0c; 底色为白色&#xff1b;偶数行字体为白色&#xff0c; 底色为黑色: 表格的每…

excel制表基础:规范的制表理念和思路让效率提升 上篇

今天的文章是一篇理论文章&#xff0c;没有函数技巧讲解&#xff0c;没有酷炫图表实例&#xff0c;也没有神奇的VBA教程&#xff0c;如果你想学技巧&#xff0c;那这篇文章不适合你的要求。但是如果你想让自己在使用Excel方面更加地得心应手&#xff0c;能够让构建的表格提高我…

可编辑表格详解

1.html部分 <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-width, initial-scale1.0"…