最近公司的项目要求实现word文档根据模板导出和打印。
我采用Jacob的来实现。
Tomcat服务启动后,第一次导出和打印,没有异常。再次调用时,报出异常:
操作word文档失败!com.jacob.com.ComFailException: Can't map name to dispid: Open
2009-03-17 15:11:41,812 WARN [org.apache.struts.action.RequestProcessor] - <Unhandled Exception thrown: class com.jacob.com.ComFailException>
2009-3-17 15:11:41 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet action threw exception
com.jacob.com.ComFailException: Can't map name to dispid: Quit
需要重新启动服务。
word操作的实现类:
public class JacobWord {
private boolean saveOnExit;
//word文档
Dispatch doc = null;
//word运行程序对象
static ActiveXComponent word;
//所有word文档
static Dispatch documents;
static{
word = new ActiveXComponent("Word.Application");
word.setProperty("Visible", new Variant(false));
documents = word.getProperty("Documents").toDispatch();
}
//构造函数
public JacobWord(){
saveOnExit = true;
}
/**
* 打开文件
* @param inputDoc 要打开的文件,全路径
* @return 打开的文件
*/
public Dispatch open(String inputDoc){
return Dispatch.call(documents, "Open", inputDoc).toDispatch();
}
/**
* 选定内容
* @return 选定的范围或插入点
*/
public Dispatch select(){
return word.getProperty("Selection").toDispatch();
}
/**
* 把插入点移动到文件首位置
* @param selection 插入点
*/
public void moveStart(Dispatch selection){
Dispatch.call(selection, "HomeKey", new Variant(6));
}
/**
* 从选定内容或插入点开始查找文本
* @param selection 选定内容
* @param toFindText 要查找的文本
* @return true:查找到并选中该文本;false:未查找到文本。
*/
public boolean find(Dispatch selection,String toFindText){
//从selection所在位置开始查询
Dispatch find = Dispatch.call(selection, "Find").toDispatch();
//设置要查找的内容
Dispatch.put(find, "Text", toFindText);
//向前查找
Dispatch.put(find, "Forward", "True");
//设置格式
Dispatch.put(find,"format","True");
//大小写匹配
Dispatch.put(find, "MatchCase", "True");
//全字匹配
Dispatch.put(find, "MatchWholeWord", "True");
//查找并选中
return Dispatch.call(find, "Execute").getBoolean();
}
/**
* 把选定内容替换为设定文本
* @param selection 选定内容
* @param newText 替换为文本
*/
public void replace(Dispatch selection,String newText){
Dispatch.put(selection, "Text", newText);
}
/**
* 全局替换
* @param selection 选定内容或起始插入点
* @param oldText 要替换的文本
* @param replaceObj 替换为文本
*/
public void replaceAll(Dispatch selection,String oldText,Object replaceObj){
//移动到文件开头
moveStart(selection);
String newText = (String)replaceObj;
while(find(selection,oldText)){
replace(selection,newText);
Dispatch.call(selection, "MoveRight");
}
}
/**
* 保存文件
* @param outputPath 输出文件(包含路径)
*/
public void save(String outputPath){
Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(), "FileSaveAs",outputPath);
}
/**
* 关闭文件
* @param doc 要关闭的文件
*/
public void close(Dispatch doc){
Dispatch.call(doc, "Close",new Variant(saveOnExit));
}
/**
* 根据模板、数据生成word文件
* @param inputPath 模板文件(包含路径)
* @param outPath 输出文件(包含路径)
* @param data 数据包(包含要填充的字段、对应的数据)
*/
public void toWord(String inputPath,String outPath,HashMap data){
String oldText;
Object newValue;
try{
doc = open(inputPath);
Dispatch selection = select();
Iterator keys = data.keySet().iterator();
while(keys.hasNext()){
oldText = (String)keys.next();
newValue = data.get(oldText);
replaceAll(selection,oldText,newValue);
}
save(outPath);
}catch(Exception ex){
System.out.println("操作word文档失败!"+ex);
}finally{
if(doc != null){
close(doc);
}
}
}
public void saveDoc(String inPath,String outPath,HashMap map,boolean isPrint){
toWord(inPath,outPath,map);
ActiveXComponent objWord = new ActiveXComponent("word.Application");
Dispatch wordObject = (Dispatch)objWord.getObject();
Dispatch.put((Dispatch)wordObject,"Visible",new Variant(false));
Dispatch documents = objWord.getProperty("Documents").toDispatch();
Dispatch document = Dispatch.call(documents, "Open", outPath).toDispatch();
if(isPrint){
Dispatch.call(document, "PrintOut"); //打印
}
Dispatch.call(document, "Close", new Variant(false));
objWord.invoke("Quit", new Variant[0]);
word.invoke("Quit", new Variant[0]);
}
}
解决:
经过多次调试,发现内存消耗严重。查看任务管理器,有多个word进程积压未关闭。
发现原因:第一次调用完后,虽然word已经被关闭。但装载word的ActiveXComponent并没有被关闭。
所以,加入管理com组件的线程,在关闭word之后,关闭线程。
重构后的代码:
public class JacobWord {
/**
* 打开文件
* @param documents
* @param inputDocPath
* @return
*/
private Dispatch open(Dispatch documents,String inputDocPath){
return Dispatch.call(documents,"Open",inputDocPath).toDispatch();
}
/**
* 选定内容
* @param word
* @return
*/
private Dispatch select(ActiveXComponent word){
return word.getProperty("Selection").toDispatch();
}
/**
* 把插入点移动到文件首位置
* @param selection
*/
private void moveStart(Dispatch selection){
Dispatch.call(selection, "HomeKey",new Variant(6));
}
/**
* 从选定内容或插入点开始查找文本
* @param selection 选定内容
* @param toFindText 要查找的文本
* @return true:查找到并选中该文本;false:未查找到文本。
*/
private boolean find(Dispatch selection,String toFindText){
//从selection所在位置开始查询
Dispatch find = Dispatch.call(selection, "Find").toDispatch();
//设置要查找的内容
Dispatch.put(find, "Text", toFindText);
//向前查找
Dispatch.put(find, "Forward", "True");
//设置格式
Dispatch.put(find,"format","True");
//大小写匹配
Dispatch.put(find, "MatchCase", "True");
//全字匹配
Dispatch.put(find, "MatchWholeWord", "True");
//查找并选中
return Dispatch.call(find, "Execute").getBoolean();
}
/**
* 把选定内容替换为设定文本
* @param selection
* @param newText
*/
private void replace(Dispatch selection,String newText){
Dispatch.put(selection, "Text", newText);
}
/**
* 全局替换
* @param selection
* @param oldText
* @param replaceObj
*/
private void replaceAll(Dispatch selection,String oldText,Object replaceObj){
moveStart(selection);
String newText = (String)replaceObj;
while(find(selection,oldText)){
replace(selection,newText);
Dispatch.call(selection, "MoveRight");
}
}
/**
* 打印
* @param document
*/
private void print(Dispatch document){
Dispatch.call(document, "PrintOut");
}
/**
* 保存文件
* @param word
* @param outputPath
*/
private void save(ActiveXComponent word,String outputPath){
Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(), "FileSaveAs",outputPath);
}
/**
* 关闭文件
* @param doc
*/
private void close(Dispatch doc){
Dispatch.call(doc, "Close",new Variant(true));
}
/**
* 保存打印doc文档
* @param inputDocPath
* @param outPutDocPath
* @param data
* @param isPrint
*/
public void saveDoc(String inputDocPath,String outPutDocPath,HashMap data,boolean isPrint){
//初始化com的线程
ComThread.InitSTA();
//word运行程序对象
ActiveXComponent word = new ActiveXComponent("Word.Application");
//文档对象
Dispatch wordObject = (Dispatch) word.getObject();
//设置属性 Variant(true)表示word应用程序可见
Dispatch.put((Dispatch)wordObject,"Visible", new Variant(false));
//word所有文档
Dispatch documents = word.getProperty("Documents").toDispatch();
//打开文档
Dispatch document = this.open(documents,inputDocPath);
Dispatch selection = this.select(word);
Iterator keys = data.keySet().iterator();
String oldText;
Object newValue;
while(keys.hasNext()){
oldText = (String)keys.next();
newValue = data.get(oldText);
this.replaceAll(selection, oldText, newValue);
}
//是否打印
if(isPrint){
this.print(document);
}
this.save(word,outPutDocPath);
this.close(document);
word.invoke("Quit", new Variant[0]);
//关闭com的线程
ComThread.Release();
}
}
分享到:
相关推荐
《使用Jacob库导出Word文档详解》 在Java编程中,有时我们需要与Microsoft Office应用程序进行交互,例如创建、编辑或导出Word文档。在这种情况下,Jacob(Java COM Bridge)库是一个非常有用的工具。Jacob允许Java...
标签中的"java导出word文档"、"jacob word导出"和"word导出图"暗示了这个项目可能还涵盖了在Word文档中插入图片的功能。使用Jacob,可以调用Word的API来插入图片,如下所示: ```java // 获取当前活动文档的Body...
最近因项目开发的需要,整理了一份用JAVA导出WORD文档,其部署步骤如下: 1、将jacob-1.14.3-x86.dll放在服务器的系统盘(或运行本机的系统):\WINDOWS\system32目录下。 2、将jacob-1.14.3-x86.dll放在JDK 的 bin ...
总的来说,Jacob提供了一种在Java中自动化处理Word文档的方法,适用于批量处理、数据导入导出、文档生成等场景。通过深入理解和运用Jacob库,开发者可以实现对Word文档的灵活控制和定制化处理。
下面我们将深入探讨jacob库以及如何使用它来导出Word文档。 首先,jacob是一个开源的Java库,它为Java程序员提供了一个接口,使得可以在Java代码中调用COM组件,例如Microsoft Office套件中的Word。这使得开发者...
基于Java语言来导出Word文档的方式也有很多种,如Jacob,Apache POI,Freemarker,PageOffice,java2word 等等。。。。 在这里将通过Freemarker这个模板引擎来实现导出 Word,项目不限于Swing,SSH,SSM,Spring ...
6. **保存并关闭**:转换完成后,记得保存PDF文件,并关闭Word文档以释放资源。 在实际应用中,需要注意的是,由于是通过Office的COM接口进行转换,所以这个过程可能会受到Office版本的影响,不同版本的Office对...
错误可能出现在生成Word文档、使用Jacob操作Word,或者转换为PDF的任一阶段。可能的原因包括但不限于: 1. FreeMarker模板语法错误:模板中的表达式或控制结构可能有误。 2. 数据绑定问题:Java代码未能正确地将...
### Java使用JACOB操作Word文档详解 #### 一、简介 在企业级应用开发中,经常需要将数据导出为Word文档格式。Java通过调用Microsoft Office API可以实现这一功能,但通常需要安装Office环境,这在服务器环境中是不...
通过以上步骤,你可以在Flash Builder中利用JACOB库来创建和操作Word文档,实现自动化报告生成、数据导出等功能。这种方法尤其适用于需要批量生成Word文档,或者与现有Flex应用程序集成的场景。
7. **保存和关闭文档**:完成内容写入后,记得保存并关闭Word文档,释放COM资源。 这个过程涉及到的知识点包括Java COM编程、FreeMarker模板语法、数据绑定以及文件I/O操作。通过这样的组合,开发者可以在不直接...
在Java编程环境中,有时我们需要生成包含图片的Word文档,这时可以使用Jacob库。Jacob是一个Java和COM接口的桥梁,允许Java程序调用Windows API,包括Microsoft Office的各种功能。本篇文章将详细讲解如何使用Jacob...
5. **释放资源**:完成转换后,记得使用`dispose()`方法释放COM对象,防止资源泄露。 **注意事项:** 1. **系统配置**:在64位系统上运行32位Jacob或反之,可能需要配置系统环境变量,比如设置`java.library.path`...
- 打开 Word 文档,使用 `Document` 类并调用 `open()` 方法。 - 调用 `saveAs()` 方法,将 `Document` 保存为 HTML 格式,设置相应的输出路径和文件名。 - 关闭 `Document` 和 `WordApplication`,释放资源。 3...
首先,`MsWordUtils.java`可能是一个包含具体操作Word文档方法的工具类,例如打开文档、读取内容、修改内容、保存文档等。这些方法通常会利用jacob库提供的`ActiveXComponent`、`Dispatch`等接口,创建与Word应用...
4. **错误处理和资源释放**:在进行转换时,必须考虑到可能的异常情况,如文件不存在、权限问题等,需要捕获并适当地处理这些异常。转换完成后,记得关闭Word文档和释放COM对象,防止资源泄漏。 5. **`WordToJPG....
Java2Word 是一个Java库,用于将数据转换为...总的来说,Java2Word通过Jacob组件为Java开发者提供了便捷的途径,使他们能够在服务器端生成、修改和合并Word文档,这对于自动化报告生成、数据导出等业务场景非常有用。
### Word导出方案知识点概述 本文档主要围绕Word导出技术进行探讨,特别是...作者提出的自定义解决方案不仅克服了这些限制,而且提供了一个更加灵活和实用的方法来实现在不同操作系统之间高效地生成和管理Word文档。
虽然描述中没有提供具体细节,但我们可以推测博主可能分享了关于如何设置和配置Jawin与Jacob,以及如何利用它们创建、读取、修改或导出Word文档的步骤和示例代码。 标签“源码”暗示了博客内容可能包括了一些实际的...