EasyExcel 单元格根据图片数量动态设置宽度

在使用 EasyExcel 导出 Excel 时,如果某个单元格是图片内容,且存在多张图片,此时就需要单元格根据图片数量动态设置宽度。
经过自己的研究和实验,导出效果如下:
image.png
具体代码如下:

  1. EasyExcel 版本
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version>
</dependency>
  1. 定义Excel图片链接转换工具
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ImageData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.IoUtils;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;/*** Excel图片链接转换工具** @author 天航星* @date 2024-07-05 15:03*/
public class ExcelImageUrlConverterUtils implements Converter<List<String>> {@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic WriteCellData<?> convertToExcelData(List<String> value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {List<ImageData> imageDataList = new ArrayList<>();for (String url : value) {try {URL imageUrl = new URL(url);byte[] bytes = IoUtils.toByteArray(imageUrl.openConnection().getInputStream());ImageData imageData = new ImageData();imageData.setImage(bytes);imageDataList.add(imageData);} catch (Exception e) {e.printStackTrace();}}WriteCellData writeCellData = new WriteCellData();writeCellData.setImageDataList(imageDataList);writeCellData.setType(CellDataTypeEnum.STRING);return writeCellData;}
}
  1. 定义图片属性
@ExcelProperty(value = "现场图片(模拟机器人视角)", converter = ExcelImageUrlConverterUtils.class)
private List<String> images;
  1. 定义单元格图片写入拦截器
import cn.hutool.core.util.ObjUtil;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.ImageData;
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.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.Units;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;/*** 单元格图片写入拦截器* * @author 天航星* @date 2024-07-05 15:03*/
public class ImageCellWriteHandler implements CellWriteHandler {private final Map<String,List<ImageData>> imageDataMap = new HashMap<>();/*** 单元格的图片最大张数(每列的单元格图片张数不确定,单元格宽度需按照张数最多的长度来设置)*/private final AtomicReference<Integer> MAX_IMAGE_SIZE = new AtomicReference<>(0);@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {if (isHead) {return;}// 将单元格图片数据复制出来,清空单元格图片数据if (!ObjUtil.isEmpty(cellData.getImageDataList())) {imageDataMap.put(cell.getRowIndex() + "_" + cell.getColumnIndex(), cellData.getImageDataList());cellData.setType(CellDataTypeEnum.EMPTY);cellData.setImageDataList(new ArrayList<>());}}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {if (isHead || ObjUtil.isEmpty(cellDataList)) {return;}String key = cell.getRowIndex() + "_" + cell.getColumnIndex();List<ImageData> imageDataList = imageDataMap.get(key);if (ObjUtil.isEmpty(imageDataList)) {return;}if (imageDataList.size() > MAX_IMAGE_SIZE.get()) {MAX_IMAGE_SIZE.set(imageDataList.size());}Sheet sheet = cell.getSheet();// 设置单元格行高sheet.getRow(cell.getRowIndex()).setHeight((short) 900);// 设置单元格列宽(乘多少代表容纳多少张图片)sheet.setColumnWidth(cell.getColumnIndex(), MAX_IMAGE_SIZE.get() > 0 ? 3493 * MAX_IMAGE_SIZE.get() : 3493);// 插入图片for (int i = 0; i < imageDataList.size(); i++) {ImageData imageData = imageDataList.get(i);if (ObjUtil.isEmpty(imageData)) {continue;}byte[] image = imageData.getImage();this.insertImage(sheet, cell, image, i);}imageDataMap.remove(key);}private void insertImage(Sheet sheet, Cell cell, byte[] pictureData, int i) {// 图片宽度int pictureWidth = Units.pixelToEMU(100);int index = sheet.getWorkbook().addPicture(pictureData, HSSFWorkbook.PICTURE_TYPE_PNG);Drawing<?> drawing = sheet.getDrawingPatriarch();if (ObjUtil.isEmpty(drawing)) {drawing = sheet.createDrawingPatriarch();}CreationHelper helper = sheet.getWorkbook().getCreationHelper();ClientAnchor anchor = helper.createClientAnchor();// 设置图片在哪个单元格中anchor.setCol1(cell.getColumnIndex());anchor.setCol2(cell.getColumnIndex());anchor.setRow1(cell.getRowIndex());anchor.setRow2(cell.getRowIndex() + 1);// 设置图片在单元格中的位置anchor.setDx1(pictureWidth * i);anchor.setDx2(pictureWidth + pictureWidth * i);anchor.setDy1(0);anchor.setDy2(0);// 设置图片可以随着单元格移动anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);drawing.createPicture(anchor, index);}
}
  1. 写入时引用
EasyExcel.write("Excel文件名称.xlsx", DemoData.class).sheet("测试").registerWriteHandler(new ImageCellWriteHandler()).doWrite(new DemoData());

环境:

