EasyExcel导出Excel和多个图片到Zip,并实现超链接

前言:之前做了将图片直接插入到excel的需求,由于数据太多会导致导出慢或者直接报错,于是采用了将图片和excel分开放在一个zip压缩包中,并且,excel中对应图片的列点击后可以直接超链接到对应的图片。

 实现效果:

 

依赖版本:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.0</version>
        </dependency>

动态添加超链接处理类:

package com.aicut.monitor.utils;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.ss.usermodel.*;

import java.util.List;

/**
 * excel动态添加超链接处理类
 */
public class ExcelHyperlinkHandler implements CellWriteHandler {
    /**
     * 添加超链接的字段的下标
     */
    private int[] mergeColumnIndex;
    /**
     * 从第几行开始添加,0代表标题行
     */
    private int mergeRowIndex;

    public ExcelHyperlinkHandler() {
    }

    public ExcelHyperlinkHandler(int mergeRowIndex, int[] mergeColumnIndex) {
        this.mergeRowIndex = mergeRowIndex;
        this.mergeColumnIndex = mergeColumnIndex;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
                                 Head head, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell,
                                Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();

        if (curRowIndex >= mergeRowIndex) {
            for (int i = 0; i < mergeColumnIndex.length; i++) {
                if (curColIndex == mergeColumnIndex[i]) {
                    mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                    break;
                }
            }
        }
    }

    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {

        //获得超链接,当前单元格的内容就是一个超链接
        String stringCellValue = cell.getCellType()==CellType.STRING ? cell.getStringCellValue():null;
        if (StrUtil.isNotBlank(stringCellValue)) {
            CreationHelper creationHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper();
            Hyperlink hyperlink = creationHelper.createHyperlink(HyperlinkType.URL);
            hyperlink.setAddress(stringCellValue);
            cell.setHyperlink(hyperlink);//添加超链接
        }
    }
}

导出zip方法:

@PostMapping("/exportZip")
    public void exportZip(HttpServletResponse response,
                       @RequestParam(value = "startTime",required = false)String startTime,
                       @RequestParam(value = "endTime",required = false)String endTime,
                       @RequestParam(value = "deviceName",required = false)String deviceName) throws IOException {
        List<CutterImageVO> cutterImageVOList = CutterImageService.getCutterImageList(startTime, endTime, deviceName);

        String fileName = "豁口图片数据";
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".zip", "UTF-8"));

        //easyExcelUtil.exportExcelInZip(response,fileName,"豁口图片数据",CutterImageVO.class, cutterImageVOList);

        ServletOutputStream outputStream = response.getOutputStream();
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        byte[] buf = new byte[1024];
        try {
            GetPresignedObjectUrlArgs args = null;
            for (CutterImageVO cutterImageVO : cutterImageVOList) {
                args = GetPresignedObjectUrlArgs.builder()
                        .bucket(minioConfig.getBucketName())
                        .object(cutterImageVO.getImageUrl())
                        .expiry(1, TimeUnit.DAYS)
                        .method(Method.GET)
                        .build();
               String imgUrl = client.getPresignedObjectUrl(args);
               URL url = new URL(imgUrl);
               URLConnection conn = url.openConnection();
               InputStream in = conn.getInputStream();
               zipOutputStream.putNextEntry(new ZipEntry(cutterImageVO.getImageUrl()));
               int len = -1;
               while ((len=in.read(buf))!=-1){
                    zipOutputStream.write(buf,0,len);
               }
               in.close();
            }
            //构建一个excel对象,这里注意type要是xls不能是xlsx,否则下面的写入后流会关闭,导致报错
            ExcelWriter excelWriter = EasyExcel.write()
                    .excelType(ExcelTypeEnum.XLS)
                    .registerWriteHandler(new ExcelHyperlinkHandler(1, new int[]{7}))
                    .build();
            //构建一个sheet页
            WriteSheet writeSheet = EasyExcel.writerSheet(fileName).build();
            //构建excel表头信息
            WriteTable writeTable0 = EasyExcel.writerTable(0).head(CutterImageVO.class).needHead(Boolean.TRUE).build();
            //将表头和数据写入表格
            excelWriter.write(cutterImageVOList, writeSheet, writeTable0);

            //创建压缩文件
            ZipEntry zipEntry = new ZipEntry(fileName + ".xls");
            zipOutputStream.putNextEntry(zipEntry);
            Workbook workbook = excelWriter.writeContext().writeWorkbookHolder().getWorkbook();
            //将excel对象以流的形式写入压缩流
            workbook.write(zipOutputStream);

        }catch (Exception e){
            log.error(e.getMessage(), e);
            //抛出异常结束程序
            throw new RuntimeException("数据导出接口异常");
        }finally {
            IOUtils.closeQuietly(zipOutputStream);
            IOUtils.closeQuietly(outputStream);
        }
    }

