前一个月搞的一个招生项目需要动态生成word文档并插入数据。好找一遍发现了Java2Word这个包。java2word是com桥jacob包的封装,它专门针对word文档的操作做了封装,方便使用。
说实话,java2word本身做的不咋地,兼容性不好,也不大稳定。在设计解决方案的时候因为这一点费了不少劲。现总结如下:
1. 安装java2word。该过程将其中的jacob.dll动态链接库复制到system32目录下,可能还有注册操作;
2. 将java2word.jar包复制到tomcat的lib下,引用至工程的build path中,或者直接复制到工程lib下。这两步保证了其中的jacob类正常连接com组件;
3. 编写访问类(见附录);
Java2word中每个word文档对应一个document对象。Document对象拥有open、close、insert以及find和replace等多种方法。另外,document还含有style属性及其getter和setter来设置word文档指定元素的格式,但这一属性我没用到。原因是只需在目标word文档中待插入数据的位置预先设置好格式,即可保证插入后的文档符合要求(除非需要动态改变)。
4. Eclipse的兼容性问题。
Java2word,或者说jacob本身对eclipse支持不是很好,在netbean上倒是可以正常调用。对于使用myeclipse的工程,仅按照上面设置可能会出错。这时可作如下处理:
将jacob.dll复制一份到eclipse使用的jdk/bin下(无需注册。需要注意的是eclipse默认使用自带的jdk,而不一定是我们安装的jdk,在复制前需要确认一下),这样就可以保证Jacob or java2word的正常工作。(这问题当时快把我给折腾死了)
5. Word本身对象模型的兼容性问题。
由于涉及到com组件,就必须考虑到与其通信的com组件本身的特性。我在开发时,系统环境是word 2007(当然是D版^^),结果错误百出,经常报java.lang.exception或者application.word没有注册的错误。在朋友提醒后我才恍然大悟:word2003跟2007的对象模型压根儿就是不一样的(至少有差别)。在换成2003后,问题搞定。
后话:其实对于传统word文档的操作一般都会使用asp.net等语言去完成,java与com组件的通信还是其一大软肋。当前的com桥有poi、jcom、jacob等。其中poi简洁易用但功能较弱,jacob功能强大但上手较慢,需视需求而定。
但这个问题在以openxml为基础的2007文档中是不存在的。2007文档实际上是对一组xml的压缩包,其内部结构可以通过将.docx的文档改名为.rar后打开查看便一目了然。这时我们只需要找到存储数据的xml,按照其格式来读取即可。
至于2007格式的word文档,见我转载的文章Java操作office 2007文档。
---------------------------------------------------------
附录:Convertor 类
/**
* This is the basic class to operate office files by Java, it's not suggested
* to use itself.Please use the classes derived from it.
*
* @filename: Convertor.java
* @author Me
*/
package ***.***.system.document;
import com.heavenlake.wordapi.Document;
import java.io.File;
import java.util.List;
public class Convertor
{
Document doc = null;
//DocumentLock dl = new DocumentLock( ); //加锁操作会与word程序本身的文件锁冲突
public Document open( String strFileName)
{
if ( "".equals( strFileName) || null == strFileName)
{
System.err.println( "File name error !");
return null;
}
//lock the word document. The release operation will appear in the funtion close()
//dl.setFile( strFileName);
//dl.lock( );
// judge the state of the file
File file = new File( strFileName);
if ( !file.canRead( ))
{
System.err.println( "File can not Read ! file:" + strFileName);
return null;
}
// Generate the Instance of Document
try
{
doc = new Document( );
}
catch ( Exception e1)
{
System.err.println( "Create Instance Failed (file name:"
+ strFileName);
e1.printStackTrace( );
return null;
}
// open the target document
try
{
if ( null == doc)
{
return null;
}
doc.open( strFileName);
return doc;
}
catch ( Exception e)
{
System.err.println( "The operation Open Failed (file name:"
+ strFileName);
e.printStackTrace( );
// close without save
if ( !this.close( false))
{
System.err.println( "Error occured when close the file:"
+ strFileName);
}
return null;
}// end catch
}
public boolean close( boolean bSave)
{
if ( null != doc)
{
// try to close
try
{
doc.close( bSave);
return true;
}
// if close failed
catch ( Exception e1)
{
// if bSave = true( means tried to close with save failed)
if ( bSave)
{
// try to close without save
try
{
if ( null != doc)
{
doc.close( !bSave);
}
}
// try to close without save failed
catch ( Exception e)
{
e.printStackTrace( );
}// end inner try
}// end inner if
System.err.println( "The operation Close Failed (document id:"
+ doc.toString( ));
}// end outer try
finally
{
//dl.release( );
}
}
return false;
}
/**
* Copy a word's document from a template(not *.dot, but *.doc)
*
* @param from:
* the template file
* @param to:
* the target file
* @return: result of the copy operation
*/
public boolean copy( String from, String to)
{
if ( null == from || "".equals( from) || null == to || "".equals( to))
{
return false;
}
// 简单的复制操作。对副本进行插入动作,保证原word文档不因插入操作失败而被损坏
return CopyFile.copyFile( from, to);
}
/**
* insert data into the place identified by bookmarks
*
* @param file:
* target file
* @param bookmark:
* List of bookmarks
* @param data:
* List of data
* @return result of the Insert operation
*/
public boolean conv( String file, List< String> bookmark, List< String> data)
{
if ( bookmark.size( ) != data.size( ))
{
System.err.println( "The count differs (" + file
+ ":bookmark and data)");
return false;
}
boolean result = false;
//Document doc = this.open( file);
if ( null == doc)
{
return result;
}
// open file and insert
try
{
result = true;
for ( int i = 0; i < bookmark.size( ); i++)
{
// when exception occurs, continue with the section FOR
try
{
doc.insertAtBookmark( bookmark.get( i), data.get( i));
}
catch ( Exception e)
{
System.err.println( "data insert failed (index:"
+ String.valueOf( i) + ")");
result = false;
continue;
}
}
}
catch ( Exception e1)
{
System.err.println( "Open file failed when trying to insert data:"
+ file);
// close the file
if ( !this.close( true))
{
result = false;
}
}
return result;
}
public boolean insertPic( String strFileName, String bookmark, File fImage)
{
if ( null == fImage)
{
System.err.println( "Image to insert into is INVALID !");
return false;
}
//Document doc = this.open( strFileName);
if ( null == doc)
{
return false;
}
try
{
doc.insertAtBookmark( bookmark, fImage);
return true;
}
catch ( Exception e)
{
System.err
.println( "Open file failed when trying to insert image, file name is "
+ strFileName);
e.printStackTrace( );
if ( !this.close( true))
{
return false;
}
return false;
}
}
public boolean replaceText( String strFilePath, String toFindText,
String toInsText, int index)
{
if ( null == strFilePath || "".equals( strFilePath))
{
System.err.println( "Document Path is INVALID !");
return false;
}
else if ( null == toFindText || "".equals( toFindText))
{
System.err.println( "Text to find is INVALID !");
return false;
}
else if ( null == toInsText || "".equals( toInsText))
{
System.err.println( "Text to Insert is INVALID !");
return false;
}
//Document doc = this.open( strFilePath);
if ( null == doc)
{
return false;
}
// insert
int i = 0;
try
{
// find to the former toFindText
for ( ; i < index; i++)
{
doc.find( toFindText);
}
// replace the next toFindText
if ( !doc.replace( toFindText, toInsText))
{
System.err.println( "No Matching ! index:" + i);
return false;
}
return true;
}
catch ( Exception e)
{
System.err.println( "Insert error ! File:" + strFilePath);
e.printStackTrace( );
// close
if ( !this.close( true))
{
return false;
}
return false;
}
}
//test//
public static void main( String[] args)
{
Convertor conv = new Convertor( );
Convertor conv1 = new Convertor( );
conv.open( "e:/1.doc");
conv1.open( "e:/1.doc");
}
}