Java调用微软com组件
背景
在一些企业级的JAVA应用开发中,需要对微软的office文档进行处理。比如:
- 将office文件软件为pdf
- 读取office文件中的内容
- 根据office文件模板生成office文件
- 修改office文件中的内容
- 。。。。。。
最常用的实现方式是使用Apache POI来实现office文件的操作功能。通过POI组件的使用,可以对office的word,excel,viviso,publiser的文档格式进行基本操作。但由于微软不是对自己所有office文档存储格式规范都开公的,比如(project),就没有办法使用POI组件进行操作。
即使公开结构的文档在使用POI组件进行一些特定操作时,也会有一些问题,比如:对文档进行格式化的操作,总是出现一些问题至使文件通过office软件打开以后不够美观。
有没有一种办法可以处理POI解决不了或是支持不好的问题呢,问题是肯定的。这里有一种组件jacob,可以提供选择。
jacob简介
什么是jacob
官方对jacob组件的说明如下:
JACOB is a JAVA-COM Bridge that allows you to call COM Automation components from Java.
It uses JNI to make native calls into the COM and Win32 libraries.
The JACOB project started in 1999 and is being actively used by thousands of developers worldwide.
As an open-source project, it has benefitted from the combined experience of these users, many of whom have made modifications to the code and submitted them back for inclusion in the project.
它把其技术组件的技术实现原理说得比较明白了,我用自己的理解说明一下。微软为office文档的操作提供了com组件,jacob就是通过自己编写的DLL(动态连接库)对office的com组件进行调用,并且提供java组件通过JNI对DLL进行调用,最终使用对office文件的操作。
下面具体说明一下jacob的使用。
运行环境安装
前置条件
要实现jacob组件对office文档的操作,首先需要安装office。也就是说需要在windows环境下运行(注:mac上可以安装office,但一般不会将一些应用部署在mac系统上,所以没有验证过该方式是否可行,也没有验证的意义。_!
网上也有说明可以通过Wine将office安装在Linux系统上,但因为有兼容问题,考虑到使用不稳定的因素,也没有进行尝试。待有需求的时候,再做尝试。)
安装DLL
因为我们是java程序,所以首先得安装JDK或JRE。
安装完成以后,下载jacob组件。将压缩包中的jacob-xxx.dll文件到系统环境变量目录中
一般情况就放在jdk或jre的bin目录下。
搭建开发环境
在工程中导入jacob组件中的java组件包jacob.jar
基于jacob开发
组件初始化
ComThread.InitSTA();
ActiveXComponent activexComponent = new ActiveXComponent("XX.Application");
其中ActiveXComponent类的构造函数中的参数可以是:
- PowerPoint.Application
- Word.Application
- Excel.Application
- MsProject.Application
- ......
执行指令
组件初始化完成以后就可以使用Dispatch.call,将对文件做操作了:
Dispatch.call(activexComponent,......)
比如打开一个project文件:
Dispatch.call(activexComponent, "FileOpen", new Object[] { mpxFilePath });
基本上对office文档的处理都是通过Dispatch.call方法来执行,返回一个句柄对象,再将句柄对象作为参数传给下一个Dispatch.call调用执行。
下面问题来了,我怎么知道我要对文档操作对应的指令是什么呢
?比如上面的例子中打开文件的指令是FileOpen
呢?办法就是打开office软件录制宏,下面为一段文件另存操作所录制的宏脚本:
Sub Macro11()
' 宏 Macro11
FileSaveAs Name:="C:\Users\ab053045\Documents\xxxx.mpp", FormatID:="MSProject.MPP"
End Sub
其中的文件另存为的指令为FileSaveAs
,指令需要传入两个参数,一个参数Name
为文件名称,另一个参数FormatID
为文件格式。但其中的参数还有哪些指令,哪些指令又是必填项和可选项呢?
这就需要引入office的参考文档了,开发office宏指令的开发文档。
在文档的标题筛选框
中输入指令名称,就可以查看指令的详细说明。
例子
大家都知道有一个组件MPXJ可以对Office的文件进行操作,但因为mpp文件的格式并没有对外公开,所以该组件的运维人员只能根据文件流的规律来封装。这不免无法提供全部的功能,也会对mpp文件的格式兼容性无法满足。比如:如果我的计划是基于最新的Office的Project软件编辑的,而且是mpx格式,那怎么办呢?
这里给出的一种解决方案就是使用Jacob打开这个文件,使用另存为指令,将该文件保存为mpp格式,后面就可以使用mpxj组件来读取该文件了。
下面是将mpx文件另存为mpp文件的代码,可以参照一下:
/**
* @param mpxFilePath
* mpx文件的文件路径包括文件名和文件后缀 转换执行成功,会在同文件夹下创建同文件名的mpp文件; 如:入参是
* C:\project\test-kjdp.mpx 成功转换后会在输出 C:\project\test-kjdp.mpp
*/
public static boolean convertMpxToMpp(String mpxFilePath) {
if ((StringUtils.isEmpty(mpxFilePath)) || (mpxFilePath.length() < 5)) {
return false;
}
ActiveXComponent activexComponent = null;
try {
ComThread.InitSTA();
activexComponent = new ActiveXComponent("MsProject.Application");
Variant localVariant = activexComponent.getProperty("Version");
activexComponent.setProperty("Visible", new Variant(false));
activexComponent.setProperty("DisplayAlerts", new Variant(false));
Dispatch.call(activexComponent, "FileOpen", new Object[] { mpxFilePath });
Dispatch.call(activexComponent, "FileSaveAs", new Object[] { mpxFilePath.substring(0, mpxFilePath.length() - 4) + ".mpp" });
} catch (Error error) {
error.printStackTrace();
} catch (Exception exception) {
exception.printStackTrace();
} finally {
if (activexComponent != null) {
Dispatch.call(activexComponent, "Quit", new Object[] { Integer.valueOf(0) });
}
ComThread.Release();
}
return true;
}