word导出图表
package com.bjs.glasses.controller.test;import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth;import java.io.FileOutputStream;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;public class DynamicWordExporter {public static void exportCombinedReport(String outputPath) {try (XWPFDocument document = new XWPFDocument()) {// 添加文档标题addDocumentTitle(document);// 添加概述addOverview(document);// 添加折线图 - 近视趋势分析addLineChart(document);// 添加柱状图 - 各年级近视分布addBarChart(document);// 添加饼图 - 近视程度分布addPieChart(document);// 添加数据表格addDataTable(document);// 添加总结addConclusion(document);// 保存文档try (FileOutputStream fos = new FileOutputStream(outputPath)) {document.write(fos);System.out.println("综合视力分析报告导出成功: " + outputPath);}} catch (Exception e) {System.err.println("导出失败: " + e.getMessage());e.printStackTrace();}}private static void addDocumentTitle(XWPFDocument document) {// 主标题XWPFParagraph titlePara = document.createParagraph();titlePara.setAlignment(ParagraphAlignment.CENTER);XWPFRun titleRun = titlePara.createRun();titleRun.setText("学生视力筛查综合分析报告");titleRun.setBold(true);titleRun.setFontSize(18);titleRun.setFontFamily("宋体");// 副标题XWPFParagraph subTitlePara = document.createParagraph();subTitlePara.setAlignment(ParagraphAlignment.CENTER);XWPFRun subTitleRun = subTitlePara.createRun();subTitleRun.setText("2024年度视力健康数据分析");subTitleRun.setFontSize(14);subTitleRun.setItalic(true);// 报告日期XWPFParagraph datePara = document.createParagraph();datePara.setAlignment(ParagraphAlignment.RIGHT);XWPFRun dateRun = datePara.createRun();dateRun.setText("报告生成时间: " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()));dateRun.setFontSize(10);dateRun.setColor("666666");document.createParagraph(); // 空行}private static void addOverview(XWPFDocument document) {XWPFParagraph overviewPara = document.createParagraph();XWPFRun overviewRun = overviewPara.createRun();overviewRun.setText("报告概述:");overviewRun.setBold(true);overviewRun.setFontSize(12);XWPFParagraph contentPara = document.createParagraph();XWPFRun contentRun = contentPara.createRun();contentRun.setText("本报告基于2022-2024年度全校视力筛查数据,全面分析学生视力状况变化趋势。"+ "通过折线图展示近视率年度变化,柱状图展示各年级分布情况,饼图展示近视程度构成。"+ "数据显示近视率呈逐年上升趋势,需加强视力保护措施。");contentRun.setFontSize(11);document.createParagraph();}private static void addLineChart(XWPFDocument document) {try {// 图表标题addChartTitle(document, "1. 近三年近视趋势分析");// 创建图表段落XWPFParagraph chartPara = document.createParagraph();chartPara.setAlignment(ParagraphAlignment.CENTER);// 创建chart图表对象XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER);// 图表相关设置chart.setTitleText("近三年各年级近视率趋势"); // 图表标题chart.setTitleOverlay(false); // 图例是否覆盖标题// 图例设置XDDFChartLegend legend = chart.getOrAddLegend();legend.setPosition(LegendPosition.TOP); // 图例位置// X轴(分类轴)相关设置XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); // 创建X轴,并且指定位置xAxis.setTitle("年份"); // x轴标题String[] xAxisData = new String[] {"2022", "2023", "2024"};XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(xAxisData); // 设置X轴数据// Y轴(值轴)相关设置XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT); // 创建Y轴,指定位置yAxis.setTitle("近视率(%)"); // Y轴标题yAxis.setMinimum(0.0);yAxis.setMaximum(50.0);// 创建折线图对象XDDFLineChartData lineChart = (XDDFLineChartData) chart.createData(ChartTypes.LINE, xAxis, yAxis);// 各年级近视率数据Double[] grade1Data = new Double[]{25.0, 27.5, 29.0}; // 一年级Double[] grade2Data = new Double[]{28.0, 30.5, 32.0}; // 二年级Double[] grade3Data = new Double[]{32.5, 35.0, 37.5}; // 三年级Double[] grade4Data = new Double[]{36.0, 38.5, 41.0}; // 四年级Double[] grade5Data = new Double[]{40.5, 43.0, 45.5}; // 五年级Double[] grade6Data = new Double[]{45.0, 47.5, 50.0}; // 六年级// 加载折线图数据集 - 多个系列addLineSeries(lineChart, xAxisSource, XDDFDataSourcesFactory.fromArray(grade1Data), "一年级", MarkerStyle.CIRCLE);addLineSeries(lineChart, xAxisSource, XDDFDataSourcesFactory.fromArray(grade2Data), "二年级", MarkerStyle.SQUARE);addLineSeries(lineChart, xAxisSource, XDDFDataSourcesFactory.fromArray(grade3Data), "三年级", MarkerStyle.DIAMOND);addLineSeries(lineChart, xAxisSource, XDDFDataSourcesFactory.fromArray(grade4Data), "四年级", MarkerStyle.TRIANGLE);addLineSeries(lineChart, xAxisSource, XDDFDataSourcesFactory.fromArray(grade5Data), "五年级", MarkerStyle.STAR);addLineSeries(lineChart, xAxisSource, XDDFDataSourcesFactory.fromArray(grade6Data), "六年级", MarkerStyle.DOT);// 绘制折线图chart.plot(lineChart);document.createParagraph(); // 空行} catch (Exception e) {System.err.println("创建折线图时出错: " + e.getMessage());addChartPlaceholder(document, "折线图 - 近视趋势分析");}}private static void addBarChart(XWPFDocument document) {try {// 图表标题addChartTitle(document, "2. 各年级近视人数分布");// 创建图表段落XWPFParagraph chartPara = document.createParagraph();chartPara.setAlignment(ParagraphAlignment.CENTER);// 创建chart图表对象XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER);// 图表相关设置chart.setTitleText("2024年各年级近视程度分布"); // 图表标题chart.setTitleOverlay(false); // 图例是否覆盖标题// 图例设置XDDFChartLegend legend = chart.getOrAddLegend();legend.setPosition(LegendPosition.TOP); // 图例位置// X轴(分类轴)相关设置XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); // 创建X轴,并且指定位置xAxis.setTitle("年级"); // x轴标题String[] xAxisData = new String[] {"一年级", "二年级", "三年级", "四年级", "五年级", "六年级"};XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(xAxisData); // 设置X轴数据// Y轴(值轴)相关设置XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT); // 创建Y轴,指定位置yAxis.setTitle("人数"); // Y轴标题yAxis.setCrossBetween(AxisCrossBetween.BETWEEN); // 设置图柱的位置:BETWEEN居中// 创建柱状图对象XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, xAxis, yAxis);barChart.setBarDirection(BarDirection.COL); // 设置柱状图的方向:COL竖向// 各年级不同近视程度数据Double[] mildData = new Double[]{25.0, 32.0, 45.0, 58.0, 67.0, 75.0}; // 轻度近视Double[] moderateData = new Double[]{12.0, 18.0, 28.0, 35.0, 42.0, 48.0}; // 中度近视Double[] highData = new Double[]{5.0, 8.0, 12.0, 18.0, 25.0, 32.0}; // 高度近视// 加载柱状图数据集 - 多个系列addBarSeries(barChart, xAxisSource, XDDFDataSourcesFactory.fromArray(mildData), "轻度近视");addBarSeries(barChart, xAxisSource, XDDFDataSourcesFactory.fromArray(moderateData), "中度近视");addBarSeries(barChart, xAxisSource, XDDFDataSourcesFactory.fromArray(highData), "高度近视");// 绘制柱状图chart.plot(barChart);document.createParagraph(); // 空行} catch (Exception e) {System.err.println("创建柱状图时出错: " + e.getMessage());addChartPlaceholder(document, "柱状图 - 各年级近视分布");}}private static void addPieChart(XWPFDocument document) {try {// 图表标题addChartTitle(document, "3. 近视程度分布");// 创建图表段落XWPFParagraph chartPara = document.createParagraph();chartPara.setAlignment(ParagraphAlignment.CENTER);// 创建chart图表对象XWPFChart chart = document.createChart(15 * Units.EMU_PER_CENTIMETER, 10 * Units.EMU_PER_CENTIMETER);// 图表相关设置chart.setTitleText("2024年近视程度构成"); // 图表标题chart.setTitleOverlay(false); // 图例是否覆盖标题// 图例设置XDDFChartLegend legend = chart.getOrAddLegend();legend.setPosition(LegendPosition.RIGHT); // 图例位置// 分类数据:饼图中的图例显示String[] categoryData = new String[] {"正常视力", "轻度近视", "中度近视", "高度近视"};XDDFCategoryDataSource categorySource = XDDFDataSourcesFactory.fromArray(categoryData);// 值数据:饼图中的圆形显示Double[] valueData = new Double[]{642.0, 147.6, 182.4, 99.6};XDDFNumericalDataSource<Double> valueSource = XDDFDataSourcesFactory.fromArray(valueData);// 创建饼图对象,饼状图不需要X,Y轴,只需要数据集即可XDDFPieChartData pieChart = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null);// 加载饼图数据集XDDFPieChartData.Series pieSeries = (XDDFPieChartData.Series) pieChart.addSeries(categorySource, valueSource);pieSeries.setTitle("视力分布", null); // 系列提示标题// 绘制饼图chart.plot(pieChart);document.createParagraph(); // 空行} catch (Exception e) {System.err.println("创建饼图时出错: " + e.getMessage());addChartPlaceholder(document, "饼图 - 近视程度分布");}}private static void addDataTable(XWPFDocument document) {// 表格标题addChartTitle(document, "4. 详细数据统计");// 创建表格XWPFTable table = createTableSafely(document, 7, 7);// 设置表头String[] headers = {"年级", "筛查人数", "正常视力", "轻度近视", "中度近视", "高度近视", "近视率%"};setTableRowSafely(table, 0, headers, true, 10);// 填充数据String[][] tableData = {{"一年级", "200", "158", "25", "12", "5", "21.0%"},{"二年级", "200", "142", "32", "18", "8", "29.0%"},{"三年级", "200", "115", "45", "28", "12", "42.5%"},{"四年级", "200", "89", "58", "35", "18", "55.5%"},{"五年级", "200", "66", "67", "42", "25", "67.0%"},{"六年级", "200", "72", "75", "48", "32", "77.5%"}};for (int i = 0; i < tableData.length; i++) {setTableRowSafely(table, i + 1, tableData[i], false, 9);}document.createParagraph(); // 空行}private static void addConclusion(XWPFDocument document) {XWPFParagraph conclusionTitle = document.createParagraph();XWPFRun titleRun = conclusionTitle.createRun();titleRun.setText("分析与建议:");titleRun.setBold(true);titleRun.setFontSize(12);XWPFParagraph contentPara = document.createParagraph();XWPFRun contentRun = contentPara.createRun();contentRun.setText("• 近视率呈逐年上升趋势,高年级学生近视问题尤为突出\n"+ "• 六年级近视率高达77.5%,需要重点关注和干预\n"+ "• 高度近视比例随年级升高而增加,需加强早期干预\n"+ "• 建议加强眼保健操质量监督,确保每天户外活动时间\n"+ "• 定期开展视力保护健康教育,提高学生和家长重视程度\n"+ "• 对已近视学生建立视力档案,定期跟踪视力变化情况");contentRun.setFontSize(11);}// 辅助方法:添加折线图系列private static void addLineSeries(XDDFLineChartData chart, XDDFCategoryDataSource categoryData,XDDFNumericalDataSource<Double> valueData, String title, MarkerStyle markerStyle) {XDDFLineChartData.Series series = (XDDFLineChartData.Series) chart.addSeries(categoryData, valueData);series.setTitle(title, null);series.setSmooth(false); // 折线series.setMarkerSize((short) 6); // 标记点大小series.setMarkerStyle(markerStyle); // 标记点样式}// 辅助方法:添加柱状图系列private static void addBarSeries(XDDFBarChartData chart, XDDFCategoryDataSource categoryData,XDDFNumericalDataSource<Double> valueData, String title) {XDDFBarChartData.Series series = (XDDFBarChartData.Series) chart.addSeries(categoryData, valueData);series.setTitle(title, null);}// 辅助方法:添加图表标题private static void addChartTitle(XWPFDocument document, String title) {XWPFParagraph titlePara = document.createParagraph();XWPFRun titleRun = titlePara.createRun();titleRun.setText(title);titleRun.setBold(true);titleRun.setFontSize(12);document.createParagraph();}// 辅助方法:图表占位符private static void addChartPlaceholder(XWPFDocument document, String chartTitle) {XWPFParagraph placeholder = document.createParagraph();placeholder.setAlignment(ParagraphAlignment.CENTER);XWPFRun run = placeholder.createRun();run.setText("[" + chartTitle + " - 图表生成失败]");run.setColor("FF0000");run.setItalic(true);document.createParagraph();}// 安全创建表格private static XWPFTable createTableSafely(XWPFDocument document, int rows, int cols) {XWPFTable table = document.createTable();// 创建表头行XWPFTableRow headerRow = table.getRow(0);if (headerRow == null) {headerRow = table.createRow();}// 确保表头行有足够的单元格while (headerRow.getTableCells().size() < cols) {headerRow.addNewTableCell();}// 创建数据行for (int i = 1; i < rows; i++) {XWPFTableRow dataRow = table.createRow();while (dataRow.getTableCells().size() < cols) {dataRow.addNewTableCell();}}// 设置表格宽度CTTbl ctTbl = table.getCTTbl();CTTblPr tblPr = ctTbl.getTblPr() == null ? ctTbl.addNewTblPr() : ctTbl.getTblPr();CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();tblWidth.setType(STTblWidth.DXA);tblWidth.setW(BigInteger.valueOf(9000));return table;}// 安全设置表格行private static void setTableRowSafely(XWPFTable table, int rowIndex, String[] data,boolean isHeader, int fontSize) {if (table == null || data == null) return;XWPFTableRow row;if (rowIndex < table.getNumberOfRows()) {row = table.getRow(rowIndex);} else {row = table.createRow();}// 确保行有足够的单元格while (row.getTableCells().size() < data.length) {row.addNewTableCell();}for (int i = 0; i < data.length && i < row.getTableCells().size(); i++) {XWPFTableCell cell = row.getCell(i);if (cell != null) {setCellContentSafely(cell, data[i], isHeader, fontSize);}}}// 安全设置单元格内容private static void setCellContentSafely(XWPFTableCell cell, String text,boolean isHeader, int fontSize) {try {// 清除现有内容for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {cell.removeParagraph(i);}// 添加新段落XWPFParagraph paragraph = cell.addParagraph();paragraph.setAlignment(ParagraphAlignment.CENTER);// 创建运行并设置文本XWPFRun run = paragraph.createRun();run.setText(text != null ? text : "");run.setFontSize(fontSize);if (isHeader) {run.setBold(true);}} catch (Exception e) {System.err.println("设置单元格内容失败: " + e.getMessage());try {cell.setText(text != null ? text : "");} catch (Exception ex) {System.err.println("备用设置方法也失败: " + ex.getMessage());}}}public static void main(String[] args) {// 导出到指定目录String outputDir = "D:/视力报告目录";String fileName = "综合视力分析报告_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".docx";String outputPath = outputDir + "\\" + fileName;exportCombinedReport(outputPath);}
}
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.xmlbeans</groupId><artifactId>xmlbeans</artifactId><version>3.1.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>ooxml-schemas</artifactId><version>1.4</version></dependency> ———————————————— 版权声明:本文为CSDN博主「zhao_java_drao」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/zhao_java_drao/article/details/124303418
https://www.bilibili.com/opus/608370314915365852