Report Scriptlets

Wir haben in unseren vorherigen Kapiteln gesehen, dass die im Bericht angezeigten Daten normalerweise aus Berichtsparametern und Berichtsfeldern abgerufen werden. Diese Daten können mit den Berichtsvariablen und ihren Ausdrücken verarbeitet werden. Es gibt Situationen, in denen eine komplexe Funktionalität mit Berichtsausdrücken oder -variablen nicht einfach erreicht werden kann. Beispiele hierfür können komplexe String-Manipulationen, das Erstellen von Karten oder Listen von Objekten im Speicher oder Manipulationen von Daten mithilfe von Java-APIs von Drittanbietern sein. In solchen Situationen bietet uns JasperReports eine einfache und leistungsstarke Möglichkeit, dies zu tunScriptlets.

Scriptlets sind Sequenzen von Java-Code, die jedes Mal ausgeführt werden, wenn ein Berichtsereignis auftritt. Die Werte von Berichtsvariablen können durch Scriptlets beeinflusst werden.

Scriptlet-Erklärung

Wir können ein Scriptlet auf zwei Arten deklarieren:

  • Verwenden von <scriptlet> Element. Dieses Element hat Namen Attribut und Klasse - Attribut. Das Klassenattribut sollte den Namen der Klasse angeben, wodurch die JRAbstractScriptlet- Klasse erweitert wird. Die Klasse muss zum Zeitpunkt der Berichterfüllung im Klassenpfad verfügbar sein und über einen leeren Konstruktor verfügen, damit die Engine sie sofort instanziieren kann.

  • Verwenden des Attributs scriptletClass des Elements <jasperReport> in der Berichtsvorlage (JRXML). Durch Festlegen dieses Attributs mit dem vollständig qualifizierten Namen des Scriptlets (einschließlich des gesamten Paketnamens) geben wir an, dass wir ein Scriptlet verwenden möchten. Die mit diesem Attribut erstellte Scriptlet-Instanz verhält sich wie das erste Scriptlet in der Liste der Scriptlets und hat den vordefinierten Namen REPORT.

Scriptlet-Klasse

Ein Scriptlet ist eine Java-Klasse, die eine der folgenden Klassen erweitern muss:

  • net.sf.jasperreports.engine.JRAbstractScriptlet- Diese Klasse enthält eine Reihe abstrakter Methoden, die in jeder Implementierung überschrieben werden müssen. Diese Methoden werden von JasperReports zum richtigen Zeitpunkt automatisch aufgerufen. Der Entwickler muss alle abstrakten Methoden implementieren.

  • net.sf.jasperreports.engine.JRDefaultScriptlet- Diese Klasse enthält leere Standardimplementierungen aller Methoden in JRAbstractScriptlet. Ein Entwickler muss nur die Methoden implementieren, die er für sein Projekt benötigt.

In der folgenden Tabelle sind die Methoden in der obigen Klasse aufgeführt. Diese Methoden werden von der Berichts-Engine zu gegebener Zeit während der Berichtsfüllphase aufgerufen.

S.NO. Methode und Beschreibung
1

public void beforeReportInit()

Wird vor der Berichtsinitialisierung aufgerufen.

2

public void afterReportInit()

Wird nach der Berichtsinitialisierung aufgerufen.

3

public void beforePageInit()

Wird aufgerufen, bevor jede Seite initialisiert wird.

4

public void afterPageInit()

Wird aufgerufen, nachdem jede Seite initialisiert wurde.

5

public void beforeColumnInit()

Wird aufgerufen, bevor jede Spalte initialisiert wird.

6

public void afterColumnInit()

Wird aufgerufen, nachdem jede Spalte initialisiert wurde.

7

public void beforeGroupInit(String groupName)

Wird aufgerufen, bevor die im Parameter angegebene Gruppe initialisiert wird.

8

public void afterGroupInit(String groupName)

Wird aufgerufen, nachdem die im Parameter angegebene Gruppe initialisiert wurde.

9

public void beforeDetailEval()

Wird aufgerufen, bevor jeder Datensatz im Detailabschnitt des Berichts ausgewertet wird.

