通過使用COM技術,我們用微軟Office應用程序能夠建立很多應用程序擴展,但是Java開發人員卻無法享受它帶來的便利–除非他們擁有方便的Java訪問COM的途徑(Java-to-COM橋)。使用JCom的時候,你可以在Java中控制幾乎所有的COM對象,而且它還帶有一些用於Excel的強大的輔助類。
在你每次編寫用HTML表格樣式或Java表格對象顯示數據的應用程序的時候,通常都需要帶有”導出到Excel”功能。那麼頭疼的問題就出現瞭。怎麼樣實現這種功能呢?在HTML中顯示的可以在Office 2003中處理嗎?沒有這麼好!你還必須支持Office 97!
你隻能去找一個符合當前需求的工具瞭,但是接著收到更多的要求瞭。”這能在Word中做到嗎?Powerpoint能做到嗎?能不能用調制解調器撥號到遠程服務器上並發佈數據?Java無法實現這些功能是什麼意思啊?Java可以實現任何功能。”
感謝作為Java和COM橋梁的框架組件,它使你在遇到這些情況的時候都可以回答”Yes”。Java-COM橋梁使你能夠根據自己的需要操作Windows組件–以前這是VB、C++和.NET開發人員的領地。你通過實現一個與DCOM後端(back end)對話的Java前端(front end),可以遠離端對端(end-to-end)的COM系統。在本文的末尾,你可以使用其中一個Java-to-COM橋:它可以被命名為JCom。
Excel基礎知識
開始之前,你需要首先從Sourceforge網站下載API。它包含瞭JCom所使用的Java類的所有源代碼、C++代碼和JCom用於配置Java和COM的編譯好的DLL。把這個DLL放到你的Java主目錄的/bin/目錄下面,否則會出現問題。同時,為瞭不出現問題,還要正確地設置JAVA_HOME環境變量。JCom的大多數文檔目前都是用日語寫的,但是翻譯工作正在進行中,因此以後會有些改進的。
下載和安裝過程完成以後,用列表1中的代碼試一試。這段代碼會建立到Excel的JCom接口,並把”Hello World”寫入第一個單元格中。你可以看到如圖1所示的結果。盡管JCom是一個通用的COM類庫,但是還是帶有很多用於Excel的輔助類,這是因為Excel可能是最常用的自動化COM應用程序。這些輔助類可以為我們節省很多時間,它們使JCOM成為一個更好的類庫瞭。
列表1:開始使用JCOM和Excelimport jp.ne.so_net.ga2.no_ji.jcom.excel8.*;
import jp.ne.so_net.ga2.no_ji.jcom.*;
public class testSimple
{
public static void main(String[] args) throws Exception {
ReleaseManager rm = new ReleaseManager();
try {
System.out.println(“EXCEL is Starting…”);
ExcelApplication excel = new ExcelApplication(rm);
excel.Visible(true);
ExcelWorkbooks xlBooks = excel.Workbooks();
ExcelWorkbook xlBook = xlBooks.Add();
ExcelWorksheets xlSheets = xlBook.Worksheets();
ExcelWorksheet xlSheet = xlSheets.Item(1);
ExcelRange xlRange = xlSheet.Cells();
xlRange.Item(1,1).Value(“Hello, World!” );
}
catch(Exception e) { e.printStackTrace(); }
finally { rm.release(); }
}
}
圖1:Java中使用Excel的第一個COM自動化
如果曾經使用VB或VBA來自動化Excel,那麼你應該很熟悉列表1中的代碼瞭。ExcelApplication類暴露瞭Workbooks()屬性,它列舉出Excel中當前打開的工作薄(workbook),並允許你向運行的Excel副本增加或刪除工作薄。使用.Add()方法增加工作薄,這個方法會返回一個工作薄的引用。
在Excel中工作薄用於保存輸入的數據。工作薄是XLS文件的基礎。一個工作薄由多個工作表(worksheet,在圖1中有三個工作表,分別叫做Sheet1、Sheet2和Sheet3)。工作表通過Item屬性來枚舉。你可以使用這個屬性訪問特定的工作表。在圖1中,Sheet 1是第一個工作表,因此你可以使用xlSheets.Item(1)來獲取對它的引用。
有瞭工作表之後,你就可以使用range(范圍)來操作它上面的數據。Range是一個單元格或多個單元格。例如,單元格A1可以使用range (1,1)來引用,接著可以使用Value屬性把數據載入單元格中。
更有意義的例子
假設你希望把Excel作為數據庫中某些數據的表現層。在Java中你希望通過JDBC獲取數據,並把數據顯示在Excel前端。這種假設是很好的,因為復雜業務邏輯中的用例(use case)已經用Excel前端顯示瞭,更不用說工作流中的其它的數據項的顯示和交互操作瞭。現在你不需要瞭解業務邏輯或分析,就可以使用原始的電子表格,並使用Java中的自動化來”填充它們之間的裂痕”。
我將給出一個演示這種操作的簡單示例:本文下載中所包含的內容是建立比較銷售行為的一個簡單的MySQL數據庫的。它有三個表:
· Sales是銷售的細節信息,包括銷售項、數量、銷售價格、是誰銷售的以及銷售地區。
· People包含銷售人員的姓名和傭金。
· Districts包含瞭銷售地區的名稱和稅率。
生成報表的時候,你需要使用下面的業務邏輯來算出真正的數值:
· 毛銷售額等於銷售項乘以銷售價格加上地稅金額。
· 純銷售額等於毛銷售額減去銷售人員提取的稅前傭金。
這都是一些在Java中可以實現的簡單直接的計算過程,但是我在本文中使用它們的目的是演示如何把這些數據寫入Excel電子表格並讓Excel自動計算。對於更復雜的情況(使用瞭更復雜的Excel公式),原理也是一樣的。
此外,下載的內容中還包含瞭如圖2所示的電子表格。它是作為”模板”供你填充適當的數據的電子表格。
圖2:用於前端填充數據的Excel模板
使用JCOM的時候,查詢數據庫中所有銷售數據需要使用下面的SQL:SELECT sales.id, sales.description, sales.quantity, sales.price, districts.districtname,districts.salestax,people.name,people.commission
FROM sales,districts,people
WHERE (sales.district = districts.id) AND (sales.salesperson = people.id)
接著使用自動化(automation)把每條記錄都寫入Excel電子表格的適當的列中。下載的內容中包含瞭完整的代碼(列表2所示)。在下面的部分,我將為你解釋代碼中使用JCOM的自動化部分。
列表2:從數據庫中獲取數據並載入Excel中的代碼// 首先建立Excel的引用
ExcelApplication excel = new ExcelApplication(rm);
// 使它可視
excel.Visible(true);
// 接著打開我們將使用的模板工作薄
ExcelWorkbooks xlBooks = excel.Workbooks();
ExcelWorkbook xlBook = xlBooks.Open(“c:\sales.xls”);
// 接著獲取我們將修改的范圍的引用
ExcelWorksheets xlSheets = xlBook.Worksheets();
ExcelWorksheet xlSheet = xlSheets.Item(1);
ExcelRange xlRange = xlSheet.Cells();
…
// 此處放置數據庫鏈接和查詢建立代碼
…
if (stmt.execute(strSql))
{
rs = stmt.getResultSet();
}
int nColCount = rs.getMetaData().getColumnCount();
int nRow=1;
int nCol=0;
// 在記錄集中循環
while(rs.next())
{
// 記錄集中的每行都是電子表格中的一行
nRow++;
for(int i=1;i<=nColCount;i++)
{
// 匹配DB列和電子表格列
nCol = getExcelColumn(i);
// 查找於行和列對應的單元格,並把它設置為適當的記錄集字段
xlRange.Item(nRow,nCol).Value(rs.getObject(i).toString());
}
// 填入公式
xlRange.Item(nRow,7).Value(“=RC[-2]*RC[-1]”);
xlRange.Item(nRow,9).Value(“=RC[-2]*RC[-1]/100”);
xlRange.Item(nRow,10).Value(“=RC[-3]+RC[-1]”);
xlRange.Item(nRow,11).Value(“=RC[-4]*((100-RC[2])/100)”);
}
在列表2的第一部分中,其目標是獲取希望修改的單元格的控制權。這會花費瞭一定的開銷。
· 首先你必須獲取表現Excel本身的對象,有瞭JCOM輔助類的幫助以後,這一步操作相當直接。ExcelApplication excel = new ExcelApplication(rm);
· 下一步,你希望獲取對工作薄集合的訪問權。你希望打開自己的模板工作薄(本示例中這個模板在C:sales.xls中),在工作薄集合中打開它。ExcelWorkbooks xlBooks = excel.Workbooks();
· 下一步,你希望打開自己的工作薄並獲取該工作薄集合的引用。ExcelWorkbook xlBook = xlBooks.Open(“c:\sales.xls”);
ExcelWorksheets xlSheets = xlBook.Worksheets();
· 最後,你希望獲取集合中的第一個工作表,並把工作范圍定義為整個工作表。ExcelWorksheet xlSheet = xlSheets.Item(1);
ExcelRange xlRange = xlSheet.Cells();
完成這些工作以後,你的xlRange對象將允許你在單元中放入值和公式瞭。通過在前面的記錄集(從提交給數據庫的SQL命令中返回的)中循環,使用xlRange.Item(nRow,nCol).Value(“whatever”)語法,逐行逐列地把記錄集中的值插入到電子表格中(語法中的whatever來自於記錄集)。通過使用rs.getObject(i).toString可以得到當前行中I列的值。通過使用rs.movenext(),當前行一直向後移動,直到記錄集的末尾。
你在列表2中可能會註意到一個奇怪的函數調用:nCo