掘金 后端 ( ) • 2024-04-14 09:53

前言

年后回来到三月底一直忙于项目,前段时间才稍微空闲下来。在这个项目中遇到了很多之前没有接触过的东西(虽然不是多高级的东西,但是也算是自己第一次使用),因此打算逐一记录下来,以便以后回看这段时光。

本篇内容主要记录对于EasyExcel的初次使用。

正篇

提到EasyExcel,大多数人都知道是用于生成Excel文件的,而无论是在项目中直接生成还是生成后提供下载,邮件发送等等场景,可以看到首先最重要的就是要生成一个Excel文件。所以,掌握文件的生成至关重要。

EasyExcel简单介绍: EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下,它支持读写百M级别的Excel文件。相较于其他Java领域的Excel解析、生成框架(如Apache POI、jxl等),EasyExcel以其使用简单和节省内存的特点而著称。
(没错,答案来自文心一言,别问我为什么是文心一言,因为不用每次都用登录~)

官方文档地址:https://easyexcel.opensource.alibaba.com/docs/current/
Github地址:https://github.com/alibaba/easyexcel

使用EasyExcel去生成具体的Excel文件可以有多种方式,下面记录我所用到的几种方式

1、使用注解生成

使用注解生成的方式很简单,根据要生成的文件定义不同的实体,在实体的不同属性上灵活运用相关注解就能达到目的,例如以下的列子:
目标生成文件内容截图

image.png
可以看到,表头是姓名,年龄,性别等,而表格里有两条记录。因此,结合官方文档,能够很容易得写出这个生成的代码,根据表头定义Person实体类
Person类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    @ExcelProperty("姓名")
    private String name;

    @ExcelProperty("住址")
    private String address;

    @ExcelProperty("性别")
    private String gender;

    @ExcelProperty("年龄")
    private int age;

    @ExcelProperty("工作单位")
    private String workPlace;
}  

上述代码可以看到每一个属性上面都有一个@ExcelProperty注解,结合表格的内容,可以看到注解的属性就是我们的表头的值
那么,如何结合这个生成一个文件呢,示例代码如下

public static void main(String[] args) {

    String fileName = "demoExcel.xlsx";
    EasyExcel.write(fileName, Person.class)
            .sheet()
            .doWrite(getPersonInfo());
}

public static List<Person> getPersonInfo() {
    List<Person> personList = Lists.newArrayList();
    Person person1 = new Person();
    person1.setName("张三");
    person1.setAge(23);
    person1.setGender("男");
    person1.setAddress("中国北京市");
    person1.setWorkPlace("保密单位");
    personList.add(person1);

    Person person2 = new Person();
    person2.setName("李四");
    person2.setAge(28);
    person2.setGender("男");
    person2.setAddress("中国上海市");
    person2.setWorkPlace("互联网公司");
    personList.add(person2);

    return personList;
}

生成效果如下:

image.png
当然,你会发现这里的表头样式和宽度等等都和最开始的模板不一致,这是因为EasyExcel在生产表头时有默认的规则和宽度,我们可以使用相关组件或内容去修改这些内容,例如,我们可以使用@ColumnWidth注解来指定当前表头所在的列的宽度是多少,例如:

@ExcelProperty("工作单位")
@ColumnWidth(15)
private String workPlace;

image.png
可以看到,最后一列的宽度得到了改变。什么?你发现列的顺序与模板的不一致,很好办,调整实体类的顺序就可以了。
这个时候有的人可能就会问到我已经有一个Person类了, 但是我里面有一些其他属性,在文件模板中又不想展示这个字段应该怎么办? 这点EasyExcel已经替我们想到了,使用@ExcelIgnore注解,该注解的作用就是在文件生成head(表头)的时候忽略该字段,不进行填充,例如在Person类中新增了一个属性salary,你会发现,如果我们不标记任何注解,那么生成出来的内容是下面这个

image.png
而我们又不想标识出来薪水,因此可以使用@ExcelIgnore注解来实现,例如

@ExcelIgnore
private String salary;

