使用 JFreeChart 顯示您的 Oracle 數據庫數據

作者:Dustin Marx 和 Michael G. Martin

使用 JFreeChart 可以輕鬆繪製 Oracle 數據庫數據圖表,並可以選擇多種高質量的圖表類型。

2007 年 9 月發佈

藉助圖表、數字和圖形可更快速地瞭解和分析大型數據集。俗話說“百聞不如一見”,因爲圖片可以傳達有關難以從文本數據本身獲得的數據的重要概述和比較信息。JFreeChart 是一個基於 Java 的開源(免費)庫,利用它可以輕鬆創建多種類型的以數據爲中心的高質量圖表。這個功能強大的庫提供了一個非常方便的 API,使不熟悉 JFreeChart 的開發人員可以快速創建表示其數據的高質量圖表。

在本文中,我們將使用 Oracle 數據庫 10g 快捷版 (XE) 中的 HR 模式數據提供一個該過程的示例。

JFreeChart 簡介

JFreeChart 項目的啓動可追溯到 2000 年。這個庫的最新版本 1.0.6 版於 2007 年 6 月發佈,本文使用的就是該版本。

JFreeChart 支持生成多種不同類型的圖表,包括從餅形圖、條形圖、面積圖、直線圖、柱狀圖以及 Gantt 圖表等常見類型到 Candlestick、Wind 以及 Wafer Map 圖表等較專業、不太常用的類型。確定 JFreeChart 支持的現成圖表類型的最快的一種方法是檢查 JFreeChart 的 ChartFactory 類的 Javadoc API 文檔。

在一些開發環境中,可以使用 JFreeChart 有效地生成面向數據的圖表,這些環境包括:

  • 生成的文件爲可移植網絡圖形 (PNG) 或 JPEG 格式
  • 基於 Java SE Swing 的應用程序,包括小程序
  • Java EE servlet 和 JavaServer 頁面 (JSP)
  • 與 iText 集成創建 PDF
  • 與 Batik 集成創建 SVG 格式

要繪製成圖表的數據

本文的圖表中要以圖形方式表示的數據來自於 Oracle 數據庫快捷版提供的 HR 模式。圖 1 顯示了 Oracle 數據庫快捷版附帶的 SQL*Plus 編輯器中顯示的 HR 模式中的表。

marx-jchart-f1.gif

圖 1:SQL 命令行工具中顯示的 HR 模式表

Oracle 數據庫快捷版還提供了一個非常有用、易於使用的基於 Web 的管理工具,該工具是在 Oracle Application Express 上構建的。圖 2 演示了該工具,並且再次顯示了 HR 模式中的某些對象(在本示例中爲表)。

marx-jchart-f2.gif

圖 2:Oracle Application Express 中的 HR 模式表

Oracle 數據庫快捷版爲開發人員提供了很多優勢,而且自身與 JFreeChart 兼容。Oracle 免費提供 Oracle 數據庫快捷版用於開發和生產。除了免費的優點之外,一個佔用空間較小、易於安裝和管理以及非常有用的集成 Web 管理工具,也是該數據庫產品的其他優勢之一。其缺點主要影響大型企業用戶,因爲缺陷涉及存儲空間、內存大小以及比傳統 Oracle 數據庫產品小的特性集。對於開發和構建原型,甚至對於小型生產數據庫,Oracle 數據庫快捷版都非常適合。對於預算有限的企業或項目來說尤爲如此。

圖 3 中的快照再次顯示了這個基於 Web 的管理工具,該工具顯示了 Oracle 數據庫快捷版的某些最重要的限制。Oracle 數據庫快捷版中一個實例的存儲空間被限制爲 5 GB(包括系統表空間),因此目前爲止使用的 710 MB 在該工具的屏幕截圖中被描述爲大約是該限制的 14%。內存使用被限制爲 1 GB,因此該實例的 314 MB RAM 使用情況也是據此描述的。以 SYSTEM 身份登錄到該管理工具可以在管理屏幕上顯示更具體的存儲和內存信息。圖 3 中的屏幕截圖還顯示了該工具提供的用於管理數據庫的所有子菜單選項。

marx-jchart-f3.gif

圖 3:Oracle 數據庫快捷版工具和使用情況監視

介紹了 Oracle 數據庫快捷版和作爲本文圖表生成的數據源的 HR 模式之後,我們現在回過頭來繼續介紹 JFreeChart 本身。

下載並“安裝”JFreeChart

JFreeChart 可從 www.jfree.org/jfreechart/ 下載。單個下載文件包含幾個用於 JFreeChart 的 JAR 文件。將下載的文件解壓縮到所選目錄下後,任何使用 JFreeChart 的應用程序的類路徑至少需要指向 jfreechart-1.0.5.jar 和 jcommon-1.0.9.jar 文件。可以通過將這些 JAR 文件添加到您喜歡的 IDE 的項目中來處理此問題。爲了在 IDE 的外部構建和運行,Java SE 6 允許在類路徑中使用通配符指定 JAR,因此 JFreeChart 庫目錄中的 JAR 都可以包括在類路徑中的一個 *.jar 表達式中。除了解壓縮分發文件並將您的應用程序的類路徑指向相應的 JFreeChart JAR 文件之外,不需要任何重要的安裝工作。

爲示例代碼相關性配置 Oracle JDeveloper

圖 4 顯示了構建和運行本文中的大多數代碼示例所需的相關 JAR 文件。列出了前面提到的兩個 JFreeChart JAR,以及 iText(用於生成 PDF)、Batik(用於生成 SVG)和 Oracle JDBC(用於對 Oracle 數據庫進行 Java 訪問)的 JAR。即使您沒使用 JDeveloper,圖 4 還是會在一個單獨的位置顯示您將需要置於類路徑中以構建和運行本文中討論的大多數工具的相關性。

marx-jchart-f4.gif

圖 4:要添加到 JDeveloper 項目(或類路徑中的其他位置)的 JAR

生成 JFreeChart Javadoc API 文檔

JFreeChart 壓縮的分發文件還包括一個 build.xml 文件,該文件對於生成基於 JFreeChart Javadoc 的文檔尤爲有用。要生成 JFreeChart 文檔,請在提供的 Ant build.xml 文件上運行“javadoc”目標(在“ant”子目錄中運行“ant javadoc”)。假定您已經安裝了 Ant,該將在 JFreeChart 文件的解壓縮目錄中生成一個“javadoc”子目錄,並將生成的 Javadoc 文件放在該目錄中。JFreeChart Web 站點也在線提供 JFreeChart 的 Javadoc 文檔。

簡要介紹 JFreeChart 的主要類和接口

JFreeChart 附帶了許多程序包、類和接口,但您只需瞭解其中很少一部分就可以開始使用 JFreeChart。本節簡要介紹一些主要的類和接口,它們是使用 JFreeChart 的基礎並將在本文的示例中使用。

JFreeChart 類

JFreeChart 庫中最重要的類之一是它本身,名爲 JFreeChart。該類提供一種 Java 二維圖表的表示。利用該類上的方法,開發人員可以控制生成的圖表的各個方面,並可以創建表示圖表的抽象窗口工具包 (AWT) BufferedImage。您只需非常少的額外工作即可直接使用 JFreeChart 創建幾種簡單的圖表類型,但 JFreeChart 卻可以提供對代表(如允許對所生成的圖表進行更多控制的 Plot)的訪問。

ChartFactory 類

ChartFactory 類用於創建不同類型的圖表。該類的每種靜態方法都根據其生成的圖表類型命名,無論調用何種類型的圖表,每種方法都返回一個通用的 JFreeChart 類實例。掃描該類的 Javadoc 文檔可以加深瞭解,也是確定 JFreeChart 提供的現成的基本圖表類型的最簡單方法之一。

