后台实现动态生成报表文档

236 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

前言

最近遇到了一个需求:后台根据存储数据生成一个PDF报表,里面还会有各种分析图表,经过技术调研后,大体技术栈如下

  1. 使用poi-tl来作为报表模板,生成word文档
  2. 使用jfreechart来进行各种分析图表生成
  3. 随后将生成word文档转换为PDF即可

开放思路理清后,下面就来了解一下怎么编码把~

poi-tl

poi-tl(poi template language)是Word模板引擎,使用Word模板和数据创建很棒的Word文档

上面就是官方的介绍,它支持动态将标签渲染为文本、图片、表格、图表等,能够满足我们的各种需求。

同时官方还列举了与其他word模板框架的对比:

方案移植性功能性易用性
Poi-tlJava跨平台Word模板引擎,基于Apache POI,提供更友好的API低代码,准备文档模板和数据即可
Apache POIJava跨平台Apache项目,封装了常见的文档操作,也可以操作底层XML结构文档不全,这里有一个教程:Apache POI Word快速入门
FreemarkerXML跨平台仅支持文本,很大的局限性不推荐,XML结构的代码几乎无法维护
OpenOffice部署OpenOffice,移植性较差-需要了解OpenOffice的API
HTML浏览器导出依赖浏览器的实现,移植性较差HTML不能很好的兼容Word的格式,样式糟糕-
Jacob、winlibWindows平台-复杂,完全不推荐使用

那么下面就来写个demo试试,是否能够满足我的需求~

demo例子

首先创建一个word文档,创建了一个文本标签和图片标签

// quick-start.docx
{{str}}
{{@img}}

随后在项目中引入相关依赖

<dependency>
  <groupId>com.deepoove</groupId>
  <artifactId>poi-tl</artifactId>
  <version>1.12.0</version>
</dependency>
    @Test
    public void testPoiTl() throws IOException {
        InputStream inputStream = this.getClass().getResourceAsStream( "/word/quick-start.docx" );
        JFreeChart barChart = generateJFreeChart();
        BufferedImage bufferedImage = barChart.createBufferedImage( 640, 480 );
        XWPFTemplate template = XWPFTemplate.compile( inputStream ).render(
            new HashMap<String, Object>() {{
                put( "str", "Hi, poi-tl Word模板引擎" );
                put( "img", Pictures.ofBufferedImage( bufferedImage, PictureType.PNG ).size( 640,480 ).create() ); // 先不用理这一行
            }} );
        template.writeAndClose( new FileOutputStream( "./word/output.docx" ) );
    }
​

上面的代码可以分为三部分:

  1. 调用compile方法对word模板进行编译,读取相关标签
  2. 调用render方法替换标签,进行渲染数据操作
  3. 随后将渲染后的word文档进行输出

将其称为:TDO模式:Template + data-model = output

jfreechart

通过上面的代码,可以看到图表的生成我使用了JFreeChart类,这是jfreechart中条状图的实现类。

JFreeChart是一个适用于Java™平台的综合免费图表库,可以在客户端(JavaFX和Swing)或服务器端使用,可导出多种格式,包括SVG、PNG和PDF。

该项目的文档可能比较少,不过官方提供了一个demo库来让我们学习相关API:jfree/jfree-demos: Various demo programs for JFree projects (github.com)

demo例子

    @Test
    public void testGenerateChart() throws IOException {
        JFreeChart barChart = generateJFreeChart();
        ChartUtils.saveChartAsJPEG( new File( "./word/chart.jpeg" ), barChart, 640, 480 );
    }
​
    public JFreeChart generateJFreeChart() {
        // 条状图的标题
        String chartTitle = "测试条状图"; 
        
        // 行名称
        String departmentName1 = "文商学院"; 
        String departmentName2 = "汽车学院";
        String departmentName3 = "创意学院";
        // 需要注意中文图表需要使用Font类来进行设置,否则会乱码
        
        Font font = new Font( "宋体", Font.BOLD, 15 );
        DefaultCategoryDataset categoryDataset = new DefaultCategoryDataset();
        // 设置图表值
        categoryDataset.setValue( 90, departmentName1, departmentName1 );
        categoryDataset.setValue( 91, departmentName2, departmentName2 );
        categoryDataset.setValue( 81, departmentName3, departmentName3 );
​
​
        JFreeChart barChart = ChartFactory.createBarChart(
            chartTitle,
            "部门",
            "分数",
            categoryDataset,
            PlotOrientation.VERTICAL,
            true, true, false
        );
        
        // 设置font类型
        barChart.getTitle().setFont( font );
        barChart.getLegend().setItemFont( font );
        CategoryPlot categoryPlot = barChart.getCategoryPlot();
        CategoryAxis domainAxis = categoryPlot.getDomainAxis();
        domainAxis.setLabelFont( font );
        domainAxis.setTickLabelFont( font );
        categoryPlot.getRangeAxis().setLabelFont( font );
        categoryPlot.getRangeAxis().setTickLabelFont( font );
        return barChart;
    }

最终生成的图表图片如下图:

image.png

小结

通过上面两个例子就可以看到,使用poi-tl和jfreechart框架就可以实现各种报表文档的生成拉,如果还有其他需求就去官方看看把。