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.pswp.cn/pingmian/91053.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91053.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91053.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡原理--HTTPHTTPS

目錄 一、HTTP 1.1 HTTP是什么 1.2 HTTP協議的工作過程 1.3 HTTP協議格式 1.3.1 抓包工具的使用 1.3.2 抓包結果 1.4 HTTP請求 1.4.1 URL 1.4.2 認識“方法” (method) 1.4.3 認識請求“報頭”(header) 1.4.4 認識請求“正文”(body) 1.5 HTTP 響應詳解 1.5.1 HTTP…

『 C++ 入門到放棄 』- 哈希表

一、哈希的概念 哈希&#xff0c;也稱「 散列 」是一種用來進行高效查找的數據結構&#xff0c;查找的時間復雜度平均為O(1)&#xff0c;其本質就是依賴哈希函數這個算法來將 key 和該 key 存儲位置建立一個映射關系。 而因為是有著映射關系&#xff0c;所以哈希的事件復雜度為…

零售收銀系統開源代碼全解析:連鎖門店一體化解決方案(含POS+進銷存+商城)

過去10年&#xff0c;收銀系統技術經歷了從單機版到云服務、從單純結算到全渠道整合的快速演進。面對連鎖多門店、AI稱重、智能分賬、跨店庫存同步等新需求&#xff0c;很多企業的現有傳統saas系統已顯乏力。本文將梳理收銀系統關鍵技術指標&#xff0c;助您在系統升級時做出明…

能源高效利用如何實現?樓宇自控系統智能化監管建筑設備

隨著全球能源危機日益嚴峻和“雙碳”目標的持續推進&#xff0c;建筑領域作為能耗大戶&#xff08;約占社會總能耗的40%&#xff09;&#xff0c;其節能潛力備受關注。樓宇自控系統&#xff08;Building Automation System&#xff0c;簡稱BAS&#xff09;作為建筑智能化的核心…

校園二手交易小程序的設計與實現

文章目錄前言詳細視頻演示具體實現截圖后端框架SpringBoot微信小程序持久層框架MyBaits成功系統案例&#xff1a;參考代碼數據庫源碼獲取前言 博主介紹:CSDN特邀作者、985高校計算機專業畢業、現任某互聯網大廠高級全棧開發工程師、Gitee/掘金/華為云/阿里云/GitHub等平臺持續…

Redis(二):Redis高級特性和應用(慢查詢、Pipeline、事務)

Redis的慢查詢 許多存儲系統&#xff08;例如 MySQL)提供慢查詢日志幫助開發和運維人員定位系統存在的慢操作。所謂慢查詢日志就是系統在命令執行前后計算每條命令的執行時間&#xff0c;當超過預設閥值,就將這條命令的相關信息&#xff08;例如:發生時間&#xff0c;耗時&…

如何為你的WordPress網站選擇合適的安全插件

在管理WordPress網站時&#xff0c;安全因素至關重要。由于WordPress的廣泛使用&#xff0c;它也成為了黑客攻擊的首要目標。為了避免潛在的安全風險&#xff0c;選擇合適的安全插件至關重要。而Wordfence和iThemes&#xff0c;作為兩款頗具人氣的WordPress安全插件&#xff0c…

我們使用Rust開發的AI知識庫應用

這段時間陸陸續續的開發了2個AI知識庫應用&#xff0c;一個面向企業&#xff0c;一個面向C端用戶。 飛樹智庫&#xff1a;一個安全高效的面向 企業的知識庫平臺&#xff08;https://fskb.coderbox.cn/&#xff09;。 小飛樹&#xff1a;一個專注于個人知識管理的AI應用&#…

自動化測試實戰篇

目錄 1. 自動化實施步驟 1.1 編寫web測試用例 1.2 自動化測試腳本開發 1.3 將自動化測試補充至測試報告 1. 自動化實施步驟 1.1 編寫web測試用例 1.2 自動化測試腳本開發 TestDevelopment: 測試用例 - Gitee.comhttps://gitee.com/Axurea/test-development/tree/master/2…

idea 服務器Debug端口啟動設置