ChartUtilities 類

與 ChartFactory 類相似,ChartUtilities 類也具有大量靜態方法。該類提供的大多數方法都可以將圖表轉換爲一種圖像格式或基本的 HTML 圖像映射。

數據集接口和實現類

檢查 ChartFactory 圖表創建方法表明這些方法中的每一種都接受某種類型的數據集擴展的接口(注意類名稱中的數據集)作爲參數。針對數據集接口生成的 Javadoc 文檔顯示了它是由幾個子接口擴展的,由更多具體類實現的。

用於各種類型圖表的數據集子接口通常是顯而易見的,因爲圖表類型的名稱通常出現在接口名稱中。例如,PieDataset 用於餅形圖,XYDataset 用於許多 x,y 類型圖表。CategoryDataset 用於直線圖和麪積圖,其他擴展數據集接口的子接口用於其他圖表類型。

數據集子接口是爲要在圖表中表示的 ChartFactory 類提供數據的機制。創建適當數據集子接口的具體實現,對其進行填充並傳遞到 ChartFactory 的xiangy create***Chart 方法,其中 *** 是相關的圖表類型。

不要將 JFreeChart 提供的數據集接口與 JDBC 4 提供的數據集接口混淆。JFreeChart 提供的數據集接口無需從數據庫填充,也不必以任何方式與數據庫相關。相反,JFreeChart 數據集接口及其子接口是爲使用數據填充 JFreeChart 圖表而設計的。

在運行中瞭解 JFreeChart:示例

本文的其餘部分主要用於闡釋某些 JFreeChart 特性以及 JFreeChart 是多麼容易上手。本文通過一系列代碼示例以及所生成圖表的快照來闡釋 JFreeChart 的可用性及特性。介紹每個示例時,還會介紹與每個具體示例有關的方面以及其他常用的 JFreeChart 概念。

示例 1:使用餅形圖直接繪製 HR 模式數據圖表

本文的大多數示例都涉及到使用 JFreeChart 根據 Oracle 數據庫快捷版提供的 HR 模式中存儲的數據創建圖表。由於我們要繪製數據庫中存儲的數據的圖表,因此面向 JDBC 的數據集類尤爲便利。這第一個示例顯示瞭如何使用餅形圖繪製每個部門的員工數量的圖表。

清單 1 演示了根據數據庫中存儲的數據創建圖表是多麼容易。databaseAccess.getOracleDbConnection() 方法(未在此處顯示)是一個簡單方法,它提供了一個 Oracle 數據庫連接(返回一個 java.sql.Connection)。

清單 1: 使用 JFreeChart 的 JDBCPieDataset 創建一個餅形圖

/**
* Create pie chart representing percentage of employees in each department
* that has at least one employee.
    * 
* @return Pie chart; null if no image created.
    */
public JFreeChart createNumberEmpsPerDeptPieChart()
   {
JFreeChart pieChart = null;

final String QUERY_NUMBER_EMPLOYEES_PER_DEPARTMENT =
"SELECT departments.department_name, count(*) AS num_employees " +
"FROM departments, employees " +
"WHERE employees.department_id = departments.department_id " +
"GROUP BY departments.department_name";

final String TITLE_EMPS_PER_DEPT = “Employees Per Department”;

try
      {
PieDataset pieDataset =
new JDBCPieDataset( databaseAccess.getOracleDbConnection(),
QUERY_NUMBER_EMPLOYEES_PER_DEPARTMENT );

pieChart =
ChartFactory.createPieChart( TITLE_EMPS_PER_DEPT, // chart title
pieDataset,
true,      // legend displayed
true,      // tooltips displayed
false );   // no URLs

      }
catch (SQLException sqlEx)    // checked exception
      {
System.err.println("Error trying to acquire JDBCPieDataset.");
System.err.println("Error Code:" + sqlEx.getErrorCode());
System.err.println("SQLSTATE:" + sqlEx.getSQLState());
sqlEx.printStackTrace();
      }

return pieChart;
   }

如清單 1 所示,從數據庫生成一個餅形圖只需要兩條重要的 Java 代碼語句。創建相應的數據集,然後將其傳遞給 ChartFactory 的 createPieChart 方法,該方法返回包含所生成的餅形圖的 JFreeChart。構造一個 JDBCPieDataset,並傳遞一個數據庫連接和一個數據庫 SQL 查詢字符串。由於該具體類實現 PieDataset 接口,因此我們可以通過接口將其傳遞給 createPieChart 方法。該代碼清單中 SQLException 的 catch 塊是必需的,因爲 JDBCPieDataset 構造器拋出檢查到的 SQLException 異常。

以 JFreeChart 類的實例形式創建了一個圖表之後,我們可以對該圖表進行一些操作。對創建的圖表可以做的最簡單的操作之一是將其作爲圖像文件寫入文件系統。清單 2 中的代碼闡釋瞭如何使用 ChartUtilities 將新創建的 JFreeChart 作爲一個 PNG 格式的圖像寫入文件系統。

清單 2: 將圖表寫入 PNG 文件

   /**
* Write .png file based on provided JFreeChart.
    * 
* @param aChart JFreeChart.
* @param aFileName Name of file to which JFreeChart will be written..
* @param aWidth Width of image.
* @param aHeight Height of image.
    */
public void writePngBasedOnChart( JFreeChart aChart,
String aFileName,
int aWidth,
int aHeight )
   {
try
      {
ChartUtilities.writeChartAsPNG( new FileOutputStream(aFileName),
aChart,
aWidth, aHeight);
      }
catch (IOException ioEx)
      {
System.err.println("Error writing PNG file " + aFileName);
      }
   }

該代碼清單隻有一條重要的 Java 代碼語句,用於將 JFreeChart 圖表將作爲 PNG 文件寫出。這條語句調用 ChartUtilities.writeChartAsPNG 方法,向其傳遞清單 1 中新創建的 JFreeChart 圖表,以及指明要將該圖像寫入到的文件的名稱以及圖像的長度和寬度的字符串。注意,這個通用方法可以接受任何 JFreeChart 圖表,因此可用於所有圖表類型。在本示例中,我們構造了一個餅形圖(如圖 5 所示)。從該圖表可以很快看出絕大多數員工在 Shipping 或 Sales 部門工作。

marx-jchart-f5.gif

圖 5:根據 DB 查詢創建的 PNG 格式餅形圖

如果不算用於處理異常、獲得一個數據庫連接以及返回類的“基礎架構”代碼行,直接從數據庫創建圖 5 中的圖表只需三條重要的 Java 代碼語句。這三條語句對應於使用 JFreeChart 從數據庫生成基本圖表通常所需的三個步驟:

  • 用一個有效的數據庫連接和相應的數據庫 SQL 查詢字符串創建相應的面向 JDBC 的數據集的實例。
  • 將上一步驟中的面向 JDBC 的數據集傳遞給所需圖表類型對應的 ChartFactory.create***Chart 方法。
  • 以適當的格式顯示新創建的 JFreeChart(第一個示例中的 PNG 文件)。

本文的其餘部分將介紹其他顯示生成的圖表的方法以及其他類型圖表的示例。

示例 2:使用三維餅形圖間接繪製 HR 模式數據圖表

在第一個示例中,通過使用面向 JDBC 的數據集直接檢索的數據集構造了一個餅形圖。  特定的實現是使用提供的數據庫連接和 SQL 查詢語句構造的。然而,有時可能無法使用或者不希望使用面向 JDBC 的數據集。例如,JFreeChart 僅爲 PieDataset、CategoryDataset 和 XYDataset 子接口提供面向 JDBC 的數據集實現。可能還存在這樣的情況:很難以適合 JFreeChart 的格式從數據庫中提取數據,必須先在 Java 代碼中進行一些數據操作。最後,可能不希望圖表生成與數據庫查詢緊密耦合。無論上述哪種情況,都可改用非面向 JDBC 的數據集。清單 3 演示瞭如何針對三維餅形圖實現該操作。

