poi 生成word+图表 支持 柱状、折线、饼图、簇状柱状图、表格、簇状+折线组合图
引入的pom文件
1 <dependency> 2 <groupId>org.apache.poi</groupId> 3 <artifactId>poi</artifactId> 4 <version>5.2.2</version> 5 </dependency> 6 7 <dependency> 8 <groupId>commons-io</groupId> 9 <artifactId>commons-io</artifactId> 10 <version>2.11.0</version> 11 </dependency> 12 13 <dependency> 14 <groupId>org.apache.poi</groupId> 15 <artifactId>poi-ooxml</artifactId> 16 <version>5.2.2</version> 17 </dependency> 18 19 <dependency> 20 <groupId>org.apache.poi</groupId> 21 <artifactId>poi-ooxml-full</artifactId> 22 <version>5.2.3</version> 23 </dependency>
工具类:
1 public class WordUtils { 2 3 4 /** 5 * 创建文件标题 6 * 7 * @param document 文档 8 * @param docTitle 完档标题 9 */ 10 public static void createDocTitle(XWPFDocument document, String docTitle, boolean isBreak) { 11 //新建一个标题段落对象(就是一段文字) 12 XWPFParagraph titleParagraph = document.createParagraph(); 13 //样式居中 14 titleParagraph.setAlignment(ParagraphAlignment.CENTER); 15 //创建文本对象 16 XWPFRun titleFun = titleParagraph.createRun(); 17 //设置标题的名字 18 titleFun.setText(docTitle); 19 //加粗 20 titleFun.setBold(true); 21 //设置颜色 22 titleFun.setColor("000000"); 23 //字体大小 24 titleFun.setFontSize(18); 25 if (isBreak) { 26 //换行 27 titleFun.addBreak(); 28 } 29 } 30 31 32 /*** 33 * 创建段落标题 34 * @param document 文档 35 * @param parTitle 段落标题 36 * @param isBreak 是否换行 37 */ 38 public static void createParagraphTitle(XWPFDocument document, String parTitle, boolean isBreak) { 39 XWPFParagraph titleParagraph = document.createParagraph(); 40 XWPFRun titleFun = titleParagraph.createRun(); 41 titleFun.setFontFamily("宋体(中文)"); 42 titleParagraph.setAlignment(ParagraphAlignment.LEFT); 43 titleFun.setText(parTitle); 44 titleFun.setColor("000000"); 45 titleFun.setFontSize(16); 46 titleFun.setBold(true); 47 //换行 48 if (isBreak) { 49 titleFun.addBreak(); 50 } 51 } 52 53 /** 54 * 创建word文档段落 55 * 56 * @param document 文档 57 * @param align ParagraphAlignment.LEFT 居左 58 * @param paragraph 内容 59 * @param isBreak 是否换行 60 */ 61 public static void createParagraph(XWPFDocument document, ParagraphAlignment align, String paragraph, boolean isBreak, int firstLintIndent) { 62 XWPFParagraph titleParagraph = document.createParagraph(); 63 titleParagraph.setAlignment(align); 64 XWPFRun titleFun = titleParagraph.createRun(); 65 titleFun.setFontSize(14); 66 titleFun.addTab(); 67 titleFun.setFontFamily("宋体(中文)"); 68 titleFun.setText(paragraph); 69 titleFun.setColor("000000"); 70 titleFun.setFontSize(16); 71 titleParagraph.setFirstLineIndent(firstLintIndent); 72 //换行 73 if (isBreak) { 74 titleFun.addBreak(); 75 } 76 } 77 78 79 /** 80 * 创建饼图 81 * 82 * @param document 文档 83 * @param from 数据 84 * 85 * @throws Exception 86 */ 87 public static void createPieChart(XWPFDocument document, PieChartFrom from) throws Exception { 88 XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER); 89 // 设置图例位置:上下左右 90 XDDFChartLegend legend = chart.getOrAddLegend(); 91 legend.setPosition(LegendPosition.BOTTOM); 92 legend.setOverlay(false); 93 chart.setTitleText(from.getTitle()); 94 chart.setTitleOverlay(false); 95 int numOfPoints = from.getXData().size(); 96 String[] categories = from.getXData().toArray(new String[]{}); 97 XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories); 98 String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); 99 AxisYVal yData = from.getYData(); 100 XDDFNumericalDataSource<?> source = XDDFDataSourcesFactory.fromArray(yData.getVal(), range); 101 XDDFPieChartData pieChart = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null); 102 pieChart.setVaryColors(true); 103 XDDFPieChartData.Series series = (XDDFPieChartData.Series) pieChart.addSeries(categoriesData, source); 104 series.setTitle(yData.getTitle(), setTitleInDataSheet(chart, yData.getTitle(), 0)); 105 chart.plot(pieChart); 106 } 107 108 /** 109 * 创建表格 110 * 111 * @param document 文档 112 * @param from 表格数据 113 */ 114 public static void createTable(XWPFDocument document, TableFrom from) { 115 log.info(">> 开始生成表格"); 116 XWPFTable table = document.createTable(); 117 List<TableFrom.CellData> headerList = from.getHeaderList(); 118 //创建表头 119 XWPFTableRow headerRow = getTableRow(table, 0); 120 for (int i = 0; i < headerList.size(); i++) { 121 TableFrom.CellData cellData = headerList.get(i); 122 XWPFTableCell cell = getTableRowCell(headerRow, i); 123 cell.setText(cellData.getVal()); 124 } 125 //表格数据 126 List<List<TableFrom.CellData>> rowDataList = from.getRowDataList(); 127 for (int i = 0; i < rowDataList.size(); i++) { 128 int rowIndex = i + 1; 129 List<TableFrom.CellData> cellData = rowDataList.get(i); 130 XWPFTableRow row = getTableRow(table, rowIndex); 131 for (int x = 0; x < cellData.size(); x++) { 132 TableFrom.CellData cellD = cellData.get(x); 133 XWPFTableCell cell = getTableRowCell(row, x); 134 cell.setText(cellD.getVal()); 135 } 136 } 137 log.info(">> 生成表格 完成"); 138 139 } 140 141 142 private static XWPFTableCell getTableRowCell(XWPFTableRow row, int index) { 143 XWPFTableCell cell = row.getCell(index); 144 if (cell != null) { 145 return cell; 146 } 147 return row.createCell(); 148 } 149 150 private static XWPFTableRow getTableRow(XWPFTable table, int index) { 151 XWPFTableRow row = table.getRow(index); 152 if (row != null) { 153 return row; 154 } 155 return table.createRow(); 156 } 157 158 /** 159 * 生成图表 柱状图+折线+ 柱状折线组合 160 * 161 * @param document 文档 162 * @param chartForm 数据 163 * 164 * @throws Exception 165 */ 166 public static void createBarLineCharts(XWPFDocument document, BarLineChartForm chartForm) throws Exception { 167 if (chartForm == null) { 168 throw new IllegalArgumentException("数据为空"); 169 } 170 List<String> xData = chartForm.getXData(); 171 if (xData == null) { 172 throw new IllegalArgumentException("X轴数据为空"); 173 } 174 List<AxisYVal> yBarData = chartForm.getYBarData(); 175 List<AxisYVal> yLintData = chartForm.getYLineData(); 176 if (yBarData == null && yLintData == null) { 177 throw new IllegalArgumentException("柱状数据、折线数据为空"); 178 } 179 XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER); 180 // 设置图例位置:上下左右 181 XDDFChartLegend legend = chart.getOrAddLegend(); 182 legend.setPosition(LegendPosition.TOP); 183 legend.setOverlay(false); 184 // 设置标题 185 chart.setTitleText(chartForm.getTitle()); 186 //标题覆盖 187 chart.setTitleOverlay(false); 188 int numOfPoints = xData.size(); 189 //初始化X轴数据 190 String[] categories = xData.toArray(new String[]{}); 191 String cat = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); 192 XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, cat, 0); 193 //初始化X轴 194 XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); 195 bottomAxis.setTitle(chartForm.getXTitle()); 196 //初始化Y周 197 XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); 198 leftAxis.setTitle(chartForm.getYTitle()); 199 leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); 200 leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); 201 int barSize = 0; 202 if (yBarData != null) { 203 log.info(">> 开始生成柱状图 "); 204 // 创建柱状图的类型 205 barSize = yBarData.size(); 206 XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis); 207 barChart.setBarDirection(BarDirection.COL); 208 for (int i = 0; i < yBarData.size(); i++) { 209 int collIndex = i + 1; 210 String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, collIndex, collIndex)); 211 AxisYVal yVal = yBarData.get(i); 212 Number[] number = yVal.getVal(); 213 XDDFNumericalDataSource<?> source = XDDFDataSourcesFactory.fromArray(number, range); 214 XDDFBarChartData.Series series = (XDDFBarChartData.Series) barChart.addSeries(categoriesData, source); 215 series.setTitle(yVal.getTitle(), setTitleInDataSheet(chart, yVal.getTitle(), collIndex)); 216 } 217 if (yBarData.size() > 1) { 218 barChart.setBarGrouping(BarGrouping.CLUSTERED); 219 chart.getCTChart().getPlotArea().getBarChartArray(0).addNewOverlap().setVal((byte) 0); 220 } 221 chart.plot(barChart); 222 log.info(">> 生成柱状图 完毕 "); 223 } 224 225 //********************* 折线图 ************************************************* 226 if (yLintData != null) { 227 log.info(">> 开始生成折线图 "); 228 XDDFLineChartData lineChart = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis); 229 lineChart.setVaryColors(false); 230 for (int i = 0; i < yLintData.size(); i++) { 231 int collIndex = i + 1 + barSize; 232 String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, collIndex, collIndex)); 233 AxisYVal yVal = yLintData.get(i); 234 Number[] number = yVal.getVal(); 235 XDDFNumericalDataSource<?> source = XDDFDataSourcesFactory.fromArray(number, range); 236 XDDFLineChartData.Series series = (XDDFLineChartData.Series) lineChart.addSeries(categoriesData, source); 237 series.setTitle(yVal.getTitle(), setTitleInDataSheet(chart, yVal.getTitle(), collIndex)); 238 series.setMarkerStyle(MarkerStyle.DOT); 239 series.setSmooth(Boolean.FALSE); 240 } 241 chart.plot(lineChart); 242 log.info(">> 生成折线图 完毕"); 243 } 244 } 245 246 /** 247 * 生成横向柱状图 248 * @param document word文档 249 * @param chartForm 图表数据 250 * @throws Exception 251 */ 252 public static void createBarCharts(XWPFDocument document, BarLineChartForm chartForm) throws Exception { 253 if (chartForm == null) { 254 throw new IllegalArgumentException("数据为空"); 255 } 256 List<String> xData = chartForm.getXData(); 257 if (xData == null) { 258 throw new IllegalArgumentException("X轴数据为空"); 259 } 260 List<AxisYVal> yBarData = chartForm.getYBarData(); 261 List<AxisYVal> yLintData = chartForm.getYLineData(); 262 if (yBarData == null && yLintData == null) { 263 throw new IllegalArgumentException("柱状数据、折线数据为空"); 264 } 265 XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER); 266 // 设置图例位置:上下左右 267 XDDFChartLegend legend = chart.getOrAddLegend(); 268 legend.setPosition(LegendPosition.TOP); 269 legend.setOverlay(false); 270 // 设置标题 271 chart.setTitleText(chartForm.getTitle()); 272 //标题覆盖 273 chart.setTitleOverlay(false); 274 int numOfPoints = xData.size(); 275 //初始化X轴数据 276 String[] categories = xData.toArray(new String[]{}); 277 String cat = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0)); 278 XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromArray(categories, cat, 0); 279 //初始化X轴 280 XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); 281 bottomAxis.setTitle(chartForm.getXTitle()); 282 //初始化Y周 283 XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); 284 leftAxis.setTitle(chartForm.getYTitle()); 285 leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); 286 leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); 287 log.info(">> 开始生成柱状图 "); 288 // 创建柱状图的类型 289 XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis); 290 barChart.setBarDirection(BarDirection.BAR); 291 for (int i = 0; i < yBarData.size(); i++) { 292 int collIndex = i + 1; 293 String range = chart.formatRange(new CellRangeAddress(1, numOfPoints, collIndex, collIndex)); 294 AxisYVal yVal = yBarData.get(i); 295 Number[] number = yVal.getVal(); 296 XDDFNumericalDataSource<?> source = XDDFDataSourcesFactory.fromArray(number, range); 297 XDDFBarChartData.Series series = (XDDFBarChartData.Series) barChart.addSeries(categoriesData, source); 298 series.setTitle(yVal.getTitle(), setTitleInDataSheet(chart, yVal.getTitle(), collIndex)); 299 break; 300 } 301 if (yBarData.size() > 1) { 302 barChart.setBarGrouping(BarGrouping.CLUSTERED); 303 chart.getCTChart().getPlotArea().getBarChartArray(0).addNewOverlap().setVal((byte) 0); 304 } 305 chart.plot(barChart); 306 log.info(">> 生成柱状图 完毕 "); 307 308 309 } 310 311 private static CellReference setTitleInDataSheet(XWPFChart chart, String title, int column) throws Exception { 312 XSSFWorkbook workbook = chart.getWorkbook(); 313 XSSFSheet sheet = workbook.getSheetAt(0); 314 XSSFRow row = sheet.getRow(0); 315 if (row == null) { 316 row = sheet.createRow(0); 317 } 318 XSSFCell cell = row.getCell(column); 319 if (cell == null) { 320 cell = row.createCell(column); 321 } 322 cell.setCellValue(title); 323 return new CellReference(sheet.getSheetName(), 0, column, true, true); 324 } 325 326 /** 327 * 浏览器下载 328 * @param document 文档 329 * @param fileName 文件名 330 * @throws IOException 331 */ 332 public static void save(XWPFDocument document, String fileName) throws IOException { 333 ServletOutputStream out = null; 334 try { 335 if (document == null || fileName == null) { 336 throw new IllegalArgumentException("参数不能为空"); 337 } 338 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); 339 if (requestAttributes != null) { 340 ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; 341 HttpServletResponse response = servletRequestAttributes.getResponse(); 342 response.setContentType("application/octet-stream"); 343 out = response.getOutputStream(); 344 String encodedFileName; 345 try { 346 encodedFileName = URLEncoder.encode(fileName, "UTF-8"); 347 } catch (UnsupportedEncodingException var20) { 348 throw new RuntimeException(var20); 349 } 350 response.setHeader("Content-Disposition", "attachment;fileName=" + encodedFileName); 351 document.write(out); 352 return; 353 } 354 log.warn("非web请求,无法操作。"); 355 } finally { 356 if (document != null) { 357 try { 358 document.close(); 359 } catch (Exception var19) { 360 } 361 } 362 if (out != null) { 363 try { 364 out.close(); 365 } catch (Exception var18) { 366 } 367 } 368 } 369 } 370 371 /** 372 * 另存为 373 * @param document 文档 374 * @param fileName 文件名 375 * @param path 文件存储目录 376 * @throws IOException 377 */ 378 public static void saveAs(XWPFDocument document, String fileName, String path) throws IOException { 379 FileOutputStream out = null; 380 try { 381 if (document == null || fileName == null || path == null) { 382 throw new IllegalArgumentException("参数不能为空"); 383 } 384 File file = new File(FileUtils.join(path, fileName)); 385 String saveAsPath = file.getCanonicalPath(); 386 out = new FileOutputStream(file); 387 log.elapseStart("开始另存为word文件[" + saveAsPath + "]", "1"); 388 document.write(out); 389 document.close(); 390 log.elapseEnd("成功另存为excel文件[" + saveAsPath + "]", "1"); 391 return; 392 } finally { 393 if (document != null) { 394 try { 395 document.close(); 396 } catch (Exception var19) { 397 } 398 } 399 if (out != null) { 400 try { 401 out.close(); 402 } catch (Exception var18) { 403 } 404 } 405 } 406 }
封装基础类:
1 /** 2 * Y周坐标值 3 * 4 * @author liuxn 5 * @date 2022/10/27 6 */ 7 @Setter 8 @Getter 9 public class AxisYVal { 10 11 /** 12 * Y轴数据、与X轴数据数量保持一致 13 */ 14 private Number[] val; 15 /** 16 * Y轴数据 图例 17 */ 18 private String title; 19 /** 20 * Y 周颜色 21 */ 22 private XDDFColor color; 23 // todo 其他属性配置 24 }
1 /** 2 * 柱状+折线 3 * 4 * @author liuxn 5 * @date 2022/10/27 6 */ 7 @Setter 8 @Getter 9 public class BarLineChartForm extends ChartFrom { 10 11 /** 12 * X轴数据 13 */ 14 private List<String> xData; 15 /** 16 * 柱状数据 支持多组 17 */ 18 private List<AxisYVal> yBarData; 19 /** 20 * 折线数据 支持多组 21 */ 22 private List<AxisYVal> yLineData; 23 24 }
1 /** 2 * 图表属性 3 * 4 * @author liuxn 5 * @date 2022/10/27 6 */ 7 @Setter 8 @Getter 9 public class ChartFrom { 10 /** 11 * 图表标题 12 */ 13 private String title; 14 /** 15 * X轴标题 16 */ 17 private String xTitle; 18 /** 19 * Y轴标题 20 */ 21 private String yTitle; 22 }
1 /** 2 * 饼状图 3 * 4 * @author liuxn 5 * @date 2022/10/27 6 */ 7 @Setter 8 @Getter 9 public class PieChartFrom extends ChartFrom { 10 /** 11 * X轴 图例 12 */ 13 private List<String> xData; 14 15 /** 16 * 饼状数据 17 */ 18 private AxisYVal yData; 19 20 }
1 /** 2 * 表格数据 3 * 4 * @author liuxn 5 * @date 2022/10/27 6 */ 7 @Setter 8 @Getter 9 public class TableFrom { 10 //表头数据 11 private List<CellData> headerList; 12 /** 13 * 表格数据 14 */ 15 private List<List<CellData>> rowDataList; 16 17 //todo 表格其他属性 18 19 @Setter 20 @Getter 21 public static class CellData { 22 //单元格值 23 private String val; 24 // todo 其他单元格属性 25 26 public CellData(String val) { 27 this.val = val; 28 } 29 } 30 }
单元测试类:
1 public class WordUtilsTest { 2 3 4 public static void main(String[] args) throws Exception { 5 6 XWPFDocument doc = new XWPFDocument(); 7 WordUtils.createDocTitle(doc, "微信公众号信息分析报告", false); 8 WordUtils.createParagraph(doc, ParagraphAlignment.RIGHT, "2022年9月1日", false, 0); 9 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "数据来源:微信公众号", false, 0); 10 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "报告周期:2022年8月1日-2022年8月8日", false, 0); 11 WordUtils.createParagraphTitle(doc, "一、信息收发情况概述", false); 12 WordUtils.createParagraphTitle(doc, "(一)信息发布情况", false); 13 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号共发布信息XXX篇,阅读量较高的文章为XXX、XXX、XXX、XXX、XXX、XXX六篇;从发布频次看,平均XXX篇/周期;从用户阅读量看,XXX关注度最高,共被阅读XXX次,XXX排第二,为XXX次,XXX排第三,为XXX次。", false, 2); 14 // 15 TreeSet<String> xDataSet = new TreeSet<>(); 16 xDataSet.add("2022-10-01"); 17 xDataSet.add("2022-10-02"); 18 xDataSet.add("2022-10-03"); 19 xDataSet.add("2022-10-04"); 20 xDataSet.add("2022-10-05"); 21 xDataSet.add("2022-10-06"); 22 23 List<AxisYVal> yData = new ArrayList<>(); 24 25 AxisYVal val1 = new AxisYVal(); 26 val1.setTitle("人数"); 27 List<Integer> y1 = new ArrayList<>(); 28 y1.add(1); 29 y1.add(6); 30 y1.add(4); 31 y1.add(7); 32 y1.add(8); 33 y1.add(2); 34 val1.setVal(y1.toArray(new Integer[]{})); 35 yData.add(val1); 36 AxisYVal val2 = new AxisYVal(); 37 val2.setTitle("次数"); 38 List<Integer> y2 = new ArrayList<>(); 39 y2.add(13); 40 y2.add(15); 41 y2.add(12); 42 y2.add(13); 43 y2.add(19); 44 y2.add(13); 45 val2.setVal(y2.toArray(new Integer[]{})); 46 yData.add(val2); 47 48 AxisYVal val3 = new AxisYVal(); 49 val3.setTitle("平均"); 50 List<Double> y3 = new ArrayList<>(); 51 y3.add(3d); 52 y3.add(19d); 53 y3.add(21d); 54 y3.add(32d); 55 y3.add(42d); 56 y3.add(31d); 57 val3.setVal(y3.toArray(new Double[]{})); 58 List<AxisYVal> yLintData = new ArrayList<>(); 59 yLintData.add(val3); 60 61 BarLineChartForm chartForm = new BarLineChartForm(); 62 chartForm.setTitle("簇状柱形图"); 63 chartForm.setXTitle("日期"); 64 chartForm.setYTitle("数量"); 65 chartForm.setXData(new ArrayList<>(xDataSet)); 66 chartForm.setYBarData(yData); 67 chartForm.setYLineData(yLintData); 68 WordUtils.createBarLineCharts(doc, chartForm); 69 70 71 WordUtils.createParagraphTitle(doc, "(二)信息阅读情况", false); 72 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号信息的阅读总次数为XXX,阅读总人数为XXX,单位时间平均阅读次数为XXX,平均阅读人数为XXX。", false, 2); 73 74 //todo 拼接数据 75 WordUtils.createBarLineCharts(doc, chartForm); 76 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "在阅读总次数中,微信收藏XXX次、点赞XXX次、分享XXX次;在阅读总人数中,微信XXX人、点赞XXX人、分享XXX人。", false, 2); 77 78 //todo 拼接数据 79 chartForm.setYBarData(null); 80 WordUtils.createBarLineCharts(doc, chartForm); 81 WordUtils.createBarLineCharts(doc, chartForm); 82 WordUtils.createBarLineCharts(doc, chartForm); 83 84 WordUtils.createParagraphTitle(doc, "(三)信息接收情况", false); 85 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号主页共接收用户信息XXX条,从接收信息内容看,关键词主要集中在XXX、XXX、XXX、XXX、XXX、XXX六个方面。XXX出现次数最多,共XXX次,占比达XXX;XXX次之,共XXX次,占比XXX。", false, 2); 86 87 88 BarLineChartForm chartForm1 = new BarLineChartForm(); 89 chartForm1.setTitle("簇状柱形图"); 90 chartForm1.setXTitle("日期"); 91 chartForm1.setYTitle("数量"); 92 chartForm1.setXData(new ArrayList<>(xDataSet)); 93 chartForm1.setYBarData(yData); 94 chartForm1.setYLineData(null); 95 WordUtils.createBarLineCharts(doc, chartForm1); 96 97 WordUtils.createParagraphTitle(doc, "二、菜单热度分析", false); 98 WordUtils.createParagraphTitle(doc, "(一)一级菜单整体分析", false); 99 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号的一级菜单点击总人数为XX,点击总次数为XX。其中,【运输专栏】、【公众服务】、【我的指南】点击人数分别为XX、XX、XX,点击次数分别为XX、XX、XX,单位时间平均点击次数分别为XX、XX、XX。菜单热度数据表如下。", false, 2); 100 101 102 TableFrom tableFrom = new TableFrom(); 103 List<TableFrom.CellData> headerData = new ArrayList<>(); 104 headerData.add(new TableFrom.CellData("一级菜单")); 105 headerData.add(new TableFrom.CellData("点击人数")); 106 headerData.add(new TableFrom.CellData("占比")); 107 headerData.add(new TableFrom.CellData("点击次数")); 108 headerData.add(new TableFrom.CellData("占比")); 109 tableFrom.setHeaderList(headerData); 110 111 List<List<TableFrom.CellData>> rowData = new ArrayList<>(); 112 List<TableFrom.CellData> callData = new ArrayList<>(); 113 callData.add(new TableFrom.CellData("道路运输")); 114 callData.add(new TableFrom.CellData("12")); 115 callData.add(new TableFrom.CellData("10%")); 116 callData.add(new TableFrom.CellData("20")); 117 callData.add(new TableFrom.CellData("5%")); 118 rowData.add(callData); 119 rowData.add(callData); 120 rowData.add(callData); 121 rowData.add(callData); 122 tableFrom.setRowDataList(rowData); 123 WordUtils.createTable(doc, tableFrom); 124 WordUtils.createParagraphTitle(doc, "(二)二级菜单热度排行", false); 125 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "微信公众号的二级菜单共12个,本统计周期内,点击量较高的菜单是【XXX】、【XXX】、【XXX】,点击量较低的菜单是【XXX】、【XXX】、【XXX】。菜单热度数据表如下。", false, 2); 126 // todo 拼接数据 127 WordUtils.createTable(doc, tableFrom); 128 WordUtils.createParagraphTitle(doc, "三、用户分析", false); 129 WordUtils.createParagraphTitle(doc, "(一)用户关注情况", false); 130 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "微信公众号累计关注XX人。本统计周期内,公众号新增关注XX人,取消关注XX人,净增关注XX人,用户关注趋势如下。", false, 2); 131 132 //todo 数据拼接 133 WordUtils.createBarLineCharts(doc, chartForm); 134 WordUtils.createParagraphTitle(doc, "(二)用户增长渠道", false); 135 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号共增加阅读用户XXX人,从增长渠道上看,XXX最多,共XXX人,占比达XXX;XXX排第二,共XXX人,占比XXX;XXX排第三,共XXX人,占比XXX。", false, 2); 136 //拼图 137 PieChartFrom pieChartFrom = new PieChartFrom(); 138 pieChartFrom.setXData(new ArrayList<>(xDataSet)); 139 pieChartFrom.setYData(val3); 140 WordUtils.createPieChart(doc, pieChartFrom); 141 142 WordUtils.createParagraphTitle(doc, "四、政民互动统计分析", false); 143 WordUtils.createParagraphTitle(doc, "(一)互动服务情况", false); 144 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号政民互动模块共服务用户XX人次,对话轮次XX,平均对话轮次XX。共解决用户问题XX个,平均解决率为XX,平均无答案率为XX。", false, 2); 145 146 //todo 拼接数据 147 WordUtils.createBarLineCharts(doc, chartForm1); 148 WordUtils.createBarLineCharts(doc, chartForm1); 149 WordUtils.createBarLineCharts(doc, chartForm1); 150 WordUtils.createBarLineCharts(doc, chartForm1); 151 WordUtils.createBarLineCharts(doc, chartForm1); 152 153 //todo 拼接数据 154 BarLineChartForm chartForm2 = new BarLineChartForm(); 155 chartForm2.setTitle("簇状柱形图"); 156 chartForm2.setXTitle("日期"); 157 chartForm2.setYTitle("数量"); 158 chartForm2.setXData(new ArrayList<>(xDataSet)); 159 chartForm2.setYBarData(null); 160 chartForm2.setYLineData(yLintData); 161 WordUtils.createBarLineCharts(doc, chartForm2); 162 WordUtils.createBarLineCharts(doc, chartForm2); 163 WordUtils.createParagraphTitle(doc, "(二)互动热点问题", false); 164 WordUtils.createParagraph(doc, ParagraphAlignment.LEFT, "本统计周期内,微信公众号政民互动模块共收获用户问题XX个,从问题内容看,主要集中在XX、XX、XX、XX、XX、XX六个方面。XX的用户关注度最高,共XX个,XX的用户关注度次之,共XX个。", false, 2); 165 WordUtils.createBarCharts(doc, chartForm1); 166 167 WordUtils.saveAs(doc, "word图表demo.docx", "/Users/liuxn/Desktop/"); 168 } 169 170 }