效果如下

image.png

好了,到这里,就介绍了简单形式的Excel的文件生成,当然,这里生成的是xlsx格式,我们也可以使用EasyExcel提供的ExcelTypeEnum来生产多种格式的文件,例如csv。只是文件格式不同,而根本上的生成文件的方式则是相同的

EasyExcel.write(fileName, Person.class).excelType(ExcelTypeEnum.CSV)
        .sheet()
        .doWrite(getPersonInfo());

2、动态表头生成

上面的内容提到过,如果我已经有一个实体类了,里面有一些字段能满足我目标生产文件的表头要求,但是有一些不需要,同时我也不能使用@ExcelIgnore注解,因为有其他场景也需要用到这些字段。
举个具体的例子,对于Person类,A场景需要使用到name,address,gender字段,而B场景需要用到name,age,wordPlace字段,因此不能简单的将不需要的字段标记@ExcelIgnore字段。这个时候可能有人想到的是那我多定义几个实体类,在生成文件时用不同的实体类去映射就行了,这么做固然可行,但是场景少还行,如果场景多,需要使用到的字段又比较零散,那么通过这种方式就要定义很多实体类,维护起来很麻烦,这个时候可以用到动态生成表头,下面是一个简单的示例

public static void main(String[] args) {
    String fileAName = System.currentTimeMillis() + "demoAExcel.xlsx" ;
    String fileBName = System.currentTimeMillis() + "demoBExcel.xlsx" ;
    // 定义场景A所需要的表头
    List<List<String>> headsA = Lists.newArrayList();
    List<String> columnsA1 = Lists.newArrayList("姓名");
    List<String> columnsA2 = Lists.newArrayList("住址");
    List<String> columnsA3 = Lists.newArrayList("性别");
    headsA.add(columnsA1);
    headsA.add(columnsA2);
    headsA.add(columnsA3);

    // 定义场景B所需要的表头
    List<List<String>> headsB = Lists.newArrayList();
    List<String> columnsB1 = Lists.newArrayList("姓名");
    List<String> columnsB2 = Lists.newArrayList("年龄");
    List<String> columnsB3 = Lists.newArrayList("工作单位");
    headsB.add(columnsB1);
    headsB.add(columnsB2);
    headsB.add(columnsB3);

    // 构造场景A所需要的数据
    List<List<String>> dataA = Lists.newArrayList();
    List<String> rowA1 = Lists.newArrayList("张三", "中国北京市", "男");
    List<String> rowA2 = Lists.newArrayList("李四", "中国上海市", "男");
    dataA.add(rowA1);
    dataA.add(rowA2);

    // 构造场景B所需要的数据
    List<List<String>> dataB = Lists.newArrayList();
    List<String> rowB1 = Lists.newArrayList("张三", "23", "保密单位");
    List<String> rowB2 = Lists.newArrayList("李四", "28", "互联网公司");
    dataB.add(rowB1);
    dataB.add(rowB2);

    // 生成场景A的文件
    EasyExcel.write(fileAName).sheet().head(headsA).doWrite(dataA);
    // 生成场景B的文件
    EasyExcel.write(fileBName).sheet().head(headsB).doWrite(dataB);
}

下面是两个场景的输出结果
A场景: image.png
B场景: image.png
可以看到根据不同的条件我们生成了不同的文件,避免了因过多创建不同的实体类而带来的维护问题。 当然这只是一个例子,真实使用中,我们需要通过待组装的列去对实体类进行反射,拿到具体的value,在组装成文件。

结尾

上述内容其实也不算复杂,只是由于本人第一次使用EasyExcel去完成某个具体的需求,因此记录下来当时的想法,并且也没有用到EasyExcel中多复杂的功能,希望能给那些第一次使用EasyExcel的朋友一点经验。也希望能看到本文章的大佬给一些指导建议,不胜感激!
后续会再整理一篇文章,用于记录使用EasyExcel来生成多sheet,稍微复杂点的文件。

不积跬步,无以至千里,不积小流,无以成江海。

相关内容