清單 3: 手動構造數據集並生成 JPG 圖表

JFreeChart pieChart3D = null;

final DefaultPieDataset pieDataset = new DefaultPieDataset();

/* Query used by getNumberEmployeesByLocation() method:

SELECT locations.city, count(*) AS num_employees
FROM departments, employees, locations 
WHERE employees.department_id = departments.department_id
AND departments.location_id = locations.location_id
GROUP BY locations.city
      */

Map<String, Integer> empsAtEachLocation= 
databaseAccess.getNumberEmployeesByLocation();

for ( Map.Entry numEmpsAtLoc :empsAtEachLocation.entrySet() )
      {
pieDataset.setValue(
numEmpsAtLoc.getKey().toString(),
Integer.parseInt(numEmpsAtLoc.getValue().toString()) );
      }

pieChart3D = ChartFactory.createPieChart3D( TITLE_EMPS_PER_LOC,
pieDataset,
true,
true,
false );

final String fileName = "EmpsPerLocPieChart3D.jpg";
try
      {
ChartUtilities.writeChartAsJPEG( new FileOutputStream(fileName),
aChart,
aWidth, aHeight);
      }
catch (IOException ioEx)
      {
System.err.println( "Error writing JPG file " + fileName);
      }

清單 3 中的代碼比第一個實例中所需的代碼略微冗長一些,因爲它沒有利用針對餅形圖的 JDBC 數據集,而是將 Map 條目從其數據庫存取器 (databaseAccess.getNumberEmployeesByLocation) 複製到一個被傳遞給 createPieChart3D 方法的 DefaultPieDataset 中。儘管這段代碼比第一個實例所需的代碼長,但它的優點是無需處理 SQLException,而且與數據庫查詢的的直接耦合程度也沒那麼高。

該示例還生成一個 JPEG (.jpg) 文件,而非第一個實例中生成的圖像之類的 PNG (.png) 文件。這兩個文件都是圖像文件格式,這兩個示例都顯示了將一個圖表寫出到任何一種圖像格式是多麼容易。圖 6 中顯示了作爲運行清單 3 中的代碼的結果創建的實際 JPEG 圖像。

marx-jchart-f6.gif

圖 6:從數據庫創建的 JPEG 格式的三維餅形圖

這種數據圖形表示打動您的一點就在於大多數員工在南聖弗朗西斯科、牛津或西雅圖工作。

由於使用面向 JDBC 的數據集無需從 Java 集合或結果集轉換爲 JFreeChart 所需的數據集格式,因此在可能的情況下,我們將在本文的其餘部分都使用該方法以保持簡單。然而如前所述,存在這樣的情況:由於數據庫訪問與圖表生成之間的強耦合,該方法無法實現或者不是所需要的。同樣,儘管使用面向 JDBC 的數據集時需要捕獲檢查到的 SQLException 異常,但我們在本文後面的代碼清單中將省略大多數異常處理代碼。

示例 3:在 Swing 中生成條形圖

該示例演示如何使用 JFreeChart 生成條形圖,還將介紹在 Swing 中顯示 JFreeChart 生成的圖表的想法。清單 4 顯示了用於生成該圖表以及在 Swing 中顯示生成的圖表的最重要的代碼。

清單 4: 從 Java Swing 生成條形圖

   /**
* Create Bar Chart showing salary of each employee.
    * 
* @param aOrientation Horizontal or Vertical orientation of bar chart.
* @return Bar Chart.
    */
public JFreeChart createSalaryPerFinanceEmployeeBarChart(
PlotOrientation aOrientation)
   {
JFreeChart barChart = null;

try
      {
final String QUERY_SALARY_PER_FINANCE_EMPLOYEE =
"SELECT first_name || ' ' || last_name AS Name, salary " +
"FROM employees " +
"WHERE department_id = 100";

final CategoryDataset barDataset =
new JDBCCategoryDataset( databaseAccess.getOracleDbConnection(),
QUERY_SALARY_PER_FINANCE_EMPLOYEE );

barChart =
ChartFactory.createBarChart( TITLE_SALARY_PER_FINANCE_EMP, // title
LABEL_EMPLOYEES_FINANCE, // x-axis label
LABEL_SALARIES,          // y-axis label
barDataset,
aOrientation,
true,      // legend displayed
true,      // tooltips displayed
false );   // no URLs

      }
catch (SQLException sqlEx)
      {
	// . . . exception handling goes here . . .
      }    

return barChart;
   }

	. . .

JFrame frame = new JFrame(aTitle);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JFreeChart barChart =
createSalaryPerFinanceEmployeeBarChart(
PlotOrientation.VERTICAL);
         
BufferedImage image = barChart.createBufferedImage(750,450);
JLabel label = new JLabel();
label.setIcon(new ImageIcon(image));
frame.getContentPane().add(label);

frame.pack();
frame.setVisible(true);

該代碼示例使用 String 常量取代硬編碼的字符串,這些常量可以根據它們字母全部大寫、單詞之間用下劃線分隔的命名規則得以輕鬆識別。

前兩個餅形圖生成示例使用了一個 PieDataset。這個條形圖生成示例改用了一個 CategoryDataset。與餅形圖不同,方向也是條形圖的一個問題,可以指定垂直或水平兩個方向。該示例指定了一個垂直繪製方向。

在代碼清單的底部,示例代碼演示瞭如何將圖表作爲一個可以作爲圖標輕鬆應用到 JLabel 的 BufferedImage 進行檢索。圖 7 顯示了這個包含 JFreeChart 生成的條形圖的簡單的 Swing 圖形用戶界面 (GUI) 的快照圖片。

marx-jchart-f7.gif

圖 7:在 Swing 應用程序中生成的條形圖

示例 4:在 Java Servlet 中生成圖表

該示例演示瞭如何在 servlet 容器中生成一個 JFreeChart。如前一個示例所示,JFreeChart 可以向 BufferedImage 顯示任何圖表。以下代碼清單利用此功能並向 JFreeChart 生成的圖像添加一個示例公司徽標。最終圖像和 servlet 輸出流被傳遞給 JFreeChart 的 ChartUtilities 類進行寫操作。

清單 5:在 Java Servlet 中生成圖表

/**
* Processes requests for both HTTP GET and POST methods.
* @param request servlet request
* @throws javax.servlet.ServletException
* @throws java.io.IOException
* @param response servlet response
      */
protected void processRequest(HttpServletRequest request, 
				     HttpServletResponse response)
throws ServletException, IOException {
        
	ImageType imageType = ImageType.valueOf(request.getParameter("type"));
int imageWidth = Integer.valueOf(request.getParameter("width"));
int imageHeight = Integer.valueOf(request.getParameter("height"));
float imageQuality = Float.valueOf(request.getParameter("quality"));
        
if (imageType.equals(ImageType.PNG)) {
response.setContentType("image/png");
} else if (imageType.equals(ImageType.JPEG)) {
response.setContentType("image/jpg");
}
        
HrJobsData data = getHrJobData();
writeImage(imageType,data,response.getOutputStream(),imageWidth,imageHeight,
quality);
response.getOutputStream().close();
     }

清單 5 中的代碼顯示了 getHrJobData() 方法提供的數據。此處並未顯示該方法的實現,但該方法只不過是一個從持久性源檢索數據的方法。由於該代碼在一個 servlet 容器中執行,因此應使用一個數據源利用該 servlet 容器的事務支持和該數據源的連接緩衝池。使用數據源還將以與供應商無關的方式提供到我們代碼的數據庫連接。

