Tạo báo cáo phụ

Báo cáo phụ là một trong những tính năng thú vị của JasperReports. Tính năng này cho phép kết hợp một báo cáo trong một báo cáo khác, tức là một báo cáo có thể là một báo cáo con của một báo cáo khác. Báo cáo phụ giúp chúng tôi giữ cho thiết kế báo cáo đơn giản, vì chúng tôi có thể tạo nhiều báo cáo đơn giản và gói gọn chúng thành một báo cáo tổng thể. Các báo cáo phụ được tổng hợp và điền giống như các báo cáo thông thường. Bất kỳ mẫu báo cáo nào cũng có thể được sử dụng làm báo cáo phụ khi được kết hợp vào một mẫu báo cáo khác mà không có bất kỳ điều gì thay đổi bên trong (của mẫu báo cáo).

Các báo cáo phụ giống như các mẫu báo cáo bình thường. Trên thực tế , chúng là các đối tượng net.sf.jasperreports.engine.JasperReport , được lấy sau khi biên dịch đối tượng net.sf.jasperreports.engine.design.JasperDesign .

Phần tử <subreport>

Phần tử <subreport> được sử dụng khi đưa các báo cáo phụ vào báo cáo chính. Đây là danh sách các phần tử con trong phần tử JRXML <subreport>.

  • <reportElement>

  • <parametersMapExpression> - Điều này được sử dụng để chuyển một bản đồ chứa các tham số báo cáo đến báo cáo con. Bản đồ thường được lấy từ một tham số trong báo cáo chính hoặc bằng cách sử dụng tham số REPORTS_PARAMETERS_MAP tích hợp sẵn để chuyển các tham số của báo cáo mẹ đến báo cáo con. Biểu thức này phải luôn trả về một đối tượng java.util.Map trong đó các khóa là tên tham số.

  • <subreportParameter> - Phần tử này được sử dụng để chuyển các tham số cho báo cáo con. Nó có một tên thuộc tính , tên này là bắt buộc.

  • <connectionExpression> - Điều này được sử dụng để chuyển java.sql.Connection đến báo cáo con. Nó chỉ được sử dụng khi mẫu báo cáo con cần kết nối cơ sở dữ liệu trong giai đoạn điền báo cáo.

  • <dataSourceExpression> - Điều này được sử dụng để chuyển một nguồn dữ liệu đến báo cáo con. Nguồn dữ liệu này thường được lấy từ một tham số trong báo cáo chính hoặc bằng cách sử dụng tham số REPORT_DATA_SOURCE tích hợp sẵn để chuyển nguồn dữ liệu của báo cáo mẹ đến báo cáo con.

  • Các phần tử ( connectionExpression và dataSourceExpression ) không thể có mặt đồng thời trong khai báo phần tử <subreport>. Điều này là do chúng tôi không thể cung cấp cả nguồn dữ liệu và kết nối đến báo cáo phụ. Chúng ta phải quyết định một trong số chúng và bám sát nó.

  • <returnValue> - Điều này được sử dụng để gán giá trị của một trong các biến của báo cáo phụ cho một trong các biến của báo cáo chính. Phần tử phụ này có các thuộc tính như sau:

    • subreportVariable - Thuộc tính này chỉ định tên của biến báo cáo con có giá trị được trả về.

    • toVariable - Thuộc tính này chỉ định tên của biến báo cáo mẹ có giá trị được sao chép / tăng lên với giá trị từ báo cáo con.

    • tính toán - Thuộc tính này có thể nhận các giá trị: Không có gì, Đếm, Số lượng riêng biệt, Tổng, Trung bình, Thấp nhất, Cao nhất, Độ lệch chuẩn, Phương sai. Giá trị mặc định để tính toán thuộc tính là "Không có gì".

    • incrementerFactoryClass - Thuộc tính này chỉ định lớp nhà máy để tạo phiên bản incrementer.

  • <subreportExpression> - Điều này cho biết nơi tìm mẫu báo cáo đã biên dịch cho báo cáo con. Phần tử này có mộtclassthuộc tính. Các lớp thuộc tính có thể thực hiện bất kỳ những giá trị này: java.lang.String, java.io.File, java.net.URL, java.io.InputStream, net.sf.jasperreports.engine.JasperReport. Giá trị mặc định là java.lang.String .

  • isUsingCache - Đây là một thuộc tính của phần tử <subreport>. Đây là Boolean, khi được đặt thành true , công cụ báo cáo sẽ cố gắng nhận ra các đối tượng mẫu báo cáo con đã tải trước đó, sử dụng nguồn được chỉ định của chúng. Chức năng bộ nhớ đệm này chỉ khả dụng cho các phần tử báo cáo phụ có biểu thức trả về đối tượng java.lang.String làm nguồn mẫu báo cáo phụ, đại diện cho tên tệp, URL hoặc tài nguyên classpath.

