如何导出复杂格式的Excel文件?

5 篇文章 0 订阅

前言

我们平时开发会需要做一些 Excel 导出的需求,简单快捷的方式是使用 EasyExcel 来做,如果是简单的数据导出,我们可以在POJO上打ExcelProperty注解,然后直接调用 EasyExcel.write 静态方法,一行代码就搞定了!如:

// 定义模型
@Data
public class Student {
    @ExcelProperty(value = "姓名", index = 0)
    private String name;
    @ExcelProperty(value = "身份证号", index = 1)
    private String idCard;
    @ExcelProperty(value = "年龄", index = 2)
    private int age;
    @ExcelProperty(value = "性别", index = 3)
    private String gender;
}

List<Student> students = ...
// 写出 Excel 文件
EasyExcel.write(fileName, Student.class).sheet("Sheet1").doWrite(students);

但是,如果我们的要导出的 Excel 文件格式有比较复杂的要求,那问题就变得复杂了。使用 EasyExcel 或者其他的工具来操作 Excel 做复杂的格式,都不是一件容易的事情,你不得不写大量枯燥冗余的代码来实现,容易出错,也不易维护。怎么办?可以使用模板填充的方式来做。

模板填充

事实上,EasyExcel 直持 fill 模式,即模板填充,简单来说,就是你提供一个 Excel 模板,根据规则放一些占位符,然后调用相关的 API 将数据填充进去,就可以了。

模板示例

我们来看一个示例:
复杂模板
注:这里使用 {} 来表示你要用的变量 如果本来就有"{" 或 “}” 特殊字符,则用"\{" 和 "\}"代替。{xxx} 代表普通变量 {.xxx} 代表是list的变量

简单填充

如果你的模板只有 list 的变量需要填充,例如这样:
简单模板
可以一行代码搞定

// Student 对象中包含模板占位符中的属性
 List<Student> list = ...
 // out 可以是文件路径也可以是 OutputStream
 EasyExcel.write(out)
     // 选择模板,可以是文件路径也可以传 InputStream
     .withTemplate(template)
     // 选择显示 sheet
     .sheet()
     // 填充数据
     .doFill(list);

填充效果如下:
简单模板

复杂填充

但是就像上面的示例模板那样,即有普通变量又有 list 变量时,就要稍微复杂一点:
复杂模板
复杂填充完整代码

 // Student 对象中包含模板占位符中的属性
List<Student> list = ...
// 设置输出目标和模板,out和template 可以是文件路径或流
ExcelWriter excelWriter = EasyExcel.write(out).withTemplate(template).build();
// 创建 Sheet
WriteSheet writeSheet = EasyExcel.writerSheet().build();
 // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。但是这个就会把所有数据放到内存 会很耗内存
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
excelWriter.fill(list, fillConfig, writeSheet);
// 填充普通变量
Map<String, Object> map = new HashMap<String, Object>();
map.put("className", "软件工程3班");
excelWriter.fill(map, writeSheet);
excelWriter.finish(); 

生成效果如下:
生成效果
这样就完成了!

模板文件要放到哪里?

模板的功能很强大,但是第一次使用时,我们有个疑问:模板文件要放到哪里?现在,我们都使用 SpringBoot 它会将应用打包成 FatJar,我们早已习惯了将各种配置文件放到 resources 目录下,所以 resources 目录是存放模板文件的最佳位置

配置

要将模板文件放在 resources 目录下,必须在 pom.xml 文件中添加以下配置:

<build>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration>
      <!-- 过滤不编译文件类型,解决maven打包时会编译特定文件导致文件不可用的问题 -->
      <nonFilteredFileExtensions>
        <nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
        <nonFilteredFileExtension>xls</nonFilteredFileExtension>
      </nonFilteredFileExtensions>
    </configuration>
  </plugin> 
<resources>
  <resource>
     <directory>src/main/resources</directory>
     <filtering>true</filtering>
     <includes>
       <!-- 将 resources 目录下的所有文件都一起打包 -->
       <include>**/*.*</include>
     </includes>
   </resource>
  </resources>
</build>

最佳实践

实战中,我们导出一个 Excel 文件的时候,并不想也不需要写到服务器磁盘里,而是做为请求的响应,让用户去下载。或者是上传到 OSS 对象存储仓库中,然后返回一个下载链接。如何实现呢?

这里演示一下,从 resources 目录读取模板,填充数据,然后得到一个 InputStream,用于响应用户请求或者上传 OSS

// 从 /resources 目录下加载模板
try (InputStream templateInputStream = getClass().getClassLoader().getResourceAsStream("excel-template/学生名单模板.xlsx");
     ByteArrayOutputStream out = new ByteArrayOutputStream()) {
       // 设置输出目标和模板
    ExcelWriter excelWriter = EasyExcel.write(out).withTemplate(templateInputStream).build();
    // 创建 Sheet
    WriteSheet writeSheet = EasyExcel.writerSheet().build();
     // 注意:forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。这会把所有数据放到内存,数据量大时会很耗内存
    FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
    excelWriter.fill(list, fillConfig, writeSheet);
    // 填充普通变量
    Map<String, Object> map = new HashMap<String, Object>(2);
    map.put("className", "软件工程3班");
    excelWriter.fill(map, writeSheet);
    excelWriter.finish(); 
    // 将 outputStream 转换成 InputStream 并上传到 oss 中
    try (InputStream in = new ByteArrayInputStream(out.toByteArray())) {
        // todo 在这里处理这个 InputStream,可以上传到 OSS 并返回下载接,也可以做为响应返回给用户
    }
} catch (IOException e) {
    log.error("export excel error", e);
}

参考

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值