java调用poi根据模板生成ppt

2023-12-14 15:26:06

吐槽:像这种需求半年碰不到一个 O.o

可以多去poi官网翻一下官方文档虽然很难理解但有用?

所有代码基于个人习惯编写,懒得贴图了相信兄弟们的理解能力,有问题可以留言我尽量解决。

本文所有代码生成都基于pptx文件编写,可根据具体业务修改代码

1.打开模板文件
   String modelPath = "classpath:static/模板.pptx";
   String fileName = "生成路径/test1.pptx";

 
   // 打开PPTX文件
   InputStream fis = ResourceUtils.getURL(modelPath).openStream();
   XMLSlideShow ppt = new XMLSlideShow(fis);
   fis.close();
2.创建数据映射集合
 // 文本数据映射表
 Map<String, String> textDataMap = new HashMap<>();
 
 textDataMap.put("${title}", "测试数据标题");
 textDataMap.put("${context}", "测试数据文本");


 textDataMap.put("${table_title}", "表格数据测试标题"); 
 textDataMap.put("${table_context}", "表格数据测试文本"); 


 textDataMap.put("textPic", "图片地址");


 String[] ary = new String[3];
 ary[0] = "文本框1";
 ary[1] = "文本框2";
 ary[2] = "文本框3";
 textDataMap.put("testTextBox", "ary")

注:ppt每页内容及业务不一样,需要每页单独处理,但可以封装通用方法?


private void makePPT(Integer page, XMLSlideShow ppt, Map<String, Object> textDataMap) {
         //获取幻灯片对象
         XSLFSlide slide = getShapes(page - 1, ppt);
         switch (page) {
             case 1:
                 slideShow1(slide, textDataMap);
                break;
             case 2:
                 slideShow2(slide, textDataMap);
                break;
             case 3:
                 slideShow3(XSLFSlide slide, XMLSlideShow ppt, Map<String, Object> textDataMap);
                break;
             case 4:
                 slideShow4(slide);
                break;
             case 5:
                 slideShow5(slide, textDataMap);
                break;
             case 6:
                 slideShow6(slide);
                break;
         }
}
正式调用:
//填充普通文本框 
public void sideShow1(XSLFSlide slide, Map<String, Object> textDataMap) {
        fillDateToPPT(slide, textDataMap);
}


//填充表格数据 
public void sideShow2(XSLFSlide slide, Map<String, Object> textDataMap) {
        fillTableDataToPPT(slide, textDataMap);
}


//填充图片 
public void sideShow3(XSLFSlide slide, XMLSlideShow ppt, Map<String, Object> textDataMap) {
        fillImageToPPT(ppt, slide, StringIsEmpty(textDataMap.get("textPic")), 0, 0, 200, 200);
}


//动态生成表格
public void sideShow4(XSLFSlide slide) {
       //设置表格数据数组
       String[][] ary = new String[3][3];
        
       //给数组添加数据(根据需求可以自定义数组长度并填充数据)
       ary[0][0] = "0";  
       ary[0][1] = "1";      
       ary[0][2] = "2";         

       ary[1][0] = "0";  
       ary[1][1] = "1";      
       ary[1][2] = "2";              

       ary[2][0] = "0";  
       ary[2][1] = "1";      
       ary[2][2] = "2";   

       createTable(ary , slide, 0, 0, 400.00, 200.00);
}


//填充文本框内容
public void sideShow5(XSLFSlide slide, Map<String, Object> textDataMap) {
        PPTFontStyle pptFontStyle = new PPTFontStyle();
        pptFontStyle.setFontSize(12.00);
        pptFontStyle.setFontFamily("Hiragino Sans GB W6");
        fillTextBoxDataToPPT(textDataMap, "testTextBox", "\n", slide, pptFontStyle);
}


//填充图表数据
public void sideShow6(XSLFSlide slide) {
       List<Integer> list = new ArrayList<>();
       list.add(0);
       list.add(1);
       list.add(2);
       fillChartToPPT(list, slide);
}
封装的方法:

注:根据需求可以组合使用

1.创建XSLFSlide(幻灯片)对象?
//生成ppt幻灯片对象    
private XSLFSlide getShapes(Integer page, XMLSlideShow ppt) {
        return ppt.getSlides().get(page);
    }
2.循环获取幻灯片当页所有文本框对象找到与textDataMap集合中符合的数据填充替换

注:不能使用实例化后的textShape直接setText会失去所有样式信息

    /**
     * 替换文本数据到ppt
     *
     * @param textDataMap  文本数据
     * @param slide        幻灯片对象
     */
    private void fillDateToPPT(XSLFSlide slide, Map<String, Object> textDataMap) {
        for (XSLFShape shape : slide.getShapes()) {
            if (shape instanceof XSLFTextShape) {
                XSLFTextShape textShape = (XSLFTextShape) shape;
                for (XSLFTextParagraph textParagraph : textShape.getTextParagraphs()) {
                    for (XSLFTextRun textRun : textParagraph.getTextRuns()) {
                        String text = textRun.getRawText();
                        String resultText = textDatMap.get(text);
                        textRun.setText(resultText);
                    }
                }
            }
        }
    }