從 servlet 的 doGet 和 doPost 方法調用 processRequest 方法。servlet 希望傳入圖像類型、寬度、高度和質量。目前,servlet 支持用簡單枚舉類型表示的 PNG 或 JPEG 類型的圖像。數據對象是表示我們希望繪製成圖表的數據的 XML 對象。servlet 根據傳入的圖像類型設置正確的內容類型,然後調用 writeImage 創建圖像並通過 HTTP 響應輸出流發送。

清單 6: 自定義圖表生成器

private void writeImage(ImageType imageType,HrJobsData data,
OutputStream outputStream, int width, int height, float quality)
{   
try
   {
double[][] minWages = new double[1][data.getHrJob().size()];
double[][] maxWages = new double[1][data.getHrJob().size()];
String[] categories = new String[data.getHrJob().size()];
            
int index = 0;
for (HrJob hrJob :data.getHrJob())
      {
minWages[0][index] = hrJob.getMinimumSalary();
maxWages[0][index] = hrJob.getMaximumSalary();
categories[index] = hrJob.getJobTitle();
index++;
      }
            
DefaultIntervalCategoryDataset dataset = new
DefaultIntervalCategoryDataset(minWages,maxWages);
dataset.setCategoryKeys(categories);
            
JFreeChart chart = ChartFactory.createBarChart("Job Salary Ranges", 
			"Job Title", "Salary Range",
	dataset, PlotOrientation.HORIZONTAL, false, false, false);
            
IntervalBarRenderer renderer = new IntervalBarRenderer();
((CategoryPlot)chart.getPlot()).setRenderer(renderer);
            
BufferedImage img = chart.createBufferedImage(width, height);
BufferedImage logo = getLogo();
Graphics2D graphics2D = (Graphics2D) img.getGraphics();
graphics2D.drawImage(logo, null,LOGO_OFFSET_X,  LOGO_OFFSET_Y);
graphics2D.dispose();
            
if (imageType.equals(ImageType.JPEG))
      {
ChartUtilities.writeBufferedImageAsJPEG(outputStream, quality, img);
      }
else if (imageType.equals(imageType.PNG))
      {
// PNG scales the quality from 0-9
int pngQuality = (int) (quality * 9);
ChartUtilities.writeBufferedImageAsPNG( outputStream, img,
true, pngQuality);
      }
   }
catch (IOException ex)
   {
// . . . exception handling goes here . . .
   }
}

我們要繪製成圖表的數據表示各個職位的工資範圍。具有 IntervalBarRenderer 的 JFreeChart 條形圖可以很好地反映這組數據。對傳入的 XML 數據進行迭代,用最低工資、最高工資和職位填寫三個數組。在生成的圖表上調用 createBufferedImage 可以提供一個 BufferedImage。getLogo 調用返回包含在另一個 BufferedImage 中的我們的公司徽標。使用 Java 的二維圖形功能,可以將公司徽標繪製在圖表圖像上,與原來的圖表圖像有一些小的偏移。

quality 參數允許對壓縮水平進行精細控制。對於 JPEG 圖像,質量範圍爲 0.0 到 1.0。較低的值將產生較小的文件,但是會降低圖像質量。對於 PNG 圖像,質量範圍爲 0 到 9。PNG 是一個無損壓縮格式,因此該質量適用於不會危及質量的數據的壓縮水平。生成的 PNG 圖像的質量與原來的圖像質量相同。

最後調用 ChartUtilities.writeBufferedImageAsPNG 或 ChartUtilities.writeBufferedImageAsJPEG 使得 servlet 可以很容易地將最終圖像發回到瀏覽器。

要調用 servlet,可以使用標準的 HTML img 標記。清單 7 顯示了一個簡單的 JSP 頁面,該頁面使用一個嵌入的 img 標記調用 servlet 並在 Web 頁面中顯示一個生成的圖表。

清單 7: 調用 Servlet 以生成圖表的 JSP

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Title Salary Ranges</title>
</head>
<body>
<h1 style="text-align:center">Job Salary Ranges</h1>
<img src="<%=request.getContextPath()%>/GetChart?type=PNG&width=800&height=400&quality=.9"></img>
</body>
</html>

圖 8 顯示了調用該 servlet 返回一個 JFreeChart 圖像的最終結果。

 

marx-jchart-f8.gif

圖 8:PNG 格式的 Servlet 構建的時間間隔條形圖

示例 5:使用 Cewolf 在 JSP 中生成圖表

Cewolf(支持圖表的 Web 對象框架)構建在 JFreeChart 上,使開發人員可以通過 JSP 自定義標記從 JavaServer 頁面訪問 JFreeChart 庫。與 JFreeChart 一樣,Cewolf 也提供了一個簡單的 API。Cewolf 可免費獲得。在本示例中,我們使用 Cewolf 0.9.3。

圖 9 中的圖像是使用 JFreeChart 和 Cewolf JSP 標記生成的垂直條形圖的屏幕截圖。它在 Firefox Web 瀏覽器中顯示,在 Oracle Containers for J2EE 10g 上託管。該圖像證明 HR 數據中表示的虛擬公司中的管理人員薪資很好。

marx-jchart-f9.gif

圖 9:使用 Cewolf JSP 自定義標記在 JSP 中生成的堆積條形圖

使用 Cewolf 和 JSP 創建上圖所示的圖表很簡單。下面是該 JSP 頁面的代碼:

清單 8: 使用 Cewolf 標記生成圖表的 JSP 頁面

<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:cewolf="etc/cewolf.tld">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" />
<jsp:directive.page contentType="text/html;charset=windows-1252" />
<jsp:useBean id="chartData" 
class="org.marx.hr.charting.HrDeptSalariesCategoryDataset" />
<script type="JavaScript" src="overlib.js"><!-- overLIB (c) Erik Bosrup --></script>
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252" />
<title>Render JFreeChart in JSP with Cewolf JSP Tag Library</title>
</head>
<body>
<cewolf:chart id="theChart" type="stackedverticalbar"
title="Salaries For Each Department"
xaxislabel="Departments" yaxislabel="Salaries">
<cewolf:data>
<cewolf:producer id="chartData"  />
</cewolf:data>
</cewolf:chart>
<cewolf:img chartid="theChart" renderer="/cewolf"
alt="Salaries per Employee Along Department Lines"
width="1200" height="800"  />
</body>
</html>
</jsp:root>

特定於 Cewolf 的部分代碼包括 <cewolf:chart> 元素、<cewolf:img> 元素開始標記和結束標記之間的代碼行,指向 Cewolf 命名空間以定義這些元素的 cewolf 前綴的代碼行,以及用於包括實際生成圖表的 Java 類的 jsp:useBean 代碼行。

生成該示例所需的大多數工作都位於該 JSP 頁面通過 jsp:useBean 代碼行訪問的 Java 類中。該 Java 類實現幾個主要的 Cewolf 接口,從其 produceDataset(Map) 方法(實現 Cewolf 的 DatasetProducer 接口所需的方法)返回一個 JFreeChart 數據集子接口。

produceDataset(Map) 方法中的代碼僅創建相應 JFreeChart 數據集接口的具體實現,與本文前述示例中完全相同。在本示例中,DefaultCategoryDataset 被實例化,用數據進行填充,並從 produceDataset(Map) 返回,這是因爲 JSP 頁面需要可以實現提供的 CategoryDataset 接口以生成堆積垂直條形圖的內容。