  • JDK:1.8.0_202
  • SpringBoot:2.7.17
  • EasyExcel:3.3.2

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

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

相关文章

Haxm安装失败的解决办法

确认你的处理器是否是Intel的&#xff0c;如果是AMD那就无法安装&#xff0c;如果是Intel的&#xff0c;再确认是否支持V1T 如果处理器是Intel的且支持VT&#xff0c;在开机时进入BIOS界面&#xff0c;不同的品牌进入BIOS的方法各不相同&#xff0c;通常是F2/F12/delete些&…

Python爬虫零基础实战,简洁实用!

1.爬虫简介 简单来讲&#xff0c;爬虫就是一个探测机器&#xff0c;它的基本操作就是模拟人的行为去各个网站溜达&#xff0c;点点按钮&#xff0c;查查数据&#xff0c;或者把看到的信息背回来。就像一只虫子在一幢楼里不知疲倦地爬来爬去。 你可以简单地想象&#xff1a;每个…

论文学习 --- RL Maximumdiffusion reinforcement learning

前言 个人拙见,如果我的理解有问题欢迎讨论 (●′ω`●) 文章出处:https://techxplore.com/news/2024-05-random-robots-reliable-ai-algorithm.html 研究背景 最大扩散强化学习(MaxDiff RL)是一种创新的强化学习方法,借鉴了统计力学中的扩散过程和最大熵原理。该方法在…

Hadoop的namenode启动不起来

1、 排查原因 Initialization failed for Block pool (Datanode Uuid a5d441af-d074-4758-a3ff-e1563b709267) service to node1/192.168.88.101:8020. Exiting. java.io.IOException: Incompatible clusterIDs in /data/dn: namenode clusterID CID-674c5515-3fe1-4a9c-881d…

AIGC技术加持,英智法律智能体来了!

法律行业作为一个由大量文件积累的领域&#xff0c;非常适合由数据驱动的AI智能体。人工智能在法律领域的应用已经成为不可逆转的趋势。根据最高人民法院发布的《关于规范和加强人工智能司法应用的意见》&#xff0c;国家鼓励在司法领域广泛应用人工智能技术&#xff0c;以提高…

四端口千兆以太网交换机与 SFP 扩展功能

在数字化时代&#xff0c;网络基础设施的重要性日益凸显&#xff0c;它是企业和个人取得成功的关键支撑。配备 SFP 插槽的 4 端口千兆以太网交换机提供了一种灵活且可扩展的网络解决方案&#xff0c;能够应对快速的数据传输、低延迟以及不断增长的带宽需求。本篇文章深入探讨了…

IP地址配置

1.为虚拟机配置IP地址&#xff0c;网关&#xff0c;DNS 例如&#xff1a;手动给虚拟机配置IP地址为 192.168.5.50/24&#xff1b;网关地址为&#xff1a;192.168.5.2&#xff1b;DNS地址为&#xff1a;192.168.5.2 解题步骤如下&#xff1a; #配置IP地址 [rootlocalhost ~]#…

大厂都在加急招人的大模型LLM,到底怎么学?

大模型如何入坑&#xff1f; 想要完全了解大模型&#xff0c;你首先要了解市面上的LLM大模型现状&#xff0c;学习Python语言、Prompt提示工程&#xff0c;然后深入理解Function Calling、RAG、LangChain 、Agents等 很多人不知道想要自学大模型&#xff0c;要按什么路线学&a…

【网络安全】第4讲 身份认证技术(笔记)

一、身份认证技术概述 1、身份认证 是网络安全的第一道防线。是最基本的安全服务&#xff0c;其他的安全服务都依赖于它。在物联网应用系统中&#xff0c;身份认证也是整个物联网应用层信息安全体系的基础。 2、基本身份认证技术 &#xff08;1&#xff09;双方认证 是一种双…

人员定位系统在监狱中的应用也同样重要!

监狱管理应用人员定位系统怎么样&#xff1f;新锐科创告诉你&#xff0c;人员定位系统在监狱中的应用也是很重要的&#xff0c;运用这种新型的定位系统&#xff0c;来起到管理监狱人员的作用。 人员定位系统 在监狱中&#xff0c;关押着大量的犯人&#xff0c;所以&#xff0c…

拓扑Transformer模型TopoFormer:革新药物研发的智能钥匙

在药物研发的浩瀚征途中&#xff0c;每一步都充满了挑战与未知。从发现潜在的治疗靶点&#xff0c;到筛选出有效的药物分子&#xff0c;再到通过临床试验验证其安全性和有效性&#xff0c;这一过程往往耗时漫长且成本高昂。然而&#xff0c;随着人工智能技术的飞速发展&#xf…

昇思25天学习打卡营第15天|ResNet50图像分类

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) ResNet50图像分类 图像分类是最基础的计算机视觉应用&#xff0c;属于有监督学习类别&#xff0c;如给定一张图像(猫、狗、飞机、汽车等等)&#xff0c;判断图像所属的类别。本章将介绍使用ResN…

【JAVA入门】Day13 - 代码块

【JAVA入门】Day13 - 代码块 文章目录 【JAVA入门】Day13 - 代码块一、局部代码块二、构造代码块三、静态代码块 在 Java 中&#xff0c;两个大括号 { } 中间的部分叫一个代码块&#xff0c;代码块又分为&#xff1a;局部代码块、构造代码块、静态代码块三种。 一、局部代码块…

c++11新特性-3-自动类型推导

文章目录 自动类型推导1.auto1.1 const修饰1.2 auto不能使用的场景1.3 auto应用场景 2.decltype1.1 基本语法 自动类型推导 1.auto 注意&#xff0c;auto必须进行初始化 auto i 10; //int类型auto k 3.14; //double类型auto db; //错误1.1 const修饰 当const修改指针或者…

C++:构造函数是什么东西

一、构造函数是什么 在C中&#xff0c;构造函数是一种特殊成员函数&#xff0c;它有一下几个明显的特征&#xff1a; 1、它自动在创建新对象时被调用。 2、其名称与类名相同&#xff0c; 3、没有返回类型&#xff0c; 4、通常没有参数&#xff08;除了默认情况下的隐式thi…

跟《经济学人》学英文:2024年06月01日这期 The side-effects of the TikTok tussle

The side-effects of the TikTok tussle tussle&#xff1a;美 [ˈtəsəl] 激烈扭打&#xff1b;争夺 注意发音 side-effects&#xff1a;副作用&#xff1b;&#xff08;side-effect的复数&#xff09; As the app’s future hangs in the balance, the ramifications of …

MySQL的并发控制、事务、日志

目录 一.并发控制 1.锁机制 2.加锁与释放锁 二.事务&#xff08;transactions&#xff09; 1.事物的概念 2.ACID特性 3.事务隔离级别 三.日志 1.事务日志 2.错误日志 3.通用日志 4.慢查询日志 5.二进制日志 备份 一.并发控制 在 MySQL 中&#xff0c;并发控制是确…

都有哪些离线翻译器软件?没网就用这4个

经历完痛苦的期末考&#xff0c;可算是千盼万盼等来了日思夜想的暑假&#xff01;趁着这大好时光&#xff0c;怎么能不来一场出国游呢~ 不知道有多少小伙伴和我一样&#xff0c;出国玩最怕的就是语言不通&#xff0c;不管是吃饭还是游玩体验感都会大受影响~好在多出国玩了几趟…

ES6模块化学习

1. 回顾&#xff1a;node.js 中如何实现模块化 node.js 遵循了 CommonJS 的模块化规范。其中&#xff1a; 导入其它模块使用 require() 方法 模块对外共享成员使用 module.exports 对象 模块化的好处&#xff1a; 大家都遵守同样的模块化规范写代码&#xff…

Linux 时区文件格式【man 5 tzfile】

时区文件格式标准&#xff1a;https://datatracker.ietf.org/doc/html/rfc8536 1. NAME&#xff08;名&#xff09; tzfile - 时区文件。&#xff08;非文本文件&#xff09; 2. DESCRIPTION&#xff08;描述&#xff09; 本页介绍被 tzset(3) 函数使用的时区文件的结构。这…