SpringBoot使用jxls组件实现可定制excel文件导出功能

在业务系统开发的时候经常能碰到excel文件导出的需求,在java中,excel文件导出有很多种实现方案,这里我介绍下jxls组件的实现方式。

为什么是jxls而不是其他的组件呢?

与阿里巴巴的EasyExcel这样直接数据对象的属性上使用注解标记的实现方式不同,jxls使用的是类jsp这样的模板形式,通过预先定义好excel模板实现数据的导出。个人感觉虽然jxls繁琐了一点,但是导出文件的样式和排版上jxls能有更好的灵活性(你把模板定义好就行了)EasyExcel其实也有类似jxls的填充模式,这里是早期认知不足说法有误。

jxls的官网地址:http://jxls.sourceforge.net/index.html

首先引入maven依赖

<!-- jxls -->
<dependency>
    <groupId>org.jxls</groupId>
    <artifactId>jxls</artifactId>
    <version>2.8.0</version>
</dependency>
<dependency>
    <groupId>org.jxls</groupId>
    <artifactId>jxls-poi</artifactId>
    <version>2.8.0</version>
</dependency>

接下来就是导出模板的定义,我这里直接举一个导出用户列表的例子。新建一个excel文件:用户列表导出模板.xlsx将它放在resources目录下

如上图是我们对excel的模板定义,其中${}是用来输出变量的。
图中单元格右上角带有红色小三角的该单元格加了批注,而一些如循环遍历数据等这些操作的语句就是写在批注中的

excel模板的第一个单元格A1是固定要写批注的。批注内容为:jx:area(lastCell="D5")意思是模板定义的覆盖范围为A1-D5,在这个覆盖范围内的标记会被jxls去解析填充对应的数据。

在A3单元格的位置也有一个批注,因为第3行这一行是需要进行遍历list进而填充数据的。遍历数据的批注为:jx:each(items="users" var="user" lastCell="D3")意思是遍历users这个list,跟java中的for语句基本类似。lastCell的值就是该行的覆盖范围是覆盖到D3单元格。

我在这里为了演示比较自由的定制化表格样式,我在右下角添加了一个导出时间和导出人。简单的是用${}标记进行输出。

至此我们的excel模板已经完工了,你会发现,其实跟jsp这种用模板开发html页面的形式完全一样,只是语法有点不同。接下来我们需要实现数据填充及导出的部分,直接看Controller层中的导出代码,Service层代码仅用来获取模拟数据这里就不展示了。

@GetMapping("/export")
public String export(HttpServletRequest request, HttpServletResponse response) {
    String exportTempName = "用户列表导出模板.xlsx";
    String exportFileName = "用户列表导出.xlsx";
    //获取数据并设置到jxls的Context对象中
    List<User> users = userService.listAll();
    Context context = new Context();
    context.putVar("users", users);
    context.putVar("title", "用户列表导出");
    context.putVar("time", DateUtil.now());
    context.putVar("exportUser", "王经理");

    try (
            //加载模板
            InputStream is = this.getClass().getResourceAsStream("/" + exportTempName);
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
    ) {
        //指定导出文件名称
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Disposition", "attachment;filename=" + new String(exportFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
        //导出文件
        JxlsHelper.getInstance().processTemplate(is, os, context);
        return "";
    } catch (Exception e) {
        e.printStackTrace();
        return "文件下载出错";
    }
}

这里我们新建了一个Context对象用来存放生成表格的数据,类似于Spring中的上下文对象。之后加载模板的输入流还有生成的文件输出流:

JxlsHelper.getInstance().processTemplate(is, os, context);

使用上述代码进行导出文件的生成,传入:模板的输入流,导出文件的输出流,数据context

到这我们需要导出的excel文件已经生成完毕了,除JxlsHelper这行是用于生成excel文件以外,其余代码都是为了实现文件下载的功能,具体可以参考:SpringBoot如何实现文件下载功能。看一下最终导出的excel文件:

代码:https://gitee.com/lqccan/blog-demo/tree/master/SpringBoot/jxls