知識庫 / Spring RSS 訂閱

Spring 與 JasperReports 集成開發指南

Spring
HongKong
4
02:35 PM · Dec 06 ,2025

1. 概述

JasperReports 是一款開源報告庫,它允許用户創建像素級精確的報告,這些報告可以打印或導出為多種格式,包括 PDF、HTML 和 XLS。

在本文中,我們將探索其關鍵功能和類,並實施示例以展示其功能。

2. Maven 依賴

首先,我們需要將 jasperreports 依賴添加到我們的 pom.xml 中:

<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>6.20.0</version>
</dependency>

最新版本的該組件可以在這裏找到:這裏

3. 報告模板

報告設計在 JRXML 文件中定義。這些是 JasperReports 引擎可以解釋的普通 XML 文件,具有特定的結構。

下面我們來查看 JRXML 文件的相關結構,以便更好地理解報告生成過程中的 Java 部分,這是我們的主要關注點。

讓我們創建一個簡單的報告來顯示員工信息:

<jasperReport ... >
    <field name="FIRST_NAME" class="java.lang.String"/>
    <field name="LAST_NAME" class="java.lang.String"/>
    <field name="SALARY" class="java.lang.Double"/>
    <field name="ID" class="java.lang.Integer"/>
    <detail>
        <band height="51" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression class="java.lang.String">
                  <![CDATA[$F{FIRST_NAME}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="100" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression class="java.lang.String">
                  <![CDATA[$F{LAST_NAME}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="200" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression class="java.lang.String">
                  <![CDATA[$F{SALARY}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
</jasperReport>

3.1. 編譯報告

JRXML 文件需要編譯,以便報告引擎能夠填充其中的數據。

以下使用 JasperCompilerManager 類執行此操作:

InputStream employeeReportStream
  = getClass().getResourceAsStream("/employeeReport.jrxml");
JasperReport jasperReport
  = JasperCompileManager.compileReport(employeeReportStream);

為了避免每次編譯都重新編譯,我們可以將其保存到文件中:

JRSaver.saveObject(jasperReport, "employeeReport.jasper");

4. 填充報告

最常見的方法是使用數據庫中的記錄來填充編譯後的報告。 這需要報告包含引擎執行的 SQL 查詢以獲取數據。

首先,讓我們修改報告以添加 SQL 查詢:

<jasperReport ... >
    <queryString>
        <![CDATA[SELECT * FROM EMPLOYEE]]>
    </queryString>
    ...
</jasperReport>

現在,讓我們創建一個簡單的數據源:

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder()
      .setType(EmbeddedDatabaseType.HSQL)
      .addScript("classpath:employee-schema.sql")
      .build();
}

現在,我們可以填寫報告:

JasperPrint jasperPrint = JasperFillManager.fillReport(
  jasperReport, null, dataSource.getConnection());

請注意,我們傳遞了 null 作為第二個參數,因為我們的報告目前尚未接收任何參數。

4.1. 參數

參數對於將數據傳遞給報告引擎,這些數據在它的數據源中找不到,或者當運行時條件不同時數據發生變化非常有用。

我們還可以通過接收到的參數來修改或甚至完全修改 SQL 查詢,從而在報告填充操作中進行調整。

首先,讓我們修改報告以接收三個參數:

<jasperReport ... >
    <parameter name="title" class="java.lang.String" />
    <parameter name="minSalary" class="java.lang.Double" />
    <parameter name="condition" class="java.lang.String">
        <defaultValueExpression>
          <![CDATA["1 = 1"]]></defaultValueExpression>
    </parameter>
    // ...
</jasperreport>

現在,讓我們添加一個標題部分,以顯示 參數:

<jasperreport ... >
    // ...
    <title>
        <band height="20" splitType="Stretch">
            <textField>
                <reportElement x="238" y="0" width="100" height="20"/>
                <textElement/>
                <textFieldExpression class="java.lang.String">
                  <![CDATA[$P{title}]]></textFieldExpression>
            </textField>
        </band>
    </title>
    ...
</jasperreport/>

接下來,讓我們修改查詢語句,使用 minSalarycondition 參數:

SELECT * FROM EMPLOYEE
  WHERE SALARY >= $P{minSalary} AND $P!{condition}

請注意使用 condition 參數時不同的語法。這告訴引擎該參數不應作為標準的 PreparedStatement 參數使用,而是像原始 SQL 查詢中值本身那樣使用。

最後,我們準備參數並填充報告:

Map<String, Object> parameters = new HashMap<>();
parameters.put("title", "Employee Report");
parameters.put("minSalary", 15000.0);
parameters.put("condition", " LAST_NAME ='Smith' ORDER BY FIRST_NAME");

JasperPrint jasperPrint
  = JasperFillManager.fillReport(..., parameters, ...);

請注意,參數的鍵對應於報告中的參數名稱。如果引擎檢測到某個參數缺失,它將從defaultValueExpression中獲取該參數的默認值(如果存在)。

5. 導出

要導出報告,首先,實例化一個與所需文件格式相匹配的導出器類。

然後,我們將先前填充的報告作為輸入,並定義輸出文件的位置。

可選地,我們可以設置相應的報告和導出配置對象,以自定義導出過程。

5.1. PDF

JRPdfExporter exporter = new JRPdfExporter();

exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(
  new SimpleOutputStreamExporterOutput("employeeReport.pdf"));

SimplePdfReportConfiguration reportConfig
  = new SimplePdfReportConfiguration();
reportConfig.setSizePageToContent(true);
reportConfig.setForceLineBreakPolicy(false);

SimplePdfExporterConfiguration exportConfig
  = new SimplePdfExporterConfiguration();
exportConfig.setMetadataAuthor("baeldung");
exportConfig.setEncrypted(true);
exportConfig.setAllowedPermissionsHint("PRINTING");

exporter.setConfiguration(reportConfig);
exporter.setConfiguration(exportConfig);

exporter.exportReport();

5.2. XLS

JRXlsxExporter exporter = new JRXlsxExporter();
 
// Set input and output ...
SimpleXlsxReportConfiguration reportConfig
  = new SimpleXlsxReportConfiguration();
reportConfig.setSheetNames(new String[] { "Employee Data" });

exporter.setConfiguration(reportConfig);
exporter.exportReport();

5.3. CSV

JRCsvExporter exporter = new JRCsvExporter();
 
// Set input ...
exporter.setExporterOutput(
  new SimpleWriterExporterOutput("employeeReport.csv"));

exporter.exportReport();

5.4. HTML

HtmlExporter exporter = new HtmlExporter();
 
// Set input ...
exporter.setExporterOutput(
  new SimpleHtmlExporterOutput("employeeReport.html"));

exporter.exportReport();

6. 子報表

子報表本質上是嵌入在另一個報表中的標準報表。

首先,讓我們創建一個報表來顯示員工的電子郵件:

<jasperReport ... >
    <parameter name="idEmployee" class="java.lang.Integer" />
    <queryString>
        <![CDATA[SELECT * FROM EMAIL WHERE ID_EMPLOYEE = $P{idEmployee}]]>
    </queryString>
    <field name="ADDRESS" class="java.lang.String"/>
    <detail>
        <band height="20" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="156" height="20"/>
                <textElement/>
                <textFieldExpression class="java.lang.String">
                  <![CDATA[$F{ADDRESS}]]></textFieldExpression>
            </textField>
        </band>
    </detail>
</jasperReport>

現在,讓我們修改員工報告以包含之前的報告:

<detail>
    <band ... >
        <subreport>
            <reportElement x="0" y="20" width="300" height="27"/>
            <subreportParameter name="idEmployee">
                <subreportParameterExpression>
                  <![CDATA[$F{ID}]]></subreportParameterExpression>
            </subreportParameter>
            <connectionExpression>
              <![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
            <subreportExpression class="java.lang.String">
              <![CDATA["employeeEmailReport.jasper"]]></subreportExpression>
        </subreport>
    </band>
</detail>

請注意,我們通過編譯文件的名稱引用子報表,並將 idEmployee 和當前報表連接作為參數傳遞。

接下來,讓我們編譯這兩個報表。

InputStream employeeReportStream
  = getClass().getResourceAsStream("/employeeReport.jrxml");
JasperReport jasperReport
  = JasperCompileManager.compileReport(employeeReportStream);
JRSaver.saveObject(jasperReport, "employeeReport.jasper");

InputStream emailReportStream
  = getClass().getResourceAsStream("/employeeEmailReport.jrxml");
JRSaver.saveObject(
  JasperCompileManager.compileReport(emailReportStream),
  "employeeEmailReport.jasper");

我們的代碼無需修改即可用於報告的填充和導出。

7. 條件顯示使用 <em >printWhenExpression</em >>

此外,我們還可以使用 <em >printWhenExpression</em >> 來根據特定條件,條件地顯示報告元素。這意味着文本字段、圖像和帶等元素可以根據報告中的數據或參數動態地顯示或隱藏。

下面是一個修改 JRXML 文件以包含空值檢查的示例,使用 <em >printWhenExpression</em >>。我們將檢查 <em >FIRST_NAME</em >><em >LAST_NAME</em >><em >SALARY</em >> 字段中的非空值,然後在詳細帶中渲染內容:

<jasperReport ... >
    <field name="SALARY" class="java.lang.Double"/>
    <!-- other fields -->
    
    <detail>
        <band height="51" splitType="Stretch">
            <printWhenExpression><![CDATA[$F{FIRST_NAME} != null && $F{LAST_NAME} != null && $F{SALARY} != null]]></printWhenExpression>

            <!-- Existing text fields and subreport-->
        
        </band>
    </detail>
</jasperReport>

這個表達式確保樂隊的所有內容僅在所有這些字段都具有有效(非空)值時才會顯示。 更新 JRXML 文件後,需要像以前一樣編譯和填充報告。

8. 結論

在本文中,我們對 JasperReports 庫的核心功能進行了簡要概述。

我們能夠使用數據庫中的記錄編譯和填充報告,並通過不同的運行時條件傳遞參數,從而根據不同的條件更改報告中顯示的數據,並嵌入子報告並將其導出到最常見的格式。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.