Cewolf 主頁包括一個教程,該教程演示如何對 web.xml 文件進行修改以便在適當時候可以調用 Cewolf servlet。該教程還解釋如何實現 DatasetProducer 接口以便爲 JSP 頁面中的 Cewolf 自定義標記提供數據。

示例 6:使用 Apache Batik 在 SVG 中生成圖表

無需任何專門的工作,JFreeChart 即可提供現成的 PNG 和 JPEG 圖像生成。由於圖表實際上是由直線以及諸如矩形、圓形以及其他矢量形狀組成的,因此 SVG(可伸縮矢量圖形)等基於矢量的格式似乎都非常適合圖表。儘管 JFreeChart 並不直接提供 SVG 顯示功能,但它可與 Apache 的 Batik SVG 工具包結合使用以形成其圖表的 SVG 表示。

Batik SVG 工具包是一個基於 Java 的工具包,它用於操作 SVG,免費提供。本示例中使用 Batik 1.7。分發中包括幾個可執行的 JAR 文件。其中一個文件 (batik.jar) 是一個可執行的 JAR,它運行一個名爲 Squiggle 的 SVG 處理和查看工具 (java –jar batik.jar)。

在本示例中,我們首先將在自己的 Java 代碼中將 Batik 直接用作一個庫,然後將使用可執行的 JAR (batik.jar) 運行 Squiggle 以查看生成的 SVG 文件。爲了構建和運行本示例中與 Batik 有關的代碼,必須在類路徑(或者 JDeveloper 或其他 IDE 的項目)中包括六個 JAR 文件。圖 4 顯示了這六個 JAR 文件(六個以“Batik”開頭的 JAR 文件)。

在本示例中,生成的圖表是一個顯示發貨員工資的三維條形圖。這與前面的條形圖示例(示例 3)不同,因爲它具有三維而非二維的外觀,並被指定爲一個水平條形圖而非垂直條形圖。以下兩個代碼清單分別顯示瞭如何生成該圖表以及如何以 SVG 格式寫出。

清單 9: 創建三維條形圖

   /**
* Create 3D bar chart representing salaries of shipping clerks.
    * 
* @param aOrientation Horizontal or Vertical orientation.
* @return 3D bar chart.
    */
public JFreeChart createSalaryPerShippingClerkBarChart3D(
PlotOrientation aOrientation)
   {
JFreeChart barChart = null;
      
try
      {
final String QUERY_SALARY_PER_SHIPPING_CLERK =
"SELECT first_name || ' ' || last_name AS name, salary " +
"FROM employees " +
"WHERE job_id = 'SH_CLERK'";
final CategoryDataset barDataset =
new JDBCCategoryDataset( databaseAccess.getOracleDbConnection(),
QUERY_SALARY_PER_SHIPPING_CLERK );

barChart =
ChartFactory.createBarChart3D( TITLE_COUNTRIES_PER_REGION, // title
LABEL_SHIPPING_CLERKS,
LABEL_SALARIES,
barDataset,
aOrientation,
true,      // legend displayed
true,      // tooltips displayed
false );   // no URLs
      }
catch (SQLException sqlEx)
      {
// exception handling code . . .
      }
      
return barChart;
   }

上一個代碼清單演示了創建三維條形圖與創建二維條形圖基本相同,只是 ChartFactory 類上調用的方法名不同。以下代碼清單顯示瞭如何將這個或任何其他生成的 JFreeChart 寫出爲 SVG 格式。

清單 10: 以 SVG 格式顯示 JFreeChart 生成的圖表

/**
* Write .svg file based on provided JFreeChart.
    * 
* @param aChart Chart to be written out as SVG.
* @param aFileName Name of file (without extension) to hold SVG XML.
* @param aWidth Width of image.
* @param aHeight Height of image.
    */
public void writeSvgBasedOnChart( JFreeChart aChart,
String aFileName,
int aWidth,
int aHeight )
   {
final String fileExtension = ".svg";
final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
final DOMImplementation dom =
GenericDOMImplementation.getDOMImplementation();
org.w3c.dom.Document document = dom.createDocument(svgNS, "svg", null);
SVGGraphics2D svgGraphic = new SVGGraphics2D(document);
aChart.draw( svgGraphic, new java.awt.Rectangle(aWidth, aHeight) );
      
try
      {
boolean useCSS = true; // we want to use CSS style attributes
OutputStream outputStream =
new FileOutputStream(aFileName + fileExtension);
Writer output = new OutputStreamWriter(outputStream, "UTF-8");
svgGraphic.stream(output, useCSS);                                           
outputStream.flush();
outputStream.close();
      }
catch (IOException ioEx)
      {
System.err.println("Problem encountered trying to write SVG file: ");
ioEx.printStackTrace();
      }
   }

將三維條形圖傳給上面的方法以便寫出 SVG 時,會將該條形圖寫入到所提供的文件名。生成的 SVG 文件將只是一個擴展名爲 .svg 的文本文件,包含符合 SVG 的 XML 內容。可以用任何文本編輯器查看該生成文件中的 XML,但使用 Batik、Inkscape 或幾乎是任何現代圖形文件編輯器等工具查看 SVG 顯示的圖像,則更爲有趣。實際上,可以在任何最新版本的 Firefox Web 瀏覽器中直接打開某個 .svg 文件來查看 SVG,因爲它附帶了一個內置的 SVG 查看器。此處顯示的圖形是 Batik 的 Squiggle 顯示生成的 SVG 文件的快照。

marx-jchart-f10.gif

圖 10:SVG 格式的三維水平條形圖(由 Batik Squiggle 顯示)

用 SVG 格式顯示圖表有幾個好處,其中一個最明顯的好處就是能夠根據我們的需要放大圖像且不會損失分辨率,這都多虧了 SVG 矢量圖形的可伸縮性。其他好處包括使用 Inkscape 之類的工具或者甚至手動(如果需要的話)編輯生成的 SVG 來調整生成的圖像也變得相對容易。

示例 7:使用 iText 在 PDF 中顯示圖表

圖表經常用於爲管理人員、客戶、股東和其他利益相關者提供的演示中。然而,通過 Java 應用程序或作爲純文本文件顯示圖表通常不適合這些類型的觀衆。將生成的圖表添加到 PDF 中對於向不同的觀衆演示很有幫助。有幾種 Java 到 PDF 的轉換器適用於該目的。下面我們演示一個使用其中的一個 Java 到 PDF 庫 iText 的簡單示例。

iText Java 到 PDF 庫是免費提供的。我們的示例中使用的版本是 itext-2.0.2,是一個相對較小的文件,易於下載。這個下載的編譯 JAR 是一個可執行文件,可通過 java –jar itext-2.0.2 命令或單擊 Windows 中的 JAR 運行。運行該 JAR 會彈出“iText Toolbox”人機界面 (HMI),該界面可用於將文本或 TIFF 圖像轉換爲 PDF 並提供其他實用工具功能。該示例沒有使用這個 HMI,而是將 iText 用作一個庫並使用該庫將 JFreeChart 生成的圖表轉換爲 PDF。

下載 iText JAR 後的第一個步驟是將它放在 build 和運行時類路徑或 IDE 的項目中。使用 iText 將圖表寫入 PDF 並不比下載 JAR 文件並將其放在類路徑中難很多。以下兩個代碼清單顯示了創建圓環圖(類似於餅形圖,使用 PieDataset)的代碼以及將該生成的圖表寫出到 PDF 中的代碼。

清單 11: 創建圓環圖

   /**
* Create ring chart indicating number of countries in each region.
    * 
* @return Ring (similar to Pie) Chart with number of countries per region.
    */
