文章目录

  • Note
  • Github
  • Core
  • Code
  • 总结

Note

最新更新了github,有问题欢迎评论。感谢评论+讨论的同在奋斗的人

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

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

Github

地址:https://github.com/ithuhui/hui-core-autoreport
分支:master
位置:com.hui.core.report.ReportApp

Core

效果图:

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

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;}
    • 刷新图表
        // 创建一个excelWorkbook 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);}}// 更新嵌入的workbookPOIXMLDocumentPart 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.setstrData.setPtArray((CTStrVal[]) null); // unset old axis textnumData.setPtArray((CTNumVal[]) null); // unset old values// set modellong 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可跑单元测试

POI生成动态模板PPT报告相关推荐

  1. 基于java + easyExcel实现模板填充生成动态模板并设置指定单元格为下拉框样式

    需求描述:java后端开发过程中,为了满足动态生成excel模板并设置指定单元格为下拉框,且下拉框的数据项来源为动态查询的需求,在基于easyExcel的情况下,使用模板填充的方式,完成该需求. 1. ...

  2. easyexcel生成动态模板(模板支持下拉框),动态字段导出excel表格,常规字段导出excel表格

    备注:动态字段导出主要是用了反射的原理,跟excel需要导出的字段一一映射.话不多说,直接上代码: 1.生成的动态模板如图: 如上图,如果下拉框里不是选择的值,会给用户提示,下拉框用来限制用户导入只能 ...

  3. 【Java编程系列】java用POI、Itext生成并下载PPT、PDF文件

    热门系列: [Java编程系列]WebService的使用 [Java编程系列]在Spring MVC中使用工具类调用Service层时,Service类为null如何解决 [Java编程系列]Spr ...

  4. 「实战教程」如何使用POI读取模板PPT填充数据并拼接至目标文件

    文章目录 一.PPT文件格式介绍 1.PPT文件格式的概述 2.HSLF和XSLF的区别 3.如何选择合适的POI类库 二.SlideShow 三.读取PPT文件 1. 加载PPT文件 2. 获取PP ...

  5. poi生成excel下拉菜单

    在web开发中常用到生成excel模板,在用excel poi生成excel模板时,常用到生成excel下拉菜单.下面是生成excel下拉菜单的代码: package poiexcel;import ...

  6. python自动生成ppt报告_把时间还给洞察,且看PPT调研报告自动生成攻略

    文/JSong @2017.02.28 在数据分析里面有一句话是说,80%的时间要用于数据清洗和整理,而我觉得理想的状态应该是把更多的把时间花在数据背后的洞察当中.去年11月在简书占了个坑,说要自己写 ...

  7. python生成ppt报告_python 生成 pptx 分析报告的工具包:reportgen

    reportgen v0.1.8 更新 这段时间,我对 reportgen 进行了大工程量的修改和更新.将之前在各个文章中出现的函数进行了封装,同时也对现有工具包的一些逻辑进行了调整. 1.repor ...

  8. 性能碾压 POI !利用模板语法快速生成 Excel 报表

    本期讲师:刘鹏 GcExcel项目组,核心开发者 Hello,大家好,本期葡萄城技术公开课,将由我来为大家带来<性能碾压 POI !利用模板语法快速生成 Excel 报表>的技术分享. 本 ...

  9. Java利用poi生成word(包含插入图片,动态表格,行合并)

    Java利用poi生成word(包含插入图片,动态表格,行合并) 测试模板样式: 图表 1 Word生成结果: 图表 2 需要的jar包:(具体jar可自行去maven下载) Test测试类: imp ...

  10. JAVA动态生成excel模板;列自定义下拉框赋值

    哈喽,2023大家开工大吉啊!财源滚滚! 业务需求:需要生成excel模板,且对部分列设置下拉框,进行动态赋值,效果如下: 拿上图举例:针对省这一列,不是填写,而是选择数据,也就是说我们生成excel ...

最新文章

  1. 基于SSL的mysql(MariaDB)主从复制
  2. Qt QComboBox下拉框文字重叠解决方法
  3. python分析nginx日志
  4. granule size oracle,_ksmg_granule_size oracle内存分配粒度
  5. mysql怎么禁止远程连接_mysql如何设置禁止远程连接
  6. [article]回忆录的开始
  7. 苹果mac专业音频处理软件:Audition
  8. cmd链接php mysql数据库_php连接mysql数据库_cmd连接mysql数据库 - MySQL最新手册教程 - php中文网手册...
  9. 2017年12月HCNP考试易错题汇总
  10. mysql的不等于符号
  11. 杭电计算机学硕还是专硕就业好,19计算机考研选学硕还是专硕?
  12. python-opencv:在视频中显示fps等opencv快速入门
  13. 【宣讲会感言】腾讯实习生
  14. HCI 基础知识之一
  15. 360杀毒软件无视宏病毒!
  16. 幂等矩阵(Idempotent matrix)
  17. HTML代码单元格内标题置顶,css表格标题怎么设置位置?
  18. syntax error, expect ')' 数据库报错批量插入
  19. 【保研复习】C语言保研机试笔记
  20. Fedora Project, extras 目录(进入小心)

热门文章

  1. Linux学习笔记Day01-03 Xshell,Xfpt下载安装,使用
  2. 技师学院计算机老师,技师学院计算机工程系组织开展观摩课活动
  3. transformer t5 relative position代码解读
  4. 質量機能展開(QFD)的使用及注意事項簡析
  5. Koo叔说Shader—开篇
  6. Unity 3D——打包复用资源(.unitypackage文件)
  7. Lonlife-ACM 1005 - Spoon Devil's RP Test(同余定理)——“玲珑杯”acm比赛-试运行赛
  8. mysql5.6 0000-00-00 00:00:00_Mysql sql_mode设置 timestamp default 0000-00-00 00:00:00 创建表失败处理...
  9. 怎么设置日程提醒时间
  10. 荣耀手机如何批量删除日历日程?日历日程提醒便签