当前位置: 首页 > article >正文

Java Excel转PDF POI+Itext5

由于现在存在需求,通过Java将数据文本生成特点格式Excel,再输出为PDF。

调研了一些方案,最终决定使用POI写入Excel,再使用Itext5生成PDF。

在网上找了一些Itext的转换工具类,进行了一些改动。
 

目前市面上 Excel 转 PDF 的组件较多:

  • 收费:aspose、GcExcel、spire
  • 开源:jacob、itextpdf

其中收费的组件封装得比较好,代码简洁,转换的效果也很好,但收费也高得离谱:
 

874a7fbbd006818eb458b5599059775.png


为了成本考虑,就需要考虑开源的组件了,因为它们都是免费的:

  • jacob:目前没有探索出很好的导出效果。
  • itextpdf:已探索出很好的导出效果,达到了与收费组件一致的效果(推荐)。

使用步骤

1.引入依赖
<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13.4</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
2.定义工具类
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 com.szis.tangram.common.utils.CollectionUtils;
import com.szis.tangram.common.utils.ObjectUtils;
import com.szis.tangram.common.utils.StringUtils;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
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.List;
import java.util.*;


@UtilityClass
@Slf4j
public class ExcelToPdfUtil {
    /**
     * 单元格队列
     */
    Set<String> cellSet = new HashSet<>();

    public static void main(String[] args) {
        String excelFilePath = "C:\\OSSPDF\\试卷导出A9aiAsTKmvOVqR4C.xlsx";

        String pdfFilePath = "C:\\OSSPDF\\试卷导出模板初版转换PDF预览.pdf";
        excelToPdf(excelFilePath, pdfFilePath, ".xlsx");
        System.out.println("Excel文件已成功转换为PDF!");

    }

