Report Scriptlets

Vimos em nossos capítulos anteriores que os dados exibidos no relatório geralmente são obtidos dos parâmetros e campos do relatório. Esses dados podem ser processados ​​usando as variáveis ​​do relatório e suas expressões. Existem situações em que uma funcionalidade complexa não pode ser alcançada facilmente usando expressões ou variáveis ​​de relatório. Exemplos disso podem ser manipulações complexas de String, construção de mapas ou listas de objetos na memória ou manipulações de datas usando APIs Java de terceiros. Para tais situações, JasperReports nos fornece um meio simples e poderoso de fazer isso comScriptlets.

Scriptlets são sequências de código Java que são executadas sempre que ocorre um evento de relatório. Os valores das variáveis ​​do relatório podem ser afetados por meio de scriptlets.

Declaração de Scriptlet

Podemos declarar um scriptlet de duas maneiras -

  • Usando <scriptlet> elemento. Este elemento possui atributo de nome e atributo de classe . O atributo class deve especificar o nome da classe, que estende a classe JRAbstractScriptlet . A classe deve estar disponível no caminho de classe no momento do preenchimento do relatório e deve ter um construtor vazio, para que o mecanismo possa instanciá-la instantaneamente.

  • Usando o atributo scriptletClass do elemento <jasperReport>, no modelo de relatório (JRXML). Definindo este atributo com o nome totalmente qualificado de scriptlet (incluindo o nome do pacote inteiro), indicamos que queremos usar um scriptlet. A instância de scriptlet, criada com este atributo, atua como o primeiro scriptlet na lista de scriptlets e possui o nome predefinido REPORT.

Classe scriptlet

Um scriptlet é uma classe java, que deve estender qualquer uma das seguintes classes -

  • net.sf.jasperreports.engine.JRAbstractScriptlet- Esta classe contém vários métodos abstratos que devem ser substituídos em cada implementação. Esses métodos são chamados automaticamente pelo JasperReports no momento apropriado. O desenvolvedor deve implementar todos os métodos abstratos.

  • net.sf.jasperreports.engine.JRDefaultScriptlet- Esta classe contém implementações vazias padrão de cada método em JRAbstractScriptlet. Um desenvolvedor só precisa implementar os métodos de que precisa para seu projeto.

A tabela a seguir lista os métodos da classe acima. Esses métodos serão chamados pelo mecanismo de relatório no momento apropriado, durante a fase de preenchimento do relatório.

S.NO Método e Descrição
1

public void beforeReportInit()

Chamado antes da inicialização do relatório.

2

public void afterReportInit()

Chamado após a inicialização do relatório.

3

public void beforePageInit()

Chamado antes de cada página ser inicializada.

4

public void afterPageInit()

Chamado depois que cada página é inicializada.

5

public void beforeColumnInit()

Chamado antes de cada coluna ser inicializada.

6

public void afterColumnInit()

Chamado depois que cada coluna é inicializada.

7

public void beforeGroupInit(String groupName)

Chamado antes de o grupo especificado no parâmetro ser inicializado.

8

public void afterGroupInit(String groupName)

Chamado depois que o grupo especificado no parâmetro é inicializado.

9

public void beforeDetailEval()

Chamado antes de cada registro na seção de detalhes do relatório ser avaliado.

10

public void afterDetailEval()

Chamado após cada registro na seção de detalhes do relatório ser avaliado.

Qualquer número de scriptlets pode ser especificado por relatório. Se nenhum scriptlet for especificado para um relatório, o mecanismo ainda criará uma única instância JRDefaultScriptlet e a registrará com o parâmetro REPORT_SCRIPTLET integrado.

Podemos adicionar quaisquer métodos adicionais de que precisamos aos nossos scriptlets. Os relatórios podem chamar esses métodos usando o parâmetro interno REPORT_SCRIPTLET.

Scriptlets globais

Podemos associar scriptlets de outra maneira aos relatórios, que é declarando os scriptlets globalmente. Isso faz com que os scriptlets se apliquem a todos os relatórios sendo preenchidos na implantação JasperReports fornecida. Isso é facilitado pelo fato de que scriptlets podem ser adicionados a JasperReports como extensões. O ponto de extensão scriptlet é representado pela interface net.sf.jasperreports.engine.scriptlets.ScriptletFactory . JasperReports carregará todas as fábricas de scriptlet disponíveis por meio de extensões em tempo de execução. Em seguida, ele pedirá a cada um deles a lista de instâncias de scriptlets que desejam aplicar ao relatório atual que está sendo executado. Ao solicitar a lista de instâncias de scriptlet, o mecanismo fornece algumas informações de contexto que a fábrica poderia usar para decidir quais scriptlets realmente se aplicam ao relatório atual.