public JFreeChart createCountriesPerRegionRingChart()
   {
JFreeChart ringChart = null;

try
      {
final String QUERY_NUMBER_COUNTRIES_PER_REGION =
"SELECT regions.region_name, count(*) AS num_countries " +
"  FROM regions, countries " +
"WHERE regions.region_id = countries.region_id " +
"GROUP BY regions.region_name";

final PieDataset ringDataset =
new JDBCPieDataset( databaseAccess.getOracleDbConnection(),
QUERY_NUMBER_COUNTRIES_PER_REGION );

ringChart =
ChartFactory.createRingChart(
TITLE_COUNTRIES_PER_REGION, // title
ringDataset,    // pie (ring) dataset
true,           // legend displayed
true,           // tooltips displayed
false );        // no URLs

      }
catch ( SQLException sqlEx )
      {
// exception handling code here . . . 
      }

return ringChart;
   }

上述代碼清單與本文中使用 JFreeChart 生成圖表的其他代碼清單十分相似。下一個代碼清單顯示如何將該圖表或任何其他使用 JFreeChart 生成的圖表寫入 PDF。生成的 JFreeChart(在本例中爲在上一個清單中創建的圓環圖)可以與包含應寫入的 PDF 文件的文件名的字符串一同被傳遞到下面的方法。

清單 12: 在 PDF 中顯示 JFreeChart 生成的圖表

   /**
* Write PDF based on the provided chart.
    * 
* @param aChart Chart to be written out as PDF.
* @param aOutputPdfFileName File name (without extension) to write PDF file.
* @param aWidth Width of chart to be rendered.
* @param aHeight Height of chart to be rendered.
    */
public void writePdfBasedOnChart( JFreeChart aChart,
String aOutputPdfFileName,
int aWidth,
int aHeight )
   {
final String fileExtension = ".pdf";
   
// com.lowagie.text.Document
Document document = new Document();
try
      {
PdfWriter.getInstance( document,
new FileOutputStream(  aOutputPdfFileName
+ fileExtension));
document.open();
Image png = Image.getInstance(
ChartUtilities.encodeAsPNG(
aChart.createBufferedImage(aWidth,aHeight)));
document.add(png);
document.close();
      }
catch (DocumentException docEx)  // checked exception
      {
docEx.printStackTrace();
      }
catch (IOException ioEx)     // checked exception
      {
ioEx.printStackTrace();
      }
   }

如上述代碼清單所示,只需六條與 iText 相關的 Java 代碼語句即可將提供的圖表寫入 PDF。這些步驟如下所示:

  • 創建 iText 文檔(從 com.lowagie.text 程序包中)。
  • 使用 open() 方法打開 iText 文檔。
  • 使用靜態 Image.getInstance() 方法調用實例化一個 iText 圖像,以 byte[] 形式接收圖表。
  • 將圖像添加到 iText 文檔中(使用它的 add() 方法)。
  • 關閉 iText 文檔(使用它的 close() 方法)。

圖 11 是上述代碼生成的 PDF 的屏幕截圖。

marx-jchart-f11.gif

圖 11:顯示包含生成的圓環圖的 PDF 的 Adobe Reader

JFreeChart 支持將圖表作爲 BufferedImage 以 byte[] 格式寫出,這使得將圖表轉換爲可以通過 iText 直接轉換爲 PDF 的格式變得十分簡單。

示例 8:自定義小圖

雖然該 servlet 示例顯示了某些圖表創建的自定義,但是本文前面的大多數示例都直接使用了 JFreeChart 生成的圖表,而沒有進行任何自定義。利用 JFreeChart,開發人員可以自定義圖表,但是這會增加複雜性。該示例顯示的是一些相當簡單的自定義,但是也可以進行功能強大得多也複雜得多的自定義。事實上,只要您願意編寫足夠多的代碼,自定義幾乎是沒有限制的。

在該示例中,生成的直線圖將具有一個透明的背景(透明性支持是 PNG 格式的衆多優勢中的一個),並將其系列繪圖顏色由默認的紅色改爲藍色。直線圖或許不是顯示 HR 模式中每個 Oracle 數據庫對象類型的數量的最佳圖表類型,但是使用直線圖爲我們提供了一個演示 JFreeChart 的三維直線圖功能的機會。

下面顯示了三個圖像。第一個(圖 12)是使用 Oracle 數據庫快捷版附帶的基於 Web 的管理工具的屏幕截圖,它按對象類型顯示了 HR 模式中的模式對象的數量。下一個圖像(圖 13)顯示 JFreeChart 使用默認的顏色(灰色背景和紅色繪圖色)未進行任何自定義現成生成的直線圖,第三個圖像(圖 14)顯示基於相同數據的自定義 JFreeChart 圖表。這兩個 JFreeChart 生成的圖像都顯示了各自在瀏覽器中顯示的圖表,背景顏色故意設置爲較暗的陰影以使自定義圖表的背景更明顯。

圖 14 中顯示的圖表具有一個透明的背景,這在該圖與圖 13 比較時最容易看到。但是,只有圖表的外部是透明的。具有實際圖形的繪圖部分稱爲繪圖區,在兩種情況下都是白色的。可以使用與更改整體圖表的背景相同的方式來更改繪圖區的背景顏色。按照在與在圖表自身上調用 setBackgroundPaint 方法相同的方式在繪圖區上調用 setBackgroundPaint 方法,就生成了圖 14。

marx-jchart-f12.gif

圖 12:Oracle 數據庫快捷版 Web 工具對 HR 數據庫對象的顯示

marx-jchart-f13.gif

圖 13:顯示 HR 模式中每個對象的數量的直線圖

marx-jchart-f14.gif

圖 14:與圖 13 中顯示的是同一個圖表,但是具有透明的背景顏色和藍色輪廓顏色

下一個代碼清單顯示生成自定義的三維直線圖的代碼。

清單 13: 生成具有背景透明性的 PNG 文件

   /**
* Write .png file with transparent background based on provided JFreeChart.
    * 
* @param aChart JFreeChart.
* @param aFileName Name of file to which JFreeChart will write chart.    
* @param aWidth Width of image.
* @param aHeight Height of image.
    */
public void writePngTransparentBasedOnChart( JFreeChart aChart,
String aFileName,
int aWidth,
int aHeight )
   {
final String fileExtension = ".png";
try
      {
aChart.setBackgroundPaint( new Color(255,255,255,0) );
         
CategoryItemRenderer renderer = aChart.getCategoryPlot().getRenderer();
renderer.setSeriesPaint(0, Color.blue.brighter());
renderer.setSeriesVisible(0, true); // default
renderer.setSeriesVisibleInLegend(0, true);  // default

ChartUtilities.writeChartAsPNG(
new FileOutputStream(aFileName + fileExtension),
aChart,
aWidth, aHeight,
null,
true,    // encodeAlpha
                             0 );
      }
catch (IOException ioEx)
      {
System.err.println( "Error writing PNG file "
+ aFileName + fileExtension);
      }
   }

示例 9:使用 XML 爲 JFreeChart 提供輸入數據

最後一個示例演示如何基於 XML 數據創建 JFreeChart。在本示例中,我們將使用 Oracle 數據庫支持以 XML 形式返回表中的數據。通常,當我們只使用 JDBC 數據集即可直接處理關係數據時,我們並不希望將關係數據轉換爲 XML 進行 JFreeChart 處理。但是,該關係到 XML 轉換的特性在本示例中卻很有用,因爲利用該特性,我們可以使用 HR 模式模擬面向 XML 的數據源。許多源都可以 XML 格式提供數據,包括 XML 數據庫(如存儲 XML 文檔而非傳統的標準化關係數據的 Oracle 數據庫)、XML Web 服務以及其他產品和庫。