    /**
     * 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) {
            throw new RuntimeException(e);
        }
    }

    private String getServerType() {
        // 这里只是示例,实际需根据你的获取方式来返回正确的服务器类型
        return System.getProperty("os.name").toLowerCase().contains("win") ? "windows" : "linux";
    }

    /**
     * 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) {
        // 输入流转workbook,获取sheet
        Sheet sheet = null;
        try {
            sheet = getPoiSheetByFileStream(inStream, 0, excelSuffix);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 获取列宽度占比
        float[] widths = getColWidth(sheet);
        PdfPTable table = new PdfPTable(widths);
        table.setWidthPercentage(100);
        int colCount = widths.length;
        //设置基本字体
        BaseFont baseFont = null;
        try {
            String serverType = getServerType();

            if ("windows".equals(serverType)) {
                baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            } else {
                baseFont = BaseFont.createFont("/usr/share/fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            }
//            baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);

        } catch (DocumentException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 遍历行
        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++) {
                    com.itextpdf.text.Font pdFont = new com.itextpdf.text.Font(baseFont, 13f, 0, BaseColor.BLACK);
                    table.addCell(createPdfPCell("", 0, 13f, pdFont, null));
                }
            } else {
                // 遍历单元格
                for (int columnIndex = 0; (columnIndex < row.getLastCellNum() || columnIndex < colCount) && columnIndex > -1; columnIndex++) {
                    PdfPCell pCell = null;
                        try {
                            pCell = excelCellToPdfCell(sheet, row.getCell(columnIndex), baseFont);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                        // 是否合并单元格
                        if (isMergedRegion(sheet, rowIndex, columnIndex)) {
                            int[] span = getMergedSpan(sheet, rowIndex, columnIndex);
                            //忽略合并过的单元格
                            boolean mergedCell = span[0] == 1 && span[1] == 1;
                            if (mergedCell) {
                                pCell.setPhrase(null);
                                continue;
                            }else {
                                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 PDF单元格
     */
    private static PdfPCell excelCellToPdfCell(Sheet sheet, Cell excelCell, BaseFont baseFont) {
        if (Objects.isNull(excelCell)) {
            com.itextpdf.text.Font pdFont = new com.itextpdf.text.Font(baseFont, 13f, 0, BaseColor.BLACK);
//            table.addCell(createPdfPCell("", 0, 13f, pdFont, null));
            return createPdfPCell("", 0, 13f, pdFont, null);
        }
        int rowIndex = excelCell.getRowIndex();
        int columnIndex = excelCell.getColumnIndex();
        // 获取单元格背景色(更通用的获取及转换方式开始)
        short bgColorIndex = excelCell.getCellStyle().getFillForegroundColor();
        BaseColor backgroundColor = null;
        if (bgColorIndex != IndexedColors.WHITE.getIndex()) {
            if (sheet instanceof HSSFSheet) {
                HSSFWorkbook workbook = (HSSFWorkbook) sheet.getWorkbook();
                HSSFPalette palette = workbook.getCustomPalette();
                HSSFColor hssfColor = palette.getColor(bgColorIndex);
                if (hssfColor != null) {
                    short[] argb = hssfColor.getTriplet();
                    byte r = (byte) Math.min(255, Math.max(0, argb[0]));
                    byte g = (byte) Math.min(255, Math.max(0, argb[1]));
                    byte b = (byte) Math.min(255, Math.max(0, argb[2]));
                    backgroundColor = new BaseColor(r, g, b);
                }
            } else if (sheet instanceof XSSFSheet) {
                XSSFColor xssfColor = ((XSSFCell) excelCell).getCellStyle().getFillForegroundXSSFColor();
                if (xssfColor != null) {
                    byte[] argb = xssfColor.getARGB();
                    if (argb != null && argb.length >= 4) {
                        // 将有符号的byte类型转换为无符号的int类型,并确保范围在0 - 255
                        argb[0] = (byte) (argb[0] & 0xFF);
                        argb[1] = (byte) (argb[1] & 0xFF);
                        argb[2] = (byte) (argb[2] & 0xFF);
                        argb[3] = (byte) (argb[3] & 0xFF);

                        argb[0] = (byte) Math.min(255, Math.max(0, argb[0]));
                        argb[1] = (byte) Math.min(255, Math.max(0, argb[1]));
                        argb[2] = (byte) Math.min(255, Math.max(0, argb[2]));
                        argb[3] = (byte) Math.min(255, Math.max(0, argb[3]));
                    }

//                    backgroundColor = new BaseColor(argb[1], argb[2], argb[3], argb[0]);
                    backgroundColor = new BaseColor(200, 200, 200); // 设置为默认的灰色
                }
            }
        }
        // 获取单元格字体颜色(新增代码部分开始)
        BaseColor fontColor = null;
        short fontColorIndex = -1;
        if (sheet instanceof HSSFSheet) {
            fontColorIndex = ((HSSFCell) excelCell).getCellStyle().getFont(sheet.getWorkbook()).getColor();
        } else if (sheet instanceof XSSFSheet) {
            fontColorIndex = ((XSSFCell) excelCell).getCellStyle().getFont().getColor();
        }
        if (fontColorIndex != IndexedColors.AUTOMATIC.getIndex()) {
            if (fontColorIndex == IndexedColors.BLACK.getIndex()) {
                fontColor = BaseColor.BLACK;
            } else if (fontColorIndex == IndexedColors.RED.getIndex()) {
                fontColor = BaseColor.RED;
            } else if (fontColorIndex == IndexedColors.BLUE.getIndex()) {
                fontColor = BaseColor.BLUE;
            }
            // 这里可以继续添加更多颜色判断,列举常见颜色,类似处理背景色时的方式,也可采用更通用的颜色转换方式(如下面注释掉的代码部分)
            // 以下是一种更通用的通过RGB值转换的示例(但需要进一步处理可能的异常情况等,暂注释掉先展示简单常见颜色判断方式)
//            byte[] argb = getColorArgbFromIndex(fontColorIndex, sheet);
//            // 假设定义了这个方法来获取RGB值,暂未实现
//            if (argb == null) {
//                fontColor = new BaseColor(0, 0, 0);
//            } else {
//                fontColor = new BaseColor(argb[1], argb[2], argb[3]);
//            }
        }
        // 图片信息
        List<PicturesInfo> infos = null;
        try {
            infos = getAllPictureInfos(sheet, rowIndex, rowIndex, columnIndex, columnIndex, false);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        PdfPCell pCell;
        if (CollectionUtils.isNotEmpty(infos)) {
            Image image = null;
            try {
                image = Image.getInstance(infos.get(0).getPictureData());
            } catch (BadElementException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            // 调整图片大小
            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, fontColor != null ? fontColor : BaseColor.BLACK);
            //            Integer border = hasBorder(excelCell) ? null : 0;
            Integer border = 0;
            if (hasTopBorder(excelCell)) {
                border |= com.itextpdf.text.Rectangle.TOP;
            }
            if (hasBottomBorder(excelCell)) {
                border |= com.itextpdf.text.Rectangle.BOTTOM;
            }
            if (hasLeftBorder(excelCell)) {
                border |= com.itextpdf.text.Rectangle.LEFT;
            }
            if (hasRightBorder(excelCell)) {
                border |= com.itextpdf.text.Rectangle.RIGHT;
            }
            String excelCellValue = getExcelCellValue(excelCell);
            pCell = createPdfPCell(excelCellValue, border, excelCell.getRow().getHeightInPoints(), pdFont, backgroundColor);
        }
//        if (ObjectUtils.isEmpty(pCell) || ObjectUtils.isEmpty(pCell.getLeft())) {
//            pCell = createPdfPCell(null, 0, 13f, null, null);
//        }
        // 水平居中
        pCell.setHorizontalAlignment(getHorAlign(excelCell.getCellStyle().getAlignment().getCode()));
        // 垂直对齐
        pCell.setVerticalAlignment(getVerAlign(excelCell.getCellStyle().getVerticalAlignment().getCode()));
        return pCell;
    }

    private static byte[] getColorArgbFromIndex(short fontColorIndex, Sheet sheet) {
        byte[] argb = new byte[4];
        if (sheet instanceof HSSFSheet) {
            HSSFWorkbook workbook = (HSSFWorkbook) sheet.getWorkbook();
            HSSFPalette palette = workbook.getCustomPalette();
            HSSFColor hssfColor = palette.getColor(fontColorIndex);
            if (hssfColor != null) {
                short[] triplet = hssfColor.getTriplet();
                argb[0] = (byte) 255; // Alpha通道,暂设为不透明
                argb[1] = (byte) triplet[0];
                argb[2] = (byte) triplet[1];
                argb[3] = (byte) triplet[2];
            }
        } else if (sheet instanceof XSSFSheet) {
            org.apache.poi.xssf.usermodel.XSSFColor xssfColor = new org.apache.poi.xssf.usermodel.XSSFColor(IndexedColors.fromInt(fontColorIndex), null);
            argb = xssfColor.getARGB();
        }
//        if (argb != null && argb.length >= 4) {
//            // 将有符号的byte类型转换为无符号的int类型,并确保范围在0 - 255
//            argb[0] = (byte) (argb[0] & 0xFF);
//            argb[1] = (byte) (argb[1] & 0xFF);
//            argb[2] = (byte) (argb[2] & 0xFF);
//            argb[3] = (byte) (argb[3] & 0xFF);
//
//            argb[0] = (byte) Math.min(255, Math.max(0, argb[0]));
//            argb[1] = (byte) Math.min(255, Math.max(0, argb[1]));
//            argb[2] = (byte) Math.min(255, Math.max(0, argb[2]));
//            argb[3] = (byte) Math.min(255, Math.max(0, argb[3]));
//        }
        return argb;
    }

    /**
     * 创建pdf文档,并添加表格
     *
     * @param outStream 输出流,目标文档
     * @param table     表格
     * @throws DocumentException 异常信息
     */
    private static void createPdfTableAndWriteDocument(OutputStream outStream, PdfPTable table) {
        //设置pdf纸张大小 PageSize.A4 A4横向
        try {
            Document document = new Document(PageSize.A4);
            PdfWriter.getInstance(document, outStream);
            //设置页边距 宽
            document.setMargins(20, 20, 40, 40);
            document.open();
            document.add(table);
            document.close();
        } catch (DocumentException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }

    }

    /**
     * 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, BaseColor backgroundColor) {
        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);
        }
        if (backgroundColor != null) {
            pCell.setBackgroundColor(backgroundColor);
        }
        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) {
        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 hasTopBorder(Cell excelCell) {
        short top = excelCell.getCellStyle().getBorderTop().getCode();
        return top > 0;
    }

    private static boolean hasBottomBorder(Cell excelCell) {
        short bottom = excelCell.getCellStyle().getBorderBottom().getCode();
        return bottom > 0;
    }

    private static boolean hasLeftBorder(Cell excelCell) {
        short left = excelCell.getCellStyle().getBorderLeft().getCode();
        return left > 0;
    }

    private static boolean hasRightBorder(Cell excelCell) {
        short right = excelCell.getCellStyle().getBorderRight().getCode();
        return right > 0;
    }

    /**
     * 判断单元格是否是合并单元格
     *
     * @param sheet  表
     * @param row    行
     * @param column 列
     * @return 结果
     */
    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;
    }
    /**
     * 判断指定单元格是否为合并单元格
     *
     * @param sheet  当前sheet页
     * @param row    行号
     * @param column 列号
     * @return 是否为合并单元格
     */
    private static boolean isMergedCell(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 && 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 {
                    DataFormatter formatter = new DataFormatter();
                    return formatter.formatCellValue(excelCell);
//                    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()扩展方法!");
        }
    }