参考博客:

easyExcel导出功能+图片压缩打包成ZIP,实现浏览器自动下载_eazyexcel 导出excel打包成zip-CSDN博客

使用EasyExcel动态合并单元格和对指定列添加超链接_easyexcel 超链接-CSDN博客

Java代码实现Excel导出多份文件并压缩成zip包保存到OSS服务器返回URL访问下载_java 将文件压缩成压缩包存储到服务器-CSDN博客

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

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

相关文章

东芝2323AMW数码复合机扫描文件至U盘无法选择JPEG问题解决方法

东芝eSTUDIO2323AMW数码复合机扫描文件至U盘无法选择JPEG问题解决方法 问题描述&#xff1a; 东芝eSTUDIO2323AMW数码复合机扫描文件至U盘只能输出PDF文件格式&#xff0c;而下方的JPEG是灰色的无法选择&#xff1b; 解决方法&#xff1a; 将模式选择为“彩色模式”之后“JPEG”…

【c语言】简单贪吃蛇的实现

目录 一、游戏说明 ​编辑 二、地图坐标​ ​编辑 三、头文件 四、蛇身和食物​ 五、数据结构设计​ 蛇节点结构如下&#xff1a; 封装一个Snake的结构来维护整条贪吃蛇&#xff1a;​ 蛇的方向&#xff0c;可以一一列举&#xff0c;使用枚举&#xff1a; 游戏状态&a…

利用操作符解题的精彩瞬间

下面是链接为了解释练习2的并且还有与操作符相关的知识。 C语言与操作符相关的经典例题-CSDN博客 操作符详解&#xff08;上&#xff09;-CSDN博客 操作符详解&#xff08;下&#xff09;-CSDN博客 目录 练习1&#xff1a;在一个整型数组中&#xff0c;只有一个数字出现一…

多源BFS

AcWing 173. 矩阵距离 #include <bits/stdc.h> using namespace std;const int N 1010; char g[N][N]; int n, m; typedef pair<int, int> PII; int d[N][N]; bool st[N][N];int dx[] {0, 0, 1, -1}; int dy[] {1, -1, 0, 0};void bfs() {queue<PII> q;me…

C#用正则表达式验证格式:电话号码、密码、邮编、手机号码、身份证、指定的小数点后位数、有效月、有效日

正则表达式在程序设计中有着重要的位置&#xff0c;经常被用于处理字符串信息。 用Regex类的IsMatch方法&#xff0c;使用正则表达式可以验证电话号码是否合法。 一、涉及到的知识点 Regex类的IsMatch方法用于指示正则表达式使用pattern参数中指定的正则表达式是否在输入字符串…

redis 极简分布式锁实现

写在前面 工作中遇到&#xff0c;整理 reids 做简单分布式锁的思考博文适合刚接触 redis 的小伙伴理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都是…

个人多域名SSL证书推荐

SSL数字证书和通配符SSL证书、多域名通配符SSL证书一样&#xff0c;可以同时保护多个域名站点&#xff0c;但是它们之间还是存在一些区别。其中&#xff0c;最明显的区别就是它们的保护域名网站的类型和适用场景。今天就随SSL盾小编来了解多域名SSL证书。 1.多域名SSL证书可以…

Netty源码三:NioEventLoop创建与run方法

1.入口 会调用到父类SingleThreadEventLoop的构造方法 2.SingleThreadEventLoop 继续调用父类SingleThreadEventExecutor的构造方法 3.SingleThreadEventExecutor 到这里完整的总结一下&#xff1a; 将线程执行器保存到每一个SingleThreadEventExcutor里面去创建了MpscQu…

汽车标定技术(十七)--Bypass的前世今生

