Utwórz SubReports

Podraporty są jedną z fajnych funkcji JasperReports. Ta funkcja umożliwia włączenie raportu do innego raportu, to znaczy jeden raport może być podraportem innego. Podraporty pomagają nam zachować prostotę projektów raportów, ponieważ możemy tworzyć wiele prostych raportów i umieszczać je w raporcie głównym. Podraporty są kompilowane i wypełniane tak jak zwykłe raporty. Każdy szablon raportu może zostać użyty jako podraport po włączeniu do innego szablonu raportu, bez żadnych zmian w środku (w szablonie raportu).

Podraporty przypominają zwykłe szablony raportów. W rzeczywistości są to obiekty net.sf.jasperreports.engine.JasperReport , które uzyskuje się po skompilowaniu obiektu net.sf.jasperreports.engine.design.JasperDesign .

<subreport> Element

Element <subreport> jest używany podczas wprowadzania podraportów do raportów głównych. Oto lista elementów podrzędnych w elemencie <subreport> JRXML.

  • <reportElement>

  • <parametersMapExpression> - służy do przekazywania mapy zawierającej parametry raportu do podraportu. Mapa jest zwykle uzyskiwana z parametru w raporcie głównym lub przy użyciu wbudowanego parametru REPORTS_PARAMETERS_MAP w celu przekazania parametrów raportu nadrzędnego do podraportu. To wyrażenie powinno zawsze zwracać obiekt java.util.Map, w którym klucze są nazwami parametrów.

  • <subreportParameter> - ten element służy do przekazywania parametrów do podraportu. Ma nazwę atrybutu , która jest obowiązkowa.

  • <connectionExpression> - służy do przekazywania połączenia java.sql.Connection do podraportu. Jest używany tylko wtedy, gdy szablon podraportu wymaga połączenia z bazą danych podczas fazy wypełniania raportu.

  • <dataSourceExpression> - służy do przekazywania źródła danych do podraportu. To źródło danych jest zwykle uzyskiwane z parametru w raporcie głównym lub przy użyciu wbudowanego parametru REPORT_DATA_SOURCE w celu przekazania źródła danych raportu nadrzędnego do podraportu.

  • Elementy ( connectionExpression i dataSourceExpression ) nie mogą znajdować się w tym samym czasie w deklaracji elementu <subreport>. Dzieje się tak, ponieważ nie możemy dostarczyć zarówno źródła danych, jak i połączenia z podraportem. Musimy zdecydować się na jedną z nich i się jej trzymać.

  • <returnValue> - służy do przypisywania wartości jednej ze zmiennych podraportu do jednej ze zmiennych raportu głównego. Ten element podrzędny ma następujące atrybuty -

    • subreportVariable - ten atrybut określa nazwę zmiennej podraportu, której wartość ma zostać zwrócona.

    • toVariable - ten atrybut określa nazwę nadrzędnej zmiennej raportu, której wartość ma zostać skopiowana / zwiększona o wartość z podraportu.

    • obliczenia - ten atrybut może przyjmować wartości: Nothing, Count, DistinctCount, Sum, Average, Lowest, Highest, StandardDeviation, Variance. Wartość domyślna do obliczania atrybutów to „Nic”.

    • IncrementerFactoryClass - ten atrybut określa klasę fabryki do tworzenia instancji jednostki zwiększającej.

  • <subreportExpression> - wskazuje, gdzie znaleźć skompilowany szablon raportu dla podraportu. Ten element ma rozszerzenieclassatrybut. Klasa atrybut może mieć żadnej z tych wartości: java.lang.String, java.io.File, java.net.URL, java.io.InputStream, net.sf.jasperreports.engine.JasperReport. Wartość domyślna to java.lang.String .

  • isUsingCache - jest to atrybut elementu <subreport>. Jest to wartość logiczna, po ustawieniu wartości true silnik raportowania będzie próbował rozpoznać wcześniej załadowane obiekty szablonu podraportu, korzystając z określonego źródła. Ta funkcja buforowania jest dostępna tylko dla elementów podraportu, które mają wyrażenia zwracające obiekty java.lang.String jako źródło szablonu podraportu, reprezentujące nazwy plików, adresy URL lub zasoby ścieżki klas.

Przykład

Weźmy prosty przykład, aby zademonstrować tworzenie podraportów przy użyciu JRDataSource. Najpierw napiszmy dwa nowe szablony raportów, jeden jest podraportem, a drugi raportem głównym. Zawartość szablonu podraportu (address_report_template.jrxml) jest taka, jak podano poniżej. Zapisz go w katalogu 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>

Ponieważ korzystamy ze źródła danych, musimy napisać odpowiedni plik POJO SubReportBean.java jak pokazano niżej. Zapisz go w katalogu 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;
   }
}

Tutaj zadeklarowaliśmy dwa pola „miasto” i „ulica” oraz zdefiniowano odpowiednie metody pobierające i ustawiające.

Teraz zaktualizujmy nasze istniejące DataBeanplik. Dodamy nowe pole subReportBeanList , które będzie java.util.List. W tym polu będzie przechowywana lista obiektów SubReportBean. Zawartość pliku DataBean jest następująca. Zapisz go w katalogu 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;
   }
}

Zaktualizujmy teraz plik C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \DataBeanList.java. Zawartość tego pliku jest następująca:

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

W metodzie create () w powyższym pliku ustawiamy listę SubReportBean.

Teraz napiszmy nowy szablon raportu głównego (jasper_report_template.jrxml). Zapisz ten plik w kataloguC:\tools\jasperreports-5.0.1\test. Zawartość tego pliku jest następująca -

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

W powyższym szablonie zdefiniowaliśmy nowy parametr „SUBREPORT_DIR”, który określa ścieżkę podraportu. Zdefiniowaliśmy pole subReportBeanList typu java.util.List, które odpowiada właściwości w pliku DataBean. Element <subreport> ma element podrzędny <dataSourceExpression>. Umieściliśmy listę subReportBeanList w instancji JRBeanCollectionDataSource. W elemencie podrzędnym <subreportExpression /> podaliśmy nazwę podraportu (AddressReport.jasper).

Teraz napiszmy nową klasę CreateReportaby skompilować i wykonać nasz szablon raportu. Zawartość plikuC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\CreateReport.java są jak podano poniżej -

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!!! ...");
   }
}

Tutaj widzimy, że kompilujemy zarówno szablon raportu głównego, jak i podrzędnego i przekazujemy plik raportu głównego (.jasper) do wypełnienia raportu.

Generowanie raportów

Teraz wszystkie nasze pliki są gotowe, skompilujmy je i uruchommy przy użyciu naszego zwykłego procesu kompilacji ANT. Zawartość pliku build.xml (zapisanego w katalogu C: \ tools \ jasperreports-5.0.1 \ test) jest taka, jak podano poniżej.

Plik importu - baseBuild.xml jest pobierany z rozdziału Konfiguracja środowiska i powinien być umieszczony w tym samym katalogu, co plik 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>

Następnie otwórzmy okno wiersza poleceń i przejdźmy do katalogu, w którym znajduje się plik build.xml. Na koniec wykonaj polecenieant -Dmain-class=com.tutorialspoint.CreateReport (viewFullReport jest domyślnym celem) w następujący sposób -

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

W wyniku powyższej kompilacji otworzy się okno JasperViewer, jak pokazano na poniższym ekranie -

Tutaj widzimy, że wyświetlane są atrybuty Nazwa, Kraj i Adres.