在本示例中,我們將收集 HR 模式中有關員工佣金率的信息。我們在此處假定表中佣金值爲空的員工沒有佣金補償,因此只繪製了確實收到佣金的人員的佣金率圖表。清單 14 顯示了與此相關的一般關係數據查詢。

清單 14:用於佣金查詢的 SQL SELECT

SELECT commission_pct, count(commission_pct)
FROM   employees
WHERE commission_pct IS NOT NULL
GROUP BY commission_pct
ORDER BY commission_pct;

清單 14 中的查詢返回收到各個佣金級別(百分比)的員工的人數。總計中不包括未收到佣金的員工。

我們需要提供給 JFreeChart 以生成我們的圖表的 XML 數據需要滿足 JFreeChart 期望的 XML 語法。在清單 15 中,我們顯示了一個在清單 14 中首次列出的查詢的修改版本,它部分滿足 JFreeChart 對 XML 語法的期望。

清單 15: 使用列別名將查詢結果與 JFreeChart 期望的 XML 相匹配

SELECT commission_pct AS "Key"
count(commission_pct) AS "Value" 
FROM   employees
WHERE commission_pct IS NOT NULL
GROUP BY commission_pct
ORDER BY commission_pct

這個新版本的查詢重命名在 SELECT 語句中返回的列或使用該列的別名。我們現在不使用 commission_pct 和 count(commission_pct) 作爲列標題,而改用這兩個列標題的別名,分別稱爲 Key 和 Value。

雖然清單 15 對該查詢進行了修改,但是我們仍然不能以 XML 格式檢索數據。清單 16 提供了使用 OracleResultSet 以 XML 格式檢索數據庫中的數據的 Java 代碼。

清單 16: 以 XML 格式獲取 Oracle 數據庫中的數據

   /**
* Get commission percentage breakdown from database.
    */
public String getCommissionPercentageBreakdownAsXml()
   {
final String QUERY_NUMBER_EACH_COMMISSION_LEVEL =
"SELECT commission_pct AS /"" + DatasetTags.KEY_TAG + "/", " +
"count(commission_pct) AS /"" + DatasetTags.VALUE_TAG + "/" " +
"FROM employees " +
"WHERE commission_pct IS NOT NULL " +
"GROUP BY commission_pct " +
"ORDER BY commission_pct";

OracleXMLQuery qry =
new OracleXMLQuery( getOracleDbConnection(),
QUERY_NUMBER_EACH_COMMISSION_LEVEL);
qry.setRowTag(DatasetTags.ITEM_TAG);
qry.setRowsetTag(DatasetTags.PIEDATASET_TAG);

return qry.getXMLString();
   }

在清單 16 中,我們使用 JFreeChart 提供的靜態常量(DatasetTags.KEY_TAG 和 DatasetTags.VALUE_TAG)而非兩個列標題的硬編碼值(Key 和 Value),因此,在 JFreeChart 的以後版本中,該查詢仍將保持與這些常量的任何更改同步。

清單 16 顯示瞭如何使用 OracleXMLQuery 以 XML 格式獲得查詢數據。setRowTag 和 setRowsetTag 調用很重要,因爲利用通過它們,我們可以輕鬆更改行標記和行集標記以與滿足 JFreeChart 期望。如前所述,我們使用 JFreeChart 提供的常量(DatasetTags.ITEM_TAG 和 DatasetTags.PIEDATASET_TAG)指定這些標記的名稱。最後,在我們的 OracleXMLQuery 實例上調用 getXMLString 方法以完備的 XML 格式返回所有結果。清單 17 顯示該生成的 XML 字符串的內容。

清單 17: 通過 Oracle 數據庫查詢生成的 JFreeChart 兼容 XML

<?xml version = '1.0'?>
<PieDataset>
<Item num="1">
<Key>0.1</Key>
<Value>6</Value>
</Item>
<Item num="2">
<Key>0.15</Key>
<Value>5</Value>
</Item>
<Item num="3">
<Key>0.2</Key>
<Value>7</Value>
</Item>
<Item num="4">
<Key>0.25</Key>
<Value>6</Value>
</Item>
<Item num="5">
<Key>0.3</Key>
<Value>7</Value>
</Item>
<Item num="6">
<Key>0.35</Key>
<Value>3</Value>
</Item>
<Item num="7">
<Key>0.4</Key>
<Value>1</Value>
</Item>
</PieDataset>

如上面提到的,DatasetTags 常量用於提供 JFreeChart 期望的標記名稱 PieDataset、Item、Key 和 Value。由於有了 OracleXMLQuery 類、使用返回列的別名的能力以及 JFreeChart 提供的常量,我們現在已經準備好 XML 文檔可以將其填充到 JFreeChart 餅形圖中了。

清單 18 顯示如何使用 JFreeChart 的 DatasetReader 相應地將準備好的 XML 作爲輸入數據用於圖表生成。

清單 18: 使用 DatasetReader 處理 XML 輸入用於圖表生成

   /**
* Create 3D pie chart displaying the number of employees at each
* commission level.This method demonstrates use of DatasetReader to
* translate data from XML format to JFreeChart data format.
    * 
* @return 3D Pie Chart showing number of employees at each commission
*         level.
    */
public JFreeChart createCommissionsPercentagePerLevelPieChart()
   {
PieDataset pieData = null;

final String xmlData =
databaseAccess.getCommissionPercentageBreakdownAsXml();

final DatasetReader reader = new DatasetReader();
try
      {
pieData = reader.readPieDatasetFromXML(
new ByteArrayInputStream(xmlData.getBytes()) );
      }
catch (IOException ioEx)
      {
ioEx.printStackTrace();
      }

JFreeChart chart =
ChartFactory.createPieChart3D(
"Commissioned Employees at Each Commission Level",
pieData,
false, true, false );

// Chart specifically provides getCategoryPlot() and getXYPlot() methods,
// but not a getPiePlot() or getPiePlot3D() method.
final PiePlot3D plot = (PiePlot3D) chart.getPlot();
plot.setDepthFactor(0.35);       // pie depth 35% of plot height
plot.setForegroundAlpha(0.5f);   // Declare explicitly as float (50%)
plot.setLabelGenerator(new HrCommissionsPieGenerator());

return chart;
   }

清單 18 中在 DatasetReader 上調用的方法是專爲 PieDataset 實施設計的,方法名 (readPieDatasetFromXML) 證明了這一點。JFreeChart 的 DatasetReader 當前支持的另一個類型的數據集是 CategoryDataset(用於條形圖、直線圖等)。

清單 18 中的方法返回的 JFreeChart 實例的行爲方式與在前面所有示例中顯示的相同類的實例的行爲方式相似。換言之,這個從 XML 輸入數據生成 JFreeChart 可以保存爲 PNG 或 JPEG 文件,可以在 Swing 應用程序中顯示,可以在 servlet 或 JSP 頁面中顯示,甚至可以作爲 SVG 圖像或在 PDF 文件內顯示。

圖 15 顯示了從清單 18 中生成的 JFreeChart 顯示的 PNG。

marx-jchart-f15.gif

圖 15:用 XML 源數據生成的三維餅形圖

當您用數據庫數據構建圖表時,直接從數據庫結果構建通常要比先轉換爲 XML 然後再構建數據集簡單。這是因爲 XML 生成會給該過程增添額外的步驟,而且易於使用的 JDBC 數據集支持的圖表類型要比 XML 的 DatasetReader 支持的更多。DatasetReader 支持 PieDataset 和 CategoryDataset,同時除了用於餅形圖的 JDBC 數據集 (JDBCPieDataset) 和用於類別圖的 JDBC 數據集 (JDBCCategoryDataset) 之外,還有一個用於基於 x,y 的圖表的 JDBC 數據集 (JDBCXYDataset)。

