本文主要是介绍Java使用POI-TL和JFreeChart动态生成Word报告,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Java使用POI-TL和JFreeChart动态生成Word报告》本文介绍了使用POI-TL和JFreeChart生成包含动态数据和图表的Word报告的方法,并分享了实际开发中的踩坑经验,通过代码...
前言
在开发过程中,我们经常需要生成包含动态数据和图表的 Word 报告。本文将介绍如何结合 POI-TL 和 JFreeChart,实现动态生成 Word 报告的功能,并分享一些实际开发中的踩坑经验。
word生成方案:
- freemarker+ftl
- pot-tl模板替换
- poi硬编码
一、需求背景
在之前的文章中,我们已经介绍了如何使用模板替换、复杂表格和图片插入等功能。此次的需求是生成一个包含统计图的 Word 报告,统计图需要根据动态数据生成。面临的主要问题包括:
- 选择 Word 生成方案:如何在 Word 中动态插入数据和图表?
- 图片插入方案:如何将生成的统计图插入到 Word 中?
- 生成统计图表方案:如何根据数据动态生成统计图?
二、方案分析
- POI 硬编码
直接使用 Apache POI 硬编码生成 Word 文档,虽然可行,但代码复杂且难以维护,因此不推荐。 - FreeMarker + FTL
FreeMarker 可以实现文本替换和图片插入,理论上符合需求。但 FTL 模板的维护较为繁琐,尤其是在处理复杂表格和图片时。 - POI-TL + JFreeChart
POI-TL 是一个基于 Apache POI 的模板引擎,支持文本替换、图片插入等功能。结合 JFreeChart 生成统计图,可以很好地满足需求。
三、 POI-TL + JFreeChart 实现
关于JFreeChart请移步Java使用JFreeChart创建动态图表的代码示例_java_China编程(www.chinasem.cn)
3.1 Maven 依赖
首先,需要在项目中引入 POI-TL 和 JFreeChart 的依赖。注意 POI 和 POI-TL 的版本需要对应,否则可能会出现 NoSuchMethod 等错误。
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooXML</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.poi</groupId> &ljst;artifactId>poi-excelant</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.jfree</groupId> <artifactId>jfreechart</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.10.0</version> </dependency>
3.2 word模板设置
在 Word 模板中,使用占位符标记需要替换的内容。对于图片,需要在占位符前加 @,例如:
- 替换文本:时间 -> ${date}
- 插入图片:${@dailyOnlinePic}
3.3 实现代码
以下是核心实现代码:
private static final String TEMPLATE_PATH = "classpath:template/report.docx"; private static final String OUTPUT_DIR = "D:/data/upload/analysis/"; private static final String PIC_DIR = OUTPUT_DIR + "pic/"; public void getWord(String curDistCode) { try { // 获取模板文件 File file = ResourceUtils.getFile(TEMPLATE_PATH); // 构建模板替换的数据 Map<String, Object> dataMap = buildTemplateData(curDistCode); // 生成最终文件路径 String fileName = UUIDUtil.genUUID32() + ".docx"; String filePath = OUTPUT_DIR + fileName; // 使用 POI-TL 渲染模板并保存 try (XwpFTemplate template = XWPFTemplate.compile(file, Conwww.chinasem.cnfigure.newBuilder().buildGramer("${", "}").build()) .render(dataMap)) { template.writeToFile(filePath); } //上传文件返回附件id } catch (Exception e) { e.printStackTrace(); } } private Map<String, Object> buildTemplateData(String curDistCode) throws IOException { Map<String, Object> dataMap = new HashMap<>(); // 设置日期和在线总数 dataMap.put("date", LocalDate.now()); // 查询设备数据 dataMap.put("onlineTotal", 100); // 生成每日在线图表 DefaultCategoryDataset dailyData = buildDailyDataset(stationByTime); String dailyPicFile = generateChart(dailyData, "监测站总在线数", "小时", "数量", dailyOnlineTxtEnum); dataMap.put("dailyOnlinePic", Pictures.ofStream(new FileInputStream(dailyPicFile), PictureType.JPEG).size(600, 200).create()); return dataMap; } // 构建每日在线图表的数据集 private DefaultCategoryDataset buildDailyDataset(List<FireStationByTimeDTO> stationByTime) { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); stationByTime.forEach(t -> dataset.addValue(t.getOnlineNum(), "", t.getTime())); return dataset; } // 生成图表并保存为图片 private String generateChart(DefaultCategoryDataset dataset, String title, String xAxisLabel, String yAxisLabel, DailyOnlineTxtEnum style) throws IOException { // 设置全局字体(支持中文) StandardChartTheme chartTheme = new StandardChartTheme("CN"); chartTheme.setExtraLargeFont(new Font("宋体", Font.PLAIN, 14)); // 标题字体 chartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 14)); // 图例字体 chartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 12)); // 轴标签字体 ChartFactory.setChartTheme(chartTheme); // 创建图表 JFreeChart chart = ChartFactory.createLineChart(title, xAxisLabel, yAxisLabel, dataset); setChartStyle(chart, style); // 保存图表为图片 String picFile = PIC_DIR + UUIDUtil.genUUID32() + ".png"; //int numberOfCategories = dataset.getColumnCount(); //int width = Math.max(800, numberOfCategories * 50); // 每个类别宽度为50,最小宽度为800 ChartUtils.saveChartASPNG(new File(picFile), cpythonhart, 1200, 400); return picFile; } // 设置图表样式 private void setChartStyle(JFreeChart chart) { CategoryPlot plot = chart.getCategoryPlot(); chart.setBackgroundPaint(Color.WHITE); plot.setBackgroundPaint(Color.WHITE); plot.setDomainGridlinePaint(Color.LIGHT_GRAY); plot.setRangeGridlinePaint(Color.LIGHT_GRAY); // 设置第一条折线的粗细 plot.getRenderer().setSeriesStroke(0, new BasicStroke(5.0f)); // 根据样式设置折线颜色 plot.getRenderer().setSeriesPaint(0, Color.RED); }
效果
踩坑
- 插入图片如何占位
与常规文本替换不同,图片插入需要在占位符前加 @,例如${@dailyOnlinePic}
或{{@pic}}
- 统计图中文乱码
JFreeChart 默认不支持中文,需要通过设置全局字体解决:
// 设置全局字体(支持中文) StandardChartTheme chartTheme = new StandardChartTheme("CN"); chartTheme.setExtraLargeFont(new Font("宋体", Font.PLAIN, 14)); // 标题字体 chartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 14)); // 图例字体 chartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 12)); // 轴标签字体 ChartFactory.setChartTheme(chartTheme);
- 统计图横坐标…
如果生成的图片宽度不够,横坐标可能会显示不全。可以通过增加图片宽度解决,插入时等比例缩放:
ChartUtils.saveChartAsPNG(new File(picFile), chart, 1200, 400);
dataMap.put("dailyOnlinePic", Pictures.ofStream(new FileInputStream(dailyPicFile), PictureType.JjavascriptPEG).size(600, 200).create());
或动态计算需要生成的图片宽度:
int numberOfCategories = dataset.getColumnCount(); int width = Math.max(800, numberOfCategories * 50); // 每个类别宽编程度为50,最小宽度为800
到此这篇关于Java使用POI-TL和JFreeChart动态生成Word报告的文章就介绍到这了,更多相关Java POI-TL JFreeChart生成Word报告t内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!
这篇关于Java使用POI-TL和JFreeChart动态生成Word报告的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!