如何使用EasyExcel生成多列表组合填充的复杂Excel示例

作者:Funky_oaNiu

    • 一、(需求)生成的表格效果:
    • 二、搞一个模板文件
    • 三、建立对应的表格实体类
    • 四、开始填充
    • 五、Vue3前端发起请求下载
    • 六、官方文档及AI问答

一、(需求)生成的表格效果:

其中只有顶部日期、中间表格数据、底部总计数据,是通过模板填充的
表头、绿色区域、列名、背景颜色、四个表格的结构是模板中定义好的
本文主要可学习如何填充数据
在这里插入图片描述

二、搞一个模板文件

这模板文件是自己编写的,占位符使用{xx}的形式,注意观察一下表格和外部的站位符区别,表格是{data1.xxx}这种形式,用来标识不同表格
在这里插入图片描述

三、建立对应的表格实体类

@Data
public class FillData {
    private String name;
    private double number;
    private Date date;
}

四、开始填充

这里是SpringBoot项目,写在Controller里的,仔细看代码注释,这里就不过多描述了

@Operation(summary = "导出excel")
@GetMapping("/export-excel")
public void exportExcel(PsbLoc psbLoc, HttpServletResponse response) throws IOException {
    // 读取资源文件(这样打成jar模板文件也在里面,防止模板文件被修改导致功能不可用,文件是在src/main/resources/excelTemplates下的)
    ClassPathResource resource = new ClassPathResource("excelTemplates"+File.separator+"productReceiveSendTemplate.xlsx");
    // 组织并填充模板数据
    ByteArrayOutputStream byteArrayOutputStream = compositeFill(resource.getInputStream());

    // 这里文件名不起作用是因为前端是写死的
    String fileName = "多列表" + System.currentTimeMillis() + ".xlsx";
    // 设置响应头,告诉浏览器这是一个下载的文件,这里文件名
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

    // 将文件内容写入响应输出流,浏览器可以直接触发下载
    response.getOutputStream().write(byteArrayOutputStream.toByteArray());
    response.getOutputStream().flush();
}

private ByteArrayOutputStream compositeFill(InputStream templateInputStream) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    // 使用EasyExcel的模板填充功能,在这里指定合并单元格,这里应该是easyExcel的bug,第一列无法合并,其他列都可以,所以第一列单独用原生poi进行合并
    try (ExcelWriter excelWriter = EasyExcel.write(byteArrayOutputStream).withTemplate(templateInputStream)
            // 这里的参数就是圈了个合并区域,在这个正方形内的单元格都会合并,要注意索引是从0开始的,并且区域内不能存在已经合并的单元格否则报错
            .registerWriteHandler(new OnceAbsoluteMergeStrategy(2, 14, 9, 9))
            .registerWriteHandler(new OnceAbsoluteMergeStrategy(15, 27, 9, 9))
            .build()) {
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        // 防止上面两个表格覆盖下面两个表格,每一行都采用新增一行的方式
        FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
        // 使用模板填充,必须使用FillWrapper,这是官方要求,并且每行两个表格只能有一个表格设置增行,否则会存在一个表格有空行,这里是造的测试数据
        excelWriter.fill(new FillWrapper("data1", makeTestData(1)), fillConfig, writeSheet);
        excelWriter.fill(new FillWrapper("data2", makeTestData(2)), writeSheet);
        excelWriter.fill(new FillWrapper("data3", makeTestData(3)), fillConfig, writeSheet);
        excelWriter.fill(new FillWrapper("data4", makeTestData(4)), writeSheet);

        // 设置表格外的填充数据,例如总计、日期等数据
        HashMap<String, Object> map = new HashMap<>();
        map.put("date", "2024年11月15日");
        map.put("allInStaockQty", 1);
        map.put("allOutStockQty", 2);
        map.put("allConvertStockQty", 3);
        map.put("allStockQty", 4);
        map.put("convertCenterStockQty", 5);
        map.put("mixOutStockQty", 6);
        map.put("endItem1", 7);
        map.put("endItem2", 8);
        map.put("endItem3", 9);
        map.put("endItem4", 10);
        map.put("endItem5", 11);
        excelWriter.fill(map, writeSheet);
    }
    // 合并单元格,由于easyExcel自带的OnceAbsoluteMergeStrategy合并策略bug,这里需要用poi合并一下
    return mergeCells(byteArrayOutputStream);
}

public ByteArrayOutputStream mergeCells(ByteArrayOutputStream inputStream) {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(inputStream.toByteArray());
         Workbook workbook = new XSSFWorkbook(byteArrayInputStream)) {
        // 获取第一个工作表
        Sheet sheet = workbook.getSheetAt(0);

        // 合并第1列第3行到第15行,注意行索引从0开始
        CellRangeAddress range1 = new CellRangeAddress(2, 14, 0,0);
        sheet.addMergedRegion(range1);

        // 合并第1列第16行到第28行,注意行索引从0开始
        CellRangeAddress range2 = new CellRangeAddress(15, 27, 0, 0);
        sheet.addMergedRegion(range2);

        // 设置合并单元格的样式
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        // 将修改后的内容写入 ByteArrayOutputStream
        workbook.write(outputStream);
        // 刷新一下,确保数据完全写入
        outputStream.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return outputStream;
}

