使用easyexcel导出复杂模板,同时使用bean,map,list填充

背景

在使用easyexcel导出时,如果遇到一个模板中同时存在 一部分是实体类中的字段,另外部分是列表的字段,需要特殊处理一下,比如下面的模板:

这里面 useraddr 是实体类(或者map),extra是一个字符串,datadata1是两组列表数据。

准备数据的代码如下:

java 复制代码
    private static Map<String, Object> getParams() {
        // 准备导出的数据
        User user = new User();
        user.setName("user");
        Map<String, Object> addr = new HashMap<>();
        addr.put("name", "addr");
        String extra = "extra";
        List<Data> dataList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Data data = new Data();
            data.setName("data" + i);
            data.setAge(i);
            dataList.add(data);
        }


        Map<String, Object> params = HashMap.newHashMap(16);
        params.put("user", user);
        params.put("addr", addr);
        params.put("extra", extra);
        params.put("data", dataList);
        params.put("data1", dataList);
        return params;
    }

问题

我们一开始的想法很简单,直接把这些参数打包丢到map里面,直接fill一次不就成功了,但是,实际上并没有成功,导出代码如下:

java 复制代码
var params = getParams();
String templateFileName = "D:\\test.xlsx";

String fileName = "D:\\test-res.xlsx";
try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
    WriteSheet writeSheet = EasyExcel.writerSheet().build();
    excelWriter.fill(params, writeSheet);
}

导出结果:

可以看到,除了没有前缀的的extra,所有带前缀的都导出失败了,仔细查阅文档后,发现这些需要用FillWrapper包装一下,为了方便使用,这里写了一个工具类,代码如下:

java 复制代码
    public static void export(String templateFileName, String outputFile, Map<String, Object> params){

        try (ExcelWriter excelWriter = EasyExcel.write(outputFile).withTemplate(templateFileName).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            // 先把不带前缀的都fill进去
            excelWriter.fill(params, writeSheet);

            params.forEach((key, val) -> {
                // 基础类型都是不带前缀的,前面处理了,不再处理。
                if (ClassUtil.isBasicType(ClassUtil.getClass(val))) {
                    return;
                }

                if (val instanceof Collection<?> collectionVal) {
                    // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。
                    // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用
                    // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
                    FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                    excelWriter.fill(new FillWrapper(key, collectionVal), fillConfig, writeSheet);
                }else {
                    // bean/map 只能假装是个列表了
                    excelWriter.fill(new FillWrapper(key, Collections.singleton(val)), writeSheet);
                }
            });
        }
    }

代码中的ClassUtilhutool

导出结果:

可以看到,几处都填充成功了。

补充

web环境下把导出方法的前俩参数直接改成对应的输出/输入流就行了。

相关推荐
Uluoyu10 小时前
支持Word (doc/docx) 和 PDF 转成一张垂直拼接的长PNG图片工具类
java·pdf·word
__XYZ10 小时前
RedisTemplate 实现分布式锁
java·spring boot·redis·分布式·junit
闭着眼睛学算法10 小时前
【双机位A卷】华为OD笔试之【模拟】双机位A-新学校选址【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
java·c语言·javascript·c++·python·算法·华为od
源码_V_saaskw10 小时前
JAVA校园跑腿校园外卖源码校园外卖小程序校园代买帮忙外卖源码社区外卖源码小程序+公众号+h5
java·开发语言·微信小程序·小程序
源码哥_博纳软云10 小时前
JAVA同城预约服务家政服务美容美发洗车保洁搬家维修家装系统源码小程序+公众号+h5
java·开发语言·微信小程序·小程序
红尘客栈211 小时前
Kubernetes 集群调度
java·linux·网络·容器·kubernetes
编程岁月11 小时前
java面试-0203-java集合并发修改异常、快速/安全失败原理、解决方法?
java·开发语言·面试
whltaoin11 小时前
AI 超级智能体全栈项目阶段五:RAG 四大流程详解、最佳实践与调优(基于 Spring AI 实现)
java·人工智能·spring·rag·springai
junnhwan11 小时前
【苍穹外卖笔记】Day05--Redis入门与店铺营业状态设置
java·数据库·redis·笔记·后端·苍穹外卖
摇滚侠11 小时前
Spring Boot 3零基础教程,Spring Boot 特性介绍,笔记02
java·spring boot·笔记