EasyExcel 实现 批量生成多sheet多Excel打包zip下载

在这里插入图片描述

说明

需求场景

导出学校中高年级的学生信息,根据班级名称分组,一个班级一个excel导出,如果多个excel需要打包成zip压缩包下载,一个excel里面存在多个sheet的情况。

实现

1、准备一个excel模板

在这里插入图片描述
另一个sheet属于动态填充的表头和内容,里面不需要有什么信息
在这里插入图片描述

2、把整个excel模板放在resources里面

在这里插入图片描述

3、重点代码

@GetMapping("/upload")
    public void upload() {
        //初始化excel的数据体
        List<Map<String, String>> maps = new LinkedList<>();
        for (int i = 6; i < 13; i++) {
            HashMap<String, String> map = new HashMap<>();
            map.put("name", "小" + i);
            map.put("age", "" + i);
            maps.add(map);
        }


        //获取模板文件,模板文件需放在 resource下
        String templateExcelFileName = "upload.xlsx";
        InputStream templateExcelInputStream = this.getClass().getClassLoader().getResourceAsStream(templateExcelFileName);
        if (null == templateExcelInputStream) {
            log.info("模板文件不存在");
        }

        ByteArrayOutputStream outputStream = null;
        ZipOutputStream zipOut = null;
        try {
            //处理导出的zip 文件名称,避免中文乱码
            String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
            String encodedFileName = URLEncoder.encode("高年级数据导出-" + date + ".zip", StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
            response.setContentType("application/octet-stream; charset=UTF-8");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + encodedFileName);
            zipOut = new ZipOutputStream(response.getOutputStream());

            //复制输入模板文件流,避免第一次以后读取为空问题
            ByteArrayOutputStream bos = cloneInputStream(templateExcelInputStream);

            //多个excel名称
            List<String> classList = Arrays.asList("四(二)", "五(二)", "六(二)");

            //excel集合
            for (int i = 0; i < classList.size(); i++) {

                String className = classList.get(i);

                InputStream copyInputStream = new ByteArrayInputStream(bos.toByteArray());
                outputStream = new ByteArrayOutputStream();
                ExcelWriter excelWriter = EasyExcel.write(outputStream).withTemplate(copyInputStream).excelType(ExcelTypeEnum.XLSX).build();

                //设置 zip 中的每个文件名称
                zipOut.putNextEntry(new ZipEntry("班级 - " + className + templateExcelFileName.substring(templateExcelFileName.lastIndexOf("."))));

                /******************  值填充逻辑开始,请按实际业务修改  ************************/

                //固定模板填充内容 {}单个数据填充  {.}是集合数据填充,但是需要转义 这个要注意
                WriteSheet writeSheet = EasyExcel.writerSheet(0, "学校信息").build();
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("schoolName", "新民小学");
                map.put("className", className + "班");
                map.put("count", maps.size());
                map.put("uploadDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
                excelWriter.fill(map, writeSheet);

                //动态填充表头和内容
                WriteSheet attrSheet = EasyExcel.writerSheet(1, "班级学生信息").build();
                List<String> heads = Arrays.asList("name", "age");
                List<List<String>> excelHeaders = heads.stream().map(Collections::singletonList).collect(Collectors.toList());
                attrSheet.setHead(excelHeaders);
                excelWriter.write(excelDatas(heads, maps), attrSheet);

                /******************  值填充逻辑结束,请按实际业务修改  ************************/

                excelWriter.finish();
                outputStream.writeTo(zipOut);
                outputStream.flush();
                outputStream.close();
                zipOut.closeEntry();

                copyInputStream.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("导出 excel -> zip 时出现异常" + e.getMessage());
        } finally {
            if (null != outputStream) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != zipOut) {
                try {
                    zipOut.flush();
                    zipOut.finish();
                    zipOut.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }

    /**
     * 复制InputStream
     * <p>
     * InputStream inputStream = new ByteArrayInputStream(ByteArrayOutputStream.toByteArray());
     *
     * @param input
     * @return
     */
    public static ByteArrayOutputStream cloneInputStream(InputStream input) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            return baos;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 数据体转换后填充excel的数据
     *
     * @param attrs
     * @param maps
     * @return
     */
    public List<List<String>> excelDatas(List<String> attrs, List<Map<String, String>> maps) {
        List<List<String>> excelDatas = maps.stream().map(data ->
                attrs.stream().map(column ->
                        Optional.ofNullable(data.get(column)).map(Object::toString).orElse("")
                ).collect(Collectors.toList())
        ).collect(Collectors.toList());

        return excelDatas;
    }

效果图

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如果有更完善性能更好地方案,欢迎评论提出。

单个excel下载看这里:EasyExcel 实现写入多个sheet数据进excel模板并下载

就先说到这 \color{#008B8B}{ 就先说到这} 就先说到这
在下 A p o l l o \color{#008B8B}{在下Apollo} 在下Apollo
一个爱分享 J a v a 、生活的小人物, \color{#008B8B}{一个爱分享Java、生活的小人物,} 一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞! \color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值