在企業應用系統中,經常要輸出各種格式的數據報表。
著名的開源項目<JasperReports可以很好的解決這個問題。
使用JasperReports可以在預先設定好格式的報表基礎上進行數據的填充並可導出各種格式的報表。
下圖說明了JasperReports報表生成的基本步驟:
1. 擴展名為.jrxml的文件為標准的xml文件,該文件定義了報表的格式和數據構成。可以通過jasperReports的“黃金搭檔”iReport以可視化的方式生成並編輯這個文件。
2. jrxml文件經過JasperReports API 編譯后將生成擴展名為.jasper的二進制文件。
3. 可以調用JasperReports API針對jasper文件進行數據和參數的填充,生成擴展名為.jrprint的文件。
4. 調用JasperReports API可以將jrprint文件最終導出成PDF、Excel、Html等各種格式的文件。
下面將采用iReport + JasperReports 生成如下圖的PDF格式報表,表格中的數據來源於數據庫,是在固定格式報表基礎上,由JasperReport填充得到的。
整個報表的生成過程需要兩個步驟:
1. 使用iReport生成規定報表格式和數據構成的jrxml文件。
2. 調用JasperReports API 編譯、填充並導出固定格式的報表。
一、用iReport生成報表文件(.jrxml)
開源工具iReport用於定義報表的格式,可以從其官方網站下載
http://ireport.sourceforge.net/cap3.html
本應用所使用的是iReport-1.2.2-windows-installer.exe 安裝程序,啟動后,按照向導即可安裝(要確認系統中裝有1.4版本以上JDK)。
下面的操作大致分為12個步驟:
步驟1:安裝成功后啟動該程序,將顯示如下畫面,選擇菜單“File->New Document”新建報表文檔,可在彈出的對話框選擇報表的大小、版式等。
步驟2:按照默認版式創建報表,選擇菜單“Data->Connections/Datasources”
指定數據庫連接或數據源,在彈出的對話框中單擊“New”,並在彈出的對話框中指定數據庫的連接參數(驅動類、URL、用戶名和密碼等)
iReport通過JDBC連接數據庫,要確認相應數據庫的驅動類置於iReport安裝路徑的lib文件夾下。
步驟3:選擇菜單“Data->Report Query”
在彈出的對話框中輸入SQL語句:
select id, name, salary from emp,
選中所有查詢的字段后,單擊“OK”。
該SQL語句查詢的數據為將來報表中要顯示的數據,除了用SQL語句,這里還支持HQL(Hibernate Query Language)等其他多種查詢方式。
這樣的操作將在報表的xml文件中生成如下定義:
<queryString><![CDATA[select id, name, salary from emp]]></queryString>
<field name="id" class="java.lang.Integer"/>
<field name="name" class="java.lang.String"/>
<field name="salary" class="java.lang.Double"/>
其中元素定義了用於獲取數據的查詢語句,將來JasperReports將通過這樣的方式查詢數據。
元素定義了對應於查詢結果的字段名稱和類型,將來報表中可以使用$F{字段名稱}獲取並顯示查詢得到的數據。
步驟4:選擇菜單“Format->Styles”用於指定報表元素將使用的樣式,
這里的Style類似於HTML中CSS樣式,一個樣式規定了字體、前景色、背景色等顯示特征,樣式創建后,可以將其施加於特定的報表元素。
為了便於維護,樣式之間可以實現繼承關系,子樣式將擁有父樣式的一切特征。
在彈出的對話框中單擊“New”指定一個名為default的樣式(通過Style name指定樣式名稱),指定其字體、顏色等特征。
步驟5:繼續指定一些其他的樣式,如用於表頭字體的“灰底白字”的樣式header,將這些樣式的Parent style值指定為剛剛創建的default樣式,
即指定default是所有樣式的父樣式,這樣可以通過編輯default樣式指定一些所有樣式共同的特征。
步驟5:繼續指定一些其他的樣式,如用於表頭字體的“灰底白字”的樣式header,將這些樣式的Parent style值指定為剛剛創建的default樣式,
即指定default是所有樣式的父樣式,這樣可以通過編輯default樣式指定一些所有樣式共同的特征。
步驟6:單擊“Edit->Insert element...->Static Text”或使用工具欄的按鈕,
在報表頁面中添加靜態文本框,將這些文本框置於合適的位置並填入文字,作為表頭,
通過右邊的Element properties 視圖將這些文本框的Style(樣式)置為方才創建的header。
步驟7:打開右邊Library視圖的Fields圖標,可以看到id,name,salary三個標識,這三個標識對應在“步驟3”中創建的“查詢字段”,
用鼠標直接拖動這些字段到報表頁面的適當位置,這樣的操作將在報表xml文本中產生形如:
<textFieldExpression class="java.lang.Integer"><![CDATA[$F{字段名稱}]]></textFieldExpression>
的文本。其中$F{字段名稱}表示該字段的查詢值。
步驟8:在Library視圖中單擊右鍵,在彈出的快捷菜單中選擇“Add...->Parameter”,用於創建參數,在彈出的對話框中指定參數的名稱和數據類型。
步驟9:在Library視圖的Parameter下可以看到剛剛建立的名為“Title”的參數,用鼠標拖到其到指定位置,並適用在步驟5中創建的title樣式,此處為報表的標題。
這樣的操作將在xml文件中產生如下內容:
<textFieldExpression class="java.lang.String"><![CDATA[$P{Title}]]></textFieldExpression>
其中的$P{Title}對應Title參數的值,將來將通過JasperReports API 對“Title”參數賦值。
步驟10:選擇菜單“File->Save”保存生成的xml文件,注意,文件的擴展名一般為jrxml,該文件定義的報表的格式及其數據構成。
步驟11:可以通過iReport的編譯工具對生成的報表文件進行測試,
單擊工具欄的按鈕編譯報表文件,
如果無誤可單擊工具欄的按鈕將顯示報表生成的樣式,
如果單擊工具欄的按鈕,iReport將會查詢數據顯示填充數據后的報表,
注意:這里的報表的標題顯示null是因為沒有對報表的“Title”賦值,這里僅僅是通過iReport工具對生成的報表進行測試,
下面將通過JasperReports API以編程的方式編譯、填充並導出報表。
步驟12:為了是將來導出的PDF格式報表支持中文顯示,可以手工的編輯iReport生成的xml文件,
在定義default樣式的位置加入支持中文的PDF字體和編碼設置:
<style name="default" isDefault="true" mode="Opaque" pdfFontName="STSong-Light" pdfEncoding="UniGB-UCS2-H" />
由於其他樣式繼承了該樣式,從而自動擁有的支持中文的設置。
二、用JasperReports編譯、填充,並導出報表 可以從JasperReports的官方網站下
http://www.jasperforge.org/jaspersoft/opensource/business_intelligence/jasperreports/
載JasperReports的發行包,本應用使用的版本是jasperreports-1.2.3,將其發行包中dist目錄下的:
jasperreports-1.2.3.jar
以及lib目錄下的如下jar文件:
poi-2.0-final-20040126.jar
jdt-compiler-3.1.1.jar
itext-1.3.1.jar
commons-beanutils-1.5.jar
commons-collections-2.1.jar
commons-digester-1.7.jar
commons-javaflow-20060411.jar
commons-loggin-1.0.2.jar
復制到應用的類路徑(CLASSPATH)下。
為了支持中文的PDF報表導出,還需要有iTextAsian.jar文件,
該文件可以從http://prdownloads.sourceforge.net/itext/iTextAsian.jar?download 處下載。
注意,由於要連接數據庫,還需要將數據庫的JDBC驅動類包復制到類路徑下。
編譯報表(.jrxml -> .jasper),JasperCompileManager類的靜態方法compileReportToFile用於編譯報表文件第一個String參數為待編譯的報表xml文件,
第二個String參數為編譯后的文件名。
代碼如下所示:
public void testCompile() throws Exception { JasperCompileManager.compileReportToFile("test.jrxml", "test.jasper"); }
填充報表(.jasper -> .jrprint),JasperFillMangager類的靜態方法fillReportToFile用於實現對二進制報表文件的填充,
該方法有三個參數:
1. 一個參數為String類型,表示待填充的文件名。
2. 第二個參數為Map對象,存放用於填充報表參數(對應與報表中的$P{參數名稱})的鍵值對,下面代碼中map對象中存有鍵值對{Title=員工列表},則對應報表中的$P{Title}位置將被填充為“員工列表”。
3. 第三個參數為數據庫的連接(java.sql.Connection)對象,方法進行數據填充時需要用到該連接實現查詢。
代碼如下所示:
public void testFill() throws Exception { Map map = new HashMap(); map.put("Title", "員工列表"); JasperFillManager.fillReportToFile("test.jasper", map, getConnection()); } private Connection getConnection() throws Exception { Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root"); return con; }
導出報表,JRPdfExporter類用於將.jrprint格式的報表導出Pdf格式,
類似的類還有:
JRXlsExporter 導出成Excel文件格式
JRHtmlExporter 導出成HTML文件格式
JRCsvExporter 導出成Csv文件格式
JRRtfExporter 導出成RTF文件格式
JRTextExporter 導出成純文本文件格式
JRXmlExporter 導出成Xml文件格式
JasperPrint類用於封裝.jrprint文件數據。
JRPdfExporter的setParameter用於指定導出屬性,如:需要到處的JasperPrint對象、導出文件的文件名等。
JRPdfExporter的exprotReport方法將實現報表的導出產生相應的PDF報表文檔。
public void testExportToPdf() throws Exception { JasperPrint jp = (JasperPrint) JRLoader.loadObject("test.jrprint"); JRPdfExporter exporter = new JRPdfExporter(); //指定要導出的jrprit數據 exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp); //指定導出文件的文件名 exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "test.xls"); //實現報表的導出 exporter.exportReport(); }
下面兩個方法用於演示Excel格式和HTML格式報表的導出。
public void testExportToExcel() throws Exception { JasperPrint jp = (JasperPrint) JRLoader.loadObject("test.jrprint"); JRXlsExporter exporter = new JRXlsExporter(); exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp); exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "test.pdf"); exporter.exportReport(); } public void testExportToHtml() throws Exception { JasperPrint jp = (JasperPrint) JRLoader.loadObject("test.jrprint"); JRHtmlExporter exporter = new JRHtmlExporter(); exporter.setParameter(JRExporterParameter.JASPER_PRINT, jp); exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "test.html"); exporter.exportReport(); }