java poi导出ppt文件

287 阅读5分钟

在我工作时遇到了导出ppt文件的需求,这种需求还是比较冷门的,网上的资料也比较零散,而且这只是一个工具,大部分人也不想花太多精力去学这玩意,所以我将这项工作的总结写成文章,基本能满足工作中自动导出ppt的需求,希望能帮上大家,话不多说,直接上代码。

依赖

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.15.0</version>
</dependency>

工具类

在操作ppt之前,我们先写一个导出、读取ppt的一个工具类。当然,不写也行,主要作用是美化代码

public class FileUtil {
    /**
     * 将给定的 XMLSlideShow 对象导出为 PPT 文件。
     *
     * @param xmlSlideShow 要导出的 XMLSlideShow 对象
     * @param outputPath   导出的 PPT 文件路径
     */
    public static void exportPPT(XMLSlideShow xmlSlideShow, String outputPath) {
        try (FileOutputStream out = new FileOutputStream(outputPath)) {
            xmlSlideShow.write(out);
            System.out.println("文件已导出");
        } catch (IOException e) {
            handleException(e);
        }
    }

    /**
     * 从指定文件路径读取 PPT 文件并返回对应的 XMLSlideShow 对象。
     *
     * @param filePath PPT 文件的路径
     * @return 代表 PPT 的 XMLSlideShow 对象,如果读取失败则返回 null
     */
    public static XMLSlideShow readPPT(String filePath) {
        // 使用 ClassPathResource 获取指定路径的文件资源
        ClassPathResource resource = new ClassPathResource(filePath);
        try (InputStream inputStream = resource.getInputStream()) {
            // 从输入流中创建 XMLSlideShow 对象并返回
            return new XMLSlideShow(inputStream);
        } catch (IOException e) {
            // 处理异常情况
            handleException(e);
        }
        return null;
    }

    /**
     * 处理 IOException 异常的辅助方法,打印错误信息和异常堆栈。
     *
     * @param e IOException 异常对象
     */
    private static void handleException(IOException e) {
        System.err.println("导出文件时发生错误: " + e.getMessage());
        e.printStackTrace();
    }

}

生成PPT

凭空生成一张ppt,用与导出的ppt比较简单的情况

创建ppt

    //创建ppt
    XMLSlideShow ppt = new XMLSlideShow();
    //创建一张幻灯片
    XSLFSlide slide = ppt.createSlide();

创建文本框

//创建一个文本框
XSLFTextBox textBox = slide.createTextBox();
//设置文本框位置已经宽高
textBox.setAnchor(new Rectangle2D.Double(30, 20, 400, 30));
//修改文本框内容
TextRun textRun = textBox.setText("PPT生成");
textRun.setBold(true);
textRun.setFontSize(30.0);

创建表格

//创建一个5*5的表格
XSLFTable table = slide.createTable(5, 5);
TextRun run;
//遍历表格的行
for (int i = 0; i < table.getNumberOfRows(); i++) {
    //遍历列
    for (int j = 0; j < i + 1; j++) {
        int num1 = i + 1;
        int num2 = j + 1;
        //获取单元格
        XSLFTableCell cell = table.getCell(i, j);
        //修改单元格内容
        run = cell.setText(num2 + "*" + num1 + "=" + num1 * num2);
        run.setFontSize(16.0);
        run.setFontColor(Color.black);
        run.setFontFamily("微软雅黑");
        //修改边框宽度
        cell.setBorderWidth(TableCell.BorderEdge.top, 1);
        cell.setBorderWidth(TableCell.BorderEdge.left, 1);
        cell.setBorderWidth(TableCell.BorderEdge.right, 1);
        cell.setBorderWidth(TableCell.BorderEdge.bottom, 1);
        //修改边框颜色
        cell.setBorderColor(TableCell.BorderEdge.top, Color.black);
        cell.setBorderColor(TableCell.BorderEdge.left, Color.black);
        cell.setBorderColor(TableCell.BorderEdge.right, Color.black);
        cell.setBorderColor(TableCell.BorderEdge.bottom, Color.black);
    }
}
for (int i = 0; i < table.getNumberOfColumns(); i++) {
    //修改单元格的宽高
    table.setColumnWidth(i, 80.0);
    table.setRowHeight(i, 30);
}
//设置表格的位置和宽高
table.setAnchor(new Rectangle2D.Double(30, 60, 400, 150));