一&#xff1a;在阿里云服務器安全組已經設置了端口授權對象&#xff1a;正確命令&#xff1a;nohup java -Xdebug -Xrunjdwp:transportdt_socket,servery,suspendn,address9998 -jar -Duser.timezoneGMT08 -Xms256m -Xmx256m /opt/projects/*/*/*-starter-1.0-SNAPSHOT.jar -…

大模型量化004

Bert P-tuning BertPET、BertP-Tuning Chain of Thought Few shot Cot Auto-COT 解決手動編寫高質量CoT示例麻煩耗時的問題 Auto COT 自動思維鏈生成器 1.業務場景&#xff1a; 每天收到很多反饋&#xff0c;之前需要人工整理&#xff0c;找到重點&#xff0c;做判斷那些需要立…

C#(基本語法)

數據類型C#是一種強類型語言&#xff0c;變量必須聲明類型。基本數據類型包括整型&#xff08;int、long&#xff09;、浮點型&#xff08;float、double&#xff09;、布爾型&#xff08;bool&#xff09;、字符型&#xff08;char&#xff09;和字符串型&#xff08;string&a…

ARM-I2C軟實現

開發流程引腳初始化引腳功能定義實現讀操作實現寫操作GD32F4軟件I2C初始化void SoftI2C_init() {// 時鐘配置rcu_periph_clock_enable(SCL_RCU);// 設置輸出模式gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCL_PIN);gpio_output_options_set(SCL_PORT, GPIO_O…

防水醫用無人機市場報告:現狀、趨勢與洞察

市場規模與增長趨勢在全球醫療科技快速發展的當下&#xff0c;防水醫用無人機市場正嶄露頭角&#xff0c;展現出強勁的發展勢頭。據 QYR統計&#xff0c;2023 年全球醫用無人機市場銷售額達到 1.9 億美元&#xff0c;預計到 2030 年將飆升至 8.5 億美元&#xff0c;年復合增長率…

haproxy代理

一.負載均衡 1.1.什么是負載均衡 負載均衡&#xff1a;Load Balance&#xff0c;簡稱LB&#xff0c;是一種服務或基于硬件設備等實現的高可用反向代理技術&#xff0c;負載均 衡將特定的業務(web服務、網絡流量等)分擔給指定的一個或多個后端特定的服務器或設備&#xff0c;…

【面試】軟件測試面試題

1. 測試用例如何編寫 2. bug的生命周期 項目有多少人&#xff1f;多少條測試用例&#xff1f;多少bug&#xff1f;自己發現的第一條&#xff1f;&#xff08;是不是bug&#xff09; 3. 缺陷管理工具 包括Jira, PingCode, 禪道&#xff0c;BugZilla&#xff0c;Redmine, TAPD&am…

HbuilderX開發小程序

1.打卡HbuilderX&#xff0c;選擇文件—新建—項目2.創建項目3.在HbuilderX中運行前要確定微信開發這工具的服務端口號是打開的4.HbuilderX中點擊預覽可以實時預覽5.在微信開發者中進行本地測試點擊后自動跳轉到微信開發者工具中運行項目

Netty中FastThreadLocal解讀

io.netty.util.concurrent.FastThreadLocal 是 Netty 中提供的高性能線程局部存儲&#xff08;Thread-Local Storage&#xff09;實現&#xff0c;位于 io.netty.util.concurrent 包。它是 Java 標準庫 ThreadLocal 的替代品&#xff0c;旨在優化性能&#xff0c;減少內存分配和…

上海迪士尼游玩攻略 小鐵寄存柜讓你輕松暢玩

去上海迪士尼玩最煩帶一堆行李&#xff0c;其實有小鐵寄存柜幫忙就能輕裝上陣&#xff0c;各個關鍵位置都有分布&#xff0c;玩起來特別省心。?剛到迪士尼的時候&#xff0c;要是坐地鐵到上海國際旅游度假區站&#xff0c;1/2 號口安檢區就有小鐵柜&#xff0c;行李箱、大背包…

飛算科技重磅出品:飛算 JavaAI 重構 Java 開發效率新標桿

在 Java 開發領域&#xff0c;一款由國家級高新技術企業自主研發的智能工具正引發行業關注 —— 飛算 JavaAI 不僅承載著中國原創技術的創新基因&#xff0c;更以貼合實際開發場景的功能設計&#xff0c;成為眾多企業提升 Java 開發效率的核心助力。?作為飛算數智科技&#xf…