目录
- 需求介绍
- itextpdf实现
- 引入maven依赖
- 代码实现
- ASPose-cell实现
- 简介
- 主要功能包括但不限于:
- 特别亮点
- 下载jar包
- crack使用
- 反编译jar包
- 生成 aspose-cells-20.7-crack.jar
- 测试 aspose-cells-20.7-crack.jar 使用
- 先生成图片再转pdf
- 直接转换
需求介绍
在企业级系统使用或日常使用中,我们经常使用excel表格数据进行浏览数据,但有时候我们会想要将excel转换成pdf进行预览使用,这时就需要进行程序编写实现这个需求,本篇博文以Java进行编写多种实现方式实现多sheet页excel转换一个pdf的需求
itextpdf实现
引入maven依赖
引入所需依赖,下面五个是主要依赖
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooXML</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency>
具体哪几个博主忘了,如果上面依赖导入后写代码还有缺失的,可以直接把下面完整的都copy下
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-asian</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.27</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency>
代码实现
由于在使用时,有时候excel里会插入图片,所以我们在转换时候需要考虑到图片的业务
先对图片类型进行建模处理
import java.io.Serializable; /** * 图片信息 */ public class PicturesInfo implements Serializable { private static final long serialVersionUID = 1L; /** * 最小行 */ private int minRow; /** * 最大行 */ private int maxRow; /** * 最小列 */ private int minCol; /** * 最大列 */ private int maxCol; /** * 扩展 */ private String ext; /** * 图片数据 */ private byte[] pictureData; 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; } public byte[] getPictureData() { return pictureData; } public PicturesInfo setPictureData(byte[] pictureData) { this.pictureData = pictureData; return this; } }
书写转换工具类
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 org.apache.poi.hssf.usermodel.*; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.Font; 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.util.*; import java.util.List; /** * Excel转PDF * @author 廖航 * @date 2024-08-29 10:52 */ //@UtilityClass //@Slf4j public class ExcelToPdfUtil { /** * 日志输出 */ // private static final log log = log.getlog(ExcelToPdfUtil.class); /** * 单元格队列 */ static Set<String> cellSet = new HashSet<>(); /** * Excel转PDF * * @param excelPath Excel文件路径 * @param pdfPath PDF文件路径 * @param excelSuffix Excel文件后缀 */ 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) { } } /** * 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,获取sheet 读取Excel文件 Workbook workbook = getPoiWorkbookByFileStream(inStream, excelSuffix); www.devze.com //设置pdf纸张大小 PageSize.A4 A4横向 // Document document = new Document(PageSize.B0); Document document = new Docume编程客栈nt(PageSize.A2.rotate()); // 绑定PDF写入器到输出流 PdfWriter.getInstance(document, outStream); // 设置页面四周边距 document.setMargins(50, 50, 30, 30); document.open(); // 准备开始写入内容 //设置基本字体 BaseFont baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); for (int j = 0; j < workbook.getNumberOfSheets(); j++) { if(j != 0) { document.newpage(); // 新的Sheet开始新的一页 } //获取sheet Sheet sheet = workbook.getSheetAt(j); // 获取列宽度占比 float[] widths = getColWidth(sheet); PdfPTable table = new PdfPTable(widths); // 设置表格宽度为页面内容区域的百分比 table.setWidthPercentage(100); int colCount = widths.length; // 遍历行 for (int rowIndex = sheet.getFirstRowNum(); rowIndex <= sheet.getLastRowNum(); rowIndex++) { Row row = sheet.getRow(rowIndex); if (Objects.isNull(row)) { // 插js入空对象 for (int i = 0; i < colCount; i++) { table.addCell(createPdfPCell(null, 0, 11f, 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); } } } document.add(table); } document.close(); } protected static CellRangeAddress getColspanRowspanByExcel(int rowIndex, int colIndex,Sheet sheet) { CellRangeAddress result = null; int num = sheet.getNumMergedRegions(); for (int i = 0; i < num; i++) { CellRangeAddress range = sheet.getMergedRegion(i); if (range.getFirstColumn() == colIndex && range.getFirstRow() == rowIndex) { result = range; } } return result; } // 获取Workbook对象 public static Workbook getPoiWorkbookByFileStream(InputStream inputStream, String excelSuffix) throws IOException { if (excelSuffix.endsWith(".xlsx")) { return new XSSFWorkbook(inputStream); } else { return new HSSFWorkbook(inputStream); } } /** * 单元格转换,poi cell 转换为 itext cell * * @param sheet poi sheet页 * @param excelCell poi 单元格 * @param baseFont 基础字体 * @return PDF单元格 */ private static PdfPCell excelCellToPdfCell(Sheet sheet, Cell excelCell, BaseFont baseFont) throws Exception { if (Objects.isNull(excelCell)) { return createPdfPCell(null, 0, 11f, null); } int rowIndex = excelCell.getRowIndex(); int columnIndex = excelCell.getColumnIndex(); // 图片信息 List<PicturesInfo> infos = getAllPictureInfos(sheet, rowIndex, rowIndex, columnIndex, columnIndex, false); PdfPCell pCell; if (infos != null && !infos.isEmpty()) { Image image = Image.getInstance(infos.get(0).getPictureData()); // 调整图片大小 image.scaleAbsolute(527, 215); pCell = new PdfPCell(image); } 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; } /** * 创建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对齐方式 * * @param align 对齐 * @return 结果 */ 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水平对齐方式 * * @param align 对齐 * @return 结果 */ 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) { // xls if (sheet instanceof HSSFSheet) { Workbook workbook = sheet.getWorkbook(); return ((HSSFCell) cell).getCellStyle().getFont(workbook); } // xlsx return ((XSSFCell) cell).getCellStyle().getFont(); } /** * 判断excel单元格是否有边框 * * @param excelCell 单元格 * @return 结果 */ private static boolean hasBorder(Cell excelCell) { CellStyle style = excelCell.getCellStyle(); BorderStyle top = style.getBorderTop(); BorderStyle bottom = style.getBorderBottom(); BorderStyle left = style.getBorderLeft(); BorderStyle right = style.getBorderRight(); return top != BorderStyle.NONE || bottom != BorderStyle.NONE || left != BorderStyle.NONE || right != BorderStyle.NONE; } /** * 判断单元格是否是合并单元格 * * @param sheet 表 * @param row 行 * @param column 列 * @return 结果 */ private static boolean isMergedRegion(Sheet sheet, int row, int column) { int sheeandroidtMergeCount = 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; } /** * 计算合并单元格合并的跨行跨列数 * * @param sheet 表 * @param row 行 * @param column 列 * @return 结果 */ 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中每列宽度的占比 * * @param sheet 表 * @return 结果 */ 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中列数最多的行号 * * @param sheet 表 * @return 结果 */ 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) { // // 处理日期格式、时间格式 // 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 ""; if (excelCell == null) { return ""; } DataFormatter formatter = new DataFormatter(); return formatter.formatCellValue(excelCell); } /** * 根据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()扩展方法!"); } } /** * 获取XLS图片信息 * * @param sheet 表 * @param minRow 最小行 * @param maxRow 最大行 * @param minCol 最小列 * @param maxCol 最大列 * @param onlyInternal 只在内部 * @return 图片信息列表 */ 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)) { // String item = StrUtil.format("{},{},{},{}", anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2()); String item = String.format("%d,%d,%d,%d", anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2()); if (cellSet.contains(item)) { continue; } cellSet.add(item); 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; } /** * 获取XLSX图片信息 * * @param sheet 表 * @param minRow 最小行 * @param maxRow 最大行 * @param minCol 最小列 * @param maxCol 最大列 * @param onlyInternal 只在内部 * @return 图片信息列表 */ 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)) { // String item = StrUtil.format("{},{},{},{}", anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2()); String item = String.format("%d,%d,%d,%d", anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2()); if (cellSet.contains(item)) { continue; } cellSet.add(item); 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; } /** * 是内部的或相交的 * * @param rangeMinRow 最小行范围 * @param rangeMaxRow 最大行范围 * @param rangeMinCol 最小列范围 * @param rangeMaxCol 最大列范围 * @param pictureMinRow 图片最小行 * @param pictureMaxRow 图片最大行 * @param pictureMinCol 图片最小列 * @param pictureMaxCol 图片最大列 * @param onlyInternal 只在内部 * @return 结果 */ 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))); } } public static void main(String[] args) { ExcelToPdfUtil.excelToPdf("原excel文件路径.xlsx", "转换后输出pdf路径.pdf", ".xlsx"); } }
测试时直接创建一个多sheet页的excel表格,并填入一些测试数据进行测试,查看转换后的结果
在主方法里更改路径进行测试
等待程序执行完后在导出路径查看转换后的pdf
点击查看
可以看到转换后的效果还是不错的,表格内容宽度自动使用pdf页面的宽度,每个sheet页都另起新的页面,多个sheet页拼接在一个pdf里,后续纸张大小参数等都可以在代码里进行灵活调整
aspose-cell实现
简介
Aspose.Cells for Java 是一款功能强大的 Java 库,专门用于操作 Microsoft Excel 文件而无需依赖 Microsoft Office。提供了丰富的API来创建、修改、转换和打印Excel文档。
主要功能包括但不限于:
- 文件格式支持:全面支持 Excel 的各种格式,如
.xls
,.xlsx
,.xlsm
,.xltx
,.xltm
等。 - 数据处理:轻松读取、写入及修改工作表中的数据,支持复杂的数据类型与结构。
- 格式化:灵活设置单元格、行、列的格式,包括字体、颜色、边框、背景色等,并支持条件格式化。
- 图表与图形:创建、更新或删除图表,添加图片和其他图形元素到工作表中。
- 公式计算:支持复杂的公式计算,确保数据准确性。
- PDF 转换:高质量地将 Excel 文档转换为 PDF 格式,同时支持自定义页面大小、方向等属性。
- 安全性和保护:对 Excel 文件进行加密、解密,以及设置打开或修改密码。
- 批量处理:高效处理大量数据集,适用于大规模数据操作场景。
特别亮点
- 无须安装 Microsoft Office:由于其独立性,开发者可以在没有安装 MS Office 的环境中使用此库执行所有相关任务。
- 跨平台兼容性:完全基于Java开发,可在任何支持Java的平台上运行。
- 性能优越:优化了内存管理和处理速度,即使对于大型文件也能保持良好的性能表现。
注意该jar包是收费的,收费版本试用时候会有水印和行数多少限制,一旦达到一定数据量可能会导致程序报错,可以进行破解使用
下载jar包
该jar包在国内镜像源里是拉取不到的,可以在官网直接下载jar包,后导入到本地使用
aspose官网链接
在官网里找到对应版本依赖,如果是国外镜像源或者其他源库可以尝试拉取试试,如果没有也可以直接下载jar包到本地后安装到本地使用
点击后下载
输入下面命令进行安装到本地
mvn install:install-file "-Dfile=jar包所在路径\jar包名.jar" "-DgroupId=com.aspose" "-DartifactId=aspose-cells" "-Dversion=版本号" "-Dpackaging=jar"
修改对应的jar包路径和包名后在idea命令行里执行安装jar包
没有报错说明安装成功,在pom文件里书写下对应的依赖刷新下maven即可
刷新下maven即可然后书写测试类尝试转换
执行转换
可以看到导出后的效果还是不错的,但是有水印
crack使用
这里以aspose-cells-20.7 去除水印及次数限制破解作为示例
反编译jar包
使用 jd-gui.exe 反编译查看jar包,直接搜索 License
1.修改
public static boolean isLicenseSet() { return (a != null); }
改为
public static boolean isLicenseSet() { return true; }
2.修改
public void setLicense(InputStream stream) { Document document = null; if (stream != null) try { DocumentBuilder documentBuilder = zad.b(); document = documentBuilder.parse(stream); } catch (Exception exception) { throw new CellsException(9, zf.a(new byte[] { -20, 93, -23, 54, -20, -49, -59, 86, -9, -86, 49, 44, -59, 71, -52, -86, -90, 6, -90, -25, -86, 1, -1, -92, -91, -126, 7, 113, -66, -95, -121, 16, -122, -126, 7, 104, -40, -70, -10, -37, 126, 7, -111, -121, -121 }) + exception.getMessage()); } a(document); }
改成
public void setLicense(InputStream paramInputStream){ a = new License(); zbiw.a(); }
3.修改
private static Date k(String paramString) { if (paramString == null || paramString.length() < 8) return null; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(zf.a(new byte[] { 79, 89, 33, -52, 79, -121, -125, 33, 71, -126, 105, -121 })); try { return simpleDateFormat.parse(paramString); } catch (ParseException parseException) { throw new IllegalArgumentException(zf.a(new byte[] { -21, -113, -77, 13, -115, 27, Byte.MIN_VALUE, 35, 103, -52, -20, -106, 71, 95, 31, -73, -76, -38, 13, 31, -91, -97, -102, 85, -68, -33, -19, -87, -127, -14, 78, -23, 6, -25, -94, 1, -97, -95, -57, -121 })); } }
改成
private static Date k(String paramString){ return new Date(Long.MAX_VALUE); }
修改完后使用jdi保存所有的文件为另存
生成 aspose-cells-20.7-crack.jar
修改 class 这里使用 javassist:
新建一个 Spring boot 项目:pom 文件中引用 javassist引入破解所需依赖
<dependency><!--aspose的jar破解工具--> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.20.0-GA</version> </dependency>
指定目录生成修改后的License.class文件
public static void crackAspose(String JarPath) throws Exception { // 这个是得到反编译的池 ClassPool pool = ClassPool.getDefault(); // 取得需要反编译的jar文件,设定路径 pool.insertClassPath(JarPath); CtClass cc_License = pool.get("com.aspose.cells.License"); CtMethod method_isLicenseSet = cc_License.getDeclaredMethod("isLicenseSet"); method_isLicenseSet.setBody("return true;"); CtClass cc_License2 = pool.get("com.aspose.cells.License"); CtMethod method_setLicense = cc_License2.getDeclaredMethod("setLicense"); method_setLicense.setBody("{ a = new com.aspose.cells.License();\n" + " com.aspose.cells.zbiw.a();}"); CtMethod method_k = cc_License.getDeclaredMethod("k"); method_k.setBody("return new java.util.Date(Long.MAX_VALUE);"); cc_License.writeFile("输出目录路径"); }
执行该方法
在指定目录下可以看到生成后的编译文件
复制一个 aspose-cells-20.7.jar 改名为 aspose-cells-20.7-crack.zip 然后解压
把刚才生成的 License.class 文件 替换到解压的源代码中。
造一个 License xml 文件,这里文件名为 com.aspose.cells.lic_2999.xml, 位置直接放源代码解压的根目录
文件内容为:
<License> <Data> <Products> <Product>Aspose.Cells for Java</Product> </Products> <EditionType>Enterprise</EditionType> <SubscriptionExpiry>29991231</SubscriptionExpiry> <LicenseExpiry>29991231</LicenseExpiry> <SerialNumber>evilrule</SerialNumber> </Data> <Signature>evilrule</Signature> </License>
防止文件指纹校验,我们需要删除掉源代码解压包中的 META_INF 文件夹。
最后的根目录:压缩源代码(注意要是 zip 格式)
然后重命名后缀为:jar
测试 aspose-cells-20.7-crack.jar 使用
封装一个 License 验证方法:
public static boolean authrolizeLicense() { boolean result = false; try { InputStream is = com.aspose.cells.License.class.getResourceAsStream("/com.aspose.cells.lic_2999.xml"); License asposeLicense = new License(); asposeLicense.setLicense(is); is.close(); result = true; } catch (Exception e) { e.printStackTrace(); } return result; }
修改 main 方法测试使用:
public static void main(String[] args) { // 测试破解后的 aspose-cells-20.7-crack.jar boolean auth = authrolizeLicense(); if (!auth) { System.out.println("aspose 许可无效!"); return; } System.out.println("aspose 已就绪!"); try{ Workbook wb = new Workbook("F:\\aaa123.xlsx"); Worksheet ws = wb.getWorksheets().get(0); ImageOrPrintOptions imgOptions = new ImageOrPrintOptions(); imgOptions.setImageFormat(ImageFormat.getPng()); imgOptions.setCellAutoFit(true); imgOptions.setOnePagePerSheet(true); SheetRender render = new SheetRender(ws, imgOptions); render.toImage(0, "F:\\aaa\\123.png"); } catch (Exception e){ e.printStackTrace(); } }
这里图片和excel可以随便搞一个尝试测试使用
先生成图片再转pdf
前面的破解工作都做好后就可以尝试测试了,aspose可以先将excel转成图片后再转成pdf
public static void main(String[] args) { // 授权检查(假设你已经破解) boolean auth = authrolizeLicense(); if (!auth) { System.out.println("aspose 许可无效!"); return; } System.out.println("aspose 已就绪!"); try { Workbook wb = new Workbook("C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼.xlsx"); ImageOrPrintOptions imgOptions = new ImageOrPrintOptions(); imgOptions.setImageFormat(ImageFormat.getPng()); imgOptions.setCellAutoFit(true); imgOptions.setOnePagePerSheet(true); String outputPdfPath = "C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼Aspose导出图片版.pdf"; // 创建一个无边距的文档 Document document = new Document(PageSize.A4); // 使用 A4 纸张尺寸 PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputPdfPath)); // 设置页面无边距(非常重要) document.setMargins(0, 0, 0, 0); // 左、右、上、下全部为 0 document.open(); for (int i = 0; i < wb.getWorksheets().getCount(); i++) { Worksheet ws = wb.getWorksheets().get(i); SheetRender render = new SheetRender(ws, imgOptions); String imageFilePath = "C:\\Users\\d\\Desktop\\excelToPdf\\sheet_" + i + ".png"; render.toImage(0, imageFilePath); Image img = Image.getInstance(imageFilePath); // 自动缩放图片以适配页面宽度和高度 img.scaleToFit(document.getPageSize().getWidth(), document.getPageSize().getHeight()); // 居中显示(iText 默认就是居中的,但我们可以更明确地设置) img.setAlignment(Image.ALIGN_CENTER); // 新增一页 document.newPage(); // 插入图片到当前页面 document.add(img); } document.close(); writer.close(); System.out.println("✅ PDF 文件已生成: " + outputPdfPath); } catch (Exception e) { e.printStackTrace(); } }
执行测试
查看生成的效果
可以看到原有的水印都没了
直接转换
aspose也可以直接进行转换
public static void main(String[] args) throws Exception { // // 授权检查(假设你已经破解) // boolean auth = authrolizeLicense(); // if (!auth) { // System.out.println("aspose 许可无效!"); // return; // } // // System.out.println("aspose 已就绪!"); // // try { // Workbook wb = new Workbook("C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼.xlsx"); // ImageOrPrintOptions imgOptions = new ImageOrPrintOptions(); // imgOptions.setImageFormat(ImageFormat.getPng()); // imgOptions.setCellAutoFit(true); // imgOptions.setOnePagePerSheet(true); // // String outputPdfPath = "C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼aspose导出图片版.pdf"; // // // 创建一个无边距的文档 // Document document = new Document(PageSize.A4); // 使用 A4 纸张尺寸 // PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputPdfPath)); // // // 设置页面无边距(非常重要) // document.setMargins(0, 0, 0, 0); // 左、右、上、下全部为 0 // document.open(); // // for (int i = 0; i < wb.getWorksheets().getCount(); i++) { // Worksheet ws = wb.getWorksheets().get(i); // SheetRender render = new SheetRender(ws, imgOptions); // String imageFilePath = "C:\\Users\\d\\Desktop\\excelToPdf\\sheet_" + i + ".png"; // render.toImage(0, imageFilePath); // // Image img = Image.getInstance(imageFilePath); // // // 自动缩放图片以适配页面宽度和高度 // img.scaleToFit(document.getPageSize().getWidth(), document.getPageSize().getHeight()); // // // 居中显示(iText 默认就是居中的,但我们可以更明确地设置) // img.setAlignment(Image.ALIGN_CENTER); // // // 新增一页 // document.newPage(); // // // 插入图片到当前页面 // document.add(img); // } // // document.close(); // writer.close(); // // System.out.println("✅ PDF 文件已生成: " + outputPdfPath); // } catch (Exception e) { // e.printStackTrace(); // } // 加载 Excel 文件 Workbook workbook = new Workbook("C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼.xlsx"); // 设置 PDF 导出选项 PdfSaveOptions saveOpts = new PdfSaveOptions(); // 设置页面尺寸为 A2(单位是 像素 或 毫米,这里使用像素) // A2 尺寸:4961 x 7016 像素(分辨率为 300 DPI) PageSetup pageSetup = workbook.getWorksheets().get(0).getPageSetup(); pageSetup.setPaperSize(PaperSizeType.PAPER_A_3); // 设置为 A2 纸张 pageSetup.setOrientation(PageOrientationType.LANDSCAPE); // 设置为横向 // 如果你想对所有 sheet 都生效,可以循环设置每个 sheet 的页面属性 for (int i = 0; i < workbook.getWorksheets().getCount(); i++) { Worksheet sheet = workbook.getWorksheets().get(i); sheet.getPageSetup().setPaperSize(PaperSizeType.PAPER_A_3); sheet.getPageSetup().setOrientation(PageOrientationType.LANDSCAPE); } // 设置每张工作表输出为一页 PDF saveOpts.setOnePagePerSheet(true); // 导出为 PDF String outputPdfPath = "C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼aspose导出.pdf"; workbook.save(outputPdfPath, saveOpts); System.out.println("✅ 已成功导出 A2 横向 PDF: " + outputPdfPath); }
查看效果
这种方式虽然可直接转换,但是还是会有水印,所以还是推荐先转图片后再转pdf的方式
以上就是Java多种方式实现Excel转Pdf的保姆级教程的详细内容,更多关于Java Excel转Pdf的多种方式的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论