创建柱状、折线图

//创建图表,并设置图表标题
XSLFChart chart = ppt.createChart();
chart.setTitleText("图表生成");
//准备数据
String[] xs = new String[]{"类别1", "类别2", "类别3", "类别4"};
Integer[] ys = new Integer[]{1, 2, 3, 4};
Integer[] lineYs = new Integer[]{3, 1, 4, 2};
//建立x轴,于图表的下方
XDDFCategoryAxis categoryAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
//建立左y轴
XDDFValueAxis valueAxis = chart.createValueAxis(AxisPosition.LEFT);
//设置数据和y轴之间的空隙
valueAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
//建立柱状图的数据集
XDDFChartData data = chart.createData(ChartTypes.BAR, categoryAxis, valueAxis);
//转成柱状图
XDDFBarChartData bar = (XDDFBarChartData) data;
//设置柱状图方向,峰状
bar.setBarDirection(BarDirection.COL);
//设置柱状图分组,标准
bar.setBarGrouping(BarGrouping.STANDARD);
//建立x轴数据
XDDFCategoryDataSource xValue = XDDFDataSourcesFactory.fromArray(xs);
//建立y轴数据
XDDFNumericalDataSource<Integer> yValue = XDDFDataSourcesFactory.fromArray(ys);
//将x轴的数据和y轴的数据建立成系列数据集
XDDFChartData.Series series = data.addSeries(xValue, yValue);
//设置系列名
series.setTitle("柱状图数据", null);
//绘制数据
chart.plot(data);
//建立右y轴
XDDFValueAxis lineValueAxis = chart.createValueAxis(AxisPosition.RIGHT);
//设置轴距,max表示在右侧拉满
lineValueAxis.setCrosses(AxisCrosses.MAX);
//关联x轴
lineValueAxis.crossAxis(categoryAxis);
//建立折现图的数据集
XDDFChartData lineData = chart.createData(ChartTypes.LINE, categoryAxis, lineValueAxis);
//建立右y轴数据
XDDFNumericalDataSource<Integer> lineYValue = XDDFDataSourcesFactory.fromArray(lineYs);
//将x轴的数据和右y轴的数据建立成系列数据集,并转型为折线数据集
XDDFLineChartData.Series lineSeries = (XDDFLineChartData.Series) lineData.addSeries(xValue, lineYValue);
// 设置系列名
lineSeries.setTitle("条形图数据", null);
//折线是否圆滑
lineSeries.setSmooth(false);
//折线点大小
lineSeries.setMarkerSize((short) 2);
//折线点样式
lineSeries.setMarkerStyle(MarkerStyle.NONE);
//绘制数据
chart.plot(lineData);
//获取数据系列标签
XDDFChartLegend orAddLegend = chart.getOrAddLegend();
//将数据系列标签置于图表下方
orAddLegend.setPosition(LegendPosition.BOTTOM);
//设置图表的位置和宽高
slide.addChart(chart, new Rectangle(500000, 3000000, 4000000, 3000000));

创建饼状图

String[] xs = new String[]{"类别1", "类别2", "类别3", "类别4"};
Integer[] ys = new Integer[]{1, 2, 3, 4};
//创建图表,并设置图表标题
XSLFChart chart = ppt.createChart();
chart.setTitleText("饼状图生成");