目录 1.Bypass的诞生 2.Bypass的发扬光大 2.1 基于XCP的Bypassing 2.2 基于Debug的Bypass 2.3 小结 3.Bypass的实际应用 1.Bypass的诞生 下图我相信只要用过INCA的朋友都非常熟悉。 这是远古时期(2000年左右&#xff1f;我猜)ETAS针对发动机控制参数标定设计的一种并行数据…

【鸿蒙开发】第十二章 Stage模型应用组件-信息传递载体Want

1 概述 上一章节我们学习了UIAbility组件【鸿蒙开发】第十一章 Stage模型应用组件-UIAbility&#xff0c;其中组件间的交互传递信息的媒介就是Want&#xff0c;本章节我们来更加深入学习Want的相关知识。 Want是一种对象&#xff0c;用于在应用组件之间传递信息。 2 类型 显…

【CSS】常见

一. 溢出隐藏 1.1 单行文本溢出 .content{max-width:200px; /* 定义容器最大宽度 */overflow:hidden; /* 隐藏溢出的内容 */text-overflow:ellipsis; /* 溢出部分...表示 */white-space: nowrap; /* 确保文本在一行内显示 */ }问题&#xff1a;display:flex 和 ellipsis 冲…

Centos7安装原生Nginx并配置反向代理

一、背景 当我的应用程序需要集群化部署之时&#xff0c;必然需要一个反向代理&#xff0c;当然Nginx的大名&#xff0c;这里不做更多的介绍了&#xff0c;这里介绍一下Nginx常用的四大阵营 1 Ngnix 原生版本 nginx news 2 Nginx Plus 商用版&#xff08;收费的&#xff09…

【JAVA】Long类型返回到前端,精度丢失

一. 问题阐述 20位long类型的数字&#xff0c;从后端接口返回到前端后【四舍五入】 MYSQL端 &#xff08;1&#xff09;bigint (20) &#xff08;2&#xff09;具体某一条数据 JAVA端 &#xff08;1&#xff09;实体类 &#xff08;2&#xff09;服务类 &#xff08;3&…

传统企业要实现数字化转型,需要从哪些方面入手?

数字化转型是一个综合过程&#xff0c;涉及利用数字技术从根本上改变企业运营方式并为客户提供价值。希望踏上数字化转型之旅的传统企业应考虑几个关键方面&#xff0c;以确保成功、平稳过渡。以下是一些需要开始的基本方面&#xff1a; 1.领导承诺&#xff1a; 自上而下的支…

idea Statistic使用

问题描述&#xff1a;本地idea版本为2018.3.5&#xff0c;安装Statistic插件后没有出现Statistic图标 原因如下&#xff1a;插件版本太新了&#xff0c;需要历史版本 解决办法&#xff1a; IDEA安装代码统计插件Statistic后左下角图标出不来(亲测)_idea statistic不展示-CSD…

20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动

20240130在ubuntu20.04.6下卸载NVIDIA显卡的驱动 2024/1/30 12:58 缘起&#xff0c;为了在ubuntu20.4.6下使用whisper&#xff0c;以前用的是GTX1080M&#xff0c;装了535的驱动。 现在在PDD拼多多上了入手了一张二手的GTX1080&#xff0c;需要将安装最新的545的驱动程序&#…

老网工秒懂的行业“黑话”,你对齐颗粒度了吗?

你们好&#xff0c;我的网工朋友。 年关将至&#xff0c;多少网工朋友放假了&#xff1f;学技术的心是不是都飘走了。 快过年了&#xff0c;准备和大家聊点有趣、轻松的话题。 前两天部门团建&#xff0c;大家一起去看了年会不能停&#xff0c;挺有意思。 互联网黑话那是一…

解析Kubernets pod DNS域名

k8s dns理解 这个博主讲的很详细 我的这篇文章主要是演示测试 k8s的dns nslookup怎么解析到k8spod域名 创建一个busybox的pod&#xff0c;测试一下pod内是否可以解析 1、流程验证 cat >dns-Deployment.yaml<<EOF apiVersion: apps/v1 kind: Deployment metadata:nam…

PLC找出数据队列里的最大数和最小数所在序号(完整SCL代码)

对于一些需要根据累计运行时间智能启泵和停泵的应用场景,可能会用到此算法,在学习本算法之前,我们需要了解如何在一组数据队列里找出最大数和最小数(这里不涉及排序,只要找到最大数和最小数)。 最大数和最小数搜索FC 请参考下面文章链接: https://rxxw-control.blog.csd…

java+springboot企业员工工作日志审批管理系统ssm+vue

企业OA管理系统具有管理员角色&#xff0c;用户角色&#xff0c;这两个操作权限。 ①管理员 管理员在企业OA管理系统里面查看并管理人事信息&#xff0c;工作审批信息&#xff0c;部门信息&#xff0c;通知公告信息以及内部邮件信息。 管理员功能结构图如下&#xff1a; ide工具…