Thí dụ

Hãy lấy một ví dụ đơn giản để chứng minh việc tạo các báo cáo con bằng JRDataSource. Đầu tiên chúng ta hãy viết hai mẫu báo cáo mới, một là báo cáo phụ và một là báo cáo Chính. Nội dung của mẫu báo cáo phụ (address_report_template.jrxml) như được cung cấp bên dưới. Lưu nó vào thư mục C: \ tools \ jasperreports-5.0.1 \ test.

<?xml version = "1.0" encoding = "UTF-8"?>
<jasperReport
   xmlns = "http://jasperreports.sourceforge.net/jasperreports"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://jasperreports.sourceforge.net/jasperreports
   http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
   name = "address_report_template" pageWidth = "175" pageHeight = "842" 
   columnWidth = "175" leftMargin = "0" rightMargin = "0" 
   topMargin = "0" bottomMargin = "0">

   <field name = "city" class = "java.lang.String"/>
   <field name = "street" class = "java.lang.String"/>
   
   <background>
      <band splitType = "Stretch"/>
   </background>
   
   <title>
      <band height = "20" splitType = "Stretch">
         
         <staticText>
            <reportElement x = "0" y = "0" width = "100" height = "20"/>
            
            <textElement>
               <font size = "14" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Addresses]]></text>
         </staticText>
      
      </band>
   </title>
   
   <pageHeader>
      <band height = "12" splitType = "Stretch"/>
   </pageHeader>
   
   <columnHeader>
      <band height = "12" splitType = "Stretch"/>
   </columnHeader>
   
   <detail>
      <band height = "27" splitType = "Stretch">
         
         <textField>
            <reportElement x = "0" y = "0" width = "120" height = "20"/>
            
            <textElement>
               <font size = "12" isBold = "true"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{city}+" Address:"]]>
            </textFieldExpression>
         </textField>
         
         <textField isStretchWithOverflow = "true">
            <reportElement x = "120" y = "0" width = "435" height = "20"/>
            
            <textElement>
               <font size = "12"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{street}]]>
            </textFieldExpression>
         </textField>
      
      </band>
   </detail>
   
   <columnFooter>
      <band height = "8" splitType = "Stretch"/>
   </columnFooter>
  
   <pageFooter>
      <band height = "11" splitType = "Stretch"/>
   </pageFooter>
   
   <summary>
      <band height = "9" splitType = "Stretch"/>
   </summary>

</jasperReport>

Khi chúng tôi sử dụng một nguồn dữ liệu, chúng tôi cần viết một tệp POJO tương ứng SubReportBean.java như hình bên dưới. Lưu nó vào thư mục C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint -

package com.tutorialspoint;

public class SubReportBean {
   private String city;
   private String street;

   public String getCity() {
      return city;
   }

   public void setCity(String city) {
      this.city = city;
   }

   public String getStreet() {
      return street;
   }

   public void setStreet(String street) {
      this.street = street;
   }
}

