zoukankan      html  css  js  c++  java
  • JasperReports with Spring

    1. Overview

     

    JasperReports is an open source reporting library that enables users to create pixel-perfect reports that can be printed or exported in many formats including PDF, HTML, and XLS.

    In this article, we'll explore its key features and classes, and implement examples to showcase its capabilities.

    2. Maven Dependency

     

    First, we need to add the jasperreports dependency to our pom.xml:

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

    The latest version of this artifact can be found here.

    3. Report Templates

     

    Report designs are defined in JRXML files. These are ordinary XML files with a particular structure that JasperReports engine can interpret.

    Let's now have a look at only the relevant structure of the JRXML files – to understand better the Java part of the report generation process, which is our primary focus.

    Let's create a simple report to show employee information:

    <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. Compiling Reports

     

    JRXML files need to be compiled so the report engine can fill them with data.

    Let's perform this operation with the help of the JasperCompilerManager class:

    InputStream employeeReportStream
      = getClass().getResourceAsStream("/employeeReport.jrxml");
    JasperReport jasperReport
      = JasperCompileManager.compileReport(employeeReportStream);
    To avoid compiling it every time, we can save it to a file:
    
    JRSaver.saveObject(jasperReport, "employeeReport.jasper");
    

      

    The most common way to fill compiled reports is with records from a database. This requires the report to contain a SQL query the engine will execute to obtain the data.

    First, let's modify our report to add a SQL query:

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

    Now, let's create a simple data source:

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

    Now, we can fill the report:

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

    Note that we are passing null to the second argument since our report doesn't receive any parameters yet.

    4.1. Parameters

    Parameters are useful for passing data to the report engine that it can not find in its data source or when data changes depending on different runtime conditions.

    We can also change portions or even the entire SQL query with parameters received in the report filling operation.

    First, let's modify the report to receive three parameters:

    <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>

    Now, let's add a title section to show the title parameter:

    <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/>

    Next, let's alter the query to use the minSalary and condition parameters:

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

    Note the different syntax when using the condition parameter. This tells the engine that the parameter should not be used as a standard PreparedStatement parameter, but as if the value of that parameter would have been written originally in the SQL query.

    Finally, let's prepare the parameters and fill the report:

    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, ...);

    Note that the keys of parameters correspond to parameter names in the report. If the engine detects a parameter is missing, it will obtain the value from defaultValueExpression of the parameter if any.

    5. Exporting

    To export a report, first, we instantiate an object of an exporter class that matches the file format we need.

    Then, we set our previous filled report as input and define where to output the resulting file.

    Optionally, we can set corresponding report and export configuration objects to customize the exporting process.

    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. Subreports

    Subreports are nothing more than a standard report embedded in another report.

    First, let's create a report to show the emails of an employee:

    <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>

    Now, let's modify our employee report to include the previous one:

    <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>

    Note that we are referencing the subreport by the name of the compiled file and passing it the idEmployee and current report connection as parameters.

    Next, let's compile both reports:

    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");

    Our code for filling and exporting the report doesn't require modifications.

    7. Conclusion

    In this article, we had a brief look at the core features of the JasperReports library.

    We were able to compile and populate reports with records from a database; we passed parameters to change the data shown in the report according to different runtime conditions, embedded subreports and exported them to the most common formats.

    Complete source code for this article can be found over on GitHub.

     

     

     

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

  • 相关阅读:
    落花美眷,终究抵不过逝水流年,回忆我的2016,展望2017。
    如何对于几百行SQL语句进行优化?
    基于.NET Socket API 通信的综合应用
    数据库备份定期删除程序的开发。
    如何开发应用程序将客户服务器数据库的备份,下载到本地的云服务上?
    从大公司做.NET 开发跳槽后来到小公司的做.NET移动端微信开发的个人感慨
    asp.net mvc entity framework 数据库 练习(一)
    ASP.NET CORE小试牛刀:干货(完整源码)
    [开源].NET数据库访问框架Chloe.ORM
    SqlBulkCopy简单封装,让批量插入更方便
  • 原文地址:https://www.cnblogs.com/Jeely/p/14675726.html
Copyright © 2011-2022 走看看