3.和上一个方法类似,获取页面表格并循环每个?单元格拿到匹配数据替换

    /**
     * 根据集合循环填充表格数据
     *
     * @param textDataMap 文本数据地图
     * @param slide       幻灯片对象
     */
    private void fillTableDataToPPT(Map<String, Object> textDataMap, XSLFSlide slide) {
        for (XSLFShape shape : slide.getShapes()) {
            if (shape instanceof XSLFTable) {
                XSLFTable table = (XSLFTable) shape;
                for (int row = 0; row < table.getNumberOfRows(); row++) {
                    for (int colum = 0; colum < table.getNumberOfColumns(); colum++) {
                        // 遍历单元格匹配修改内容
                        XSLFTableCell cell = table.getCell(row, colum);
                        for (XSLFTextParagraph textParagraph : cell.getTextParagraphs()) {
                            for (XSLFTextRun textRun : textParagraph.getTextRuns()) {
                                String text = textRun.getRawText();
                                String resultText = textDataMap.get(text)
                                textRun.setText(resultText);
                            }
                        }
                    }
                }
            }
        }
    }
4.获取当前幻灯片页中为空的文本框

注:此方法为填充文本框需用appendText不会破坏原本样式

    /**
     * 填充文本框带编号
     *
     * @param textDataMap  - 文本数据
     * @param key          -   集合对象
     * @param split        - 分隔符
     * @param slide        - 幻灯片对象
     * @param pptFontStyle - ppt字体样式
     */
    private void fillTextBoxDataToPPT(Map<String, Object> textDataMap, String key, String split, XSLFSlide slide, PPTFontStyle pptFontStyle) {
        // 根据换行符拆分字符串
        String[] lines = StringIsEmpty(textDataMap.get(key)).split(split);
        // 将拆分的字符串保存到集合中
        List<String> list = new ArrayList<>();
        Collections.addAll(list, lines);

        for (XSLFShape shape : slide.getShapes()) {
            if (shape instanceof XSLFTextBox) {
                XSLFTextBox textBox = (XSLFTextBox) shape;
                String text = textBox.getText();
                if ("".equals(text)) {
                    XSLFTextRun xslfTextRun = null;
                    for (int i = 0; i < list.size(); i++) {
                        boolean isFirstItem = true;
                        if (i == 0) {
                            isFirstItem = false;
                        }
                        xslfTextRun = textBox.appendText(list.get(i), isFirstItem);
                        xslfTextRun.setFontSize();
                        xslfTextRun.setFontFamily();
                    }
                }
            }
        }
    }
5.设置字体样式,这里处理的是基本的几种属性
    /**
     * 设置字体样式
     *
     * @param pptFontStyle
     */
    private void setFontStyle(PPTFontStyle pptFontStyle) {
        if (ObjectUtils.isEmpty(pptFontStyle)) {
            return;
        }
        XSLFTextRun textRun = null;
        if (!ObjectUtils.isEmpty(pptFontStyle.getCell())) {
            XSLFTextParagraph paragraph = pptFontStyle.getCell().addNewTextParagraph();
            textRun = paragraph.addNewTextRun();
        } else {
            textRun = pptFontStyle.getTextRun();
        }

        if (!StringUtils.isEmpty(pptFontStyle.getText())) {
            textRun.setText(pptFontStyle.getText());
        }
        if (!StringUtils.isEmpty(pptFontStyle.getFontSize())) {
            textRun.setFontSize(pptFontStyle.getFontSize());
        }
        if (!StringUtils.isEmpty(pptFontStyle.getFontFamily())) {
            textRun.setFontFamily(pptFontStyle.getFontFamily());
        }
        if (!StringUtils.isEmpty(pptFontStyle.getFontColor())) {
            textRun.setFontColor(pptFontStyle.getFontColor());
        }
    }

实体类

