iReport學習筆記(2)

iReport學習筆記

iReport學習筆記(2)

這篇開始來講一些比較細部的東西

Style(樣式)

在iReport中可以定義各種樣式並套用在元素上面,以控制元素與外觀相關的一組屬性(顏色、字型...等)

在左邊Report Inspector的最上面可以看到有個「Styles」,對著它按右鍵→加入→Style,接著底下就會出現一個新的Style,右邊的屬性視窗可以對其做修改

假設我現在設定Forecolor為深藍色,並將Style套用到獎金的欄位中,在屬性中的Style可以透過下拉式選單來選擇,選好後可以看到畫面上的字已經變深藍色了

實際效果

也可以設定動態的條件,比如說當獎金大於0時顯示深藍色,等於0時還是顯示黑色

先將style的字體顏色改回來,接著在左邊Report Inspector找到剛剛新增的Style,對其按左鍵→加入Conditional Style,加入後可以在右邊看到它的屬性

透過設定Condition Expression來控制要在什麼時候套用該樣式,以剛剛的需求來講,輸入$F{COMM}.intValue() > 0 ? true : false

可以看到畫面上的字還是黑色,但是點Preview看一下,發現已經成功做出我要的效果了

Fields/Parameters/Variables

iReport中能夠儲存資料的主要有這幾種,可以把它們想成Java中的變數,隨著邏輯改變而有所不同,在使用的時候會對應到某種Java的類別,像是String、Date、Integer......

在左邊Report Inspector中可以看到它們,在每個種類上面按右鍵可以新增

Fields

Fields是用來顯示從Dataresource中動態取回來的資料,屬性有Name、Field Class(對應的Java類別)、Description(可選)

可以透過多種方式新增,以下簡單的介紹幾個

  1. 在Report Inspector的Fields按右鍵→加入Field
  2. 如上篇文章所示,透過SQL查詢來把table中的欄位加進Fields中,Field Class是根據該欄位在SQL中的類型來決定的
  3. 用JavaBean產生Fields

首先定義一個JavaBean


package test;
import java.sql.Date;

public class EmpVO implements java.io.Serializable{
	private Integer empno;
	private String ename;
	private String job;
	private Date hiredate;
	private Double sal;
	private Double comm;
	private Integer deptno;

	public EmpVO() {

	}

	public EmpVO(Integer empno, String ename, String job, Date hiredate, Double sal, Double comm, Integer deptno) {
		super();
		this.empno = empno;
		this.ename = ename;
		this.job = job;
		this.hiredate = hiredate;
		this.sal = sal;
		this.comm = comm;
		this.deptno = deptno;
	}
	
	public Integer getEmpno() {
		return empno;
	}
	public void setEmpno(Integer empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public Date getHiredate() {
		return hiredate;
	}
	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	public Double getSal() {
		return sal;
	}
	public void setSal(Double sal) {
		this.sal = sal;
	}
	public Double getComm() {
		return comm;
	}
	public void setComm(Double comm) {
		this.comm = comm;
	}
	public Integer getDeptno() {
		return deptno;
	}
	public void setDeptno(Integer deptno) {
		this.deptno = deptno;
	}
}

再定義一個Factory類別,裡面有靜態方法可以產生一些EmpVO物件(因為只是簡單看一下能不能出現一樣的效果,所以直接用塞值的)


package test;

import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Vector;

public class EmpCollFactory {

	public static Collection generateCollection() {
		Vector collection = new Vector();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			collection.add(new EmpVO(7001, "KING", "PRESIDENT", new Date(sdf
					.parse("1981-11-17").getTime()), 5000.5, 0D, 10));
			collection.add(new EmpVO(7002, "BLAKE", "MANAGER", new Date(sdf
					.parse("1981-05-01").getTime()), 2850D, 0D, 30));
			collection.add(new EmpVO(7003, "CLARK", "MANAGER", new Date(sdf
					.parse("1981-01-09").getTime()), 2450D, 0D, 10));
			collection.add(new EmpVO(7004, "JONES", "MANAGER", new Date(sdf
					.parse("1981-04-02").getTime()), 2975D, 0D, 20));
			collection.add(new EmpVO(7005, "MARTIN", "SALESMAN", new Date(sdf
					.parse("1981-09-28").getTime()), 1250D, 1400D, 30));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return collection;
	}