Ở đây, chúng tôi đã khai báo hai trường 'thành phố''đường phố' và các phương thức getter và setter tương ứng được xác định.

Bây giờ, hãy cập nhật DataBeantập tin. Chúng tôi sẽ thêm một trường subReportBeanList mới , đó là java.util.List. Trường này sẽ chứa danh sách các đối tượng SubReportBean. Nội dung của tệp DataBean như bên dưới. Lưu nó vào thư mục C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint.

package com.tutorialspoint;

import java.util.List;

public class DataBean {
   private String name;
   private String country;
   private List<SubReportBean> subReportBeanList;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public String getCountry() {
      return country;
   }

   public void setCountry(String country) {
      this.country = country;
   }

   public List<SubReportBean> getSubReportBeanList() {
      return subReportBeanList;
   }

   public void setSubReportBeanList(List<SubReportBean> subReportBeanList) {
      this.subReportBeanList = subReportBeanList;
   }
}

Bây giờ chúng ta hãy cập nhật tệp C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \DataBeanList.java. Nội dung của tệp này là:

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DataBeanList {
   public ArrayList<DataBean> getDataBeanList() {

      // Create sub report data
      SubReportBean subBean1 = new SubReportBean();
      subBean1.setCity("Mumbai");
      subBean1.setStreet("M.G.Road");
      SubReportBean subBean2 = new SubReportBean();
      subBean2.setCity("New York");
      subBean2.setStreet("Park Street");
      SubReportBean subBean3 = new SubReportBean();
      subBean3.setCity("San Fransisco");
      subBean3.setStreet("King Street");

      ArrayList<DataBean> dataBeanList = new ArrayList<DataBean>();

      // Create master report data
      dataBeanList.add(produce("Manisha", "India",
         Arrays.asList(subBean1)));
      dataBeanList.add(produce("Dennis Ritchie", "USA",
         Arrays.asList(subBean2)));
      dataBeanList.add(produce("V.Anand", "India",
         Arrays.asList(subBean1)));
      dataBeanList.add(produce("Shrinath", "California",
         Arrays.asList(subBean3)));

      return dataBeanList;
   }

   /*
    * This method returns a DataBean object,
    * with name, country and sub report
    * bean data set in it.
    */
   private DataBean produce(String name, String country,
      List<SubReportBean> subBean) {
      DataBean dataBean = new DataBean();

      dataBean.setName(name);
      dataBean.setCountry(country);
      dataBean.setSubReportBeanList(subBean);

      return dataBean;
   }
}

Trong phương thức production () trong tệp trên, chúng ta đang thiết lập danh sách SubReportBean.

Bây giờ, hãy viết một mẫu báo cáo chính mới (jasper_report_template.jrxml). Lưu tệp này vào thư mụcC:\tools\jasperreports-5.0.1\test. Nội dung của tệp này như dưới đây:

