Report Scriptlet

Abbiamo visto nei nostri capitoli precedenti, i dati visualizzati nel report vengono generalmente recuperati dai parametri del report e dai campi del report. Questi dati possono essere elaborati utilizzando le variabili del report e le loro espressioni. Ci sono situazioni in cui non è possibile ottenere facilmente una funzionalità complessa utilizzando espressioni o variabili del report. Esempi di ciò possono essere manipolazioni complesse di stringhe, creazione di mappe o elenchi di oggetti in memoria o manipolazioni di date utilizzando API Java di terze parti. Per tali situazioni, JasperReports ci fornisce un mezzo semplice e potente per farloScriptlets.

Gli scriptlet sono sequenze di codice Java che vengono eseguite ogni volta che si verifica un evento di report. I valori delle variabili di report possono essere influenzati tramite scriptlet.

Dichiarazione Scriptlet

Possiamo dichiarare uno scriptlet in due modi:

  • Utilizzando <scriptlet> elemento. Questo elemento ha l' attributo name e l' attributo class . L' attributo class dovrebbe specificare il nome della classe, che estende la classe JRAbstractScriptlet . La classe deve essere disponibile nel classpath al momento della compilazione del report e deve avere un costruttore vuoto, in modo che il motore possa istanziarlo al volo.

  • Utilizzando l'attributo scriptletClass dell'elemento <jasperReport>, nel modello di rapporto (JRXML). Impostando questo attributo con il nome completo dello scriptlet (incluso l'intero nome del pacchetto), indichiamo che vogliamo utilizzare uno scriptlet. L'istanza dello scriptlet, creata con questo attributo, agisce come il primo scriptlet nell'elenco degli scriptlet e ha il nome predefinito REPORT.

Classe scriptlet

Uno scriptlet è una classe java, che deve estendere una delle seguenti classi:

  • net.sf.jasperreports.engine.JRAbstractScriptlet- Questa classe contiene una serie di metodi astratti che devono essere sovrascritti in ogni implementazione. Questi metodi vengono chiamati automaticamente da JasperReports al momento opportuno. Lo sviluppatore deve implementare tutti i metodi astratti.

  • net.sf.jasperreports.engine.JRDefaultScriptlet- Questa classe contiene le implementazioni vuote predefinite di ogni metodo in JRAbstractScriptlet. A uno sviluppatore è richiesto solo di implementare quei metodi di cui ha bisogno per il suo progetto.

La tabella seguente elenca i metodi nella classe precedente. Questi metodi saranno chiamati dal motore di report al momento opportuno, durante la fase di compilazione del report.

S.NO Metodo e descrizione
1

public void beforeReportInit()

Chiamato prima dell'inizializzazione del report.

2

public void afterReportInit()

Chiamato dopo l'inizializzazione del report.

3

public void beforePageInit()

Chiamato prima che ogni pagina venga inizializzata.

4

public void afterPageInit()

Chiamato dopo che ogni pagina è stata inizializzata.

5

public void beforeColumnInit()

Chiamato prima che ogni colonna venga inizializzata.

6

public void afterColumnInit()

Chiamato dopo che ogni colonna è stata inizializzata.

7

public void beforeGroupInit(String groupName)

Chiamato prima che il gruppo specificato nel parametro venga inizializzato.

8

public void afterGroupInit(String groupName)

Chiamato dopo che il gruppo specificato nel parametro è stato inizializzato.

9

public void beforeDetailEval()

Chiamato prima della valutazione di ogni record nella sezione dei dettagli del report.

10

public void afterDetailEval()

Chiamato dopo la valutazione di ogni record nella sezione dei dettagli del report.

È possibile specificare qualsiasi numero di scriptlet per rapporto. Se per un report non viene specificato alcuno scriptlet, il motore crea comunque una singola istanza JRDefaultScriptlet e la registra con il parametro REPORT_SCRIPTLET incorporato.

Possiamo aggiungere qualsiasi metodo aggiuntivo di cui abbiamo bisogno ai nostri scriptlet. I report possono chiamare questi metodi utilizzando il parametro incorporato REPORT_SCRIPTLET.

Scriptlet globali

Possiamo associare gli scriptlet in un altro modo ai report, ovvero dichiarando gli scriptlet globalmente. Questo fa sì che gli scriptlet si applichino a tutti i rapporti compilati nella distribuzione JasperReports data. Ciò è reso semplice dal fatto che gli scriptlet possono essere aggiunti a JasperReports come estensioni. Il punto di estensione dello scriptlet è rappresentato dall'interfaccia net.sf.jasperreports.engine.scriptlets.ScriptletFactory . JasperReports caricherà tutte le factory di scriptlet disponibili tramite estensioni in fase di esecuzione. Quindi, chiederà a ciascuno di loro l'elenco di istanze di scriptlet che desiderano applicare al report corrente in esecuzione. Quando si richiede l'elenco delle istanze di scriptlet, il motore fornisce alcune informazioni di contesto che la fabbrica potrebbe utilizzare per decidere quali scriptlet si applicano effettivamente al report corrente.

Report Governors

I governatori sono solo un'estensione degli scriptlet globali che ci consentono di affrontare un problema del motore di report che entra in loop infinito in fase di esecuzione, durante la generazione di report. I modelli di report non validi non possono essere rilevati in fase di progettazione, perché la maggior parte delle volte le condizioni per l'immissione dei cicli infiniti dipendono dai dati effettivi che vengono immessi nel motore in fase di esecuzione. I Report Governor aiutano a decidere se un determinato rapporto è entrato in un ciclo infinito e possono interromperlo. Ciò impedisce l'esaurimento delle risorse per la macchina che esegue il report.

JasperReports ha due semplici report governor che interrompono l'esecuzione di un report in base a un numero massimo specificato di pagine o un intervallo di timeout specificato. Sono -

  • net.sf.jasperreports.governors.MaxPagesGovernor- Questo è uno scriptlet globale che cerca due proprietà di configurazione per decidere se applicare o meno al report attualmente in esecuzione. Le proprietà di configurazione sono:

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

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

  • net.sf.jasperreports.governors.TimeoutGovernor- Questo è anche uno scriptlet globale che cerca le due proprietà di configurazione seguenti per decidere se applicare o meno.

    Le proprietà di configurazione sono:

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

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

Le proprietà per entrambi i governatori possono essere impostate a livello globale, nel file jasperreports.properties, oa livello di report, come proprietà di report personalizzate. Ciò è utile perché diversi rapporti possono avere dimensioni stimate o limiti di timeout diversi e anche perché potresti voler attivare i regolatori per tutti i rapporti, disattivarli per alcuni o viceversa.

Esempio

Scriviamo una classe scriptlet (MyScriptlet). I contenuti del file C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ MyScriptlet.java sono i seguenti:

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

}

