天天看點

jasperReport+iReport的使用

(1)

JasperReports是一個開源的java報表制作引擎

iReport是JasperReports的一個GUI工具,用來生成JasperReports的jrxml檔案。

JasperReports的報表是用XML檔案來定義的,約定用jrxml作字尾名。一個典型的jrxml檔案包含以下元素:

    * <jasperReport> - 根元素

    * <title> - 報表的标題,一篇報表裡隻在開頭列印一次

    * <pageHeader> - 頁眉,報表每頁開頭列印一次

    * <detail> - 報表正文

    * <pageFooter> - 頁腳,報表每頁末尾列印一次

    * <band> - 定義報表部件,以上所有元素都包含一個band元素作為他們唯一的子元素

  ·Summary:可能需要對幾頁(你的報表可能有幾個頁組成)的統計值。比如50個銷售記錄共占用了3頁,那麼放置這些統計記錄的統計值最好的地方就是summary。

  ·groupHeader:每個表的内容可能需要根據某個屬性進行劃分顯示内容和計算内容,比如希望以月份為機關每組分開顯示銷售記錄,那麼就可以定義一個組(組的定義參考後文),groupHeader就是放置組說明或是組标志最好的地方。

  ·Groupfooter:放置組的統計或是說明

(2)

各元素分析:

static text:靜态文本,隻是用來在報表中顯示;

$P--->表示是參數;

如:"20"+$P{statement_current_date}

$F--->表示是textfield變量.

如:$F{account_code}

此變量是在<field name>中定義的.其值是在<queryString>中,通過select資料庫後,得到的.

select的列名 = field name

$V--->表示一個變量

如:$V{balance}

變量的預設值是在報表中設定的.一般設定為0.其真正的值是通過 $P或$F來獲得的.

(3)

A,報表中的QueryString語句,可以通過界面上的DataBase中的Report SQL Query來進行添加-->會自動生成相應的TextField.若不行,則可自動手動添加.

B,如果要直接修改代碼,可以選擇界面上的'編輯'-->'直接編輯XML Source'-->先進行儲存-->就會出現代碼界面.

C,如果要修改JASPER REPORT的屬性,可以選擇界面上的'預覽'-->'報表屬性'

E,添加group,可以通過點選界面上的相應'group'按鈕來添加.

F,隐藏不要的區域,要設bank=0,而不能删除為空.删除為空,則為預設值

G,IReport中的左欄中的各元素的後面的[X,Y]内的資料,是指此元素偏離'左上角'的X,Y距離.

H,設定子報表時,要将子報表的屬性中的"上邊界,下邊界,左邊界,右邊界"全部設定為0,否則會出現子報表傳回來的資料,在主報表中沒法對齊的現象.

(4)

當沒有資料(是指QueryString語句SELECT出來的資料為NULL)時,設定怎樣顯示:

相關代碼:

whenNoDataType="NoPages / BlankPage / AllSectionsNoDetail"

NoPages:當沒資料時,會彈出一個對話框提示你沒資料,然後顯示一個沒激活的框.

BlankPage :不會提示,隻是顯示一個白紙.

AllSectionsNoDetail:不會提示,但那些靜态的文本,以及從上一層或JAVA檔案中傳來顯示的參數,都可以顯示.

(5)

内置的報表變量:

$V{PAGE_NUMBER}:(常用)

這個變量儲存目前的頁号,在報表裝填結束的時候,這個變量就儲存着最終文檔的總頁數。是以要在JasperReport的文本字段中顯示頁号和總頁數你都可以用它。

A,

隻需要添加一個系統的變量:$V{PAGE_NUMBER};

對于$V{PAGE_NUMBER}:當evaluationTime="Now"時,即是計算當頁所在哪一頁.   (now:即時執行此表達式.)

                    當evaluationTime="Report"時,即是計算當頁所在哪一頁.(Report:整個報表執行完後才執行此表達式)

B,

并将其轉換為String的類型.

C,總體代碼:

<textField evaluationTime="Now">

  <textFieldExpression class="java.lang.String">

"Page " + String.valueOf($V{PAGE_NUMBER}) + "   Of"

  </textFieldExpression>