<?xml version = "1.0" encoding = "UTF-8"?>
<jasperReport xmlns = "http://jasperreports.sourceforge.net/jasperreports"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://jasperreports.sourceforge.net/jasperreports
   http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
   name = "jasper_report_template" language = "groovy" pageWidth = "595"
   pageHeight = "842" columnWidth ="555" leftMargin = "20" rightMargin = "20"
   topMargin = "20" bottomMargin = "20">

   <parameter name = "SUBREPORT_DIR" class = "java.lang.String" isForPrompting = "false">
      <defaultValueExpression>
         <![CDATA["C:\\tools\\jasperreports-5.0.1\\test\\"]]>
      </defaultValueExpression>
   </parameter>
   
   <field name = "country" class = "java.lang.String"/>
   <field name = "name" class = "java.lang.String"/>
   <field name = "subReportBeanList" class = "java.util.List"/>
   
   <background>
      <band splitType = "Stretch"/>
   </background>
   
   <title>
      <band height = "35" splitType = "Stretch">
         
         <staticText>
            <reportElement x = "0" y = "0" width = "204" height = "34"/>
            
            <textElement>
               <font size = "26" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Contact Report]]></text>
         </staticText>
      
      </band>
   </title>
   
   <pageHeader>
      <band height = "17" splitType = "Stretch"/>
   </pageHeader>
   
   <columnHeader>
      <band height = "21" splitType = "Stretch"/>
   </columnHeader>
   
   <detail>
      <band height = "112" splitType = "Stretch">
            
         <staticText>
            <reportElement x = "0" y = "0" width = "100" height = "20"/>
            
            <textElement>
               <font size = "12" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Name:]]></text>
         </staticText>
         
         <staticText>
            <reportElement x = "0" y = "20" width = "100" height = "20"/>
            
            <textElement>
               <font size = "12" isBold = "true"/>
            </textElement>
				
            <text><![CDATA[Country:]]></text>
         </staticText>
         
         <textField>
            <reportElement x = "104" y = "0" width = "277" height = "20"/>
            
            <textElement>
               <font size = "12"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{name}]]>
            </textFieldExpression>
         </textField>
         
         <textField>
            <reportElement x = "104" y = "20" width = "277" height = "20"/>
            
            <textElement>
               <font size = "12"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{country}]]>
            </textFieldExpression>
         </textField>
         
         <subreport>
            <reportElement positionType = "Float" x = "335" y = "25" width = "175"
               height = "20" isRemoveLineWhenBlank = "true" backcolor = "#99ccff"/>

            <dataSourceExpression>
               new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
                  ($F{subReportBeanList})
            </dataSourceExpression>
            
            <subreportExpression class = "java.lang.String">
               <![CDATA[$P{SUBREPORT_DIR} + "address_report_template.jasper"]]>
            </subreportExpression>
         </subreport>
         
         <line>
            <reportElement x = "0" y = "50" width = "550" height = "1"/>
         </line>
      
      </band>
   </detail>
   
   <columnFooter>
      <band height = "19" splitType = "Stretch"/>
   </columnFooter>
   
   <pageFooter>
      <band height = "18" splitType = "Stretch"/>
   </pageFooter>
   
   <summary>
      <band height = "14" splitType = "Stretch"/>
   </summary>

</jasperReport>

Trong mẫu trên, chúng tôi đã xác định một tham số mới "SUBREPORT_DIR", xác định đường dẫn của báo cáo phụ. Chúng tôi đã xác định một trường subReportBeanList kiểu java.util.List, tương ứng với thuộc tính trong tệp DataBean. Phần tử <subreport> có phần tử con <dataSourceExpression>. Chúng tôi đã đặt danh sách subReportBeanList trong một phiên bản của JRBeanCollectionDataSource. Trong phần tử con <subreportExpression />, chúng tôi đã đặt tên báo cáo con (AddressReport.jasper).

Bây giờ, chúng ta hãy viết một lớp mới CreateReportđể biên dịch và thực thi mẫu báo cáo của chúng tôi. Nội dung của tệpC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\CreateReport.java như được đưa ra dưới đây -

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class CreateReport {

   public static void main(String[] args) {
      String masterReportFileName = "C://tools/jasperreports-5.0.1/test"
         + "/jasper_report_template.jrxml";
      String subReportFileName = "C://tools/jasperreports-5.0.1/test"
         + "/AddressReport.jrxml";
      String destFileName = "C://tools/jasperreports-5.0.1/test"
         + "/jasper_report_template.JRprint";
			
      DataBeanList DataBeanList = new DataBeanList();
      ArrayList<DataBean> dataList = DataBeanList.getDataBeanList();
      JRBeanCollectionDataSource beanColDataSource = new 
         JRBeanCollectionDataSource(dataList);

      try {
         /* Compile the master and sub report */
         JasperReport jasperMasterReport = JasperCompileManager
            .compileReport(masterReportFileName);
         JasperReport jasperSubReport = JasperCompileManager
            .compileReport(subReportFileName);

         Map<String, Object> parameters = new HashMap<String, Object>();
         parameters.put("subreportParameter", jasperSubReport);
         JasperFillManager.fillReportToFile(jasperMasterReport, 
            destFileName, parameters, beanColDataSource);

      } catch (JRException e) {

         e.printStackTrace();
      }
      System.out.println("Done filling!!! ...");
   }
}