	public static EmpVO[] generateBeanArray() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		EmpVO[] empArray = new EmpVO[5];
		try {
			empArray[0] = new EmpVO(7001, "KING", "PRESIDENT", new Date(sdf.parse(
					"1981-11-17").getTime()), 5000.5, 0D, 10);
			empArray[1] = new EmpVO(7002, "BLAKE", "MANAGER", new Date(sdf.parse(
					"1981-05-01").getTime()), 2850D, 0D, 30);
			empArray[2] = new EmpVO(7003, "CLARK", "MANAGER", new Date(sdf.parse(
					"1981-01-09").getTime()), 2450D, 0D, 10);
			empArray[3] = new EmpVO(7004, "JONES", "MANAGER", new Date(sdf.parse(
					"1981-04-02").getTime()), 2975D, 0D, 20);
			empArray[4] = new EmpVO(7005, "MARTIN", "SALESMAN", new Date(sdf.parse(
					"1981-09-28").getTime()), 1250D, 1400D, 30);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return empArray;
	}
}

另外要注意一個非常重要的一點,不能用JDK1.8去Compile,我在這邊卡了好一陣子,想說明明設定都ok,為什麼就是沒反應,改用JDK1.7之後就好了

接著如上一篇文章所提到的步驟,在Classpath加入.class檔所在的位置(比如說D:\jdk7work\JavaBean\bin),接著新增Datasource,不一樣的是這次要選擇「JavaBeans set datasource」

設定如下:
Name:識別名稱,可以隨便打
Factory class:Factory類別的完整名稱,預設是com.jaspersoft.ireport.examples.SampleJRDataSourceFactory,用這個也可以,但在預覽的時候看不到實際的資料
Collection of javaBeans/Array of javaBeans:取決於Factory類別的方法是回傳一個集合還是一個陣列
The static method...:方法名稱
設定完後按下Test,如果出現Connection test successful!就可以按Save存起來了

  • 集合

  • 陣列

一樣點選Preview旁邊的按鈕,這次選擇JavaBean Datasource,輸入JavaBean類別的完整名稱後按Read Attributes,底下就會出現這個類別所擁有的屬性

將要加入Field中的屬性選取,點選Add selected field(s),可以看到中間出現剛剛選取的屬性,這時再按Refresh Preview Data,底下就會出現之前在Factory類別中所塞的EmpVO們

點選OK之後,Field就有剛剛設定的欄位了

將報表上每個元素的位置擺好後,預覽看看效果是否相同

在薪水跟獎金的部分,因為從資料庫撈出來的型態是BigDecimal,而JavaBean中是定義為Double,所以就算小數點後面為0也會顯示出來

Parameters

Parameters通常是從外部傳入的一些參數,可以用在報表的標題字串、或是在SQL中的查詢字串......等等,每個Parameters對應的類型也是一個Java類別

在Report Inspector可以看到目前有定義的Parameters,在報表中可以用$P{Parameter name}來取得值

  1. 報表的標題字串

假設新增一個名為title的Parameter,預設值放入"員工資料",接著將原本報表中Static Text的員工資料替代為Text Field的$P{title}

按下Preview時會出現一個視窗要求輸入參數值

這時可以輸入一個值,也可以按下Use default使用預設值,但如果沒有定義預設值時,就會出現null

  • 使用輸入的值

  • 使用預設值

  • 按Use default但沒有定義預設值時:

  1. SQL的查詢字串

新增一個名為EMPNO的Parameter,接著點開Report query的畫面,將SQL指令改成select * from emp2 where EMPNO = $P{EMPNO}

按下Preview,舉例來說輸入7001,就只會出現EMPNO為7001的員工資料

此外也可以把Parameter當做一整個where的查詢條件,例如新增一個名為myQuery的Parameter,接著點開Report query的畫面,將SQL指令改成select * from emp2 $P!{myQuery}

按下Preview,輸入where EMPNO = 7001,出來的結果是一樣的

iReport內建的Parameters

iReport本身有內建一些Parameters,但它們是唯讀的,以下取其中幾個做說明

參數名 說明
REPORT_PARAMETERS_MAP java.util.Map物件,包含在填充報表時要傳給報表引擎的各種Parameter
REPORT_CONNECTION java.sql.Connection物件,報表可以根據傳入的JDBC Connection取得相應的資料
REPORT_DATA_SOURCE net.sf.jasperreports.engine.JRDataSource物件,可以從外部的程式傳入一個Datasource
REPORT_SCRIPTLET net.sf.jasperreports.engine.JRAbstractScriptlet物件,在填充報表時可以使用或控制Scriptlet物件在填充過程中已經準備好的資料。如果沒有指定使用的Scriptlet,則預設為net.sf.jasperreports.engine.JRDefaultScriptlet
IS_IGNORE_PAGINATION java.lang.Boolean物件,可以控制分頁功能的開關,預設為打開,但在輸出html或excel時不做分頁處理
REPORT_LOCALE java.util.Locale物件,用來設定地區,如果沒有提供則用系統預設的
REPORT_TIME_ZONE java.util.TimeZone物件,用來設定時區,如果沒有提供則用系統預設的
REPORT_RESOURCE_BOUNDLE java.util.ResourceBundle物件,指定報表要載入的資源文件,可用於i18n

Variables

Variables是用來儲存對某個表達式計算後的結果,可以在報表中使用$V{variable name}來表示,每個Variable也都一樣對應到一種Java類別,以下是各種設定的定義

Variable Class Type:對應的Java類別
Calculation:要如何對表達式做計算,iReport會根據指定的Calculation對從Datasource撈出來的每一筆資料做計算,並更新Variable的值

類型 說明
Nothing 不做任何計算,直接根據表達式把值印出
Count 計算有幾筆資料
Distinct Count 計算有幾筆不重複的資料
Sum 把資料的值累加
Average 累加結果的平均值
Lowest 表達式的最小值
Highest 表達式的最大值
StandardDeviation 根據表達式的所有值傳回標準差
Variance 根據表達式的所有值傳回變異數
System 可以自己控制計算方式(比如用Java程式)

Reset Type:Variable在什麼時候進行重置(初始化)

類型 說明
None Variable不會被重置
Report 只有在報表創建時會進行重置
Page 在每一頁都重置一次
Column 在每一列都重置一次
Group 在每一個群組重置一次,需設定底下的Reset group

Reset group:搭配Reset Type選擇Group時使用
Increment Type:這個網路上寫的定義有點籠統,應該可以理解成Variable在什麼時候做計算

類型 說明
None Variable對於每筆資料都會做運算
Report 只有在報表的最後計算一次
Page 在每一頁都計算一次
Column 在每一列的最後計算一次
Group 在每一個群組計算一次,需設定底下的Increment group

Increment group:搭配Increment Type選擇Group時使用
Incrementer Factory Class Name:用來進行計算的一個Java類別,需要實作net.sf.jasperreports.engine.fill.JRIncrementerFactory介面,報表引擎會用它在執行期間根據Variable的Calculation屬性設定來實體化Incrementer物件
Variable Expression:要用來迭代做計算的變數
Initial Value Expression:Variable初始化時的值

假設定義一個名為COMMTOTAL的Variable來計算總共發了多少獎金,設定如下:

實際呈現的結果:
第一頁

第二頁

iReport內建的Variable

跟Parameter一樣,iReport也有一些內建的Variable,是無法做修改的

名稱 說明
PAGE_NUMBER 可以顯示當前所在的頁數,也可以顯示報表的總頁數(根據TextField的evaluationTime屬性設定為Now還是Report決定要顯示什麼)
COLUMN_NUMBER 當前的列數
REPORT_COUNT 報表到目前為止共包含幾筆資料
PAGE_COUNT 當前頁包含幾筆資料
COLUMN_COUNT 當前列包含幾筆資料
[GroupName]_COUNT 當前組包含幾筆資料

假設在報表上使用了如圖的這些Variable,PAGE_NUMBER分別將evaluationTime屬性設定為Now跟Report

到第二頁的實際效果是這樣