private List<FillData> makeTestData(Integer listIndx) {
        List<FillData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            FillData fillData = new FillData();
            list.add(fillData);
            fillData.setName("张三"+listIndx);
            fillData.setNumber(5.2);
            fillData.setDate(new Date());
        }
        return list;
    }

五、Vue3前端发起请求下载

const handleExport = async () => {
  try {
  	// 这里的确认框、loading框代码就省略了
    // 发起导出
    const data = await ReportTestApi.testReport(queryParams)
    download.excel(data, '测试模板填充.xlsx')
  } catch {
  } finally {
    exportLoading.value = false
  }
}

const download = {
  // 下载 Excel 方法
  excel: (data: Blob, fileName: string) => {
    download0(data, fileName, 'application/vnd.ms-excel')
  },
  // 下载 Word 方法
  word: (data: Blob, fileName: string) => {
    download0(data, fileName, 'application/msword')
  },
  // 下载 Zip 方法
  zip: (data: Blob, fileName: string) => {
    download0(data, fileName, 'application/zip')
  },
  // 下载 Html 方法
  html: (data: Blob, fileName: string) => {
    download0(data, fileName, 'text/html')
  },
  // 下载 Markdown 方法
  markdown: (data: Blob, fileName: string) => {
    download0(data, fileName, 'text/markdown')
  }
}

const download0 = (data: Blob, fileName: string, mineType: string) => {
  // 创建 blob
  const blob = new Blob([data], { type: mineType })
  // 创建 href 超链接,点击进行下载
  window.URL = window.URL || window.webkitURL
  const href = URL.createObjectURL(blob)
  const downA = document.createElement('a')
  downA.href = href
  downA.download = fileName
  downA.click()
  // 销毁超连接
  window.URL.revokeObjectURL(href)
}

六、官方文档及AI问答

直接拉到下面,看“多列表组合填充”
https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill#%E6%A8%A1%E6%9D%BF-2
easyExcel官方问答AI,对比了一下,其他AI都没有它答的好
无疑: https://answer.opensource.alibaba.com/docs/intro

客官点个赞再走呗

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

手机ip地址异常怎么解决

在现代社会中&#xff0c;手机已成为我们日常生活中不可或缺的一部分&#xff0c;无论是工作、学习还是娱乐&#xff0c;都离不开网络的支持。然而&#xff0c;有时我们会遇到手机IP地址异常的问题&#xff0c;这不仅会影响我们的网络体验&#xff0c;还可能带来安全隐患。本文…

Python酷库之旅-第三方库Pandas(218)

目录 一、用法精讲 1021、pandas.DatetimeIndex.inferred_freq属性 1021-1、语法 1021-2、参数 1021-3、功能 1021-4、返回值 1021-5、说明 1021-6、用法 1021-6-1、数据准备 1021-6-2、代码示例 1021-6-3、结果输出 1022、pandas.DatetimeIndex.indexer_at_time方…

基于 CentOS7.6 的 Docker 下载常用的容器(MySQLRedisMongoDB),解决拉取容器镜像失败问题

安装MySQL&Redis&MongoDB mysql选择是8版本&#xff0c;redis是选择4版本、mongoDB选择最新版&#xff0c;也可以根据自己的需要进行下载对应的版本&#xff0c;无非就是容器名:版本号 这样去拉去相关的容器镜像。如果你还不会在服务器中安装 docker&#xff0c;可以查…

讯飞、阿里云、腾讯云:Android 语音合成服务对比选择

在 移动端 接入语音合成方面&#xff0c;讯飞和腾讯云等都是优秀的选择&#xff0c;但各有其特点和优势。咱们的需求是需要支持普通话/英语/法语三种语言&#xff0c;以下是对各个平台的详细比较&#xff1a; 一、讯飞语音合成介绍 与语音听写相反&#xff0c;语音合成是将一段…

设计模式之责任链模式(Chain Of Responsibility)

一、责任链模式介绍 1、责任链模式介绍 职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在 一起&#xff0c;让多个对象都有机会处理请求。将接收请求的对象连接成一条链&#xff0c;并且沿着这条链 传递请求&#xff0c;直到有一个对…

游戏引擎学习第12天

视频参考:https://www.bilibili.com/video/BV1yom9YnEWY 这节没讲什么东西&#xff0c;主要是改了一下音频的代码 后面有介绍一些alloc 和malloc,VirtualAlloc 的东西 _alloca 函数&#xff08;或 alloca&#xff09;分配的是栈内存&#xff0c;它的特点是&#xff1a; 生命周…

更改liunx的磁盘名称

目录 1. 问题的提出 2. 机器环境说明 3. 解决方法 1. 问题的提出 今天在Linux上部署软件&#xff0c;发现要部署软件的硬盘名称带中文&#xff0c;当访问该磁盘时&#xff0c;中文则被转为长长的一串数字字符串&#xff0c;这很不方便&#xff0c;于是需要将带有中文的磁盘名…

基于Python 和 pyecharts 制作招聘数据可视化分析大屏

