【EasyExcel实践】导出多个sheet到多个excel文件,并压缩到一个zip文件

文章目录

  • 前言
  • 正文
    • 一、项目依赖
    • 二、封装表格实体和Sheet实体
      • 2.1 表格实体
      • 2.2 Sheet实体
    • 三、核心实现
      • 3.1 核心实现之导出为输出流
      • 3.2 web导出
      • 3.3 导出为字节数组
    • 四、调试
      • 4.1 构建调试用的实体类
      • 4.2 控制器调用
      • 4.3 测试结果
    • 五、注册大数转换器,长度大于15时,转换为字符串
      • 5.1 实现转换器
      • 5.2 使用转换器

前言

工作中遇到一个需求,一次导出多个Excel 文件,并且每个excel中可能存在1到多个sheet页。
好在没有那种单元格合并的要求。

总体的思路是,设计两个实体,一个表示表格,一个表示sheet 数据。并且表格包含一个list 类型的sheet对象。

然后再使用ZipOutputStreamExcelWriterBuilderEasyExcel#writerSheet(...) 等类和方法去组装表格,最终进行压缩。

项目整体使用 java 8 和 阿里的easyexcel工具包。

正文

一、项目依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.2.0.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.11</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency></dependencies>

二、封装表格实体和Sheet实体

2.1 表格实体

/*** excel数据*/
@Data
public static class ExcelData {// sheet的列表private final List<ExcelShellData<?>> shellDataList = new ArrayList<>();// 表格文件名private String filename;public void addShellData(ExcelShellData<?> excelShellData) {this.shellDataList.add(excelShellData);}
}

2.2 Sheet实体

/*** sheet数据*/
@Data
@AllArgsConstructor
public static class ExcelShellData<T> {// 数据private List<T> list;// sheet名private String sheetName;// 数据实体类型private Class<T> clazz;
}

三、核心实现

3.1 核心实现之导出为输出流

这一步主要组装表格数据,以及生成sheet。最终将数据放到输出流outputStream中 。

