共计 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({"顶格"})
结果如下:
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.amjun.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。
提醒:本文发布于572天前,文中所关联的信息可能已发生改变,请知悉!