Java 使用 EasyExcel 导出基本使用方法


共计 7390 个字符,预计需要花费 19 分钟才能阅读完成。

工作中要说用到 excel 的情况说多也不多,说少也不少,但是很多次遇到似乎都要去查一遍 EasyExcel 的用法,所以这里把经常用到的注解记录一下。

1. 基本导出

1.1 指定标题

常规导出情况下,只需要指定单元格头部标题,和忽略部分字段即可。

public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

1.2 指定行高和列宽

行高和列宽可以先对所有字段统一设置,再根据每个字段具体调整。

// 指定头部行高、内容行高和宽度
@HeadRowHeight(20)
@ContentRowHeight(10)
@ColumnWidth(25)
public class WidthAndHeightData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    /**
     * 宽度为50
     */
    @ColumnWidth(50)
    @ExcelProperty("数字标题")
    private Double doubleData;
}

2. 指定字段排序和导出内容

2.1 指定字段排序

可以设置 index 或者 order 来指定字段所在的列。

@ExcelProperty(value = "字符串标题", index = 0)
private String string;
// 使用 order 的好处是,当排除字段时不会出现空行
@ExcelProperty(value = "字符串标题", order = 0)
private String string;

2.2 指定导出字段

// 根据用户传入字段 假设我们只要导出 date
Set<String> includeColumnFieldNames = new HashSet<>();
includeColumnFieldNames.add("date");
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).includeColumnFieldNames(includeColumnFieldNames).sheet("模板")
    .doWrite(data());

2.3 指定排除字段

// 根据用户传入字段 假设我们要忽略 date
Set<String> excludeColumnFieldNames = new HashSet<>();
excludeColumnFieldNames.add("date");
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).excludeColumnFieldNames(excludeColumnFieldNames).sheet("模板")
    .doWrite(data());

3. 设置复杂头

通过对单元格头部设置多个标题来实现复杂头。

@ExcelProperty({"主标题", "字符串标题"})
private String string;
@ExcelProperty({"主标题", "日期标题"})
private Date date;
@ExcelProperty({"主标题", "数字标题"})
private Double doubleData;

通过对所有字段设置相同的标题可以将单元格合并,如果想要设置更复杂的头部,参考示例:

@ExcelProperty({"顶格", "顶格", "两格"})
private String string0;
@ExcelProperty({"顶格", "顶格", "两格"})
private String string1;
@ExcelProperty({"顶格", "四联", "四联"})
private String string2;
@ExcelProperty({"顶格", "四联", "四联"})
private String string3;
@ExcelProperty({"顶格"})

结果如下:

Java 使用 EasyExcel 导出基本使用方法

/>

4. 分页查询数据写入

数据量太大的情况下,可以考虑分页查询数据,然后再多次写入。

try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
    // 这里注意 如果同一个sheet只要创建一次
    WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
    // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来
    for (int i = 0; i < 5; i++) {
        // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
        List<DemoData> data = data();
        excelWriter.write(data, writeSheet);
    }
}

5. 写入不同sheet

写入不同 sheet 也是一个很常见的功能需求,比如导出员工数据时根据部分进行划分 sheet。

5.1 写入相同的对象


try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {
    // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
    for (int i = 0; i < 5; i++) {
        // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
        WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
        // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
        List<DemoData> data = data();
        excelWriter.write(data, writeSheet);
    }
}

5.2 写入不同的对象

try (ExcelWriter excelWriter = EasyExcel.write(fileName).build()) {
    // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
    for (int i = 0; i < 5; i++) {
        // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class
        // 实际上可以一直变
        WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();
        // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
        List<DemoData> data = data();
        excelWriter.write(data, writeSheet);
    }
}

6. 格式转换

EasyExcel 提供对常用的日期、数字转换的注解,同时也提供了自定义格式转换器。

public class ConverterData {
    /**
     * 我自定义 转换器,不管数据库传过来什么 。我给他加上“自定义:”
     */
    @ExcelProperty(converter = CustomStringStringConverter.class)
    private String string;
    /**
     * 这里用string 去接日期才能格式化。我想接收年月日格式
     */
    @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
    private String date;
    /**
     * 我想接收百分比的数字
     */
    @NumberFormat("#.##%")
    private String doubleData;
}

其实大部分情况下还是需要格式转换器来转换,比如员工性别,数据库的数据是 0 和 1,需要将其转换问男和女。

下面是 EasyExcel 提供的一个示例:

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

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

    /**
     * 这里读的时候会调用
     *
     * @param context
     * @return
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) {
        return "自定义:" + context.getReadCellData().getStringValue();
    }

    /**
     * 这里是写的时候会调用 不用管
     *
     * @return
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
        return new WriteCellData<>(context.getValue());
    }
}

7. 写入图片

可以通过多种方式写入图片,比如 url,file 对象,Stream 流。

String imagePath = TestFileUtil.getPath() + "converter" + File.separator + "img.jpg";
try (InputStream inputStream = FileUtils.openInputStream(new File(imagePath))) {
    List<ImageDemoData> list = ListUtils.newArrayList();
    ImageDemoData imageDemoData = new ImageDemoData();
    list.add(imageDemoData);
    // 放入五种类型的图片 实际使用只要选一种即可
    imageDemoData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
    imageDemoData.setFile(new File(imagePath));
    imageDemoData.setString(imagePath);
    imageDemoData.setInputStream(inputStream);
    imageDemoData.setUrl(new URL(
        "https://www.qcyqq.com/wp-content/uploads/2023/04/f09d57b823cf06b3d50fba052e21baf.png"));
    // 写入数据
    EasyExcel.write(fileName, ImageDemoData.class).sheet().doWrite(list);
}

其中 ImageDemoData.java 类如下:

@Getter
@Setter
@EqualsAndHashCode
@ContentRowHeight(100)
@ColumnWidth(100 / 8)
public class ImageDemoData {
    private File file;
    private InputStream inputStream;
    /**
     * 如果string类型 必须指定转换器,string默认转换成string
     */
    @ExcelProperty(converter = StringImageConverter.class)
    private String string;
    private byte[] byteArray;
    /**
     * 根据url导出
     *
     * @since 2.1.1
     */
    private URL url;

    /**
     * 根据文件导出 并设置导出的位置。
     *
     * @since 3.0.0-beta1
     */
    private WriteCellData<Void> writeCellDataFile;
}

可以看见 string 使用了 StringImageConverter 转换器,这个转换器将给定的路径读取文件,然后再进行写入。

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

    @Override
    public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) throws IOException {
        return new WriteCellData<>(FileUtils.readFileToByteArray(new File(value)));
    }
}

8. 导出并合并

可能会遇到这种情况,某些字段导出的内容也需要进行合并。

public void mergeWrite() {
    // 方法1 注解
    String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
    // 在DemoStyleData里面加上ContentLoopMerge注解
    EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data());

    // 方法2 自定义合并单元格策略
    fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx";
    // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写
    LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
    EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("模板").doWrite(data());
}

其中 DemoMergeData 类如下:

public class DemoMergeData {
    // 这一列 每隔2行 合并单元格
    @ContentLoopMerge(eachRow = 2)
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
}

9. 自定义样式

自定义样式可以自定义单元格的背景,单元格的文字大小等等。

// 头背景设置成红色 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 DemoStyleData {
    // 字符串的头背景设置成粉红 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;
}

10. 其他

其他比如生成动态头部、插入超链接、拦截器形式自定义样式等等,更多内容参考:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write

提醒:本文发布于514天前,文中所关联的信息可能已发生改变,请知悉!

Tips:清朝云网络工作室

阅读剩余
THE END