poi生成动态模板ppt

版权声明:本文为博主原创文章,未经博主允许不得转载。转载请附上博主博文网址,并标注作者。违者必究 https://blog.csdn.net/HuHui_/article/details/83350049

前言

需求:(项目又一反人类需求)不同的样式模板,替换数据生成新的PPT

花了我4天时间,转载请注明作者感谢~

核心

效果图:

在这里插入图片描述

在这里插入图片描述

  • 读取模板,样式不变只替换其中数据
  • POI操作
  • 数据封装

Core - Code

  1. 接口设计

    流程: 读取模板 -》 构建每一页的PPT(图表,表格,文本框) -》把传入的数据参数进行替换 -》保存生成新的PPT

在这里插入图片描述

  1. 接口实现

    /**
     * <b><code>PowerPointGenerator</code></b>
     * <p/>
     * Description:
     * <p/>
     * <b>Creation Time:</b> 2018/10/23 21:15.
     *
     * @author Hu Weihui
     */
    public class PowerPointGenerator {
    
        private PowerPointGenerator() {
        }
    
        /**
         * PPT构造方法
         *
         * @param templateFilePath
         * @param destFilePath
         * @param slideDataMap
         * @throws IOException
         */
        public static void generatorPowerPoint(String templateFilePath, String destFilePath, Map<Integer, SlideData> slideDataMap) throws IOException, NoSuchChartTypeException {
            XMLSlideShow ppt = readPowerPoint(templateFilePath);
            List<XSLFSlide> slideList = ppt.getSlides();
            for (XSLFSlide slide : slideList) {
                int slidePage = slide.getSlideNumber();
                SlideData slideData = slideDataMap.get(slidePage);
                generatorSlide(slide, slideData);
            }
            savePowerPoint(ppt, destFilePath);
        }
    
        /**
         * 保存ppt到指定路径
         *
         * @param ppt
         * @param outputFilePath
         * @throws IOException
         */
        private static void savePowerPoint(XMLSlideShow ppt, String outputFilePath) throws IOException {
            try (
                    FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath);
    
            ) {
                ppt.write(fileOutputStream);
                ppt.close();
            }
        }
    
    
        /**
         * 读取模板库PPT
         *
         * @param inputFilePath
         * @return
         * @throws IOException
         */
        private static XMLSlideShow readPowerPoint(String inputFilePath) throws IOException {
            FileInputStream fileInputStream = new FileInputStream(inputFilePath);
            XMLSlideShow ppt = new XMLSlideShow(fileInputStream);
            return ppt;
        }
    
    
        /**
         * 替换每一页数据
         *
         * @param slide
         * @param slideData
         * @throws IOException
         */
        private static void generatorSlide(XSLFSlide slide, SlideData slideData) throws IOException, NoSuchChartTypeException {
            List<POIXMLDocumentPart> partList = slide.getRelations();
            int chartNum = 0;
            for (POIXMLDocumentPart part : partList) {
                if (part instanceof XSLFChart) {
                    List<SeriesData> seriesDataList = slideData.getChartDataList().get(chartNum).getSeriesDataList();
                    generatorChart((XSLFChart) part, seriesDataList);
                    chartNum++;
                }
            }
    
    
            List<XSLFShape> shapeList = slide.getShapes();
    
            for (XSLFShape shape : shapeList) {
                Map<String, String> textMap = slideData.getTextMap();
                List<TableData> tableDataList = slideData.getTableDataList();
                int tableNum = 0;
                //判断文本框
                if (shape instanceof XSLFTextShape) {
                    generatorTextBox((XSLFTextShape) shape, textMap);
                }
                //判断表格
                if (shape instanceof XSLFTable) {
                    List<TableRowData> tableRowDataList = tableDataList.get(tableNum).getTableRowDataList();
                    generatorTable((XSLFTable) shape, tableRowDataList);
    
                }
            }
    
        }
    
    
        /**
         * 构造图表
         *
         * @param chart
         * @param seriesDataList
         * @throws IOException
         */
        private static void generatorChart(XSLFChart chart, List<SeriesData> seriesDataList) throws IOException, NoSuchChartTypeException {
            if (seriesDataList.size() < 1) {
                return;
            }
            GraphUtils.refreshGraph(chart, seriesDataList);
        }
    
        /**
         * 构造文本
         *
         * @param textShape
         * @param textMap
         */
        private static void generatorTextBox(XSLFTextShape textShape, Map<String, String> textMap) {
            List<XSLFTextParagraph> textParagraphList = textShape.getTextParagraphs();
            for (XSLFTextParagraph textParagraph : textParagraphList) {
                String text = textParagraph.getText();
                String regex = "\\$\\{.*?\\}";
                Pattern pattern = Pattern.compile(regex);
                Matcher matcher = pattern.matcher(text);
                List<String> keys = new ArrayList<>();
                while (matcher.find()) {
                    keys.add(matcher.group());
                }
                for (String key : keys) {
                    String textKey = key.substring(2, key.length() - 1);
                    text = text.replace(key, textMap.get(textKey) == null ? " " : textMap.get(textKey));
                }
    
                List<XSLFTextRun> textRuns = textParagraph.getTextRuns();
                for (XSLFTextRun textRun : textRuns) {
                    String textStr = textRun.getRawText() == null ? "" : textRun.getRawText();
                    textRun.setText("");
                }
                if (textRuns.size() > 0) {
                    textRuns.get(0).setText(text);
                }
            }
        }
    
        /**
         * 构造表格
         *
         * @param table
         * @param tableDataList
         */
        private static void generatorTable(XSLFTable table, List<TableRowData> tableDataList) {
            List<XSLFTableRow> rows = table.getRows();
            int rowSize = rows.size() - 1;
            for (int i = 0; i < tableDataList.size(); i++) {
                if (i < rowSize) {
                    List<XSLFTableCell> cells = rows.get(i + 1).getCells();
                    for (int j = 0; j < tableDataList.get(i).getDataList().size(); j++) {
                        String s = tableDataList.get(i).getDataList().get(j);
                        cells.get(j).setText(s);
                    }
                } else {
                    table.addRow();
                    XSLFTableRow row = rows.get(i + 1);
                    for (int j = 0; j < tableDataList.get(i).getDataList().size(); j++) {
                        String s = tableDataList.get(i).getDataList().get(j);
                        row.addCell().setText(s);
                    }
                }
            }
            table.getCell(0, 0).setText("");
        }
    
  2. 图表的构造工具

    图表构造工具没时间重构,只有个demo,这里只挑core代码进行记录。

    • 判断图表类型

    参考别人,判断图表的类型真的是反人类,但是暂时还没找到其他的方法。

            String chartType = "";
            CTPlotArea plotArea = part.getCTChart().getPlotArea();
            if (plotArea.getLineChartList().size() != 0) {
                chartType = "lie";
            }
            if (plotArea.getBarChartList().size() != 0) {
                chartType = "bar";
            }
            if (plotArea.getLineChartList().size() != 0
                    && plotArea.getBarChartList().size() != 0) {
                chartType = "barAndlie";
            }
            if (plotArea.getPieChartList().size() != 0) {
                chartType = "pie";
            }
    
            if (chartType == null) {
                throw new NoSuchChartTypeException("no Such Chart Type be found");
            } else {
                return chartType;
            }
    
    
    • 刷新图表
        // 创建一个excel
                Workbook wb = new XSSFWorkbook();
                Sheet sheet = wb.createSheet();
    
                // 先生成excel表格,在刷新函数中往excel表格中添加数据
                for (int i = 0; i <= seriesDataList.get(0).getCategoryDataList()
                        .size(); i++) {
                    sheet.createRow(i);
                    for (int j = 0; j <= seriesDataList.size(); j++) {
                        sheet.getRow(i).createCell(j);
                    }
                }
                CTChart ctChart = chart.getCTChart();
                // 获取图表区域
                CTPlotArea plotArea = ctChart.getPlotArea();
    
                // 获取柱状图表
                CTBarChart barChart = plotArea.getBarChartArray(0);
                
                // 获取图表的系列
                for (int i = 0; i < barChart.getSerList().size(); i++) {
                        CTSerTx barTx = barChart.getSerArray(i).getTx();
                        barTx.getStrRef().getStrCache().getPtArray(0)
                                .setV(seriesDataList.get(i).getSeriesName());
                        sheet.getRow(0).getCell(i + 1)
                                .setCellValue(seriesDataList.get(0).getSeriesName());
                        String barTitleRef = new CellReference(sheet.getSheetName(), 0,
                                i + 1, true, true).formatAsString();
                        barTx.getStrRef().setF(barTitleRef);
                        CTAxDataSource barCat = barChart.getSerArray(i).getCat();
                        CTNumDataSource barVal = barChart.getSerArray(i).getVal();
                        refreshGraphContent(sheet, barCat, barVal, seriesDataList.get(i),
                                i + 1);
                    }
    
                }
    
                // 更新嵌入的workbook
                POIXMLDocumentPart xlsPart = chart.getRelations().get(0);
                OutputStream xlsOut = xlsPart.getPackagePart().getOutputStream();
                 wb.write(xlsOut);刷新图表数据
    
    • 刷新图表Excel内容
    /**
         * 刷新图表内容.
         *
         * @param sheet 
         * @param cat 
         * @param val 
         * @param seriesData 
         * @param cellNum 
         * @author Hu Weihui
         */
        private static void refreshGraphContent(final Sheet sheet,
                                                final CTAxDataSource cat, final CTNumDataSource val,
                                                final SeriesData seriesData, final int cellNum) {
            // 获取类别
            CTStrData strData = cat.getStrRef().getStrCache();
            // 获取系列对应的值
            CTNumData numData = val.getNumRef().getNumCache();
            // strData.set
            strData.setPtArray((CTStrVal[]) null); // unset old axis text
            numData.setPtArray((CTNumVal[]) null); // unset old values
    
            // set model
            long idx = 0;
            int rownum = 1;
            for (CategoryData categoryData : seriesData.getCategoryDataList()) {
                CTNumVal numVal = numData.addNewPt();
                numVal.setIdx(idx);
                numVal.setV(categoryData.getVal() + "");
    
                CTStrVal sVal = strData.addNewPt();
                sVal.setIdx(idx);
                sVal.setV(categoryData.getCategoryName());
    
                idx++;
                rownum++;
            }
    
            // 设置excel的值
            sheet.getRow(0).getCell(cellNum).setCellValue(seriesData.getSeriesName());
            for (int i = 1; i < sheet.getLastRowNum() + 1; i++) {
                sheet.getRow(i).getCell(cellNum).setCellValue(
                        seriesData.getCategoryDataList().get(i - 1).getVal());
            }
            // 设置excel的标题
            for (int i = 0; i < seriesData.getCategoryDataList().size(); i++) {
                String serName = seriesData.getCategoryDataList().get(i).getCategoryName();
                sheet.getRow(i + 1).getCell(0).setCellValue(serName);
            }
    
            numData.getPtCount().setVal(idx);
            strData.getPtCount().setVal(idx);
    
            String numDataRange = new CellRangeAddress(1, rownum - 1, cellNum,
                    cellNum).formatAsString(sheet.getSheetName(), true);
            val.getNumRef().setF(numDataRange);
            String axisDataRange = new CellRangeAddress(1, rownum - 1, 0, 0)
                    .formatAsString(sheet.getSheetName(), true);
            cat.getStrRef().setF(axisDataRange);
    
        }
    
    1. 封装能提供一页PPT的数据实体
    /**
     * <b><code>SlideData</code></b>
     * <p/>
     * Description:一页PPT的内容
     * <p/>
     * <b>Creation Time:</b> 2018/10/23 19:34.
     *
     * @author huweihui
     */
    public class SlideData implements Serializable {
    
        private static final long serialVersionUID = -69655131782023929L;
    
        private Integer slidePage;//页码
    
        private List<TableData> tableDataList;//表格数据(有可能有多个表格)
    
        private List<ChartData> chartDataList;//图表数据(有可能有多个图表)
    
        private Map<String,String> textMap;//文本框里面文本数据
    }
    
    /**
     * <b><code>SeriesData</code></b>
     * <p/>
     * Description:图表的系列(不能想象的话可以PPT新建一个柱状图就看到了)
     * <p/>
     * <b>Creation Time:</b> 2018/10/19 11:37.
     *
     * @author huweihui
     */
    public class SeriesData {
        // 系列名称
        private String seriesName;
    
        // 所有类别的值
        private List<CategoryData> categoryDataList = new ArrayList<>();
    }
    
    /**
     * <b><code>SeriesData</code></b>
     * <p/>
     * Description:图表的类别
     * <p/>
     * <b>Creation Time:</b> 2018/10/19 11:37.
     *
     * @author huweihui
     */
    public class CategoryData {
        // 类别名称
        private String categoryName;
    
        // 类别值
        private double Val;
    }
    
    /**
     * <b><code>ChartData</code></b>
     * <p/>
     * Description:图表数据
     * <p/>
     * <b>Creation Time:</b> 2018/10/24 11:46.
     *
     * @author huweihui
     */
    public class ChartData {
        private List<SeriesData> seriesDataList;
    }
    
    /**
     * <b><code>TableData</code></b>
     * <p/>
     * Description:表格一行的数据
     * <p/>
     * <b>Creation Time:</b> 2018/10/23 11:34.
     *
     * @author huweihui
     */
    public class TableRowData {
        private List<String> dataList = new ArrayList<>();
    
    }
    
    /**
     * <b><code>TableData</code></b>
     * <p/>
     * Description:表格数据
     * <p/>
     * <b>Creation Time:</b> 2018/10/24 14:19.
     *
     * @author huweihui
     */
    public class TableData {
        private List<TableRowData> tableRowDataList;
    }
    
    
    

总结

1.代码并不全,但核心思想和核心代码都出来了,以后整理放到github再更新链接。

2.这里是PPT的模板构造工具,业务上传过来的数据解析成SlideData这个类。就可以根据模板生成PPT

3.数据获取的配置也是个考验。我们是把数据和查找的SQL放到PPT模板读取并执行SQL后替换数据到PPT

4.读取Config 更为复杂,但项目的业务不一样。往后更新一个DEMO可跑单元测试

猜你喜欢

转载自blog.csdn.net/HuHui_/article/details/83350049
今日推荐