Java Excel转PDF,支持xlsx和xls两种格式, itextpdf【即取即用】

2023-10-14 08:15

本文主要是介绍Java Excel转PDF,支持xlsx和xls两种格式, itextpdf【即取即用】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java Excel转PDF itextpdf,即取即用

  • 工具方法
    • 一、使用方式
      • 1、本地转换
      • 2、网络下载
    • 二、pom依赖引入
    • 三、工具方法
    • 三、引文

本篇主要为工具方法整理,参考学习其他博主文章做了整理,方便使用。

工具方法

一、使用方式

1、本地转换

  • 导入依赖
  • 创建工具方法
  • 传入输入输出流或文档地址即可。

2、网络下载

通过POI或者easyExcel生成或填充,再由后端转换PDF响应前端
思路:将网络下载拆分为本地转换,再响应前端即可。

  • 现在服务器创建临时文件目录(临时目录可在每次下载请求开始先进行清空);
  • 将生成的Excel写入本地临时文件;
  • 获取Excel文件输入流,获取响应的输出流(response.getOutputStream(););
  • 调取公共方法传入输入输出流即可。

二、pom依赖引入

	<!-- pom相关依赖 --><poi.version>4.1.1</poi.version><itextpdf.version>5.5.13.2</itextpdf.version><!-- POI Excel--><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>${poi.version}</version></dependency><!-- iText PDF --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>${itextpdf.version}</version></dependency>

三、工具方法

