前言
近期有个项目中需要大量生成excel文件,如果用代码去生成这些excel,会出现大量重复代码,而且需求方任意修改一个地方,就需要修改代码,重新打包部署。那有没有通过模版方式生成excel,这样就可以快速开发不同单据的excel生成,而且修改内容不需要再需求代码,也不用重新部署。在网上搜了下,找到如下两个技术,目前这两个技术是比较主流的,easyexcel和jxlseasyexcel和jxls对比
特性 | EasyExcel | Jxls |
模板语法丰富度 | 极简(仅支持基础占位符 + 简单循环) | 完整(支持循环、条件、公式、变量运算、自定义标签) |
条件判断 | 需在代码中过滤数据后再填充(模板不支持 if ) | 模板中直接写 jx:if(condition="user.age>20") |
动态合并单元格 | 需代码手动计算合并规则,模板无原生支持 | 模板中通过 jx:mergeCells 标签原生支持 |
多 sheet 联动 / 动态 sheet | 需代码控制 sheet 创建和数据填充 | 模板中通过 jx:area 标签支持多 sheet 模板 |
公式动态计算 | 模板中公式需手动写死,动态参数需代码传递 | 模板中公式可直接引用变量(如 SUM(${list.age}) ) |
模板维护成本 | 低(模板简单),但代码逻辑成本高 | 高(模板稍复杂),但代码逻辑成本极低 |
学习成本 | 低(模板语法几乎不用学,只需懂代码) | 中(需学 Jxls 模板标签语法) |
easyexcel使用
模板
这里可以看到easyexcel变量名通过{}表示,如果是list可以用{.变量名}来获取最终效果
依赖
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>4.0.3</version></dependency>
代码
/** * 复杂的填充 * * @since 2.1.1 */@Testpublic void complexFill() { // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 // {} 代表普通变量 {.} 代表是list的变量 String templateFileName = TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "complex.xlsx"; String fileName = TestFileUtil.getPath() + "complexFill" + System.currentTimeMillis() + ".xlsx"; // 方案1 try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) { WriteSheet writeSheet = EasyExcel.writerSheet().build(); // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。 // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用 // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存 // 如果数据量大 list不是最后一行 参照下一个 FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); excelWriter.fill(data(), fillConfig, writeSheet); Map<String, Object> map = MapUtils.newHashMap(); map.put("date", "2019年10月9日13:28:28"); map.put("total", 1000); excelWriter.fill(map, writeSheet); }}private List<FillData> data() { List<FillData> list = ListUtils.newArrayList(); for (int i = 0; i < 10; i++) { FillData fillData = new FillData(); list.add(fillData); fillData.setName("张三"); fillData.setNumber(5.2); fillData.setDate(new Date()); } return list;}
更多用法可以参看官网:https://easyexcel.opensource.alibaba.com/docs/current/
jxls使用
模版配置
在批注中输入jxls语法,jx:area(lastCell="D5")表示整个需要赋值的区域从A1到D5,jx:each(items="students" var="e" lastCell="D4" )表示从这开始循环,到D4列结束,lastCell含义类似代码中的右大括号,表示代码结束的地方最终效果
依赖
<dependency> <groupId>org.jxls</groupId> <artifactId>jxls</artifactId> <version>2.12.0</version></dependency><dependency> <groupId>org.jxls</groupId> <artifactId>jxls-poi</artifactId> <version>2.12.0</version></dependency>
代码
publicvoidjxls() { // 加载模板 try(InputStream is = ResourceUtil.getStream("template/jxls_template.xlsx")) { try (OutputStream os = new FileOutputStream("a.xlsx")) { // 把数据加入 jxls的 上下文中 Context context = new Context(); context.putVar("students", data()); context.putVar("total", 1000); context.putVar("date", new Date()); // 渲染模板 JxlsHelper.getInstance().processTemplate(is, os, context); } catch (IOException e) { e.printStackTrace(); } } catch (IOException e) { throw new RuntimeException(e); }}
总结
两种都可以实现excel的模版配置。easyexcel使用简单,能满足大部分使用场景。jxls使用会复杂些,但功能更强大,更灵活。具体需要哪种看大家自己业务需求。