private static void exportZipStream(List<ExcelData> excelDataList, OutputStream outputStream) {try {// 开始存入try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {try {for (ExcelData excelData : excelDataList) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();com.alibaba.excel.ExcelWriter excelWriter = null;try {ExcelWriterBuilder builder = EasyExcel.write(byteArrayOutputStream).autoCloseStream(false)// 自动适配.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy());excelWriter = builder.build();zipOut.putNextEntry(new ZipEntry(excelData.getFilename()));// 开始写入excelfor (ExcelShellData<?> shellData : excelData.getShellDataList()) {WriteSheet writeSheet = EasyExcel.writerSheet(shellData.getSheetName()).head(shellData.getClazz()).build();excelWriter.write(shellData.getList(), writeSheet);}} catch (Exception e) {throw new RuntimeException("导出Excel异常", e);} finally {if (excelWriter != null) {excelWriter.finish();}}byteArrayOutputStream.writeTo(zipOut);zipOut.closeEntry();}} catch (Exception e) {throw new RuntimeException("导出Excel异常", e);}}} catch (IOException e) {throw new RuntimeException("导出Excel异常", e);}}

3.2 web导出

可以调用本方法,直接在Controller中调用之后,当访问对应url,会直接下载到浏览器。

    /*** 导出多个sheet到多个excel文件,并压缩到一个zip文件*/public static void exportZip(String zipFilename, List<ExcelData> excelDataList, HttpServletResponse response) {try {// 这里URLEncoder.encode可以防止中文乱码zipFilename = URLEncoder.encode(zipFilename, "utf-8");// 指定文件名response.setHeader("Content-disposition", "attachment;filename=" + zipFilename);response.setContentType("application/x-msdownload");response.setCharacterEncoding("utf-8");exportZipStream(excelDataList, response.getOutputStream());} catch (IOException e) {throw new RuntimeException("导出Excel异常", e);}}

3.3 导出为字节数组

当我们需要导出为字节数组时,可以调用本方法。之后随你怎么加工。

    /*** 导出多个sheet到多个excel文件,并压缩到一个zip文件。最终得到一个字节数组。*/public static byte[] exportZip(List<ExcelData> excelDataList) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();exportZipStream(excelDataList, byteArrayOutputStream);return byteArrayOutputStream.toByteArray();}

四、调试

4.1 构建调试用的实体类

指定简单的几个字段作为导出数据。

    @Data@AllArgsConstructorpublic static class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;}

4.2 控制器调用

组装假数据,进行导出。

@Controller
@RequestMapping("/excel")
public class ExcelDemoController {@GetMapping("/exportTransportDetail")public String exportTransportDetail(HttpServletResponse response) throws IOException {// 压缩包文件名String fileName = "结算单运单明细-" + System.currentTimeMillis() + ".zip";List<ExcelData> excelDataList = new ArrayList<>();// 第一个ExcelExcelData excelData1 = new ExcelData();excelData1.setFilename("结算单运单明细-1-" + System.currentTimeMillis() + ".xlsx");List<DemoData> demoData1 = new ArrayList<>();demoData1.add(new DemoData("excel-sheet1", new Date(), 123112.321));demoData1.add(new DemoData("excel-sheet1", new Date(), 34.3));List<DemoData> demoData2 = new ArrayList<>();demoData2.add(new DemoData("excel-sheet2", new Date(), 123112.321));demoData2.add(new DemoData("excel-sheet2", new Date(), 34.3));ExcelShellData<DemoData> shellData1 = new ExcelShellData<>(demoData1, "sheet1", DemoData.class);ExcelShellData<DemoData> shellData2 = new ExcelShellData<>(demoData2, "sheet2", DemoData.class);excelData1.addShellData(shellData1);excelData1.addShellData(shellData2);// 第2个ExcelExcelData excelData2 = new ExcelData();excelData2.setFilename("结算单运单明细-2-" + System.currentTimeMillis() +".xlsx");List<DemoData> demoData21 = new ArrayList<>();demoData21.add(new DemoData("excel-sheet21", new Date(), 123112.321));demoData21.add(new DemoData("excel-sheet22", new Date(), 34.3));List<DemoData> demoData22 = new ArrayList<>();demoData22.add(new DemoData("excel-sheet21", new Date(), 123112.321));demoData22.add(new DemoData("excel-sheet22", new Date(), 34.3));ExcelShellData<DemoData> shellData21 = new ExcelShellData<>(demoData21, "sheet1", DemoData.class);ExcelShellData<DemoData> shellData22 = new ExcelShellData<>(demoData22, "sheet2", DemoData.class);excelData2.addShellData(shellData21);excelData2.addShellData(shellData22);excelDataList.add(excelData1);excelDataList.add(excelData2);// 写法1///// exportZip(fileName, excelDataList , response);// 写法2///byte[] bytes = exportZip(excelDataList);response.setHeader("Content-disposition", "attachment;filename=" + fileName);response.setContentType("application/x-msdownload");response.setCharacterEncoding("utf-8");response.getOutputStream().write(bytes);response.getOutputStream().flush();return "succ";}
}

4.3 测试结果

可以看到压缩包解压后的效果:
在这里插入图片描述
其中一个文件内容如下:
sheet1:
在这里插入图片描述

sheet2:
在这里插入图片描述

五、注册大数转换器,长度大于15时,转换为字符串

5.1 实现转换器

/*** Excel 数值长度大于maxLength的数值转换为字符串*/public static class ExcelBigNumberConvert implements Converter<Long> {private final int maxLength;public ExcelBigNumberConvert() {this(15);}public ExcelBigNumberConvert(Integer maxLength) {this.maxLength = maxLength;}@Overridepublic Class<Long> supportJavaTypeKey() {return Long.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic Long convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {Object data = cellData.getData();if (data == null) {return null;}String s = String.valueOf(data);if (s.matches("^\\d+$")) {return Long.parseLong(s);}return null;}@Overridepublic CellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {if (object != null) {String str = object.toString();if (str.length() > maxLength) {return new CellData<>(str);}}return null;}}

5.2 使用转换器

在构建建造器时,增加注册转换器即可。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/229401.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

游戏开发原画的设计方法

游戏原画设计是游戏开发中至关重要的一环&#xff0c;因为它直接影响到游戏的视觉吸引力和用户体验。以下是一些常见的游戏原画设计方法&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 理解游戏概念&…

学生护眼灯怎么选?2023备考护眼台灯推荐

近期&#xff0c;许多“护眼台灯是否是智商税”的帖子频繁出现&#xff0c;引起了许多群众的关注&#xff0c;作为一名护眼台灯资深使用者&#xff0c;在这里声明一下&#xff0c;护眼台灯绝对不是智商税。护眼台灯是通过调节光线亮度和色温&#xff0c;降低蓝光辐射&#xff0…

【黑马甄选离线数仓day07_常见优化手段及核销主题域开发】

1.常见优化手段 1.1 分桶表基本介绍 分桶表: 分文件的, 在创建表的时候, 指定分桶字段, 并设置分多少个桶, 在添加数据的时候, hive会根据设置分桶字段, 将数据划分到N个桶(文件)中, 默认情况采用HASH分桶方案 , 分多少个桶, 取决于建表的时候, 设置分桶数量, 分了多少个桶最终…

一维数组,逆序存放并输出【样例输入】20 30 10 50 40 90 80 70【样例输出】70 80 90 40 50 10 30 20

一维数组&#xff0c;逆序存放并输出 【样例输入】 20 30 10 50 40 90 80 70 【样例输出】 70 80 90 40 50 10 30 20 以下是使用C语言编写的将一维数组逆序存放并输出的示例代码&#xff1a; #include <stdio.h>void reverseArray(int arr[], int size) {int start…

深入剖析 Django 与 Flask 的选择之谜

概要 在现代 Web 开发的世界里&#xff0c;Python 作为一门极具灵活性和易用性的编程语言&#xff0c;催生了多个强大的 Web 框架&#xff0c;其中 Django 和 Flask 是最受欢迎的两个。但对于开发者来说&#xff0c;选择哪一个始终是一个令人费解的难题。本文将详细地对比这两…

Mysql基础(六)多表查询

版权申明&#xff1a;本文用于个人学习记录&#xff0c;学习课程为黑马程序员的mysql教程。如需获取官方的学习视频和文档资料&#xff0c;请至黑马程序员官方获取。下面附上教学视频的链接地址&#xff0c;向提供免费教学视频的老师致敬&#xff0c;学如逆水行舟&#xff0c;不…

“华为不造车 只帮车企造好车“ 那么华为到底造不造车

大家好&#xff0c;我是极智视界&#xff0c;欢迎关注我的公众号&#xff0c;获取我的更多前沿科技分享 邀您加入我的知识星球「极智视界」&#xff0c;星球内有超多好玩的项目实战源码和资源下载&#xff0c;链接&#xff1a;https://t.zsxq.com/0aiNxERDq "华为不造车&a…

linux设置主机名

查看主机名&#xff1a;hostname 临时修改主机名&#xff1a;hostname 新主机名 [rootlocalhost ~]#hostname centos [rootlocalhost ~]#hostname centos 永久修改主机名&#xff1a; [rootlocalhost ~]#cat /etc/hostname localhost.localdomain

一起学docker系列之十四Dockerfile微服务实践

目录 1 前言2 创建微服务模块2.1 **创建项目模块**2.2 **编写业务代码** 3 编写 Dockerfile4 构建 Docker 镜像5 运行 Docker 容器6 测试微服务7 总结8 参考地址 1 前言 微服务架构已经成为现代软件开发中的一种重要方式。而 Docker 提供了一种轻量级、便携式的容器化解决方案…

哈希和unordered系列封装(C++)

哈希和unordered系列封装 一、哈希1. 概念2. 哈希函数&#xff0c;哈希碰撞哈希函数&#xff08;常用的两个&#xff09;哈希冲突&#xff08;碰撞&#xff09;小结 3. 解决哈希碰撞闭散列线性探测二次探测代码实现载荷因子&#xff08;扩容&#xff09; 开散列哈希桶代码实现扩…

1.Spring源码解析-ClassPathXmlApplicationContext

此类是读取spring的xml配置文件并解析。也是源码入口之一。 我们调试即将开始。 传递给父类设置值 经调试我们得到是给AbstractApplicationContext设置默认的应用上下文父级的值&#xff0c;很明显是空 给父类AbstractRefreshableConfigApplicationContext设置属性 刷新容器…

苹果提醒事项怎么用?几个简单步骤就能学会!

苹果提醒事项可以帮助你轻松管理待办事项&#xff0c;让你更好地安排自己的时间和工作。但是&#xff0c;有些小伙伴可能对如何使用这个功能还有一些疑问。苹果提醒事项怎么用&#xff1f;不要担心&#xff0c;小编将为大家提供使用提醒事项的方法&#xff0c;帮助你学会如何使…