5.4. 带分页、页眉和页脚的 HTML/PDF 报表示例

假设要创建一个这样的报表:横向展示、每页上都显示页码和固定的页眉页脚,使用特殊的 CSS 规则和属性进行配置。输出格式是 HTML 并可以导出为 PDF。

此报表示例及其演示项目也可在 CUBA GitHub 上找到。

  1. 数据模型

    报表将显示有关 Client 实体的信息。它包含两个 String 属性:titlesummary,在报表结构中会使用它们。

    public class Client extends StandardEntity {
    
        @NotNull
        @Column(name = "TITLE", nullable = false)
        protected String title;
    
        @Lob
        @Column(name = "SUMMARY")
        protected String summary;
    
        ...
    }
  2. 创建报表

    创建一个没有参数的简单报表。使用 JPQL 查询所有 Client 实体的本地属性:titlesummary

    example html 1
  3. 报表模板.

    现在创建报表模板文件。在这里定义页眉和页脚块,页眉和页脚会在每页 PDF 都打印 。这需要使用特殊的 page-break-before: always CSS 属性。它会在每个 Client 信息块之前生成分页符。

    如下所示,使用 FreeMarker 语法将数据插入到模板中。请在此处查看完整的 FreeMarker 参考: https://freemarker.apache.org/docs/

    <body>
    <h1>Clients report</h1>
    
    <!-- Custom HTML header -->
    <div class="header">
        Annual Report of our Company
    </div>
    
    <!-- Custom HTML footer -->
    <div class="footer">
        Address: William Road
    </div>
    
    <#assign clients = Root.bands.Clients />
    
    <#list clients as client>
    <div class="custom-page-start" style="page-break-before: always;">
        <h2>Client</h2>
    
        <p>Name: ${client.fields.title}</p>
        <p>Summary: ${client.fields.summary}</p>
    </div>
    </#list>
    </body>
  4. CSS 规则

    将使用以下 CSS 代码来调整 PDF 页面显示:

    body {
        font: 12pt Georgia, "Times New Roman", Times, serif;
        line-height: 1.3;
    }
    @page {
        /* switch to landscape */
        size: landscape;
        /* set page margins */
        margin: 0.5cm;
        @top-center {
            content: element(header);
        }
        @bottom-center {
            content: element(footer);
        }
        @bottom-right{
            content: counter(page) " of " counter(pages);
        }
    }

    此 CSS 代码将设置页眉/页脚位置:

    div.header {
        display: block;
        text-align: center;
        position: running(header);
        width: 100%;
    }
    
    div.footer {
        display: block;
        text-align: center;
        position: running(footer);
        width: 100%;
    }

    之后,需要填充主要内容的边距以防止内容和页眉/页脚重叠:

    /* Fix overflow of headers and content */
    body {
        padding-top: 50px;
    }
    .custom-page-start {
        margin-top: 50px;
    }

    最终,完整的 paging-template.html 文件如下所示:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Invoice</title>
        <style type="text/css">
     body { font: 12pt Georgia, "Times New Roman", Times, serif; line-height: 1.3; padding-top: 50px; } div.header { display: block; text-align: center; position: running(header); width: 100%; } div.footer { display: block; text-align: center; position: running(footer); width: 100%; } @page { /* switch to landscape */ size: landscape; /* set page margins */ margin: 0.5cm; @top-center { content: element(header); } @bottom-center { content: element(footer); } @bottom-right { content: counter(page) " of " counter(pages); } } .custom-page-start { margin-top: 50px; }
      </style>
    </head>
    <body>
    <h1>Clients report</h1>
    
    <!-- Custom HTML header -->
    <div class="header">
        Annual Report of our Company
    </div>
    
    <!-- Custom HTML footer -->
    <div class="footer">
        Address: William Road
    </div>
    
    <#assign clients = Root.bands.Clients />
    
    <#list clients as client>
    <div class="custom-page-start" style="page-break-before: always;">
        <h2>Client</h2>
    
        <p>Name: ${client.fields.title}</p>
        <p>Summary: ${client.fields.summary}</p>
    </div>
    </#list>
    </body>
    </html>
  5. 上传模板文件并运行报表。

    example html 3

    正如所见,报表包含标题页、每个 Client 信息前都分页、每页都显示页眉和页脚。

    example html 2