Báo cáo Scriptlets

Chúng ta đã thấy trong các chương trước của mình, dữ liệu hiển thị trên báo cáo thường được lấy từ các thông số báo cáo và trường báo cáo. Dữ liệu này có thể được xử lý bằng cách sử dụng các biến báo cáo và biểu thức của chúng. Có những tình huống khi một chức năng phức tạp không thể đạt được dễ dàng bằng cách sử dụng các biểu thức hoặc biến báo cáo. Ví dụ về điều này có thể là các thao tác Chuỗi phức tạp, xây dựng Bản đồ hoặc Danh sách các đối tượng trong bộ nhớ hoặc các thao tác ghi ngày tháng bằng cách sử dụng các API Java của bên thứ ba. Đối với những tình huống như vậy, JasperReports cung cấp cho chúng tôi một phương tiện đơn giản và mạnh mẽ để thực hiện việc này vớiScriptlets.

Các đoạn mã là chuỗi mã Java được thực thi mỗi khi một sự kiện báo cáo xảy ra. Giá trị của các biến báo cáo có thể bị ảnh hưởng thông qua các tập lệnh.

Khai báo Scriptlet

Chúng ta có thể khai báo một script theo hai cách:

  • Sử dụng <scriptlet> phần tử. Phần tử này có thuộc tính tên và thuộc tính lớp . Các lớp thuộc tính nên xác định tên của lớp, kéo dài JRAbstractScriptlet lớp. Lớp phải có sẵn trong classpath tại thời điểm điền báo cáo và phải có một hàm tạo trống, để động cơ có thể khởi tạo nó một cách nhanh chóng.

  • Sử dụng thuộc tính scriptletClass của phần tử <jasperReport>, trong mẫu báo cáo (JRXML). Bằng cách đặt thuộc tính này với tên đầy đủ đủ điều kiện của scriptlet (bao gồm toàn bộ tên gói), chúng tôi cho biết rằng chúng tôi muốn sử dụng scriptlet. Cá thể scriptlet, được tạo bằng thuộc tính này, hoạt động giống như scriptlet đầu tiên trong danh sách các scriptlet và có tên được xác định trước là REPORT.

Lớp Scriptlet

Scriptlet là một lớp java, lớp này phải mở rộng một trong các lớp sau:

  • net.sf.jasperreports.engine.JRAbstractScriptlet- Lớp này chứa một số phương thức trừu tượng phải được ghi đè trong mỗi lần thực thi. Các phương thức này được gọi tự động bởi JasperReports vào thời điểm thích hợp. Nhà phát triển phải triển khai tất cả các phương thức trừu tượng.

  • net.sf.jasperreports.engine.JRDefaultScriptlet- Lớp này chứa các triển khai trống mặc định của mọi phương thức trong JRAbstractScriptlet. Một nhà phát triển chỉ được yêu cầu thực hiện các phương pháp mà họ cần cho dự án của mình.

Bảng sau liệt kê các phương thức trong lớp trên. Các phương pháp này sẽ được công cụ báo cáo gọi vào thời điểm thích hợp, trong giai đoạn điền báo cáo.

S.NO Phương pháp và Mô tả
1

public void beforeReportInit()

Được gọi trước khi khởi chạy báo cáo.

2

public void afterReportInit()

Được gọi sau khi khởi tạo báo cáo.

3

public void beforePageInit()

Được gọi trước khi mỗi trang được khởi tạo.

4

public void afterPageInit()

Được gọi sau mỗi trang được khởi tạo.

5

public void beforeColumnInit()

Được gọi trước khi mỗi cột được khởi tạo.

6

public void afterColumnInit()

Được gọi sau khi mỗi cột được khởi tạo.

7

public void beforeGroupInit(String groupName)

Được gọi trước khi nhóm được chỉ định trong tham số được khởi tạo.

số 8

public void afterGroupInit(String groupName)

Được gọi sau khi nhóm được chỉ định trong tham số được khởi tạo.

9

public void beforeDetailEval()

Được gọi trước khi mỗi bản ghi trong phần chi tiết của báo cáo được đánh giá.

10

public void afterDetailEval()

Được gọi sau khi mỗi bản ghi trong phần chi tiết của báo cáo được đánh giá.

Có thể chỉ định bất kỳ số lượng script nào trên mỗi báo cáo. Nếu không có scriptlet nào được chỉ định cho một báo cáo, công cụ vẫn tạo một cá thể JRDefaultScriptlet duy nhất và đăng ký nó với tham số REPORT_SCRIPTLET được tích hợp sẵn.

Chúng tôi có thể thêm bất kỳ phương thức bổ sung nào mà chúng tôi cần vào script của mình. Báo cáo có thể gọi các phương thức này bằng cách sử dụng tham số REPORT_SCRIPTLET được tích hợp sẵn.

Global Scriptlets

Chúng ta có thể kết hợp các tập lệnh theo một cách khác với các báo cáo, đó là bằng cách khai báo các tập lệnh trên toàn cầu. Điều này làm cho các kịch bản áp dụng cho tất cả các báo cáo đang được điền trong triển khai JasperReports nhất định. Điều này được thực hiện dễ dàng bởi thực tế là các script có thể được thêm vào JasperReports dưới dạng phần mở rộng. Điểm mở rộng scriptlet được đại diện bởi giao diện net.sf.jasperreports.engine.scriptlets.ScriptletFactory . JasperReports sẽ tải tất cả các nhà máy scriptlet có sẵn thông qua các tiện ích mở rộng trong thời gian chạy. Sau đó, nó sẽ yêu cầu từng người trong số họ về danh sách các trường hợp script mà họ muốn áp dụng cho báo cáo hiện tại đang được chạy. Khi yêu cầu danh sách các trường hợp script, engine sẽ cung cấp một số thông tin ngữ cảnh mà nhà máy có thể sử dụng để quyết định, script nào thực sự áp dụng cho báo cáo hiện tại.

