当前位置: 首页 > news >正文

SpringBoot整合Fastexcel/EasyExcel导出Excel导出多个图片

整个工具的代码都在Gitee或者Github地址内

gitee:solomon-parent: 这个项目主要是总结了工作上遇到的问题以及学习一些框架用于整合例如:rabbitMq、reids、Mqtt、S3协议的文件服务器、mongodb、xxl-job、powerjob还有用Docker compose部署各类中间组件。如果大家有什么想要弄成通用组件的,可以给我留言,我可以研究下

github:https://github.com/ZeroNing/solomon-parent

需要引入的JAR包(版本根据自身要求使用,本教程用的版本均为最新)

    <dependency><groupId>cn.idev.excel</groupId><artifactId>fastexcel</artifactId></dependency>

1.新增对List数组的Converter转换器

public class ListExcelConverter implements Converter<List<?>> {@Overridepublic Class<?> supportJavaTypeKey() {return List.class;}@Overridepublic WriteCellData<?> convertToExcelData(List<?> list, ExcelContentProperty contentProperty,GlobalConfiguration globalConfiguration) throws IOException {if (ValidateUtils.isEmpty(list)){return new WriteCellData<>("");}Object value = list.getFirst();boolean isInputStream = value instanceof InputStream;try {if(isInputStream){List<ImageData> imageDataList = new ArrayList<>();WriteCellData<?> writeCellData = new WriteCellData<>();for(Object val : list){InputStream inputStream = (InputStream) val;ImageData imageData = new ImageData();imageData.setImage(IoUtils.toByteArray(inputStream));imageDataList.add(imageData);}writeCellData.setType(CellDataTypeEnum.EMPTY);writeCellData.setImageDataList(imageDataList);return writeCellData;} else {List<String> stringList = new ArrayList<>();for(Object val : list){stringList.add(val.toString());}return new WriteCellData<>(stringList.toString());}}catch (Exception e){return new WriteCellData<>("InputStream异常");} finally {if (ValidateUtils.isNotEmpty(list) && isInputStream){for(Object val : list){InputStream inputStream = (InputStream) val;inputStream.close();}}}}
}

2.新增对图片的excel处理类

