EasyExcel-填充excel 导出

1,316 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

1. 需求背景:

做导出excel功能的时候会遇到很复杂的格式,这时候我们可以选择根据模板填充表格的方式来完成。

2. 技术选型:

EasyExcel:
官网地址:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill

4. pom 配置

尽量按这个版本配置,这个是测试过的可以使用,不然可能会出现jar包冲突的问题。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.1.2</version>
</dependency>

5. 代码实现

这里给的代码片段只是简单列表填充,如果有需要填充复杂模板可以看下官方文档的填充方式。最下面有官网示例截图

需要注意Boolean.FALSE 这个值,我这边列表结束就是最后一行,所以定义了false,如果不是最后一行就要定义true;

image.png

 
public void excel(HttpServletRequest request, HttpServletResponse response) {
   //业务数据,根据自己业务查询出来要导出的数据。这个就不要复制了
   List<User> userList = new ArrayList();
   //创建ExcelWriter
   ExcelWriter excelWriter = null;
 
    try {
        // outputStream:要导出的文件的输出流
        OutputStream outputStream = response.getOutputStream();
        // 模版文件
        ClassPathResource classPathResource = new ClassPathResource("template/test.xlsx");
        // 使用模版文件的两种方式:
        // 	1、文件路径:.withTemplate(templateFileName)
        // 	2、输入流:.withTemplate(inputStream)
        // String templateFileName = classPathResource.getFile().getPath();
        InputStream inputStream = classPathResource.getInputStream();
        excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).
                excelType(ExcelTypeEnum.XLSX).autoCloseStream(Boolean.FALSE).build();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.FALSE).build();
        //如果有复杂模板可以参考官方给的demo。从这里往上可以完全复制(除了业务数据),
        // 注意 Boolean.FALSE , "template/test.xlsx" 这几个值。
        
        //excelWriter.fill() 这地方就是填充属性。
        excelWriter.fill(userList, fillConfig, writeSheet);
        
        
        //从这里往下也可以复制使用
        // 设置输出流格式以及文件名:
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("用户信息", "UTF-8").replaceAll("\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        // 千万别忘记close关闭流
        if (excelWriter != null) {
            excelWriter.close();
        }
    }
}

6. 可能遇见的问题

1. 官网给的常见问题

地址:easyexcel.opensource.alibaba.com/qa/

2. 遇到的问题:

1. 出现了NoClassDefFoundError

解决方法:将上面的pom 配置,配置上去。除了这个错误,官网中给另外几个错误也可以尝试使用这个方法解决。

2. 导出数据为空:

解决方法:
1. 看下自己查询出来的业务数据是否为空。这个很重要,排查问题一定不要漏掉每个细节。

2. 看下自己写的模板上的属性值是否是对的。

对象的属性如果是 name, 那么表格里就要写{name},

如果导出是列表就要加点:{.name}。

加点的这种写法针对的是下面这行代码:

        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.FALSE).build();
        excelWriter.fill(userList, fillConfig, writeSheet);

注意看userList 这行,userList代表的就是业务数据的集合。

3.可能遇到的问题

注意:如果运行时报以下错,org.apache.poi.openxml4j.exceptions:Your InputStream was neither an OLE2 stream, nor an OOXML stream则需要加依赖:

这个只是可能遇到的问题,所以记录一下,以防不测。

<plugins>
<!-- 让maven不编译xls文件,但仍将其打包 -->
    <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-resources-plugin</artifactId>
           <configuration>
               <nonFilteredFileExtensions>
                   <nonFilteredFileExtension>xls</nonFilteredFileExtension>
               </nonFilteredFileExtensions>
           </configuration>
    </plugin>
</plugins>

7.后记:

如果有更复杂的需求可以看下官网给的demo, 在看的时候只需要关注红框内的内容就可以了,这个代码对应的模板是这样的

image.png image.png

比如怎么获取模板怎么,下载,直接复用 (# 5. 代码实现)的内容就行了。 还需要注意Boolean.FALSE 这个值,我这边列表结束就是最后一行,所以定义了false,如果不是最后一行就要定义true;