    /**
     * 获取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 = StringUtils.format("{},{},{},{}", 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 = StringUtils.format("{},{},{},{}", 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)));
        }
    }


}

3.定义图片信息

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;
    }
}

参考文档:Java Excel转PDF(免费) - 天航星 - 博客园


http://www.kler.cn/a/461744.html

相关文章:

  • 【MongoDB详解】
  • UE5 Debug的一些心得
  • 【模型】Qwen2-VL 服务端UI
  • 在 macOS 上,你可以使用系统自带的 终端(Terminal) 工具,通过 SSH 协议远程连接服务器
  • 解決當前IP地址僅適用於本地網路
  • 深入理解连接池:从数据库到HTTP的优化之道
  • 【无线传感网】WSN数据管理技术
  • 自学记录鸿蒙API 13:Calendar Kit日历功能从学习到实践
  • 面试题解,JVM的运行时数据区
  • 【杂谈】-快速了解协作机器人
  • 推荐5款局域网IP扫描工具,支持电脑+Android!
  • 什么是递归解析服务器?它有什么特点
  • 正则表达式中,`$1` 是一个反向引用(backreference),它代表了匹配过程中捕获的第一个子表达式(即第一个括号内的内容)
  • 速盾:服务器CDN加速解析的好处有哪些呢?
  • leetcode热题100(79. 单词搜索)dfs回溯 c++
  • JWT包中的源码分析【Golang】
  • 解决uniapp H5页面限制输入框只能输数字问题
  • protobuf: 通讯录2.1
  • 生成文本格式日历的Python程序
  • SwanLab x LLaMA Factory:国产开源AI训练工具组合拳(含教程)
  • 如何使用Python生成词云图:结合`wordcloud`、`imageio`、`collections`和`jieba`分词模块
  • Excel VBA 自动填充空白并合并相同值的解决方案
  • 1.计算机英语
  • Spring boot对接安全证书
  • 通过 4 种方法将数据从 OnePlus 传输到Android
  • JavaScript中的JSON是什么