服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

java中使用jcom操作office对象


  通过使用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(); }
}
}

java中使用jcom操作office对象
图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所示的电子表格。它是作为"模板"供你填充适当的数据的电子表格。

java中使用jcom操作office对象
图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中可能会注意到一个奇怪的函数调用:

ncol = getexcelcolumn(i);
  这是一个简单的辅助函数,它把记录集中的列编号与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所示的电子表格。

java中使用jcom操作office对象
图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之后,就不受任何限制了。

扫描关注微信公众号