3.2.4. HTML 模板

HTML 模板在 .html 文件(无 BOMUTF-8 编码)中定义。可以使用 Flying Saucer 库的 HTML/CSS 功能;其主要指南参考 http://flyingsaucerproject.github.io/flyingsaucer/r8/guide/users-guide-R8.html

要控制页面尺寸、页眉和页脚,请使用特殊的 CSS 规则和属性。可以在示例报表中找到每页都显示页面/页脚的报表示例。

有两种方法可以在模板中放入数据:

  • 使用 FreeMarker 标签。

  • 使用 Groovy 模板引擎。

默认情况下,报表向导会生成带有 FreeMarker 标签的 HTML 模板。

在模板编辑器中使用 Template type 单选按钮切换这两种方法。

html template editor
Figure 40. HTML 模板编辑器
Groovy 模板引擎

可以将 HTML 报表模板作为 Groovy 模板进行预处理,将使用 GStringTemplateEngine 来处理模板。

模板引擎使用 JSP 格式的 <% %> 脚本和 <%= %> 表达式语法或者 GString 格式的表达式。out 变量用来绑定模板将要被写入的 writer。因此,如果定义没有问题的话,模板可以使用任何 Groovy 代码。GStringTemplateEngine 能访问:

  • 外部参数:BandName.fields.ParamName

  • 区域:BandName.bands.ChildBandName

  • 字段:BandName.fields.FieldName

方便起见,也可以使用变量,例如:

<% def headerRow = Root.bands.HeaderRow %>
<p>Date: ${headerRow.fields.reportDate}</p>

下面是一个模板的示例,输出单一用户的报表。

<?xml version="1.0" encoding="utf-8"?>
<!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" xml:lang="ru">
    <head>
        <title> Report User </title>
        <style type="text/css">
 body {font-family: 'Charis SIL', sans-serif;} tbody tr {height:20px; min-height:20px}
        </style>
    </head>
    <body>
        <% def user = Root.bands.User %>
        <p>Login: ${user.fields.login.first()}</p>
        <p>Active: ${user.fields.active.first()}</p>
    </body>
</html>

可以在报表示例部分找到使用 Groovy 模板的示例。

FreeMarker

FreeMarker 文档可以参阅 https://freemarker.apache.org/docs/

FreeMarker 文档模型的结构如下:

Band {
      bands [ bandName : [ band, .. ], .. ]
      fields [ fieldName : fieldValue, .. ]
}

例如,应该使用以下表达式访问 band 带区中第一行数据的 name 字段:

Root.bands.band[0].fields.name

为方便起见,可以使用变量,例如:

<#assign headerRow = Root.bands.Header[0]>
<p>Date: ${headerRow.fields.reportDate}</p>

下面是一个模板示例,它输出一个由两个带区(BookAuthors)组成的报表。第一个区输出书名和分类,第二个区输出本书的作者列表。

<!doctype html>
<html>
<head></head>
<body>
    <#assign book = Root.bands.Book[0] />
    <#assign authors = Root.bands.Authors />

    <p>Name: ${book.fields.name}</p>
    <p>Genre: ${book.fields.literatureType.name}</p>
    <table border="1" cellpadding="5" cellspacing="0" width="200">
        <thead>
        <tr>
            <td>First name</td>
            <td>Last name</td>
        </tr>
        </thead>
        <tbody>
        <#list authors as author>
            <tr>
                <td>${author.fields.firstName}</td>
                <td>${author.fields.lastName}</td>
            </tr>
        </#list>
        </tbody>
    </table>
</body>
</html>

下面是一个更复杂的例子。假设我们有以下报表带区结构:

Root {
    HeaderBand {
        query = return [[ "name" : "Column1" ],[ "name" : "Column2" ]]
    }
    Band1 {
        query = return [
                ["field1" : "Value 11", "field2" : "Value 12"],
                ["field1" : "Value 21" , "field2" : "Value 22"]
        ]
    }
    Band2 {
        query = return [[ "header" : "Header1" ], [ "header" : "Header2" ]]
        SubBand1 {
            query = return [["header" : 'SubHeader1'] , [ "header" : 'SubHeader2' ]]
        }
    }
}
  • 插入字段:

<!doctype html>
<html>
    <head>
        <title> Simple template </title>
    </head>
    <body>
    <#assign Tree1 = Root.bands.Band2>
        <h1> Header </h1>
        <p>
            ${Tree1[1].bands.SubBand1[0].fields.header}
        </p>
    </body>
</html>
  • 插入列表:

<!doctype html>
<html>
    <head>
        <title> List </title>
    </head>
    <body>
    <#assign Table1Header = Root.bands.HeaderBand>

        <#if Table1Header?has_content>
            <ol>
                <#list Table1Header as header>
                    <li> ${header.fields.name} </li>
                </#list>
            </ol>
        </#if>
    </body>
</html>
  • 插入表格:

<!doctype html>
<html>
<head>
    <title> Table </title>
</head>
<body>
<#assign Table1Header = Root.bands.HeaderBand>
    <#assign Table1 = Root.bands.Band1>
        <table border="1" cellpadding="5" cellspacing="0" width="200">
            <thead>
            <tr>
                <#list Table1Header as header>
                    <td> ${header.fields.name} </td>
                </#list>
            </tr>
            </thead>
            <tbody>
            <#list Table1 as row>
                <tr>
                    <td>
                        ${row.fields.field1}
                    </td>
                    <td>
                        ${row.fields.field2}
                    </td>
                </tr>
            </#list>
            </tbody>
        </table>
</body>
</html>
  • 插入多级列表:

<!doctype html>
<html>
<head>
    <title> Multi-level list </title>
</head>
<body>
<#assign Tree1 = Root.bands.Band2>
    <ul>
        <#list Tree1 as item>
            <li>
                <h2> ${item.fields.header} </h2>
                <#if item.bands.SubBand1?has_content>
                    <ul>
                        <#list item.bands.SubBand1 as subitem>
                            <li>
                                <h3> ${subitem.fields.header} </h3>
                            </li>
                        </#list>
                    </ul>
                </#if>
            </li>
        </#list>
    </ul>
</body>
</html>
嵌入图片

目前,CUBA 报表扩展不提供类似于 DOCX/XLSX 报表将图片插入 HTML 报表的方法。图片仍然可以使用 img 标签并在 src 属性中指定图片链接的方式嵌入。有两种方法可以将图片添加到 HTML 报表中:

  • 通过 URL

    图片可以托管在 Tomcat 服务或者其他地方,以便用做本地文件引用。例如,托管在 deploy\tomcat\webapps\ROOT\images 文件夹中的图片可以被插入:

<img src="http://localhost:8080/images/SomeImage.jpg" height="68" width="199" border="0" align="right"/>
  • 通过 Bitmap

    图片在 src 属性中以字节数组形式添加。此方法可以使用实体的 FileDescriptor 属性变量。甚至可以将字节数组直接添加到模板中,虽然不建议使用此方法:

<img alt="SomePicture.png" src="data:image/png;base64,iVBORw0K ..... AcEP9PwxD0hNKK1FCAAAAAElFTkSuQmCC"/>
内联编辑器

HTML 模板支持内联编辑器。可以直接在 Template editor 窗口中编辑模板,无需重新上传模板文件即可查看更改。

html report editor
Figure 41. HTML 内联编辑器