</textField>

<textField evaluationTime="Report">

  <textFieldExpression class="java.lang.String">

String.valueOf($V{PAGE_NUMBER})

  </textFieldExpression>

</textField>

$V{REPORT_COUNT}:

當evaluationTime=Report時,将記錄報表的總記錄數.

當evaluationTime=Column時,将記錄報表從開始到目前頁的總記錄數.

Variable COLUMN_NUMBER

這個變量将記錄目前的列号。

Variable PAGE_COUNT

這個變量紀錄目前頁中處理的record的數目。

Variable COLUMN_COUNT

這個變量紀錄生成目前列時所處理的record的數目。

(6)

field的動态顯示+動态顯示不同的格式:

有些報表可能需要對同種類型的資料根據重要性不同而顯示不同的風格。例如,要在訂單清單中加亮顯示金額超過100$的訂單.

而文本域的現實格式不能動态改變,我們如何實作這種功能呢?

解決辦法是:

在同樣的位置放兩個文本域來顯示相同的内容,但是設定不同的顯示格式,一個正常顯示,一個加粗并加亮顯示紅色,同時還要為他們設定<printWhenExpression>元素,讓他們可以根據條件表達式來切換。這裡的表達式就是$F{value} < 100(正常顯示的文本域)和$F{value} >= 100(加亮顯示的文本域)。

(7)

建立子報表

1)

在代碼中,将子報表以參數形式加載:

JasperReport sixUnitPrice = (JasperReport)JRLoader.loadObject("jasper/TrendAve_ItemIntel_6MonthUnitPrice.jasper");

parameters.put("sixUnitPrice", sixUnitPrice);

2)

在主報表中,建立上面的相應參數sixUnitPrice. 其類型為:net.sf.jasperreports.engine.JasperReport

3)

在iReprot中添加,劃拉出一塊子報表.

在subReport項中,選中:' use connection expression '

在subReport other項中:

設定image expression class=net.sf.jasperreports.engine.JasperReport

設定subreport expression中填寫代碼中的相應參數:$P{sixUnitPrice}

4)

設定要傳到子報表的參數,并在主報表中建立相應的參數.

5)

建立子報表,建立一參數(與主報表傳遞的參數一樣),來接收從主報表傳來的參數.-->即可應用了.

說明:

位于多層之下的子報表,也需要從主報表開始時,就可以加載,傳遞下去,否則加載不了.因為一開始,都是從JAVA檔案中從傳過來,然後一層層傳下去的.

(8)

hashmap參數在報表間傳遞值的用法

1)

如何帶參數:

在某層子報表中建立一個新的子報表,此新子報表,必須從:報表java類中定義-->主報表-->各上級父報表中對此新子報表進行定義(定義此參數+各父報表添加此新報表參數,以便其子報表可以獲得)-->目的子報表

2)hashmap參數在報表間傳遞值的用法

如上的專題記錄,$P{group_total_hash}此參數是一個hashmap,從其定義是在子報表中的,最終用:是在主報表中,作為統計資料.

怎樣用:

1.

先在主報表,以及子報表中都要定義hashmap,并在子報表的各上層報表進行指派,使參數可以主報表與子報表中間進行傳遞:

<parameter name="group_total_hash" isForPrompting="false" class="java.util.HashMap">