Báo cáo thống đốc

Thống đốc chỉ là một phần mở rộng của các tập lệnh toàn cầu cho phép chúng tôi giải quyết vấn đề của công cụ báo cáo đi vào vòng lặp vô hạn trong thời gian chạy, trong khi tạo báo cáo. Không thể phát hiện các mẫu báo cáo không hợp lệ tại thời điểm thiết kế, vì hầu hết thời gian, các điều kiện để nhập các vòng lặp vô hạn phụ thuộc vào dữ liệu thực tế được đưa vào công cụ khi chạy. Báo cáo Thống đốc giúp quyết định xem một báo cáo nhất định có đi vào vòng lặp vô hạn hay không và họ có thể ngăn chặn nó. Điều này ngăn chặn việc cạn kiệt tài nguyên cho máy chạy báo cáo.

JasperReports có hai trình quản lý báo cáo đơn giản sẽ dừng thực hiện báo cáo dựa trên số trang tối đa được chỉ định hoặc khoảng thời gian chờ được chỉ định. Họ là -

  • net.sf.jasperreports.governors.MaxPagesGovernor- Đây là một tập lệnh toàn cục đang tìm kiếm hai thuộc tính cấu hình để quyết định xem nó có áp dụng hay không cho báo cáo hiện đang được chạy. Các thuộc tính cấu hình là -

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

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

  • net.sf.jasperreports.governors.TimeoutGovernor- Đây cũng là một tập lệnh toàn cục đang tìm kiếm hai thuộc tính cấu hình sau để quyết định xem nó có áp dụng hay không.

    Các thuộc tính cấu hình là -

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

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

Các thuộc tính cho cả hai thống đốc có thể được đặt trên toàn cầu, trong tệp jasperreports.properties hoặc ở cấp báo cáo, làm thuộc tính báo cáo tùy chỉnh. Điều này hữu ích vì các báo cáo khác nhau có thể có kích thước ước tính hoặc giới hạn thời gian chờ khác nhau và cũng vì bạn có thể muốn bật chế độ thống kê cho tất cả các báo cáo, trong khi tắt nó cho một số báo cáo hoặc ngược lại.

Thí dụ

Hãy viết một lớp scriptlet (MyScriptlet). Nội dung của tệp C: \ tools \ jasperreports-5.0.1 \ test \ src \ com \ tutorialspoint \ MyScriptlet.java như sau:

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

}

Chi tiết về lớp scriptlet ở trên như sau:

  • Trong phương thức afterReportInit , chúng tôi đặt giá trị cho biến"someVar" this.setVariableValue ("someVar", new String ("Giá trị biến này đã được sửa đổi bởi scriptlet.")).

  • Ở cuối lớp, một phương thức bổ sung được gọi là 'hello'đã được xác định. Đây là một ví dụ về một phương thức có thể được thêm vào Scriptlet thực sự trả về một giá trị, thay vì đặt một Biến.

Tiếp theo, chúng tôi sẽ thêm tham chiếu lớp scriptlet trong mẫu báo cáo hiện có của chúng tôi ( Thiết kế báo cáo chương ). Mẫu báo cáo đã sửa đổi (jasper_report_template.jrxml) như sau. Lưu nó vào thư mục 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>

Dưới đây là chi tiết của mẫu báo cáo sửa đổi:

  • Chúng tôi đã tham chiếu đến lớp MyScriptlet trong thuộc tính scriptletClass của phần tử <jasperReport>.

  • Scriptlet chỉ có thể truy cập, nhưng không thể sửa đổi các trường và thông số báo cáo. Tuy nhiên, scriptlet có thể sửa đổi các giá trị biến báo cáo. Điều này có thể được thực hiện bằng cách gọi phương thức setVariableValue (). Phương thức này được định nghĩa trong lớp JRAbstractScriptlet, luôn là lớp cha của bất kỳ scriptlet nào. Ở đây, chúng tôi đã xác định một biến someVar , biến này sẽ được sửa đổi bởi MyScriptlet để có giá trị Giá trị này đã được sửa đổi bởi scriptlet .

  • Mẫu báo cáo ở trên có một lệnh gọi phương thức trong dải Tóm tắt minh họa cách viết các phương thức mới (trong scriptlets) và sử dụng chúng trong mẫu báo cáo. ($P{REPORT_SCRIPTLET}.hello())

Các mã java để điền báo cáo vẫn không thay đổi. Nội dung của tệpC:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\JasperReportFill.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.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();
      }
   }
}

Nội dung của tệp POJO C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBean.java như được đưa ra dưới đây -

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

Nội dung của tệp C:\tools\jasperreports-5.0.1\test\src\com\tutorialspoint\DataBeanList.java như được đưa ra dưới đây -

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

Tạo báo cáo

Chúng tôi sẽ biên dịch và thực thi tệp trên 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.JasperReportFill (viewFullReport là mục tiêu mặc định) là -

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

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:

Ở đây, chúng tôi thấy hai thông báo được hiển thị từ lớp MyScriptlet -

  • Trong phần tiêu đề - Giá trị biến này đã được sửa đổi bởi scriptlet
  • Ở phía dưới - Xin chào! Tôi là đối tượng scriptlet của báo cáo.