【193】Java8調用POI 5.2.5生成帶圖片的Excel文件

本文假定 Excel 文件中保存的是員工數據,并且數據中帶有員工的頭像。代碼支持的圖片格式有png、bmp、jpg、gif。但是這里需要注意,有些網站上下載的圖片雖然后綴名是 jpg,但是文件二進制內容的格式是 WebP 的。Java8 目前官方api不支持 WebP ,本文不涉及webp相關話題,本文代碼也不支持 WebP 格式。

另外我還遇到個坑,POI 5.2.5 在處理部分 jpg 格式圖片的時候,無法把圖片輸出到 Excel 文件。為了解決這個問題,我在代碼中把所有圖片強行轉成 png,保存為硬盤上的臨時文件,再重新輸出到 Excel 文件中。這個問題我沒有在 POI 4.1.2 版本遇到過。

POI 的接口是線程不安全的,多個線程同時向一個文件輸出會造成錯誤。如果讀者想要在多線程環境(比如網站后端)使用下面的代碼,要么使用鎖,要么確保各個線程輸出不同的文件。

本文的代碼計算了圖片的縮放比例,并且使用 picture.resize(scaleX, scaleY); 方法來設置圖片縮放比例。這也與 POI 4.1.2 版本不同。POI 4.1.2 版本使用 picture.resize(1, 1); 會自動縮放圖片調整成合適大小。

員工的 DTO 類:


/*** 員工DTO*/
public class EmployeeDTO {// 工號private String no;// 姓名private String name;// 性別private String gender;// 頭像private String portrait;@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("Employee{");sb.append("no='").append(no).append('\'');sb.append(", name='").append(name).append('\'');sb.append(", gender='").append(gender).append('\'');sb.append(", portrait='").append(portrait).append('\'');sb.append('}');return sb.toString();}public String getNo() {return no;}public void setNo(String no) {this.no = no;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getPortrait() {return portrait;}public void setPortrait(String portrait) {this.portrait = portrait;}
}

用來生成Excel 文件的 ImageExcelUtils 類