<defaultValueExpression ><![CDATA[new java.util.HashMap()]></defaultValueExpression>

</parameter>

2.

在子報表中,在區間的顯示屬性中添加:

$P{group_total_hash}.put();如下:

$P{trayout_hash}.put("trayout",$F{totalqty}) == null?

Boolean.TRUE:Boolean.TRUE

3.

在主報表中:

添加一Field,設定資料類型為Double,且Evaluation time=Column(否則資料出不來)

$P{group_total_hash}.get();如下:

new Double

(

((Double)$P{trayout_hash}.get("trayout")).doubleValue()

  -

((Double)$P{trayin_hash}.get("trayin")).doubleValue()

)

4.

具體可以參考ACCOUNT中的PL報表,或SCM中的item intelligence報表中的設定及用法:

主報表:

ProfitLoss_basic.jrxml

用于計算各部分total的子報表:

ProfitLoss_basic_subReport_profit_loss_total_year_list.jrxml

TrendAve_ItemIntelReport.jrxml

TrendAve_ItemIntel_trayout.jrxml.

(9)

Group的用法:

用法一:(分類顯示及計算)

假設有兩表:

mysql> select * from A;

+------+------+

| id   | name |

+------+------+

|    1 | hk   |

|    2 | hk   |

+------+------+

mysql> select * from B;

+------+------+------+-------+

| id   | Aid  | name | value |

+------+------+------+-------+

|    1 |    1 | sz   |     1 |

|    1 |    1 | cz   |     1 |

|    2 |    2 | zh   |     1 |

|    2 |    2 | gz   |     1 |

+------+------+------+-------+

報表要分兩層,第一層循環查詢A表,第二層(即子報表)循環查詢B表在屬于A表的記錄.

若不用group,則會出現(-->後面是各元件中iReport中的位置):

ID    Name  value  -->放于報表中的pageHeader

1     hk     1     -->放于第一層報表中的detail -->循環每一條記錄且顯示

  1   sz     1     -->放于第二層報表中的detail

  2   cz     1

2     hk     1     //name與上相同

  1   zh     1

  2   gz     1

若采用group按照name進行分組,則jasper會把name相同的放入一組,隻顯示一次.

采用name分組後的效果:

ID    Name  value  -->放于報表中的pageHeader

1     hk     1     -->放于第一層報表中groupHeader,将所有相同的name集合在一起,隻顯示一次

  1   sz     1     -->放于第二層報表中的detail

  2   cz     1

  1   zh     1

  2   gz     1

  sum value: 5     -->放于第一層報表中groupFooter

補充說明:

對于上面的group,須先點選"group"按鈕進行定義(如:nameGroup).

同時,可以以group的基準進行計算(結合變量variable),放于groupFooter.

(1)

在iRport中,建立變量sumValue,定義如下:

variable type: Double

caculation type: sum

Reset type: Group

Reset Group: 上面自定義的group名(如:nameGroup)

variable expression:(即進行計算的表達式) $F{value}

(2)

在groupFooter添加一field:

須定義:

Evaluation time : group,而不是now

Evaluation Group: 上面自定義的group名(如:nameGroup)

jasper報表,子報表内容顯示重疊

在jasper中,若在detail區域中,把兩個一模一樣的子報表上下放置.則在循環輸出時,會出現上下子報表

輸出内容相遮掩的結果.

解決方案:用group分離顯示.

把兩個子報表,分别放于兩個不同的group中,分組條件為主報表的每一個ID,這樣,主報表循環顯示時,就

會将各分組一一顯示出來,不會影響其顯示.

用法二:

利用group來進行分組和實作子報表傳回值:

第(8)點的傳回值,隻适合于非循環性的.

若在主報表的detail區域,需要讓每條record都将子報表傳回值到對應的record中,則要采用這種方法.上面的方法實作不了.

因為子報表的傳回值有一個問題:它們是在目前區域的所有元素都被處理之後才傳回的。如果你想在子報表所在的主報表區域顯示它的傳回值,你最終将看到它們傳回的太晚了。

具體實作方法:

1)

先在主報表,子報表建立一個同名的hashmap容器,且将主報表的這個參數作為子報表的傳遞參數,傳到

子報表中.

2)

在報表中,對視窗進行加值:

方式一:

在子報表中,在summary區域的屬性中添加:

$P{trayout_hash}.put("trayout",$F{totalqty}) == null?Boolean.TRUE:Boolean.TRUE

方式二:

在子報表中,在summary區域中添加一個不可見的直線元素,且在其中設定:

<line>

  <reportElement x="0" y="0" width="0" height="0">

    <printWhenExpression>

      $P{trayout_hash}.put("trayout",$F{totalqty}) == null?Boolean.FALSE:Boolean.FALSE

    </printWhenExpression>

  </reportElement>

</line>

3)

在主報表中,添加一個分組,以每條記錄作為一個分組.操作如下:

A,點選GROUP按鈕.

B,填寫組名;

C,分組表達式: $F{item_code}.(也可以id作為分組) -->分組的關鍵所在

D,選擇:是否start on a new page -->讓最後所得的分組,是否以分頁的形式顯示.

4)

對于detail區域中,要傳回值的field,這樣設定:

<textField evaluationTime="Group" evaluationGroup="itemcodeGroup">

  <reportElement x="335" y="50" width="175" height="15"/>

  <textFieldExpression >

    $P{trayout_hash}.get("trayout")

  </textFieldExpression>

</textField>

采用Group實作傳回值的說明:

子報表的傳回值有一個問題:它們是在目前區域的所有元素都被處理之後才傳回的。如果你想在子報

表所在的主報表區域顯示它的傳回值,你最終将看到它們傳回的太晚了。

是以,為了能在主報表中的子報表所在的同一區域顯示傳回值,我們必須延遲文本域表達式的處理時

機。這是通過加入一個無效的分組讓表達式在分組結束時處理來實作的,而這個無效分組的效果就是

資料源中的每條記錄就是一組,而且它自己沒有組頭群組尾區域。

<group >

  <groupExpression>$F{item_code}</groupExpression>

</group>

(10)

若資料類型設定為Double,則須:

$P{trayout_hash}.get("trayout")-->Object類型;

((Double)$P{trayout_hash}.get("trayout"))-->轉換成Double類型;

((Double)$P{trayout_hash}.get("trayout")).doubleValue()-->轉換成double類型,進行計算;

new Doubel(A-B)--->将最終結果轉換成Double,因為上面設定類型類型時,用了Double.

如下:

new Double

(

((Double)$P{trayout_hash}.get("trayout")).doubleValue()

  -

((Double)$P{trayin_hash}.get("trayin")).doubleValue()

)

(11)

變量還可以聲明來完成引擎内建計算的求值,如:count、sum、average、lowest、highest、 variance等等。一個完成Quantity字段sum計算的變量定義如下:

<variable name="QuantitySum"

class="java.lang.Double" calculation="Sum">

<variableExpression>$F{Quantity}</variableExpression>

</variable>

我們還可以通過制定初始化級别來改變計算過程,預設的級别是Report就是變量僅在報表開始處初 始化一次,一直到報表結束完成計算。

我們可以選擇更低的級别讓變量在每個Page、Column或者Group級别重新初始化。假如我們想計算 計算每頁的總數,變量聲明如下:

<variable name="QuantitySum" class="java.lang.Double"

resetType="Page" calculation="Sum">

<variableExpression>$F{Quantity}</variableExpression>

<initialValueExpression>new Double(0) </initialValueExpression>

</variable>

變量将在每一頁的開始處被初始化為0。

(12)

變量的resetType解釋:

報表變量的值可以在每一次疊代(iteration)中被改變,但也可以在裝填過程中的某一特定的時間(specified moments)通過它的初始的value表達式恢複其初始值。這一行為是由resetType屬性控制的,這一屬性規定了報表裝填過程中當報表變量在何時需要重新進行初始化(或恢複到初始值)。該元素有五種選項值:

4.1

No Reset:變量将不會使用其initial value expression對自身進行初始化,而将僅報表從變量表達式中所求得的值(resetType=”None”)。

4.2

Report Level Reset:變量将在報表填充過程的起始階段使用其初始化表達式初始化一次(resetType=”Report”)。

預設的屬性為resetType=”Report”

4.3

Page Level Reset:變量将在每一頁的起始時被重新初始化(resetType=”Page”)。

4.4

Colunm Level Reset:變量将在每個新列的開始被初始化(resetType=”Column”)

4.5

Group Level Reset:變量将在每次resetGroup屬性提供的break的地方被重新初始化(resetType=”Group”)。

Reset Group

如果存在的話,resetGroup屬性包含了報表的組的名字并且僅與resetType=”Gropu”的resetType屬性相關聯。

(13)

報表的分層顯示方法:

外層,在主報表中查詢循環顯示;

下層,在子報表中查詢循環顯示.