XDDFCategoryAxis categoryAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
XDDFValueAxis valueAxis = chart.createValueAxis(AxisPosition.LEFT);
//建立饼状图数据集
XDDFChartData data = chart.createData(ChartTypes.DOUGHNUT, categoryAxis, valueAxis);
XDDFDataSource<String> countries = XDDFDataSourcesFactory.fromArray(xs);
//建立饼图数据
XDDFNumericalDataSource<Integer> value = XDDFDataSourcesFactory.fromArray(ys);
//将数据添加进数据集
data.addSeries(countries, value);
chart.plot(data);
//获取饼状图
CTDLbls dLbls = chart.getCTChart().getPlotArea().getDoughnutChartArray(0).getSerArray(0).addNewDLbls();
//饼状图上 显示数据
dLbls.addNewShowVal().setVal(true);
//饼状图上  显示数据名称
dLbls.addNewShowCatName().setVal(true);
//饼状图上  显示类别名称
dLbls.addNewShowSerName().setVal(false);
//饼状图上  显示百分比
dLbls.addNewShowPercent().setVal(true);
//饼状图上  数据用字符串隔开
dLbls.setSeparator("\n");
slide.addChart(chart, new Rectangle(5000000, 3000000, 4000000, 3000000));

读取、修改PPT

读取ppt原型,并修改原ppt中的内容,用于ppt比较复杂,要素过多的情况。

这是我存放ppt原型的位置,具体位置自行更改,这里仅做演示。

image.png

//读取ppt文件
XMLSlideShow xmlSlideShow = FileUtil.readPPT("template/template.pptx");
//获取到ppt集合
List<XSLFSlide> slides = xmlSlideShow.getSlides();
//假设学生表
String[][] students = new String[][]{{"张三", "13", "男"}, {"李四", "14", "女"}};
TextRun textRun;
//遍历文件中的每页ppt
for (XSLFSlide slide : slides) {
    //遍历ppt中的每一种元素:文本框、图表、表格
    for (XSLFShape shape : slide.getShapes()) {
        //获取元素的简单名称,判断出不同的元素,做出不同的操作
        switch (shape.getClass().getSimpleName()) {
        
            case "XSLFTextBox":
                //转型成文本框
                XSLFTextBox textShape = (XSLFTextBox) shape;
                textRun = textShape.setText(textShape.getText().replace("type", "学生"));
                textRun.setFontColor(Color.black);
                textRun.setBold(true);
                textRun.setFontSize(20.0);
                textRun.setFontFamily("微软雅黑");
                break;
                
            case "XSLFTable":
                //转型成表格
                XSLFTable tableShape = (XSLFTable) shape;
                //遍历行
                for (int i = 1; i < tableShape.getNumberOfRows(); i++) {
                    //遍历列
                    for (int j = 0; j < tableShape.getNumberOfColumns(); j++) {
                        textRun = tableShape.getCell(i, j).setText(students[i - 1][j]);
                        textRun.setFontSize(16.0);
                        textRun.setFontColor(Color.red);
                        textRun.setFontFamily("微软雅黑");
                    }
                }
                break;
                
            case "XSLFGraphicFrame":
                //转型成图表
                XSLFGraphicFrame frame = (XSLFGraphicFrame) shape;
                //获取chart图
                XSLFChart chart = frame.getChart();
                //准备新数据
                String[] xs = new String[]{"类别1", "类别2", "类别3", "类别4"};
                Integer[] ys = new Integer[]{1, 2, 3, 4};
                //将新数据转换成x轴和y轴数据
                XDDFCategoryDataSource xddfCategoryDataSource = XDDFDataSourcesFactory.fromArray(xs);
                XDDFNumericalDataSource<Integer> count = XDDFDataSourcesFactory.fromArray(ys);

                List<XDDFChartData> chartSeries = chart.getChartSeries();
                for (XDDFChartData chartData : chartSeries) {
                    //遍历图表中的系列
                    for (XDDFChartData.Series series : chartData.getSeries()) {
                        //遍历系列里数据的长度
                        for (int i = 0; i < series.getValuesData().getPointCount(); i++) {
                            //根据下标获取相应数据
                            System.out.print(series.getValuesData().getPointAt(i) + "  ");
                        }
                        System.out.println();
                    }
                }
                for (XDDFChartData chartData : chartSeries) {
                    for (XDDFChartData.Series series : chartData.getSeries()) {
                        //修改系列数据
                        series.replaceData(xddfCategoryDataSource, count);
                    }
                    //将新数据绘制到图表
                    chart.plot(chartData);
                }
                break;
        }
    }
}
FileUtil.exportPPT(xmlSlideShow, "src/main/resources/template/template2.pptx");