import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
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.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Picture;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;import javax.imageio.ImageIO;public class ImageExcelUtils {/*** 讀取jpg圖片* @param path 圖片文件路徑* @return BufferedImage*/public static BufferedImage readBufferedImage(String path) {BufferedImage originImage = null;BufferedImage result = null;try {File file = new File(path);originImage = ImageIO.read(file);// 確保圖片顏色只有RGB,沒有alpha透明度result = new BufferedImage(originImage.getWidth(),originImage.getHeight(),BufferedImage.TYPE_INT_RGB);result.getGraphics().drawImage(originImage, 0, 0, null);} catch (IOException e) {e.printStackTrace();}return result;}/*** 設置excel文件的圖片* @param workbook 工作簿* @param sheet sheet頁* @param imgFilePath 圖片文件路徑* @param row1 圖片起始的行* @param col1 圖片起始的列* @param tempFilePath 臨時文件路徑*/public static void setExcelImg(Workbook workbook, Sheet sheet, String imgFilePath,int row1, int col1, int width, int height, String tempFilePath) {File file = new File(imgFilePath);if (!file.exists()) {return;}// 臨時文件File tempFile = new File(tempFilePath);if (tempFile.exists()) {tempFile.delete();}FileInputStream inputStream = null;boolean isClose = false;try {BufferedImage bufferedImage = readBufferedImage(imgFilePath);int imageWidth = bufferedImage.getWidth();int imageHeight = bufferedImage.getHeight();ImageIO.write(bufferedImage, "png", tempFile);inputStream = new FileInputStream(tempFile);//利用POI提供的工具類把文件流轉化成二進制數據byte[] bytes = IOUtils.toByteArray(inputStream);//向POI內存中添加一張圖片,返回圖片在圖片集合中的索引int pictureIndex = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);//參數一:圖片的二進制數據,參數二:圖片類型//從Workbook中得到繪制圖片的工具類CreationHelper helper = workbook.getCreationHelper();//創建錨點,設置圖片坐標ClientAnchor clientAnchor = helper.createClientAnchor();clientAnchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE);clientAnchor.setRow1(row1); // 設置起始行clientAnchor.setCol1(col1); // 設置起始列//從sheet對象中得到一個繪圖對象Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();//繪制圖片,錨點,圖片在內存中的位置Picture picture = drawingPatriarch.createPicture(clientAnchor, pictureIndex);// 使用固定的長寬比例系數double scaleX = 1.0;double scaleY = 1.0;if (imageWidth <= width && imageHeight <= height) {scaleX = 1.0;scaleY = 1.0;} else {scaleX = (double) width / (double) imageWidth;scaleY = (double) height / (double) imageHeight;double min = Math.min(scaleX, scaleY);scaleX = scaleY = min;}picture.resize(scaleX, scaleY);//自適應渲染圖片} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (inputStream != null && !isClose) {inputStream.close();}tempFile.delete();} catch (IOException e) {e.printStackTrace();}}}/*** 創建Excel文件* @param employeeDTOList 員工列表* @param file 輸出的 Excel 文件* @param tempFilePath 臨時文件路徑*/public static void createExcelFile(List<EmployeeDTO> employeeDTOList, File file, String tempFilePath) {//創建工作簿,excel2007版本的,如果是excel2003的話。創建的對象是:HSSFWorkbookWorkbook workbook = new SXSSFWorkbook();//創建sheetSheet sheet = workbook.createSheet("picture sheet");// 列寬分別是25個字符和40個字符,一字符等于 6.107 像素sheet.setColumnWidth(0, 25 * 256);sheet.setColumnWidth(1, 25 * 256);sheet.setColumnWidth(2, 25 * 256);sheet.setColumnWidth(3, 40 * 256);// 行高是 120 磅,1磅是 1.34039 像素sheet.setDefaultRowHeightInPoints(120f);// 設置字體,黑體Font font = workbook.createFont();font.setFontName("黑體");// 字體加粗font.setBold(true);CellStyle cellStyle = workbook.createCellStyle();cellStyle.setFont(font);cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);cellStyle.setAlignment(HorizontalAlignment.CENTER);// 表格標題行Row firstRow = sheet.createRow(0);Cell r0c0 = firstRow.createCell(0);r0c0.setCellValue("工號");Cell r0c1 = firstRow.createCell(1);r0c1.setCellValue("姓名");Cell r0c2 = firstRow.createCell(2);r0c2.setCellValue("性別");Cell r0c3 = firstRow.createCell(3);r0c3.setCellValue("頭像");r0c0.setCellStyle(cellStyle);r0c1.setCellStyle(cellStyle);r0c2.setCellStyle(cellStyle);r0c3.setCellStyle(cellStyle);int size = employeeDTOList.size();for (int i = 0; i < size; i++) {EmployeeDTO dto = employeeDTOList.get(i);int rowIndex = i + 1;Row row = sheet.createRow(rowIndex);Cell c0 = row.createCell(0);Cell c1 = row.createCell(1);Cell c2 = row.createCell(2);Cell c3 = row.createCell(3);// 向excel中輸入圖片String portrait = dto.getPortrait();if (null != portrait && portrait.trim().length() > 0) {portrait = portrait.trim();setExcelImg(workbook, sheet, portrait, rowIndex, 3, 244, 160, tempFilePath);}c0.setCellValue(dto.getNo());c1.setCellValue(dto.getName());c2.setCellValue(dto.getGender());}//創建文件輸入流FileOutputStream out = null;//創建文件輸出流try {out = new FileOutputStream(file);//調用工作簿的write創建excelworkbook.write(out);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (out != null) {out.flush();out.close();out = null;}} catch (IOException e) {e.printStackTrace();}} // end finally}
}

包含 main 方法的 Test 類,測試具體效果


import java.io.File;
import java.util.List;
import java.util.ArrayList;public class Test {public static void main(String[] args) {List<EmployeeDTO> employeeDTOList = new ArrayList<>();EmployeeDTO emp_1 = new EmployeeDTO();emp_1.setNo("1");emp_1.setName("張三");emp_1.setGender("男");emp_1.setPortrait("D:/1715284526222417922.jpg");EmployeeDTO emp_2 = new EmployeeDTO();emp_2.setNo("2");emp_2.setName("李四");emp_2.setGender("男");emp_2.setPortrait("D:\\bmptest.bmp");EmployeeDTO emp_3 = new EmployeeDTO();emp_3.setNo("3");emp_3.setName("王二");emp_3.setGender("女");emp_3.setPortrait("D:\\113.jpg");EmployeeDTO emp_4 = new EmployeeDTO();emp_4.setNo("4");emp_4.setName("涂軍");emp_4.setGender("男");emp_4.setPortrait("D:\\309446533.gif");employeeDTOList.add(emp_1);employeeDTOList.add(emp_2);employeeDTOList.add(emp_3);employeeDTOList.add(emp_4);File file = new File("D:\\ws\\tmpdir\\out.xlsx");String tempFilePath = "D:\\ws\\tmpdir\\temp.png";ImageExcelUtils.createExcelFile(employeeDTOList, file, tempFilePath);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211707.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211707.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211707.shtml

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

相關文章

【代碼隨想錄算法訓練營-第四天】【鏈表】24,19, 面試題 02.07,142

24. 兩兩交換鏈表中的節點 第一遍-遞歸-小看了一下題解 思路&#xff1a; 讀了兩遍題目才理解…相鄰節點的交換&#xff0c;這個操作很容易實現&#xff0c;但需要一個tmpNode因為是鏈表的題目&#xff0c;沒開始思考之前先加了dummyNode&#xff0c;還真管用把dummyNode作為…

空氣質量數據和氣象數據

1、北京、上海、廣州的空氣質量數據和氣象數據 要素如下&#xff1a; 逐日數據 時間跨度&#xff1a;2014.1.1-2022.3.31&#xff0c;共3012條數據 數據質量&#xff1a;98% 城市&#xff1a;只有北京、上海、廣州 可以用作論文數據 數據來源&#xff1a;中國環境監測總站…

23. 合并 K 個升序鏈表 --力扣 --JAVA

題目 給你一個鏈表數組&#xff0c;每個鏈表都已經按升序排列。 請你將所有鏈表合并到一個升序鏈表中&#xff0c;返回合并后的鏈表。 解題思路 對每個鏈表的首節點進行比較&#xff0c;獲取當前的最小節點&#xff1b;將每個階段的最小節點進行鏈接&#xff1b; 代碼展示 c…

亞馬遜云科技re_Invent 2023產品體驗:亞馬遜云科技產品應用實踐 國賽選手帶你看Elasticache Serverless

拋磚引玉 講一下作者背景&#xff0c;曾經參加過國內世界技能大賽云計算的選拔&#xff0c;那么在競賽中包含兩類&#xff0c;一類是架構類競賽&#xff0c;另一類就是TroubleShooting競賽&#xff0c;對應的分別為AWS GameDay和AWS Jam&#xff0c;想必也有朋友玩過此類競賽&…

4.權限特權轉移代碼

核心文件用戶文件引導文件 核心文件 ;------------------------新增--------------------------------; 本文件涉及了權限, 將使用調用門描述符來處理 低權限到高權限的轉移;------------------------權限---------------------------- ;此文件延用上個CORE.asm. 并做出一些修…

[linux] 解壓縮xz

在Linux命令行中解壓縮.xz文件&#xff0c;你可以使用以下幾種方法&#xff1a; 使用unxz工具&#xff1a; unxz filename.xz 這個命令會將filename.xz解壓縮為一個同名的未壓縮文件。如果原文件有其他的擴展名&#xff08;如.tar.xz&#xff09;&#xff0c;那么這個擴展名會被…

關于洛谷P1007最快的方法

P1007 獨木橋 - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) 題目背景 戰爭已經進入到緊要時間。你是運輸小隊長&#xff0c;正在率領運輸部隊向前線運送物資。運輸任務像做題一樣的無聊。你希望找些刺激&#xff0c;于是命令你的士兵們到前方的一座獨木橋上欣賞風景&#xf…

智能儀表板DevExpress Dashboard v23.1 - 支持自定義樣式創建

使用DevExpress Analytics Dashboard&#xff0c;再選擇合適的UI元素&#xff08;圖表、數據透視表、數據卡、計量器、地圖和網格&#xff09;&#xff0c;刪除相應參數、值和序列的數據字段&#xff0c;就可以輕松地為執行主管和商業用戶創建有洞察力、信息豐富的、跨平臺和設…

STM32 配置TIM定時中斷常用庫函數

單片機學習&#xff01; 目錄 ?編輯 1. 函數TIM_DeInit 2. 函數TIM_TimeBaseInit 配置時基單元 3. 函數TIM_TimeBaseStructInit 4. 函數TIM_Cmd 運行控制 5. 函數TIM_ITConfig 中斷輸出控制 6. 時基單元的時鐘選擇函數 6.1 函數TIM_InternalClockConfig 6.2 函數 TIM…

Configuring environment||ROS2環境配置

Goal: This tutorial will show you how to prepare your ROS 2 environment. Tutorial level: Beginner Time: 5 minutes ROS 2 relies on the notion &#xff08;concept&#xff09;of combining workspaces using the shell environment. “Workspace” is a ROS term …

C++進階篇8---智能指針

一、引言 為什么需要智能指針&#xff1f; 在上一篇異常中&#xff0c;關于內存釋放&#xff0c;我們提到過一個問題---當我們申請資源之后&#xff0c;由于異常的執行&#xff0c;代碼可能直接跳過資源的釋放語句到達catch&#xff0c;從而造成內存的泄露&#xff0c;對于這種…

C# Winform 日志系統

目錄 一、效果 1.刷新日志效果 2.單獨日志的分類 3.保存日志的樣式 二、概述 三、日志系統API 1.字段 Debug.IsScrolling Debug.Version Debug.LogMaxLen Debug.LogTitle Debug.IsConsoleShowLog 2.方法 Debug.Log(string) Debug.Log(string, params object[]) …

數據結構之內部排序

目錄 7-1 直接插入排序 輸入格式: 輸出格式: 輸入樣例: 輸出樣例: 7-2 尋找大富翁 輸入格式: 輸出格式: 輸入樣例: 輸出樣例: 7-3 PAT排名匯總 輸入格式: 輸出格式: 輸入樣例: 輸出樣例: 7-4 點贊狂魔 輸入格式&#xff1a; 輸出格式&#xff1a; 輸入樣例&a…

RabbitMQ在國內為什么沒有那么流行?

MQ&#xff08;消息隊列&#xff09;的世界。MQ&#xff0c;就像是一個巨大的郵局&#xff0c;負責在不同服務或應用間傳遞消息。它可以幫助我們解耦系統&#xff0c;提高性能&#xff0c;還能做到異步處理和流量削峰。 基本使用 RabbitMQ是一個開源的消息代理和隊列服務器&a…

spring boot + uniapp 微信公眾號 jsapi 支付

后端支付類 package com.ruoyi.coupon.payment;import com.google.gson.Gson; import com.ruoyi.coupon.payment.dto.PayParamJsapiDto; import com.ruoyi.coupon.payment.dto.RefundParam; import com.ruoyi.coupon.service.ICouponConfigService; import com.wechat.pay.jav…

FFmpeg抽取視頻h264數據重定向

根據視頻重定向技術解析中的 截獲解碼視頻流的思路&#xff0c;首先需要解決如何輸出視頻碼流的問題。 目前只針對h264碼流進行獲取&#xff0c;步驟如下&#xff1a; 打開mp4文件并創建一個空文件用于存儲H264數據 提取一路視頻流資源 循環讀取流中所有的包(AVPacket),為…

redis中使用pipeline批量處理請求提升系統性能

在操作數據庫時&#xff0c;為了加快程序的執行速度&#xff0c;在新增或更新數據時&#xff0c;可以通過批量提交的方式來減少應用和數據庫間的傳輸次數&#xff1b;在redis中也有這樣的技術實現批量處理&#xff0c;也就是管道——Pipeline。它也是通過批量提交數據的方式來實…

線程安全3--wait和notify

文章目錄 wait and notify&#xff08;等待通知機制notify補充 wait and notify&#xff08;等待通知機制 引入wait notify就是為了能夠從應用層面上&#xff0c;干預到多個不同線程代碼的執行順序&#xff0c;這里說的干預&#xff0c;不是影響系統的線程調度策略&#xff08…

uni-app應用設置 可以根據手機屏幕旋轉進行 (橫/豎) 屏切換

首先 我們打開項目的 manifest.json 在左側導航欄中找到 源碼視圖 然后找到 app-plus 配置 在下面加上 "orientation": [//豎屏正方向"portrait-primary",//豎屏反方向"portrait-secondary",//橫屏正方向"landscape-primary",//橫屏…

第57天:django學習(六)

模版之過濾器 語法&#xff1a; {{obj|filter__name:param}} 變量名字|過濾器名稱&#xff1a;變量 default 如果一個變量是false或者為空&#xff0c;使用給定的默認值。否則&#xff0c;使用變量的值。例如&#xff1a; {{ value|default:"nothing"}} length …