Java 基于 poi 和 itextpdf 实现 excel 转 pdf

目录

问题

实现思路

pom

Excel2PDFUtil

Excel2PDFUtilTest

输出结果


问题

工作中遇到一个需求,需要实现 excel 文件的预览,实现的思路就是将 excel 转成 pdf 文件,上传到文件服务器上得到文件地址,预览时只需要返回 pdf 预览文件地址即可。

所以主要的问题就是如何将 excel 转为 pdf,调研了相关的技术,最简单的就是使用 aspose 类库,直接一个api调用就搞定了。但是 aspose 并不是免费的,虽然网上有破解,但是为了规避版权风险,最好还是不用了。

可以使用 itextpdf 来平替 aspose 实现 excel 文件转换。由于需求中的 excel 就只是很常规的文本表格,使用 itextpdf 来创建表格,依次从 excel 获取每行每列的单元格依次填入即可将 excel 中的内容搬到新建的 pdf 中,从而实现 excel 到 pdf 的转换。

实现思路

poi 读取 excel 内容,得到 excel 文件中每一张 sheet,每张 sheet 中的所有单元格

java 复制代码
InputStream in = Files.newInputStream(Paths.get(excelPath);
//workbook
Workbook workbook = excelSuffix.endsWith(".xlsx") ? new XSSFWorkbook(in) : new HSSFWorkbook(in);

//获取所有表格
Iterator<Sheet> it = workbook.sheetIterator()
Sheet sheet = it.next();

//获取单元格
Row row = sheet.getRow(rowIndex);
Cell cell = row.getCell(columnIndex);

//获取单元格值
CellType cellType = excelCell.getCellType();
String value = excelCell.getStringCellValue();

itextpdf 创建pdf,将 excel 单元格转换成 pdf 单元格,最后写入 pdf 文件

java 复制代码
OutputStream out = Files.newOutputStream(Paths.get(pdfPath);
//创建 pdf 文档
Document document = new Document(new RectangleReadOnly(842.0F, 595.0F));
        PdfWriter.getInstance(document, outStream);

document.open();

//创建 pdf 表格
PdfPTable table = new PdfPTable();

//船舰 pdf 单元格
PdfPCell cell = new PdfPCell();

//添加单元格到表格
table.add(cell);

//新建一页
document.newPage();

//将表格写入文档
document.add(table);

document.close();

pom

XML 复制代码
    <properties>
        <poi.version>5.2.5</poi.version>
        <itextpdf.version>5.5.13.2</itextpdf.version>
    </properties>
     
    <dependencies>
         <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>${itextpdf.version}</version>
        </dependency>
    </dependencies>

Excel2PDFUtil

java 复制代码
public class Excel2PDFUtil {

    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))) {
            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 {
        //设置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();
        // 输入流转workbook,获取sheet
        Workbook workbook = excelSuffix.endsWith(".xlsx") ? new XSSFWorkbook(inStream) : new HSSFWorkbook(inStream);
        for (Iterator<Sheet> it = workbook.sheetIterator(); it.hasNext(); ) {
            Sheet sheet = it.next();
            // 获取列宽度占比
            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)) {
                    // 插入空对象
                    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));
                        //处理合并单元格
                        dealMergedRegion(sheet, rowIndex, columnIndex, pCell);

                        table.addCell(pCell);
                    }
                }
            }

            document.newPage();
            document.add(table);
        }
        document.close();
    }

    /**
     * 单元格转换,poi cell 转换为 itext cell
     *
     * @param sheet  poi sheet页
     * @param excelCell poi 单元格
     * @return com.itextpdf.text.pdf.PdfPCell
     */
    private static PdfPCell excelCellToPdfCell(Sheet sheet, Cell excelCell) {
        if (Objects.isNull(excelCell)) {
            return createPdfPCell(null, 0, 13f, null);
        }

        org.apache.poi.ss.usermodel.Font excelFont = getExcelFont(sheet, excelCell);
        //设置单元格字体
        com.itextpdf.text.Font pdFont = new com.itextpdf.text.Font();
        pdFont.setSize(excelFont.getFontHeightInPoints());
        pdFont.setStyle(excelFont.getBold() ? 1 : 0);
        pdFont.setColor(BaseColor.BLACK);
        Integer border = hasBorder(excelCell) ? null : 0;
        String excelCellValue = getExcelCellValue(excelCell);
        PdfPCell 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对齐方式
     */
    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 org.apache.poi.ss.usermodel.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单元格是否有边框
     */
    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;
    }

    /**
     * 处理合并单元格
     *
     * @param sheet 表格
     * @param row 当前行
     * @param column 当前列
     * @param pCell pdf单元格
     */
    private static void dealMergedRegion(Sheet sheet, int row, int column, PdfPCell pCell) {
        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 (firstColumn == column && firstRow == row) {
                pCell.setRowspan(lastRow - firstRow + 1);
                pCell.setColspan(lastColumn - firstColumn + 1);
                break;
            }
        }
    }

    /**
     * 获取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 "";
    }

}

Excel2PDFUtilTest

java 复制代码
class Excel2PDFUtilTest {

    @Test
    void excelToPdf() {
        String excelPath = "C:\\Users\\XXXX\\Desktop\\excel.xlsx";
        String pdfPath = "C:\\Users\\XXXX\\Desktop\\pdf.pdf";

        Excel2PDFUtil.excelToPdf(excelPath, pdfPath, ".xlsx");
    }
}

输出结果

excel文件:

pdf文件:

相关推荐
守护者17018 分钟前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云19 分钟前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
禾高网络21 分钟前
租赁小程序成品|租赁系统搭建核心功能
java·人工智能·小程序
学会沉淀。27 分钟前
Docker学习
java·开发语言·学习
如若12328 分钟前
对文件内的文件名生成目录,方便查阅
java·前端·python
热心市民运维小孙28 分钟前
Ubuntu重命名默认账户
linux·ubuntu·excel
初晴~1 小时前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·
黑胡子大叔的小屋2 小时前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark2 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
雷神乐乐3 小时前
Spring学习(一)——Sping-XML
java·学习·spring