I dettagli della classe scriptlet di cui sopra sono i seguenti:

  • Nel metodo afterReportInit , impostiamo un valore per la variabile"someVar" this.setVariableValue ("someVar", new String ("Questo valore della variabile è stato modificato dallo scriptlet.")).

  • Alla fine della lezione, viene chiamato un metodo aggiuntivo 'hello'è stata definita. Questo è un esempio di un metodo che può essere aggiunto allo Scriptlet che restituisce effettivamente un valore, invece di impostare una variabile.

Successivamente, aggiungeremo il riferimento alla classe dello scriptlet nel nostro modello di report esistente (Chapter Report Designs ). Il modello di rapporto rivisto (jasper_report_template.jrxml) è il seguente. Salvalo nella directory 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>

Di seguito vengono forniti i dettagli del modello di rapporto rivisto:

  • Abbiamo fatto riferimento alla classe MyScriptlet nell'attributo scriptletClass di <JasperReport> elemento.

  • Gli scriptlet possono solo accedere, ma non modificare, i campi e i parametri del report. Tuttavia, gli scriptlet possono modificare i valori delle variabili di report. Ciò può essere ottenuto chiamando il metodo setVariableValue (). Questo metodo è definito nella classe JRAbstractScriptlet, che è sempre la classe genitore di qualsiasi scriptlet. Qui, abbiamo definito una variabile someVar , che verrà modificata dal MyScriptlet per avere il valore Questo valore è stato modificato dallo scriptlet .

  • Il modello di rapporto sopra ha una chiamata al metodo nella banda Riepilogo che illustra come scrivere nuovi metodi (negli scriptlet) e utilizzarli nel modello di rapporto. ($P{REPORT_SCRIPTLET}.hello())

I codici java per la compilazione del report rimangono invariati. Il contenuto del fileC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\JasperReportFill.java sono come indicato di seguito -

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

Il contenuto del file POJO C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBean.java sono come indicato di seguito -

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

Il contenuto del file C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBeanList.java sono come indicato di seguito -

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

Generazione di report

Compileremo ed eseguiremo il file sopra utilizzando il nostro normale processo di compilazione ANT. I contenuti del file build.xml (salvato nella directory C: \ tools \ jasperreports-5.0.1 \ test) sono i seguenti.

Il file di importazione - baseBuild.xml viene prelevato dal capitolo Configurazione dell'ambiente e dovrebbe essere posizionato nella stessa directory di 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>

Quindi, apriamo la finestra della riga di comando e andiamo alla directory in cui si trova build.xml. Infine, esegui il comandoant -Dmain-class=com.tutorialspoint.JasperReportFill (viewFullReport è il target predefinito) come -

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

Come risultato della compilazione di cui sopra, si apre una finestra di JasperViewer come mostrato nella schermata sotto riportata -

Qui vediamo due messaggi visualizzati dalla classe MyScriptlet:

  • Nella sezione del titolo - Questo valore della variabile è stato modificato dallo scriptlet
  • In basso - Ciao! Sono l'oggetto scriptlet del report.