package com.xxx.tool.util;import cn.hutool.core.collection.CollUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import lombok.experimental.UtilityClass;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;@UtilityClass
public class ExcelToPdfUtil {public static void excelToPdf(String excelPath, String pdfPath, String excelSuffix) {try (InputStream in = Files.newInputStream(Paths.get(excelPath));OutputStream out = Files.newOutputStream(Paths.get(pdfPath))) {ExcelToPdfUtil.excelToPdf(in, out, excelSuffix);} catch (Exception e) {e.printStackTrace();}}/*** Excel转PDF并写入输出流** @param inStream    Excel输入流* @param outStream   PDF输出流* @param excelSuffix Excel类型 .xls 和 .xlsx* @throws Exception 异常信息*/public static void excelToPdf(InputStream inStream, OutputStream outStream, String excelSuffix) throws Exception {// 输入流转workbook,获取sheetSheet sheet = getPoiSheetByFileStream(inStream, 0, excelSuffix);// 获取列宽度占比float[] widths = getColWidth(sheet);PdfPTable table = new PdfPTable(widths);table.setWidthPercentage(100);int colCount = widths.length;//设置基本字体BaseFont baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);// 遍历行for (int rowIndex = sheet.getFirstRowNum(); rowIndex <= sheet.getLastRowNum(); rowIndex++) {Row row = sheet.getRow(rowIndex);if (Objects.isNull(row)) {// 插入空对象for (int i = 0; i < colCount; i++) {table.addCell(createPdfPCell(null, 0, 13f, null));}} else {// 遍历单元格for (int columnIndex = 0; (columnIndex < row.getLastCellNum() || columnIndex < colCount) && columnIndex > -1; columnIndex++) {PdfPCell pCell = excelCellToPdfCell(sheet, row.getCell(columnIndex), baseFont);// 是否合并单元格if (isMergedRegion(sheet, rowIndex, columnIndex)) {int[] span = getMergedSpan(sheet, rowIndex, columnIndex);//忽略合并过的单元格boolean mergedCell = span[0] == 1 && span[1] == 1;if (mergedCell) {continue;}pCell.setRowspan(span[0]);pCell.setColspan(span[1]);}table.addCell(pCell);}}}// 初始化PDF文档对象createPdfTableAndWriteDocument(outStream, table);}/*** 单元格转换,poi cell 转换为 itext cell** @param sheet     poi sheet页* @param excelCell poi 单元格* @param baseFont  基础字体* @return com.itextpdf.text.pdf.PdfPCell*/private static PdfPCell excelCellToPdfCell(Sheet sheet, Cell excelCell, BaseFont baseFont) throws Exception {if (Objects.isNull(excelCell)) {return createPdfPCell(null, 0, 13f, null);}int rowIndex = excelCell.getRowIndex();int columnIndex = excelCell.getColumnIndex();// 图片信息List<PicturesInfo> infos = getAllPictureInfos(sheet, rowIndex, rowIndex, columnIndex, columnIndex, false);PdfPCell pCell;if (CollUtil.isNotEmpty(infos)) {pCell = new PdfPCell(Image.getInstance(infos.get(0).getPictureData()));} else {Font excelFont = getExcelFont(sheet, excelCell);//设置单元格字体com.itextpdf.text.Font pdFont = new com.itextpdf.text.Font(baseFont, excelFont.getFontHeightInPoints(), excelFont.getBold() ? 1 : 0, BaseColor.BLACK);Integer border = hasBorder(excelCell) ? null : 0;String excelCellValue = getExcelCellValue(excelCell);pCell = createPdfPCell(excelCellValue, border, excelCell.getRow().getHeightInPoints(), pdFont);}// 水平居中pCell.setHorizontalAlignment(getHorAlign(excelCell.getCellStyle().getAlignment().getCode()));// 垂直对齐pCell.setVerticalAlignment(getVerAlign(excelCell.getCellStyle().getVerticalAlignment().getCode()));return pCell;}/*** 创建pdf文档,并添加表格** @param outStream 输出流,目标文档* @param table     表格* @throws DocumentException 异常信息*/private static void createPdfTableAndWriteDocument(OutputStream outStream, PdfPTable table) throws DocumentException {//设置pdf纸张大小 PageSize.A4 A4横向Document document = new Document(new RectangleReadOnly(842.0F, 595.0F));PdfWriter.getInstance(document, outStream);//设置页边距 宽document.setMargins(10, 10, 10, 10);document.open();document.add(table);document.close();}/*** Excel文档输入流转换为对应的workbook及获取对应的sheet** @param inputStream Excel文档输入流* @param sheetNo     sheet编号,默认0 第一个sheet* @param excelSuffix 文件类型 .xls和.xlsx* @return poi sheet* @throws IOException 异常*/public static Sheet getPoiSheetByFileStream(InputStream inputStream, int sheetNo, String excelSuffix) throws IOException {Workbook workbook;if (excelSuffix.endsWith(".xlsx")) {workbook = new XSSFWorkbook(inputStream);} else {workbook = new HSSFWorkbook(inputStream);}return workbook.getSheetAt(sheetNo);}/*** 创建itext pdf 单元格** @param content       单元格内容* @param border        边框* @param minimumHeight 高度* @param pdFont        字体* @return pdf cell*/private static PdfPCell createPdfPCell(String content, Integer border, Float minimumHeight, com.itextpdf.text.Font pdFont) {String contentValue = content == null ? "" : content;com.itextpdf.text.Font pdFontNew = pdFont == null ? new com.itextpdf.text.Font() : pdFont;PdfPCell pCell = new PdfPCell(new Phrase(contentValue, pdFontNew));if (Objects.nonNull(border)) {pCell.setBorder(border);}if (Objects.nonNull(minimumHeight)) {pCell.setMinimumHeight(minimumHeight);}return pCell;}/*** excel垂直对齐方式映射到pdf对齐方式*/private static int getVerAlign(int align) {switch (align) {case 2:return com.itextpdf.text.Element.ALIGN_BOTTOM;case 3:return com.itextpdf.text.Element.ALIGN_TOP;default:return com.itextpdf.text.Element.ALIGN_MIDDLE;}}/*** excel水平对齐方式映射到pdf水平对齐方式*/private static int getHorAlign(int align) {switch (align) {case 1:return com.itextpdf.text.Element.ALIGN_LEFT;case 3:return com.itextpdf.text.Element.ALIGN_RIGHT;default:return com.itextpdf.text.Element.ALIGN_CENTER;}}/*============================================== POI获取图片及文本内容工具方法 ==============================================*//*** 获取字体** @param sheet excel 转换的sheet页* @param cell  单元格* @return 字体*/private static Font getExcelFont(Sheet sheet, Cell cell) {// xlsif (sheet instanceof HSSFSheet) {Workbook workbook = sheet.getWorkbook();return ((HSSFCell) cell).getCellStyle().getFont(workbook);}// xlsxreturn ((XSSFCell) cell).getCellStyle().getFont();}/*** 判断excel单元格是否有边框*/private static boolean hasBorder(Cell excelCell) {short top = excelCell.getCellStyle().getBorderTop().getCode();short bottom = excelCell.getCellStyle().getBorderBottom().getCode();short left = excelCell.getCellStyle().getBorderLeft().getCode();short right = excelCell.getCellStyle().getBorderRight().getCode();return top + bottom + left + right > 2;}/*** 判断单元格是否是合并单元格*/private static boolean isMergedRegion(Sheet sheet, int row, int column) {int sheetMergeCount = sheet.getNumMergedRegions();for (int i = 0; i < sheetMergeCount; i++) {CellRangeAddress range = sheet.getMergedRegion(i);int firstColumn = range.getFirstColumn();int lastColumn = range.getLastColumn();int firstRow = range.getFirstRow();int lastRow = range.getLastRow();if (row >= firstRow && row <= lastRow) {if (column >= firstColumn && column <= lastColumn) {return true;}}}return false;}/*** 计算合并单元格合并的跨行跨列数*/private static int[] getMergedSpan(Sheet sheet, int row, int column) {int sheetMergeCount = sheet.getNumMergedRegions();int[] span = {1, 1};for (int i = 0; i < sheetMergeCount; i++) {CellRangeAddress range = sheet.getMergedRegion(i);int firstColumn = range.getFirstColumn();int lastColumn = range.getLastColumn();int firstRow = range.getFirstRow();int lastRow = range.getLastRow();if (firstColumn == column && firstRow == row) {span[0] = lastRow - firstRow + 1;span[1] = lastColumn - firstColumn + 1;break;}}return span;}/*** 获取excel中每列宽度的占比*/private static float[] getColWidth(Sheet sheet) {int rowNum = getMaxColRowNum(sheet);Row row = sheet.getRow(rowNum);int cellCount = row.getPhysicalNumberOfCells();int[] colWidths = new int[cellCount];int sum = 0;for (int i = row.getFirstCellNum(); i < cellCount; i++) {Cell cell = row.getCell(i);if (cell != null) {colWidths[i] = sheet.getColumnWidth(i);sum += sheet.getColumnWidth(i);}}float[] colWidthPer = new float[cellCount];for (int i = row.getFirstCellNum(); i < cellCount; i++) {colWidthPer[i] = (float) colWidths[i] / sum * 100;}return colWidthPer;}/*** 获取excel中列数最多的行号*/private static int getMaxColRowNum(Sheet sheet) {int rowNum = 0;int maxCol = 0;for (int r = sheet.getFirstRowNum(); r < sheet.getPhysicalNumberOfRows(); r++) {Row row = sheet.getRow(r);if (row != null && maxCol < row.getPhysicalNumberOfCells()) {maxCol = row.getPhysicalNumberOfCells();rowNum = r;}}return rowNum;}/*** poi 根据单元格类型获取单元格内容** @param excelCell poi单元格* @return 单元格内容文本*/public static String getExcelCellValue(Cell excelCell) {if (excelCell == null) {return "";}// 判断数据的类型CellType cellType = excelCell.getCellType();if (cellType == CellType.STRING) {return excelCell.getStringCellValue();}if (cellType == CellType.BOOLEAN) {return String.valueOf(excelCell.getBooleanCellValue());}if (cellType == CellType.FORMULA) {return excelCell.getCellFormula();}if (cellType == CellType.NUMERIC) {//short s = excelCell.getCellStyle().getDataFormat();if (DateUtil.isCellDateFormatted(excelCell)) {// 处理日期格式、时间格式SimpleDateFormat sdf;// 验证short值if (excelCell.getCellStyle().getDataFormat() == 14) {sdf = new SimpleDateFormat("yyyy/MM/dd");} else if (excelCell.getCellStyle().getDataFormat() == 21) {sdf = new SimpleDateFormat("HH:mm:ss");} else if (excelCell.getCellStyle().getDataFormat() == 22) {sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");} else {throw new RuntimeException("日期格式错误!!!");}Date date = excelCell.getDateCellValue();return sdf.format(date);} else if (excelCell.getCellStyle().getDataFormat() == 0) {//处理数值格式DataFormatter formatter = new DataFormatter();return formatter.formatCellValue(excelCell);}}if (cellType == CellType.ERROR) {return "非法字符";}return "";}/*** 获取sheet内的所有图片信息** @param sheet        sheet表* @param onlyInternal 单元格内部* @return 照片集合* @throws Exception 异常*/public static List<PicturesInfo> getAllPictureInfos(Sheet sheet, boolean onlyInternal) throws Exception {return getAllPictureInfos(sheet, null, null, null, null, onlyInternal);}/*** 根据sheet和单元格信息获取图片** @param sheet        sheet表* @param minRow       最小行* @param maxRow       最大行* @param minCol       最小列* @param maxCol       最大列* @param onlyInternal 是否内部* @return 图片集合* @throws Exception 异常*/public static List<PicturesInfo> getAllPictureInfos(Sheet sheet, Integer minRow, Integer maxRow, Integer minCol,Integer maxCol, boolean onlyInternal) throws Exception {if (sheet instanceof HSSFSheet) {return getXLSAllPictureInfos((HSSFSheet) sheet, minRow, maxRow, minCol, maxCol, onlyInternal);} else if (sheet instanceof XSSFSheet) {return getXLSXAllPictureInfos((XSSFSheet) sheet, minRow, maxRow, minCol, maxCol, onlyInternal);} else {throw new Exception("未处理类型,没有为该类型添加:GetAllPicturesInfos()扩展方法!");}}private static List<PicturesInfo> getXLSAllPictureInfos(HSSFSheet sheet, Integer minRow, Integer maxRow,Integer minCol, Integer maxCol, Boolean onlyInternal) {List<PicturesInfo> picturesInfoList = new ArrayList<>();HSSFShapeContainer shapeContainer = sheet.getDrawingPatriarch();if (shapeContainer == null) {return picturesInfoList;}List<HSSFShape> shapeList = shapeContainer.getChildren();for (HSSFShape shape : shapeList) {if (shape instanceof HSSFPicture && shape.getAnchor() instanceof HSSFClientAnchor) {HSSFPicture picture = (HSSFPicture) shape;HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();if (isInternalOrIntersect(minRow, maxRow, minCol, maxCol, anchor.getRow1(), anchor.getRow2(),anchor.getCol1(), anchor.getCol2(), onlyInternal)) {HSSFPictureData pictureData = picture.getPictureData();picturesInfoList.add(new PicturesInfo().setMinRow(anchor.getRow1()).setMaxRow(anchor.getRow2()).setMinCol(anchor.getCol1()).setMaxCol(anchor.getCol2()).setPictureData(pictureData.getData()).setExt(pictureData.getMimeType()));}}}return picturesInfoList;}private static List<PicturesInfo> getXLSXAllPictureInfos(XSSFSheet sheet, Integer minRow, Integer maxRow,Integer minCol, Integer maxCol, Boolean onlyInternal) {List<PicturesInfo> picturesInfoList = new ArrayList<>();List<POIXMLDocumentPart> documentPartList = sheet.getRelations();for (POIXMLDocumentPart documentPart : documentPartList) {if (documentPart instanceof XSSFDrawing) {XSSFDrawing drawing = (XSSFDrawing) documentPart;List<XSSFShape> shapes = drawing.getShapes();for (XSSFShape shape : shapes) {if (shape instanceof XSSFPicture) {XSSFPicture picture = (XSSFPicture) shape;XSSFClientAnchor anchor = picture.getPreferredSize();if (isInternalOrIntersect(minRow, maxRow, minCol, maxCol, anchor.getRow1(), anchor.getRow2(),anchor.getCol1(), anchor.getCol2(), onlyInternal)) {XSSFPictureData pictureData = picture.getPictureData();picturesInfoList.add(new PicturesInfo().setMinRow(anchor.getRow1()).setMaxRow(anchor.getRow2()).setMinCol(anchor.getCol1()).setMaxCol(anchor.getCol2()).setPictureData(pictureData.getData()).setExt(pictureData.getMimeType()));}}}}}return picturesInfoList;}private static boolean isInternalOrIntersect(Integer rangeMinRow, Integer rangeMaxRow, Integer rangeMinCol,Integer rangeMaxCol, int pictureMinRow, int pictureMaxRow, int pictureMinCol, int pictureMaxCol,Boolean onlyInternal) {int _rangeMinRow = rangeMinRow == null ? pictureMinRow : rangeMinRow;int _rangeMaxRow = rangeMaxRow == null ? pictureMaxRow : rangeMaxRow;int _rangeMinCol = rangeMinCol == null ? pictureMinCol : rangeMinCol;int _rangeMaxCol = rangeMaxCol == null ? pictureMaxCol : rangeMaxCol;if (onlyInternal) {return (_rangeMinRow <= pictureMinRow && _rangeMaxRow >= pictureMaxRow && _rangeMinCol <= pictureMinCol&& _rangeMaxCol >= pictureMaxCol);} else {return ((Math.abs(_rangeMaxRow - _rangeMinRow) + Math.abs(pictureMaxRow - pictureMinRow) >= Math.abs(_rangeMaxRow + _rangeMinRow - pictureMaxRow - pictureMinRow))&& (Math.abs(_rangeMaxCol - _rangeMinCol) + Math.abs(pictureMaxCol - pictureMinCol) >= Math.abs(_rangeMaxCol + _rangeMinCol - pictureMaxCol - pictureMinCol)));}}/*** 图片基本信息*/private class PicturesInfo {private int minRow;private int maxRow;private int minCol;private int maxCol;private String ext;private byte[] pictureData;public PicturesInfo() {}public byte[] getPictureData() {return pictureData;}public PicturesInfo setPictureData(byte[] pictureData) {this.pictureData = pictureData;return this;}public int getMinRow() {return minRow;}public PicturesInfo setMinRow(int minRow) {this.minRow = minRow;return this;}public int getMaxRow() {return maxRow;}public PicturesInfo setMaxRow(int maxRow) {this.maxRow = maxRow;return this;}public int getMinCol() {return minCol;}public PicturesInfo setMinCol(int minCol) {this.minCol = minCol;return this;}public int getMaxCol() {return maxCol;}public PicturesInfo setMaxCol(int maxCol) {this.maxCol = maxCol;return this;}public String getExt() {return ext;}public PicturesInfo setExt(String ext) {this.ext = ext;return this;}}
}

三、引文