Ở đây, chúng tôi thấy rằng chúng tôi đang biên dịch cả mẫu báo cáo chính và phụ và chuyển tệp báo cáo chính (.jasper) để điền báo cáo.

Tạo báo cáo

Bây giờ, tất cả các tệp của chúng tôi đã sẵn sàng, hãy biên dịch và thực thi chúng bằng quy trình xây dựng ANT thông thường của chúng tôi. Nội dung của tệp build.xml (được lưu trong thư mục C: \ tools \ jasperreports-5.0.1 \ test) như dưới đây.

Tệp nhập - baseBuild.xml được chọn từ chương Thiết lập môi trường và phải được đặt trong cùng thư mục với build.xml.

<?xml version = "1.0" encoding = "UTF-8"?>
<project name = "JasperReportTest" default = "viewFillReport" basedir = ".">
   <import file = "baseBuild.xml" />
   
   <target name = "viewFillReport" depends = "compile,compilereportdesing,run"
      description = "Launches the report viewer to preview the 
      report stored in the .JRprint file.">
      
      <java classname = "net.sf.jasperreports.view.JasperViewer" fork = "true">
         <arg value = "-F${file.name}.JRprint" />
         <classpath refid = "classpath" />
      </java>
   </target>
   
   <target name = "compilereportdesing" description = "Compiles the JXML file and
      produces the .jasper file.">
      
      <taskdef name = "jrc" classname = "net.sf.jasperreports.ant.JRAntCompileTask">
         <classpath refid = "classpath" />
      </taskdef>
      
      <jrc destdir = ".">
         <src>
            <fileset dir = ".">
               <include name = "*.jrxml" />
            </fileset>
         </src>
         <classpath refid = "classpath" />
      </jrc>
		
   </target>

</project>

Tiếp theo, hãy mở cửa sổ dòng lệnh và đi đến thư mục nơi build.xml được đặt. Cuối cùng, thực hiện lệnhant -Dmain-class=com.tutorialspoint.CreateReport (viewFullReport là mục tiêu mặc định) như sau:

Buildfile: C:\tools\jasperreports-5.0.1\test\build.xml

clean-sample:
   [delete] Deleting directory C:\tools\jasperreports-5.0.1\test\classes

compile:
   [mkdir] Created dir: C:\tools\jasperreports-5.0.1\test\classes
   [javac] C:\tools\jasperreports-5.0.1\test\baseBuild.xml:28: 
      warning: 'includeantruntime' was not set, defaulting to
   [javac] Compiling 7 source files to C:\tools\jasperreports-5.0.1\test\classes

compilereportdesing:
   [jrc] Compiling 1 report design files.
   [jrc] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
   [jrc] log4j:WARN Please initialize the log4j system properly.
   [jrc] log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig 
      for more info.
   [jrc] File : C:\tools\jasperreports-5.0.1\test\
      jasper_report_template.jrxml ... OK.

run:
   [echo] Runnin class : com.tutorialspoint.CreateReport
   [java] Compiling Report Design ...
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory).
   [java] log4j:WARN Please initialize the log4j system properly.
   [java] Done filling!!! ...

viewFillReport:
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.extensions.ExtensionsEnvironment).
   [java] log4j:WARN Please initialize the log4j system properly.

BUILD SUCCESSFUL
Total time: 72 minutes 13 seconds

Kết quả của quá trình biên dịch ở trên, một cửa sổ JasperViewer mở ra như được hiển thị trong màn hình dưới đây:

Tại đây, chúng ta có thể thấy rằng các thuộc tính Tên, Quốc gia và Địa chỉ được hiển thị.