10

public void afterDetailEval()

Wird aufgerufen, nachdem jeder Datensatz im Detailabschnitt des Berichts ausgewertet wurde.

Pro Bericht können beliebig viele Scriptlets angegeben werden. Wenn für einen Bericht kein Scriptlet angegeben ist, erstellt die Engine weiterhin eine einzelne JRDefaultScriptlet-Instanz und registriert sie mit dem integrierten Parameter REPORT_SCRIPTLET.

Wir können unseren Scriptlets alle zusätzlichen Methoden hinzufügen, die wir benötigen. Berichte können diese Methoden mithilfe des integrierten Parameters REPORT_SCRIPTLET aufrufen.

Globale Scriptlets

Wir können Scriptlets auf andere Weise mit Berichten verknüpfen, indem wir die Scriptlets global deklarieren. Dadurch gelten die Scriptlets für alle Berichte, die in der angegebenen JasperReports-Bereitstellung ausgefüllt werden. Dies wird durch die Tatsache erleichtert, dass Scriptlets als Erweiterungen zu JasperReports hinzugefügt werden können. Der Scriptlet-Erweiterungspunkt wird durch die Schnittstelle net.sf.jasperreports.engine.scriptlets.ScriptletFactory dargestellt . JasperReports lädt zur Laufzeit alle über Erweiterungen verfügbaren Scriptlet-Fabriken. Anschließend wird jeder von ihnen nach der Liste der Scriptlet-Instanzen gefragt, die er auf den aktuellen Bericht anwenden möchte, der ausgeführt wird. Wenn Sie nach der Liste der Scriptlet-Instanzen fragen, gibt die Engine einige Kontextinformationen an, anhand derer die Factory entscheiden kann, welche Scriptlets tatsächlich für den aktuellen Bericht gelten.

Bericht Gouverneure

Governors sind nur eine Erweiterung globaler Scriptlets, mit denen wir das Problem lösen können, dass die Berichts-Engine zur Laufzeit in die Endlosschleife eintritt, während Berichte erstellt werden. Ungültige Berichtsvorlagen können zur Entwurfszeit nicht erkannt werden, da die Bedingungen für die Eingabe der Endlosschleifen meistens von den tatsächlichen Daten abhängen, die zur Laufzeit in die Engine eingespeist werden. Berichtsgouverneure helfen bei der Entscheidung, ob ein bestimmter Bericht in eine Endlosschleife eingetreten ist, und können ihn stoppen. Dies verhindert die Erschöpfung der Ressourcen für den Computer, auf dem der Bericht ausgeführt wird.

JasperReports verfügt über zwei einfache Berichts-Governors, die eine Berichtsausführung basierend auf einer festgelegten maximalen Seitenzahl oder einem bestimmten Zeitlimit stoppen. Sie sind -

  • net.sf.jasperreports.governors.MaxPagesGovernor- Dies ist ein globales Scriptlet, das nach zwei Konfigurationseigenschaften sucht, um zu entscheiden, ob es für den aktuell ausgeführten Bericht gilt oder nicht. Die Konfigurationseigenschaften sind -

    • net.sf.jasperreports.governor.max.pages.enabled=[true|false]

    • net.sf.jasperreports.governor.max.pages=[integer]

  • net.sf.jasperreports.governors.TimeoutGovernor- Dies ist auch ein globales Scriptlet, das nach den folgenden zwei Konfigurationseigenschaften sucht, um zu entscheiden, ob sie zutreffen oder nicht.

    Die Konfigurationseigenschaften sind -

    • net.sf.jasperreports.governor.timeout.enabled=[true|false]

    • net.sf.jasperreports.governor.timeout=[milliseconds]

Die Eigenschaften für beide Regler können global, in der Datei jasperreports.properties oder auf Berichtsebene als benutzerdefinierte Berichtseigenschaften festgelegt werden. Dies ist nützlich, da verschiedene Berichte unterschiedliche geschätzte Größen- oder Zeitlimits haben können und Sie möglicherweise auch die Regler für alle Berichte aktivieren möchten, während Sie sie für einige Berichte deaktivieren möchten oder umgekehrt.