public class ImageCellWriteHandler implements CellWriteHandler {private final HashMap<String, List<ImageData>> imageDataMap = new HashMap<>(16);/*** 单元格的图片最大张数(每列的单元格图片张数不确定,单元格宽度需按照张数最多的长度来设置)*/private final AtomicReference<Integer> MAX_IMAGE_SIZE = new AtomicReference<>(0);/*** 默认图片宽度(单位像素):60*/private final static int DEFAULT_IMAGE_WIDTH = 60;/*** 默认像素转换因子:32*/private final static int DEFAULT_PIXEL_CONVERSION_FACTOR = 32;/*** 图片宽度,单位像素*/private final int imageWidth;/*** 像素转换因子*/private final int pixelConversionFactor;public ImageCellWriteHandler() {this.imageWidth = DEFAULT_IMAGE_WIDTH;this.pixelConversionFactor = DEFAULT_PIXEL_CONVERSION_FACTOR;}public ImageCellWriteHandler(int imageWidth, int pixelConversionFactor) {this.imageWidth = imageWidth;this.pixelConversionFactor = pixelConversionFactor;}@Overridepublic void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {//  在数据转换成功后 不是头就把类型设置成空if (isHead) {return;}//将要插入图片的单元格的type设置为空,下面再填充图片if (ValidateUtils.isNotEmpty(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 || ValidateUtils.isEmpty(cellDataList)) {return;}Sheet sheet = cell.getSheet();WriteCellData<?> writeCellData = cellDataList.getFirst();CellDataTypeEnum type = writeCellData.getType();if (type != CellDataTypeEnum.EMPTY) {return;}List<ImageData> imageDataList = imageDataMap.get(cell.getRowIndex() + "_" + cell.getColumnIndex());int widthValue =  imageWidth * pixelConversionFactor;sheet.setColumnWidth(cell.getColumnIndex(), widthValue * MAX_IMAGE_SIZE.get() + pixelConversionFactor);int i = 0;for (ImageData imageData : imageDataList) {// 读取文件this.insertImage(sheet, cell, imageData.getImage(), i);i = i + 1;}}/*** 重新插入一个图片** @param sheet       Excel页面* @param cell        表格元素* @param pictureData 图片数据* @param i           图片顺序*/public int insertImage(Sheet sheet, Cell cell, byte[] pictureData, int i) {int picWidth = Units.pixelToEMU(imageWidth);int index = sheet.getWorkbook().addPicture(pictureData, HSSFWorkbook.PICTURE_TYPE_PNG);Drawing<?> drawing = sheet.getDrawingPatriarch();if (drawing == null) {drawing = sheet.createDrawingPatriarch();}CreationHelper helper = sheet.getWorkbook().getCreationHelper();ClientAnchor anchor = helper.createClientAnchor();/** 设置图片坐标* 为了不让图片遮挡单元格的上边框和右边框,故 x1、x2、y1 这几个坐标点均向后移动了一个像素点*/anchor.setDx1(Units.pixelToEMU(1) + picWidth * i);anchor.setDx2(Units.pixelToEMU(1) + picWidth + picWidth * i);anchor.setDy1(Units.pixelToEMU(1));anchor.setDy2(0);//设置图片位置int columnIndex = cell.getColumnIndex();anchor.setCol1(columnIndex);anchor.setCol2(columnIndex);int rowIndex = cell.getRowIndex();anchor.setRow1(rowIndex);anchor.setRow2(rowIndex + 1);anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);drawing.createPicture(anchor, index);return index;}
}

最后需要在将转换器和excel处理器set入FastEasy/EasyExcel内,代码如下

ExcelWriterBuilder excelWriterBuilder = FastExcel.write(os, clazz).registerConverter(new ListExcelConverter()).registerWriteHandler(new ImageCellWriteHandler())

3.测试结果

3.1单行多照片测试

新增测试类

public class Test {@ExcelProperty(value = "abc")private List<InputStream> inputStream;@ExcelProperty(value = "123456")private List<String> abc = List.of("1","2","3","4","5","6","7","8","9");public List<InputStream> getInputStream() {return inputStream;}public void setInputStream(List<InputStream> inputStream) {this.inputStream = inputStream;}public List<String> getAbc() {return abc;}public void setAbc(List<String> abc) {this.abc = abc;}
}
@RestController
public class TestFileController {private final FileServiceInterface fileService;private final Logger logger = LoggerUtils.logger(TestFileController.class);public TestFileController(FileServiceInterface fileService) {this.fileService = fileService;}@PostMapping("/test")public void test(@RequestPart(name = "file") List<MultipartFile> file) throws Exception {String bucketName = "default";//判断桶是否存在
//        boolean bucketExists = fileService.bucketExists(bucketName);
//        logger.info("桶:{}{}",bucketExists,bucketExists ? "已存在" : "不存在");
//        上传文件
//        FileUpload fileUpload = fileService.upload(file,bucketName);
//        分享URL
//        String shareUrl = fileService.share(fileUpload.getFileName(),bucketName,3600L);
//        删除文件
//        fileService.deleteFile(fileUpload.getFileName(),bucketName);
//        删除桶
//        fileService.deleteBucket(bucketName);Test test = new Test();List<InputStream> inputStreams = new ArrayList<>();for(MultipartFile multipartFile: file){inputStreams.add(multipartFile.getInputStream());}test.setInputStream(inputStreams);List<Object> a = new ArrayList<>();a.add(test);fileService.upload(ExcelUtils. export("123.xls","123",Test.class,a),bucketName);
//        return new ResultVO<>("123");
//        return new ResultVO<String>(shareUrl);}
}

测试结果

3.2测试多列单照片

新增测试类

public class Test {@ExcelProperty(value = "abc")private List<InputStream> inputStream;@ExcelProperty(value = "123456")private List<String> abc = List.of("1","2","3","4","5","6","7","8","9");@ExcelProperty(value = "abc2")private List<InputStream> inputStream2;public List<InputStream> getInputStream2() {return inputStream2;}public void setInputStream2(List<InputStream> inputStream2) {this.inputStream2 = inputStream2;}public List<InputStream> getInputStream() {return inputStream;}public void setInputStream(List<InputStream> inputStream) {this.inputStream = inputStream;}public List<String> getAbc() {return abc;}public void setAbc(List<String> abc) {this.abc = abc;}
}
@RestController
public class TestFileController {private final FileServiceInterface fileService;private final Logger logger = LoggerUtils.logger(TestFileController.class);public TestFileController(FileServiceInterface fileService) {this.fileService = fileService;}@PostMapping("/test")public void test(@RequestPart(name = "file") List<MultipartFile> file) throws Exception {String bucketName = "default";//判断桶是否存在
//        boolean bucketExists = fileService.bucketExists(bucketName);
//        logger.info("桶:{}{}",bucketExists,bucketExists ? "已存在" : "不存在");
//        上传文件
//        FileUpload fileUpload = fileService.upload(file,bucketName);
//        分享URL
//        String shareUrl = fileService.share(fileUpload.getFileName(),bucketName,3600L);
//        删除文件
//        fileService.deleteFile(fileUpload.getFileName(),bucketName);
//        删除桶
//        fileService.deleteBucket(bucketName);Test test = new Test();for(MultipartFile multipartFile: file){List<InputStream> inputStream1 = test.getInputStream();if(ValidateUtils.isEmpty(inputStream1)){inputStream1 = new ArrayList<>();inputStream1.add(multipartFile.getInputStream());test.setInputStream(inputStream1);} else {List<InputStream> inputStream2 = test.getInputStream2();if(ValidateUtils.isEmpty(inputStream2)){inputStream2 = new ArrayList<>();inputStream2.add(multipartFile.getInputStream());test.setInputStream2(inputStream2);}}}List<Object> a = new ArrayList<>();a.add(test);fileService.upload(ExcelUtils. export("123.xls","123",Test.class,a),bucketName);
//        return new ResultVO<>("123");
//        return new ResultVO<String>(shareUrl);}
}

测试结果

 

http://www.dtcms.com/a/298071.html

相关文章:

  • QKV 为什么是三个矩阵?注意力为何要除以 √d?多头注意力到底有啥用?
  • MyBatis 之缓存机制核心解析
  • android JXL 导出Excel(.xls/xlsx)
  • 解决企业微信收集表没有图片、文件组件,不能收集图片的问题
  • windows 安排 openssl
  • 三、操作系统——第1章:计算机系统概述
  • 星痕共鸣 C++显示打出的攻击力
  • 【前端工程化】前端项目开发过程中如何做好通知管理?
  • AVL树和红黑树的特性以及模拟实现
  • 【CMake】CMake 与 C++ 协同:条件配置机制及控制台控制实例解析
  • [C++]string::substr
  • MindJourney:构建空间智能的新范式——VLM与视频扩散式世界模型的融合
  • 【LeetCode Solutions】LeetCode 热题 100 题解(16 ~ 20)
  • 【牛客网C语言刷题合集】(三)
  • 2025年-ClickHouse 高性能实时分析数据库(大纲版)
  • 【开发杂谈】用AI玩AI聊天游戏:使用 Electron 和 Python 开发大模型语音聊天软件
  • 如何搭建Linux环境下的flink本地集群
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-26,(知识点:硬件电路的调试方法:信号追踪,替换,分段调试)
  • 飞算 JavaAI “撤回接口信息” 功能:误删接口不用慌,一键恢复更省心
  • Linux 设备驱动模型
  • WINDOWS10系统重装软件篇
  • QML图形效果之阴影效果(DropShadow与InnerShadow)
  • Cacti命令执行漏洞分析(CVE-2022-46169)
  • compileSdkVersion和targetSdkVersion可以不一样的版本吗
  • 图论:并查集
  • 深入解析JVM垃圾回收调优:性能优化实践指南
  • Python 数据可视化之 Matplotlib 库
  • Java常用命令、JVM常用命令
  • RAG面试内容整理-3. 向量检索原理与常用库(ANN、FAISS、Milvus 等)
  • blender基本操作