Governadores de Relatório

Os governadores são apenas uma extensão de scriptlets globais que nos permitem enfrentar um problema de mecanismo de relatório que entra em loop infinito em tempo de execução, enquanto gera relatórios. Modelos de relatório inválidos não podem ser detectados em tempo de design, porque na maioria das vezes, as condições para inserir os loops infinitos dependem dos dados reais que são alimentados no mecanismo em tempo de execução. Os governadores de relatórios ajudam a decidir se um determinado relatório entrou em um loop infinito e podem interrompê-lo. Isso evita o esgotamento dos recursos da máquina que executa o relatório.

JasperReports tem dois governors de relatório simples que interromperiam a execução de um relatório com base em um número máximo de páginas especificado ou em um intervalo de tempo limite especificado. Eles são -

  • net.sf.jasperreports.governors.MaxPagesGovernor- Este é um scriptlet global que procura duas propriedades de configuração para decidir se ele se aplica ou não ao relatório que está sendo executado. As propriedades de configuração são -

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

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

  • net.sf.jasperreports.governors.TimeoutGovernor- Este também é um scriptlet global que procura as duas propriedades de configuração a seguir para decidir se ele se aplica ou não.

    As propriedades de configuração são -

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

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

As propriedades de ambos os governors podem ser definidas globalmente, no arquivo jasperreports.properties ou no nível do relatório, como propriedades de relatório customizadas. Isso é útil porque relatórios diferentes podem ter tamanhos estimados ou limites de tempo limite diferentes e também porque você pode querer ativar os governors para todos os relatórios, enquanto desativa para alguns, ou vice-versa.

Exemplo

Vamos escrever uma classe scriptlet (MyScriptlet) O conteúdo do arquivo C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ MyScriptlet.java é o seguinte -

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

}

Os detalhes da classe scriptlet acima são os seguintes -

  • No método afterReportInit , definimos um valor para a variável"someVar" this.setVariableValue ("someVar", new String ("O valor desta variável foi modificado pelo scriptlet.")).

  • No final da aula, um método extra chamado 'hello'foi definido. Este é um exemplo de método que pode ser adicionado ao Scriptlet que realmente retorna um valor, em vez de definir uma Variável.

Em seguida, adicionaremos a referência de classe scriptlet em nosso modelo de relatório existente (Capítulo Report Designs ). O modelo de relatório revisado (jasper_report_template.jrxml) são os seguintes. Salve-o no diretório 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>

Os detalhes do modelo de relatório revisado são fornecidos abaixo -

  • Fizemos referência à classe MyScriptlet no atributo scriptletClass do elemento <jasperReport>.

  • Os scriptlets podem apenas acessar, mas não modificar os campos e parâmetros do relatório. No entanto, os scriptlets podem modificar os valores das variáveis ​​de relatório. Isso pode ser feito chamando o método setVariableValue (). Este método é definido na classe JRAbstractScriptlet, que é sempre a classe pai de qualquer scriptlet. Aqui, definimos uma variável someVar , que será modificada pelo MyScriptlet para ter o valor Este valor foi modificado pelo scriptlet .

  • O modelo de relatório acima tem uma chamada de método na banda Resumo que ilustra como escrever novos métodos (em scriptlets) e usá-los no modelo de relatório. ($P{REPORT_SCRIPTLET}.hello())

Os códigos java para preenchimento de relatório permanecem inalterados. O conteúdo do arquivoC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\JasperReportFill.java são os dados abaixo -

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

O conteúdo do arquivo POJO C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBean.java são os dados abaixo -

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

O conteúdo do arquivo C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBeanList.java são os dados abaixo -

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

Geração de relatório

Vamos compilar e executar o arquivo acima usando nosso processo normal de construção ANT. O conteúdo do arquivo build.xml (salvo no diretório C: \ tools \ jasperreports-5.0.1 \ test) é fornecido a seguir.

O arquivo de importação - baseBuild.xml é obtido no capítulo Configuração do ambiente e deve ser colocado no mesmo diretório do 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>

A seguir, vamos abrir a janela da linha de comando e ir para o diretório onde build.xml está colocado. Finalmente, execute o comandoant -Dmain-class=com.tutorialspoint.JasperReportFill (viewFullReport é o destino padrão) como -

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

Como resultado da compilação acima, uma janela JasperViewer é aberta conforme mostrado na tela abaixo -

Aqui, vemos que duas mensagens são exibidas da classe MyScriptlet -

  • Na seção de título - este valor de variável foi modificado pelo scriptlet
  • Na parte inferior - Olá! Sou o objeto scriptlet do relatório.