Beispiel

Schreiben wir eine Scriptlet-Klasse (MyScriptlet). Der Inhalt der Datei C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ MyScriptlet.java lautet wie folgt:

package com.tutorialspoint;

import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;


public class MyScriptlet extends JRDefaultScriptlet {

   public void afterReportInit() throws JRScriptletException{
      System.out.println("call afterReportInit()");
      // this.setVariableValue("AllCountries", sbuffer.toString());
      this.setVariableValue("someVar", new String("This variable value 
         was modified by the scriptlet."));
   }

   public String hello() throws JRScriptletException {
      return "Hello! I'm the report's scriptlet object.";
   }

}

Details der obigen Scriptlet-Klasse sind wie folgt:

  • In der afterReportInit- Methode setzen wir einen Wert für die Variable"someVar" this.setVariableValue ("someVar", neuer String ("Dieser Variablenwert wurde vom Scriptlet geändert.")).

  • Am Ende der Klasse wird eine zusätzliche Methode aufgerufen 'hello'Wurde definiert. Dies ist ein Beispiel für eine Methode, die dem Scriptlet hinzugefügt werden kann und tatsächlich einen Wert zurückgibt, anstatt eine Variable festzulegen.

Als Nächstes fügen wir die Skriptklassenreferenz in unsere vorhandene Berichtsvorlage ein (Kapitel Berichtsentwürfe ). Die überarbeitete Berichtsvorlage (jasper_report_template.jrxml) lautet wie folgt. Speichern Sie es im Verzeichnis C: \ tools \ jasperreports-5.0.1 \ test -

<?xml version = "1.0"?>
<!DOCTYPE jasperReport PUBLIC
   "//JasperReports//DTD Report Design//EN"
   "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<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" pageWidth = "595"
   pageHeight = "842" columnWidth = "515"
   leftMargin = "40" rightMargin = "40" topMargin = "50" bottomMargin = "50"
   scriptletClass = "com.tutorialspoint.MyScriptlet">
	
   <style name = "alternateStyle" fontName = "Arial" forecolor = "red">
      
      <conditionalStyle>
         <conditionExpression>
            <![CDATA[new Boolean($V{countNumber}.intValue() % 2 == 0)]]>
         </conditionExpression>
			
         <style forecolor = "blue" isBold = "true"/>
      </conditionalStyle>
   </style>
   
   <parameter name = "ReportTitle" class = "java.lang.String"/>
   <parameter name = "Author" class = "java.lang.String"/>

   <queryString>
      <![CDATA[]]>
   </queryString>

   <field name = "country" class = "java.lang.String">
      <fieldDescription>
         <![CDATA[country]]>
      </fieldDescription>
   </field>

   <field name = "name" class = "java.lang.String">
      <fieldDescription>
         <![CDATA[name]]>
      </fieldDescription>
   </field>

   <variable name = "countNumber" class = "java.lang.Integer" 
      calculation = "Count">
      <variableExpression><
         ![CDATA[Boolean.TRUE]]>
      </variableExpression>
   </variable>

   <variable name = "someVar" class = "java.lang.String">
      <initialValueExpression>
        <![CDATA["This is the initial variable value."]]>
      </initialValueExpression>
   </variable>

   <title>
      <band height = "100">
         
         <line>
            <reportElement x = "0" y = "0" width = "515" height = "1"/>
         </line>
         
         <textField isBlankWhenNull = "true" bookmarkLevel = "1">
            <reportElement x = "0" y = "10" width = "515" height = "30"/>
            
            <textElement textAlignment = "Center">
              <font size = "22"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
              <![CDATA[$P{ReportTitle}]]>
            </textFieldExpression>
				
            <anchorNameExpression>
               <![CDATA["Title"]]>
            </anchorNameExpression>
         </textField>
        
         <textField isBlankWhenNull = "true">
            <reportElement  x = "0" y = "40" width = "515" height = "20"/>
            
            <textElement textAlignment = "Center">
               <font size = "10"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{Author}]]>
            </textFieldExpression>
         </textField>
         
         <textField isBlankWhenNull = "true">
            <reportElement  x = "0" y = "50" width = "515" 
               height = "30" forecolor = "#993300"/>
             
            <textElement textAlignment = "Center">
               <font size = "10"/>
            </textElement>
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$V{someVar}]]>
            </textFieldExpression>
				
         </textField>

      </band>
   </title>

   <columnHeader>
      <band height = "23">
         
         <staticText>
            <reportElement mode = "Opaque" x = "0" y = "3" 
               width = "535" height = "15"
               backcolor = "#70A9A9" />
            
            <box>
               <bottomPen lineWidth = "1.0" lineColor = "#CCCCCC" />
            </box>
				
            <textElement />
				
            <text>
               <![CDATA[]]>
            </text>
				
         </staticText>
         
         <staticText>
            <reportElement x = "414" y = "3" width = "121" height = "15" />
                
            <textElement textAlignment = "Center" verticalAlignment = "Middle">
               <font isBold = "true" />
            </textElement>
            
            <text><![CDATA[Country]]></text>
         </staticText>
         
         <staticText>
            <reportElement x = "0" y = "3" width = "136" height = "15" />
            
            <textElement textAlignment = "Center" verticalAlignment = "Middle">
               <font isBold = "true" />
            </textElement>
				
            <text><![CDATA[Name]]></text>
         </staticText>
      
      </band>
   </columnHeader>

   <detail>
      <band height = "16">
         
         <staticText>
            <reportElement mode = "Opaque" x = "0" y = "0" 
               width = "535"	height = "14"
               backcolor = "#E5ECF9" />
            
            <box>
               <bottomPen lineWidth = "0.25" lineColor = "#CCCCCC" />
            </box>
				
            <textElement />
				
            <text>
               <![CDATA[]]>
            </text>
         </staticText>
         
         <textField>
            <reportElement style = "alternateStyle" x="414" y = "0" 
               width = "121" height = "15" />
            
            <textElement textAlignment = "Center" verticalAlignment = "Middle">
               <font size = "9" />
            </textElement>
            
				
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{country}]]>
            </textFieldExpression>
         </textField>
         
         <textField>
            <reportElement x = "0" y = "0" width = "136" height = "15" />
            <textElement textAlignment = "Center" verticalAlignment = "Middle" />
            
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$F{name}]]>
            </textFieldExpression>
         </textField>
      
      </band>
   </detail>
   
   <summary>
      <band height = "45">
            
         <textField isStretchWithOverflow = "true">
            <reportElement x = "0" y = "10" width = "515" height = "15" />
            <textElement textAlignment = "Center"/>
               
            <textFieldExpression class = "java.lang.String">
               <![CDATA["There are " + String.valueOf($V{REPORT_COUNT}) +
                  " records on this report."]]>
            </textFieldExpression>
         </textField>
         
         <textField isStretchWithOverflow = "true">
            <reportElement positionType = "Float" x = "0" y = "30" width = "515"
               height = "15" forecolor = "# 993300" />
               
            <textElement textAlignment = "Center">
               <font size = "10"/>
            </textElement>
               
            <textFieldExpression class = "java.lang.String">
               <![CDATA[$P{REPORT_SCRIPTLET}.hello()]]>
            </textFieldExpression>
            
         </textField>
         
      </band>
   </summary>
	