public class PPTFontStyle {
    private XSLFTableCell cell;
    private String text;
    private Double fontSize;
    private String fontFamily;
    private Color fontColor;
    private XSLFTextRun textRun;
}
6.根据x轴、y轴将图片填充到幻灯片中
    /**
     * @param ppt       ppt对象
     * @param slide     幻灯片对象
     * @param fileName  图片地址
     * @param x         x轴
     * @param y         y轴
     * @param width     宽
     * @param height    高
     *///填充图片
    private void fillImage(XMLSlideShow ppt, XSLFSlide slide, String fileName, Integer x, Integer y, Integer width, Integer height) {
        if (StringUtils.isEmpty(fileName)) {
            return;
        }
        // 填充展位图片
        try {
            XSLFPictureData pictureData = ppt.addPicture(Files.newInputStream(Paths.get(fileName)), PictureData.PictureType.JPEG);
            XSLFPictureShape pictureShape = slide.createPicture(pictureData);
            pictureShape.setAnchor(new Rectangle(x, y, width, height));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
7.填充图表数据

此方法是以折线图为基础填充,两条数据线。

注:填充完数据必须刷新图表信息,否则生成后图表关联Excel中有数据但必须编辑数据后图表才会显示数据

    /**
     * 填充图表数据
     *
     * @param slide 幻灯片
     * @param list  列表
     */
    private void fillChartToPPT(List<Ineger> list, XSLFSlide slide) {
        // 遍历幻灯片上的所有形状
        for (XSLFShape shape : slide.getShapes()) {
            if (shape instanceof XSLFGraphicFrame) {
                XSLFGraphicFrame graphicFrame = (XSLFGraphicFrame) shape;
                XSLFChart chart = graphicFrame.getChart();
                XDDFChartData xddfChartData = chart.getChartSeries().get(0);
                XDDFLineChartData xddfLineChartData = (XDDFLineChartData) xddfChartData;
                if (chart != null) {
                    try {
                        //获取图表中的Excel工作簿
                        XSSFWorkbook workbook = chart.getWorkbook();
                        XSSFSheet sheet = workbook.getSheetAt(0);
                        for (int i = 0; i < list.size(); i++) {
                           //获取图表中excel对象之后根据自己需求填充数据即可
                        }

                        //对象中的数据以具体业务填充
                        //设置图表中的数据,从内嵌的表格sheet0中获取
                        XDDFDataSource<String> cat0 = XDDFDataSourcesFactory.fromStringCellRange(sheet,
                                new CellRangeAddress(0, 0, 0, 0));


                        XDDFNumericalDataSource val0 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                                new CellRangeAddress(0, 0, 0, 0));
                        XDDFNumericalDataSource val1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet,
                                new CellRangeAddress(0, 0, 0, 0));

                        XDDFChartData.Series series = xddfLineChartData.getSeries(0);
                        series.replaceData(cat0, val0);

                        XDDFChartData.Series series1 = xddfLineChartData.getSeries(1);
                        series1.replaceData(cat0, val1);

                        //设置最小限值
                        xddfChartData.getValueAxes().get(0).setMinimum(0);

                        //设置单位
                        xddfChartData.getValueAxes().get(0).setMajorUnit(4);

                        //重新绘图
                        chart.plot(xddfLineChartData);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
?8.动态生成表格并赋值

注:因为表格是动态生成的所有表格是没有样式的包括字体,需手动添加字体样式或表格样式

    /**
     * 生成表格
     *
     * @param ary         数据
     * @param slide       幻灯片对象
     * @param x           表格左上角的 x 坐标
     * @param y           表格左上角的 y 坐标
     * @param maxHeight   总行高
     * @param maxWidth    最大宽度

     */
    private void createTable(String[][] ary, XSLFSlide slide, int x, int y, Double maxHeight, Double maxWidth) {
        // 设置表格的行数和列数
        int numRows = ary.length; // 行数
        int numCols = ary[0].length; // 列数
        // 设置表格位置和大小
        XSLFTable table = slide.createTable(numRows, numCols);
        table.setAnchor(new Rectangle(new Point(x, y)));
        //设置单元格宽
        double width = maxWidth / numCols;   //列宽
        //设置行高
        double height =  maxHeight / numRows ; // 行高
        //根据数组生成单元格并设置样式
        for (int row = 0; row < numRows; row++) {
            for (int col = 0; col < numCols; col++) {
                // 获取单元格对象
                XSLFTableCell cell = table.getCell(row, col);
                cell.setVerticalAlignment(VerticalAlignment.MIDDLE);

                //填充文本
                XSLFTextRun xslfTextRun = cell.setText(ary[row][col]);                

                TableCell.BorderEdge left = TableCell.BorderEdge.left;
                TableCell.BorderEdge right = TableCell.BorderEdge.right;
                TableCell.BorderEdge top = TableCell.BorderEdge.top;
                TableCell.BorderEdge bottom = TableCell.BorderEdge.bottom;

                //设置单元格边框颜色
                cell.setBorderColor(left, new Color(241, 241, 241, 255));
                cell.setBorderColor(right, new Color(241, 241, 241, 255));
                cell.setBorderColor(top, new Color(241, 241, 241, 255));
                cell.setBorderColor(bottom, new Color(241, 241, 241, 255));

            }
        }
    }

文章来源:https://blog.csdn.net/weixin_70213588/article/details/132740410
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。