在本教程中&#xff0c;我们将展示如何使用 Python 和 pyecharts 库&#xff0c;通过对招聘数据的分析&#xff0c;制作一个交互式的招聘数据分析大屏。此大屏将通过不同类型的图表&#xff08;如柱状图、饼图、词云图等&#xff09;展示招聘行业、职位要求、薪资分布等信息。 …

论文PDF页面无法下载PDF

问题&#xff1a;通常在下载学术论文时&#xff0c;网页命名是PDF页面&#xff0c;但是无法下载PDF&#xff0c;下载的是html网页 解决&#xff1a; mac&#xff1a;按F12打开开发者界面 然后点击源代码/来源选项 然后打开下图所在位置&#xff0c;鼠标右键复制链接&#xff…

Ubuntu24 上安装搜狗输入法

link 首先在终端中依次输入以下代码 sudo apt update sudo apt install fcitx 找到语言支持 在终端中依次输入 sudo cp /usr/share/applications/fcitx.desktop /etc/xdg/autostart/ sudo apt purge ibus 进入网页 搜狗输入法linux-首页​ shurufa.sogou.com/linux 找到刚才下…

从0开始机器学习--Day27--主成分分析方法

主成分分析方法(Principal components analysis) 在降维算法中&#xff0c;比较普遍的是使用主成分分析方法&#xff08;PCA&#xff09; PCA算法简单示例 如图&#xff0c;假设我们有一个二维的特征&#xff0c;想要将其降为一维&#xff0c;简单的方法是寻找一条直线&#…

深度学习中的mAP

在深度学习中&#xff0c;mAP是指平均精度均值(mean Average Precision)&#xff0c;它是深度学习中评价模型好坏的一种指标(metric)&#xff0c;特别是在目标检测中。 精确率和召回率的概念&#xff1a; (1).精确率(Precision)&#xff1a;预测阳性结果中实际正确的比例(TP / …

【实验11】卷积神经网络(2)-基于LeNet实现手写体数字识别

&#x1f449;&#x1f3fc;目录&#x1f448;&#x1f3fc; &#x1f352;1. 数据 1.1 准备数据 1.2 数据预处理 &#x1f352;2. 模型构建 2.1 模型测试 2.2 测试网络运算速度 2.3 输出模型参数量 2.4 输出模型计算量 &#x1f352;3. 模型训练 &#x1f352;4.模…

Springboot3.3.5 启动流程之 tomcat启动流程介绍

在文章 Springboot3.3.5 启动流程&#xff08;源码分析&#xff09; 中讲到 应用上下文&#xff08;applicationContext&#xff09;刷新(refresh)时使用模板方法 onRefresh 创建了 Web Server. 本文将详细介绍 ServletWebServer — Embedded tomcat 的启动流程。 首先&…

学习日志011--模块,迭代器与生成器,正则表达式

一、python模块 在之前学习c语言时&#xff0c;我们学了分文件编辑&#xff0c;那么在python中是否存在类似的编写方式&#xff1f;答案是肯定的。python中同样可以实现分文件编辑。甚至还有更多的好处&#xff1a; ‌提高代码的可维护性‌&#xff1a;当代码被分成多个文件时…

【提高篇】3.3 GPIO(三,工作模式详解 上)

目录 一,工作模式介绍 二,输入浮空 2.1 输入浮空简介 2.2 输入浮空特点 2.3 按键检测示例 2.4 高阻态 三,输入上拉 3.1 输入上拉简介 3.2 输入上拉的特点 3.3 按键检测示例 四,输入下拉 4.1 输入下拉简介 4.2 输入下拉特点 4.3 按键检测示例 一,工作模式介绍…

Excel单元格中自适应填充多图

实例需求&#xff1a;在Excel插入图片时&#xff0c;由于图片尺寸各不相同&#xff0c;如果希望多个图片填充指定单元格&#xff0c;依靠用户手工调整&#xff0c;不仅费时费力&#xff0c;而且很难实现完全填充。如下图中的产品图册&#xff0c;有三个图片&#xff0c;如下图所…

@Autowired 和 @Resource思考(注入redisTemplate时发现一些奇怪的现象)

1. 前置知识 Configuration public class RedisConfig {Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template new RedisTemplate<>();template.setConnectionFactory(facto…

从零开始学习 sg200x 多核开发之 milkv-duo256 编译运行 sophpi

sophpi 是 算能官方针对 sg200x 系列的 SDK 仓库 https://github.com/sophgo/sophpi &#xff0c;支持 cv180x、cv81x、sg200x 系列的芯片。 SG2002 简介 SG2002 是面向边缘智能监控 IP 摄像机、智能猫眼门锁、可视门铃、居家智能等多项产品领域而推出的高性能、低功耗芯片&a…

防火墙----iptables

防火墙是位于内部网和外部网之间的屏障&#xff0c;他按照系统管理员预先定义好的规则来控制数据包的进出 一、iptables简介 防火墙会从以上至下的顺序来读取配置的策略规则&#xff0c;在找到匹配项后就立即结束匹配工作并去执行匹配项中定义的行为&#xff08;即放行或阻止&…