當要繪製成圖表的數據在 XML 中“本機”可用時,JFreeChart 對 XML 輸入數據的支持很有用。但是,即使這個時候,數據的格式也可能不是 JFreeChart 所期望的。因此,源 XML 數據需要通過 XSLT、XQuery 或自定義處理轉換爲期望的 XML 格式。此外,XML 支持提供了一種簡單的方法,將用於圖表生成的靜態數據編寫爲可以輕鬆手動編輯然後用於構建圖表的純文本文件。

除了演示如何使用 XML 爲通過 JFreeChart 生成圖表提供數據外,該示例還演示了使用 JFreeChart 的其他自定義可能。在本示例中,檢索了繪圖的特定類型 (PiePlot3D)。該繪圖繼承自 PiePlot 並增加了一些特定於其三維特性的方法(如本示例中應用的深度設置)。然後,可以使用該 PiePlot3D 向餅塊中添加一些透明性,以使餅塊更深,並自定義餅塊的標籤。將圖 15 中的輸出與本文前面的餅形圖相比較演示了該自定義如何影響最終圖表。

清單 18 包括對 HrCommissionsPieGenerator 類的引用。該類(其定義如清單 18 所示)覆蓋了生成的餅形圖中的餅塊的標籤。

清單 19: 自定義餅形圖標籤

public class HrCommissionsPieGenerator implements PieSectionLabelGenerator
{       
   /**
* Generates a customized label for a pie section of pie chart depicting
* commissions levels.
    * 
* @param aDataset Dataset destined for pie chart.
* @param aKey The identifying key for each section of the pie chart.
    * 
* @return Customized label for section of pie chart identified by aKey.
    */
public String generateSectionLabel(final PieDataset aDataset,
final Comparable aKey)
   {
String labelResult = null;
if (aDataset != null)
      {
labelResult = (int)(Double.parseDouble(aKey.toString())*100) +
"% sales (" + aDataset.getValue(aKey).intValue() +
" employees)";
      }
      
return labelResult;
   }
}

儘管我們提供了 9 個示例來演示 JFreeChart 的功能和靈活性,但還是有很多未盡之處。下一節概述本文沒有重點描述的一些 JFreeChart 吸引人的特性。

其他 JFreeChart 特性

JFreeChart 提供很多本文未提及的特性和圖表類型。其中包括:

  • 本文生成和顯示的圖表類型只是 JFreeChart 使用默認設置生成的圖表類型中的一部分。許多其他圖表類型與財務報表圖表類型有關,如 Box and Whisker、Bubble、Candlestick、Gantt、High Low、Polar、Scatter Plot、Wafer Map、Waterfall 和 Wind Plot。識別自動提供的圖表類型的最簡單的方式是在 ChartFactory 類上使用 JDeveloper 的代碼完成 (CTRL+SPACE) 並從下拉列表中選擇一種“create…”方法(參見圖 16)。滾動條的長度表明還有多少可用圖表。

marx-jchart-f16.gif

圖 16:使用 JDeveloper 自動完成識別 JFreeChart 圖表類型

  • 即使用 JFreeChart 提供的所有圖表類型,還是會有一些情況需要提供額外的靈活性才能呈現完美的圖表。雖然 JFreeChart 簡化了許多圖表類型的創建,但它也爲開發人員提供了處理其他複雜性和顯著自定義提供的圖表類型的機會。本文只演示了該圖表自定義功能的一小部分。JFreeChart 公開低級別的 API (AWT/Java2D) 以便在管理人員需要時爲他們提供額外的靈活性。
  • JFreeChart(和 Cewolf)提供爲生成的圖表生成工具提示的機制。
  • JFreeChart 支持創建 HTML 圖像映射(參見 ChartUtilities 類的文檔)。
  • JFreeChart 可以在基於標準 Widget 工具包 (SWT) 的應用程序中使用。本文提到的一個示例涉及 Swing,但 JFreeChart 還可以與 SWT 結合使用。有關 JFreeChart 與 SWT 結合使用的詳細信息可以在 http://jfree.org/phpBB2/viewtopic.php?t=4693 找到。該鏈接還展現了 JFreeChart 論壇的有益之處。

總結 JFreeChart 的主要優勢

使用 JFreeChart 生成以數據爲中心的圖表有幾個令人信服的原因。下面是其中幾個最重要的原因:

  • 許可證/購買成本 — 免費。即使您將推薦的 JFreeChart 開發人員指南包含一點微薄的費用,該成本也是極低的,很難與之競爭。JFreeChart 在 GNU Lesser 一般公用許可下分發。
  • 強大特性 — 如果一個庫或框架缺少所需的特性,免費或低成本的許可並不足以讓人選擇它。JFreeChart 支持許多不同類型的圖表,並支持在許多不同的環境中以許多不同的格式顯示這些圖表。
  • 簡單性 — 強大的、功能齊備的庫通常極其複雜,學習時間較長。但是,JFreeChart 提供了一個 API,它學習和使用都極其容易,而且支持強大的特性。使用 JFreeChart 創建基本圖表十分簡單,創建更復雜的圖表只需不斷積累的使用 JFreeChart API 的經驗。面向 JDBC 的數據集使得根據存儲在關係數據庫中的數據顯示圖表變得極爲簡單。
  • 支持 Java 的若干版本 — 如同一下將 J2SE 5 和 Java SE 6 的批註、類和其他特性注入第三方框架、庫和工具。雖然這些特性提供有吸引力的優點,但如果它們的基準 Java 版本的日期早於 J2SE 5,這些特性會妨礙開發人員對新的框架或庫的利用。JFreeChart 1.0.6(編寫本文時的最新版本)所需的最低 Java 版本爲 JDK 1.3。這是很重要的,因爲使用 Java 1.4.2 的開發人員可以使用 JFreeChart 的最新版本。反過來,JFreeChart 可以與 Java SE 6 結合使用,本文的所有示例都是針對 Java SE 6 編譯和運行的。最後,如本文所演示的,JFreeChart 可以直接應用於 Java 標準版 (SE) 和 Java 企業版 (EE) 環境中的圖表生成。

獲得有關 JFreeChart 的其他信息

本文旨在介紹 JFreeChart 的衆多特性。然而,JFreeChart 是一個強大、功能齊備的庫,僅通過一篇文章無法全部涵蓋。有些資源開發人員可以訪問有關 JFreeChart 的更多信息,這些信息大多數可以通過 JFreeChart 的主頁訪問。

JFreeChart 類和接口的 Javadoc 文檔是在這篇介紹性文章基礎上進行提高的良好起點。當您在鏈接內下鑽足夠充分時,基於 Javadoc 的聯機文檔會鏈接到包含實際的 JFreeChart 代碼的 HTML 頁面(Javadoc“linksource”樣式)。有時,該方法比通過打開源代碼文件自身來檢查代碼更容易。

在我們的示例中,我們使用了 JFreeChart 提供的常量很多次。這些內容可以很方便地在 www.jfree.org/jfreechart/api/javadoc/constant-values.html 上找到。檢查這些 JFreeChart 常量可以提供有關 JFreeChart 默認值和設置的洞察。

聯機 JFreeChart 論壇還提供有關 JFreeChart 的以前的問題和解答的存檔,並允許開發人員提問。只需一點微薄的費用,開發人員即可購買和下載《JFreeChart 開發人員指南》瞭解更全面的 JFreeChart 知識。

結論

JFreeChart 爲生成以圖形的形式表示數據庫或其他數據的高質量圖表提供了一種免費、開放源代碼的方法。該庫易於學習和使用,可以生成許多類型的圖表,並支持在衆多不同的環境中以標準或企業 Java 顯示這些圖表。

發佈了29 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章