  1. java高效实现excel转pdf,支持excel中带有图片的转换(支持.xls和.xlsx两种格式)
  2. Java Poi 读取excel 对所有类型进行处理

这篇关于Java Excel转PDF,支持xlsx和xls两种格式, itextpdf【即取即用】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/209257

相关文章

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

Spring @RequestMapping 注解及使用技巧详解

《Spring@RequestMapping注解及使用技巧详解》@RequestMapping是SpringMVC中定义请求映射规则的核心注解,用于将HTTP请求映射到Controller处理方法... 目录一、核心作用二、关键参数说明三、快捷组合注解四、动态路径参数(@PathVariable)五、匹配请

Java -jar命令如何运行外部依赖JAR包

《Java-jar命令如何运行外部依赖JAR包》在Java应用部署中,java-jar命令是启动可执行JAR包的标准方式,但当应用需要依赖外部JAR文件时,直接使用java-jar会面临类加载困... 目录引言:外部依赖JAR的必要性一、问题本质:类加载机制的限制1. Java -jar的默认行为2. 类加

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析

Swagger在java中的运用及常见问题解决

《Swagger在java中的运用及常见问题解决》Swagger插件是一款深受Java开发者喜爱的工具,它在前后端分离的开发模式下发挥着重要作用,:本文主要介绍Swagger在java中的运用及常... 目录前言1. Swagger 的主要功能1.1 交互式 API 文档1.2 客户端 SDK 生成1.3

Java中的登录技术保姆级详细教程

《Java中的登录技术保姆级详细教程》:本文主要介绍Java中登录技术保姆级详细教程的相关资料,在Java中我们可以使用各种技术和框架来实现这些功能,文中通过代码介绍的非常详细,需要的朋友可以参考... 目录1.登录思路2.登录标记1.会话技术2.会话跟踪1.Cookie技术2.Session技术3.令牌技

Java 枚举的基本使用方法及实际使用场景

《Java枚举的基本使用方法及实际使用场景》枚举是Java中一种特殊的类,用于定义一组固定的常量,枚举类型提供了更好的类型安全性和可读性,适用于需要定义一组有限且固定的值的场景,本文给大家介绍Jav... 目录一、什么是枚举?二、枚举的基本使用方法定义枚举三、实际使用场景代替常量状态机四、更多用法1.实现接

java String.join()方法实例详解

《javaString.join()方法实例详解》String.join()是Java提供的一个实用方法,用于将多个字符串按照指定的分隔符连接成一个字符串,这一方法是Java8中引入的,极大地简化了... 目录bVARxMJava String.join() 方法详解1. 方法定义2. 基本用法2.1 拼接

java连接opcua的常见问题及解决方法

《java连接opcua的常见问题及解决方法》本文将使用EclipseMilo作为示例库,演示如何在Java中使用匿名、用户名密码以及证书加密三种方式连接到OPCUA服务器,若需要使用其他SDK,原理... 目录一、前言二、准备工作三、匿名方式连接3.1 匿名方式简介3.2 示例代码四、用户名密码方式连接4

springboot项目中使用JOSN解析库的方法

《springboot项目中使用JOSN解析库的方法》JSON,全程是JavaScriptObjectNotation,是一种轻量级的数据交换格式,本文给大家介绍springboot项目中使用JOSN... 目录一、jsON解析简介二、Spring Boot项目中使用JSON解析1、pom.XML文件引入依