Java中利用JCOM操纵Office工具
副标题#e#
通过利用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和Excel
import 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包括了销售地域的名称和税率。
生成报表的时候,你需要利用下面的业务逻辑来算出真正的数值:
· 毛销售额便是销售项乘以销售价值加上地税金额。
· 纯销售额便是毛销售额减去销售人员提取的税前佣金。
#p#分页标题#e#
这都是一些在Java中可以实现的简朴直接的计较进程,可是我在本文中利用它们的目标是演示如何把这些数据写入Excel电子表格并让Excel自动计较。对付更巨大的环境(利用了更巨大的Excel公式),道理也是一样的。
另外,下载的内容中还包括了如图2所示的电子表格。它是作为"模板"供你填充适当的数据的电子表格。
图2:用于前端填凑数据的Excel模板
#p#副标题#e#
利用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中大概会留意到一个奇怪的函数挪用:
nCol = getExcelColumn(i);
#p#分页标题#e#
这是一个简朴的帮助函数,它把记录会合的列编号与Excel中存放数据的位置举办匹配。譬喻,假如你再次查察上面的SQL语句,佣金费率将返回到第8列。在电子表格中,存放它的列是第13列。这个函数用于处理惩罚两者之间的转换。更巨大的应用措施可以利用Excel中的定名(named)范畴来匹配列,可是这超出了本文的范畴。
最后,应用措施把公式输入适当的单位中。它是利用Excel的R1C1标记来实现的,因此相应的字符串是用于描写公式的。在Excel中,假设你但愿把第1行中A列的值与B列的值相加,然后放到C列中,那么你就需要在C列中输入公式"=A1+B1"。假如在第二行你也但愿这样操纵,那么可以复制和粘贴这个公式,它会自动地更新为"=A2+B2"。
从示例措施中获得这些值需要一些字符串操纵,可是假如利用"R1C1"相关的转换就很是直接了。在本文的例子中,你在C1中输入公式的时候,不需要给出"=A1+B1"引用,而是给出"=RC[-2]+RC[-1]"引用,它的意思是把向前两列的值与向前一列的值相加。
当你移动了其它行的时候,这个公式的值不会产生改变,因此它使我们生成措施所需要的值很是简朴了。这也是我用于计较总销售额、销售税金、毛销售额和纯销售额的要领,如下所示:
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)");
运行这段代码将获得图3所示的电子表格。
图3:公式:Excel显示了数据库查询的输出信息
请留意,这是一种较量好的工程学履历,即不要在应用措施中包括公式,因为公式大概随时改变,而你必定不但愿在改变公式的时候就去改变本身的代码。这种步伐使每个新数据行成为包括公式的已有数据行的副本。模板电子表格(sales.xls)包括了假数据,并在第二列中包括了公式(第一列包括了列标题)。因此,当你填充每行的时候,在你填入数据库值的之前线复制这一行的内容。通过这种步伐,公式通过复制进入了新数据行,而且你不需要在Java代码中包括任何业务逻辑。
我们看一看salesReport2.java文件(也在下载内容中)中的内容,你可以发明,我们并没有利用前面所说的公式,而是在While轮回顶部利用了下面的代码:
if(nRow>1)
{
String strDest="A"+(nRow+1);
ExcelRange xlRange2Copy = xlSheet.Range("A2:M2");
xlRange2Copy.Copy(xlSheet.Range(strDest));
}
除了第一行之外(第一行不需要处理惩罚,这样的信息已经包括在sales.xls中了),这段代码将处理惩罚A2到M2之间的单位,并把它们复制到nRow+1标识的数据行中(nRow是当前行的编号)。加上1的原因是计较了列标题(列标题在第一行)。
逾越Excel
请记着JCOM是用于COM的而不只仅是用于Excel的。你可以利用这种东西在Java中节制险些所有的COM工具。Excel是最常见的被节制工具,因为有许多很好的帮助类可以让它更简朴,可是所有的COM组件都是可以利用的。因此节制其它的应用措施(譬喻Word和Powerpoint)也是直接的。
下面是利用Word的一个例子:
IDispatch wdApp = new IDispatch(rm, "Word.Application");
wdApp.put("Visible", new Boolean(true));
由于没有用于Word的直接的帮助类,每个部门都必需通过利用IDispatch工具来实现(用于Excel的基层帮助类也是这样实现的)。上面的代码将载入微软Word副本,并通过wdApp工具使它可以自动化操纵。接着你可以利用雷同"put"(配置属性)或"method"(挪用要领)等要领来利用Word。譬喻,上面的代码把Visible属性配置为true,使得该Word应用措施可视。
假如你必然要利用Windows,那么有大量的COM组件可以扩充你的视野,它的数量比Java今朝提供的多许多。通过串行和并行口举办硬件节制也可以在Java中实现了,而这仅仅是个开始。在你的东西包中有了JCOM之后,就不受任何限制了。