3.2. Sample HTML/PDF Report with Paging, Headers and Footers

Let’s imagine that we now want to create a report with landscape orientation, page numbers, fixed header and footer on each page, configured using special CSS rules and properties. The output format is HTML exported to PDF.

This sample report with its demo project are also available on CUBA GitHub.

  1. Data model

    Our report will display information on the Client entity. It contains two String attributes: title and summary, we will use them in our report structure.

    public class Client extends StandardEntity {
    
        @NotNull
        @Column(name = "TITLE", nullable = false)
        protected String title;
    
        @Column(name = "SUMMARY")
        protected String summary;
    
        ...
    }
  2. Creating report

    Let’s create a simple report without parameters. The JPQL query will select all clients with their local attributes: title and summary.

    example html 1
  3. Report template.

    Now let’s create the report template file. Here we define header and footer blocks that will be printed on each PDF page. Also we use special page-break-before: always CSS property. It will generate page break before each client info block.

    As you can see, we use FreeMarker statements to insert data to our template. See complete FreeMarker reference here: http://freemarker.org/docs/.

    <body>
    <h1>Clients report</h1>
    <!-- Custom HTML header -->
    <div id="header">
        <h2>Annual Report of our Company</h2>
    </div>  <!-- Custom HTML footer -->
    <div id="footer">
        <h2>Address: William Road</h2>
        <span class="custom-footer-page-number">Number: </span>
    </div>
    
    <#assign clients = Root.bands.Clients />
    
    <#list clients as client>
        <!-- New page for each 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 rules

    We will use the following CSS code to tune our PDF page representation:

    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;
       /* Default footers */
       @bottom-left {
         content: "Department of Strategy";
       }
       @bottom-right {
         content: counter(page) " of " counter(pages);
      }
    }

    This CSS code will set header/footer positions:

    /* footer, header - position: fixed */
    #header {
      position: fixed;
      width: 100%;
      top: 0;
      left: 0;
      right: 0;
    }
    #footer {
      position: fixed;
      width: 100%;
      bottom: 0;
      left: 0;
      right: 0;
    }

    After that we need to fix paddings of the main content to prevent content and header/footer overlapping:

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

    What if we want to insert page number to custom position? That’s it:

    .custom-footer-page-number:after {
      content: counter(page);
    }

    So, the complete paging-template.html file will look as below:

    <!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; } @page { /* switch to landscape */ size: landscape; /* set page margins */ margin: 0.5cm; /* Default footers */ @bottom-left { content: "Department of Strategy"; } @bottom-right { content: counter(page) " of " counter(pages); } } /* footer, header - position: fixed */ #header { position: fixed; width: 100%; top: 0; left: 0; right: 0; } #footer { position: fixed; width: 100%; bottom: 0; left: 0; right: 0; } /* Fix overflow of headers and content */ body { padding-top: 50px; } .custom-page-start { margin-top: 50px; } .custom-footer-page-number:after { content: counter(page); }
      </style>
    </head>
    <body>
    <h1>Clients report</h1>
    
    <!-- Custom HTML header -->
    <div id="header">
        <h2>Annual Report of our Company</h2>
    </div>
    
    <!-- Custom HTML footer -->
    <div id="footer">
        <h2>Address: William Road</h2>
        <span class="custom-footer-page-number">Number: </span>
    </div>
    
    <#assign clients = Root.bands.Clients />
    
    <#list clients as client>
        <!-- New page for each 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. Upload the template file and run the report.

    example html 3

    As you can see, the report contains the title page and page breaks before each client’s page. There are headers and footers on each page as well.

    example html 2