</jasperReport>

Die Details der überarbeiteten Berichtsvorlage sind unten angegeben -

  • Wir haben auf die MyScriptlet-Klasse im Attribut scriptletClass des Elements <jasperReport> verwiesen.

  • Scriptlets können nur auf die Berichtsfelder und -parameter zugreifen, diese jedoch nicht ändern. Scriptlets können jedoch Berichtsvariablenwerte ändern. Dies kann durch Aufrufen der setVariableValue () -Methode erreicht werden. Diese Methode ist in der JRAbstractScriptlet-Klasse definiert, die immer die übergeordnete Klasse eines Scriptlets ist. Hier haben wir eine Variable someVar definiert , die vom MyScriptlet so geändert wird, dass sie den Wert hat. Dieser Wert wurde vom Scriptlet geändert .

  • Die obige Berichtsvorlage enthält einen Methodenaufruf im Zusammenfassungsbereich, der veranschaulicht, wie neue Methoden (in Scriptlets) geschrieben und in der Berichtsvorlage verwendet werden. (($P{REPORT_SCRIPTLET}.hello())

Die Java-Codes für das Ausfüllen von Berichten bleiben unverändert. Der Inhalt der DateiC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\JasperReportFill.java sind wie unten angegeben -

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.JasperFillManager;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class JasperReportFill {
   @SuppressWarnings("unchecked")
   public static void main(String[] args) {
      String sourceFileName = 
         "C://tools/jasperreports-5.0.1/test/jasper_report_template.jasper";

      DataBeanList DataBeanList = new DataBeanList();
      ArrayList<DataBean> dataList = DataBeanList.getDataBeanList();

      JRBeanCollectionDataSource beanColDataSource = new 
         JRBeanCollectionDataSource(dataList);

      Map parameters = new HashMap();
      /**
       * Passing ReportTitle and Author as parameters
       */
      parameters.put("ReportTitle", "List of Contacts");
      parameters.put("Author", "Prepared By Manisha");

      try {
         JasperFillManager.fillReportToFile(
         sourceFileName, parameters, beanColDataSource);
      } catch (JRException e) {
         e.printStackTrace();
      }
   }
}

Der Inhalt der POJO-Datei C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBean.java sind wie unten angegeben -

package com.tutorialspoint;

public class DataBean {
   private String name;
   private String country;

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

Der Inhalt der Datei C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBeanList.java sind wie unten angegeben -

package com.tutorialspoint;

import java.util.ArrayList;

public class DataBeanList {
   public ArrayList<DataBean> getDataBeanList() {
      ArrayList<DataBean> dataBeanList = new ArrayList<DataBean>();

      dataBeanList.add(produce("Manisha", "India"));
      dataBeanList.add(produce("Dennis Ritchie", "USA"));
      dataBeanList.add(produce("V.Anand", "India"));
      dataBeanList.add(produce("Shrinath", "California"));

      return dataBeanList;
   }

   /**
    * This method returns a DataBean object,
    * with name and country set in it.
    */
   private DataBean produce(String name, String country) {
      DataBean dataBean = new DataBean();
      dataBean.setName(name);
      dataBean.setCountry(country);
      
      return dataBean;
   }
}

Berichterstellung

Wir werden die obige Datei mit unserem regulären ANT-Erstellungsprozess kompilieren und ausführen. Der Inhalt der Datei build.xml (gespeichert im Verzeichnis C: \ tools \ jasperreports-5.0.1 \ test) ist wie folgt.

Die Importdatei - baseBuild.xml wird aus dem Kapitel Umgebungs-Setup übernommen und sollte im selben Verzeichnis wie die build.xml abgelegt werden.

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

Öffnen Sie als Nächstes das Befehlszeilenfenster und wechseln Sie in das Verzeichnis, in dem build.xml abgelegt ist. Führen Sie abschließend den Befehl ausant -Dmain-class=com.tutorialspoint.JasperReportFill (viewFullReport ist das Standardziel) als -

C:\tools\jasperreports-5.0.1\test>ant -Dmain-class=com.tutorialspoint.JasperReportFill
Buildfile: C:\tools\jasperreports-5.0.1\test\build.xml

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

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 bu
   [javac] Compiling 4 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.JasperReportFill
   [java] log4j:WARN No appenders could be found for logger
   (net.sf.jasperreports.extensions.ExtensionsEnvironment).
   [java] log4j:WARN Please initialize the log4j system properly.
   [java] call afterReportInit()
   [java] call afterReportInit()

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: 18 minutes 49 seconds

Als Ergebnis der obigen Kompilierung wird ein JasperViewer-Fenster geöffnet, wie im folgenden Bildschirm gezeigt -

Hier sehen wir, dass zwei Nachrichten aus der MyScriptlet-Klasse angezeigt werden -

  • Im Titelabschnitt - Dieser Variablenwert wurde vom Scriptlet geändert
  • Unten - Hallo! Ich bin das Scriptlet-Objekt des Berichts.