网络上已经有很多这方面的内容,在用之前也是参考了好多别人的文章,下面记录下我自己的整合过程。整个过程都比较简单:
开发环境:win8 64位系统,在2008下面部署也是一样的。
文档要求jdk的版本要1.7的某个版本以上,我用的是:java version "1.7.0_80"
其他系统和环境可以下载相应的旧版本。
我是从http://sourceforge.net/projects/jacob-project/files/jacob-project/ 这里下载最新的版本jacob-1.18-M2
一个简单的工具类:
package cn.xm.exam.utils; import java.io.File; import java.io.IOException; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; /** * word转pdf的工具 * * @author QiaoLiQiang * @time 2018年1月4日下午2:18:33 */ public class Word2PdfUtil { static final int wdDoNotSaveChanges = 0;// 不保存待定的更改。 static final int wdFormatPDF = 17;// word转PDF 格式 public static void main(String[] args) throws IOException { String source1 = "C:\Users\liqiang\Desktop\考试试卷.doc"; String target1 = "C:\Users\liqiang\Desktop\考试试卷.pdf"; Word2PdfUtil.word2pdf(source1, target1); } /** * * @param source * word路径 * @param target * 生成的pdf路径 * @return */ public static boolean word2pdf(String source, String target) { System.out.println("Word转PDF开始启动..."); long start = System.currentTimeMillis(); ActiveXComponent app = null; try { app = new ActiveXComponent("Word.Application"); app.setProperty("Visible", false); Dispatch docs = app.getProperty("Documents").toDispatch(); System.out.println("打开文档:" + source); Dispatch doc = Dispatch.call(docs, "Open", source, false, true).toDispatch(); System.out.println("转换文档到PDF:" + target); File tofile = new File(target); if (tofile.exists()) { tofile.delete(); } Dispatch.call(doc, "SaveAs", target, wdFormatPDF); Dispatch.call(doc, "Close", false); long end = System.currentTimeMillis(); System.out.println("转换完成,用时:" + (end - start) + "ms"); return true; } catch (Exception e) { System.out.println("Word转PDF出错:" + e.getMessage()); return false; } finally { if (app != null) { app.invoke("Quit", wdDoNotSaveChanges); } } } }
结果:
Word转PDF开始启动...
打开文档:C:UsersliqiangDesktop考试试卷.doc
转换文档到PDF:C:UsersliqiangDesktop考试试卷.pdf
转换完成,用时:8606ms
整个代码只需要一个jacob的jar包就可以运行了。
当然,在下载的文件里面还有个调用系统库的dll文件需要放置在jre的bin目录下:
示例:D:Javajdk1.7.0_67jreinjacob-1.18-M2-x64.dll
这样代码就可以实现word转pdf了。
下面附上maven的pom.xml配置,因为jacob包没在第三方仓库上面直接找到,所以需要手动上传到maven中央库,或者配置下本地路径,下面粘下本地路径的配置:
<dependency> <groupId>com.jacob</groupId> <artifactId>jacob</artifactId> <version>1.18-M2</version> <scope>system</scope> <systemPath>C:/Users/Downloads/jacob-1.18-M2/jacob.jar</systemPath> </dependency>
这样项目构建的时候就不会出错。
顺便提一句:在部署的服务器上面需要安装office软件,要不然转换不成功,会报错。
查看office激活剩余天数方法参考:
https://zhidao.baidu.com/question/1047689643813754659.html
在windowsServer2012服务器上安装office之后报错:VariantChangeType failed
解决办法:
Windows Vista/2012改变了COM对象默认的交互方式为“非交互”型的。Console启动本身支持应用交互,但service模式下就不行了。所以需要修改word DCOM默认的标识,改为“交互式用户”模式,即可正常调用了。 按照以下步骤修改后再测service模式下试转Word即可成功: 1) 运行命令: mmc comexp.msc -32 2) 找到:组件服务>计算机>我的电脑>DCOM组件>Microsoft Word 97-2003 文档; 3) 右键点击,选择属性,修改标识为“交互式用户”,点击“确定”;
放在服务器上也报一个错误:com.jacob.com.ComFailException: Can't co-create object解决办法
解决办法:
在使用jacob调用VB.NET写的dll时,总是报错 com.jacob.com.ComFailException: Can't co-create object at com.jacob.com.Dispatch.createInstanceNative(Native Method) at com.jacob.com.Dispatch.<init>(Dispatch.java:99) at com.jacob.samples.test.CallDll.JavaCallVbdll(CallDll.java:19) at com.jacob.samples.test.CallDll.main(CallDll.java:13) 网上找到几种解决办法: 1.没有释放com线程或者干脆没有使用com线程控制。因此解决方案即:释放com线程(ComThread.Release();)。因此修改代码为 public static String JavaCallVbdll(String str){ ComThread.InitSTA(); String res=""; try { Dispatch test = new Dispatch("TestDLL.ComClass1"); Variant result = Dispatch.call(test, "teststr", str); res=result.toString(); }catch (Exception e) { res=""; e.printStackTrace(); }finally { ComThread.Release(); } return res; } 对不起,不成功!!!! 2.在系统的服务进程中,找到“DCom Server Process Launcher”这个服务选项,请确认这个服务是关闭着的,还是开启的。 http://babystudyjava.iteye.com/blog/1746597 不好意思,我们开着呢!!! 3.JDK与JACOB版本对应,我的JDK是1.7,JACOB是1.17,电脑是win10,都是64位的。 奔溃,各版本都试过!!! 4.jar和dll文件版本需对应,jar包是64位的,dll文件是同事开发的,所以就去询问同事给我的是什么版本的dll,同事当时不造。。。 后来在Google找到一篇帖子说在VB.NET中编译选择的平台如果是Any CPU,那么久意味着生成的dll文件是32位的。没想到我们的dll文件真的是这样编译的!这里写图片描述 如上图:将Any CPU换成x64重新编译就可以了。 如此问题就解决了!!!
最后还是不稳定,最终决定直接生成pdf文件:参考http://www.cnblogs.com/qlqwjy/p/8213989.html
附一个freemarker模板生成doc文档之后转为pdf的代码:
package cn.xm.exam.action.exam.exam; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URLEncoder; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import org.apache.commons.io.FileUtils; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.struts2.ServletActionContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionSupport; import cn.xm.exam.bean.exam.Exampaper; import cn.xm.exam.service.exam.examPaper.ExamPaperService; import cn.xm.exam.utils.RemoveHtmlTag; import cn.xm.exam.utils.Word2PdfUtil; import freemarker.template.Configuration; import freemarker.template.Template; import jxl.common.Logger; /** * 导出试卷 1.查出数据 2.Word 3.打开流,提供下载 * * @author QiaoLiQiang * @time 2017年10月31日下午10:29:51 */ @Controller @Scope("prototype") @SuppressWarnings("all") public class ExtExamPaperAction extends ActionSupport { private Logger logger = Logger.getLogger(FindExamAction.class); private String fileName;// 导出的Excel名称 @Autowired private ExamPaperService examPaperService; // 1.查数据 private String paperId; public Exampaper findPaperAllInfoById() { Exampaper paper = null; try { paper = RemoveHtmlTag.removePaperTag(examPaperService.getPaperAllInfoByPaperId(paperId)); } catch (SQLException e) { logger.error("查询试卷所有信息出错!!!", e); } return paper; } // 2.写入Word public void writeExamPaper2Word(Exampaper paper) { // 获取路径 String path = ServletActionContext.getServletContext().getRealPath("/files/papers"); // 用于携带数据的map Map<String, Object> dataMap = new HashMap<String, Object>(); dataMap.put("paper", paper); String filePath = path + "\" + fileName + ".doc"; // Configuration用于读取ftl文件 Configuration configuration = new Configuration(); configuration.setDefaultEncoding("utf-8"); // 指定路径的第一种方式(根据某个类的相对路径指定) configuration.setClassForTemplateLoading(this.getClass(), ""); // 输出文档路径及名称 File outFile = new File(filePath); // 获取文件的父文件夹并删除文件夹下面的文件 File parentFile = outFile.getParentFile(); // 获取父文件夹下面的所有文件 File[] listFiles = parentFile.listFiles(); if (parentFile != null && parentFile.isDirectory()) { for (File fi : listFiles) { // 删除文件 fi.delete(); } } // 以utf-8的编码读取ftl文件 try { Template t = configuration.getTemplate("paperModel.ftl", "utf-8"); Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240); t.process(dataMap, out); out.close(); } catch (Exception e) { logger.error("写入word出错!", e); } } // 3.打开文件的流提供下载 public InputStream getInputStream() throws Exception { Exampaper paper = this.findPaperAllInfoById();// 查数据 this.writeExamPaper2Word(paper);// 写入数据 String path = ServletActionContext.getServletContext().getRealPath("/files/papers"); String filepath = path + "\" + fileName + ".doc"; String destPath = path + "\" + fileName + ".pdf"; Word2PdfUtil.word2pdf(filepath, destPath); File file = new File(destPath); // 只用返回一个输入流 return FileUtils.openInputStream(file);// 打开文件 } // 文件下载名 public String getDownloadFileName() { String downloadFileName = ""; String filename = fileName + ".pdf"; try { downloadFileName = new String(filename.getBytes(), "ISO8859-1"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return downloadFileName; } @Override public String execute() throws Exception { // 先将名字设为秒数产生唯一的名字 // this.setFileName(String.valueOf(System.currentTimeMillis())); this.setFileName("考试试卷"); return super.execute(); } // get,set方法 public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getPaperId() { return paperId; } public void setPaperId(String paperId) { this.paperId = paperId; } }
其他一些参数和word,ppt,excel,jpg转pdf转换请参考其他两个链接:
http://hu437.iteye.com/blog/844350
http://blog.csdn.net/xuchaozheng/article/details/19199721
更全的:http://blog.csdn.net/catoop/article/details/43150671
其他的转换方法参考:
一个word转html的工具类:
package cn.xm.exam.utils; import java.io.File; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.ComThread; import com.jacob.com.Dispatch; import com.jacob.com.Variant; /** * 实现word转换为HTML * * @author QiaoLiQiang * @time 2018年2月3日下午2:17:43 */ public class Word2HtmlUtil { // 8 代表word保存成html public static final int WORD_HTML = 8; public static void main(String[] args) { String docfile = "C:\Users\liqiang\Desktop\sbgl.docx"; String htmlfile = "C:\Users\liqiang\Desktop\sbgl.html"; Word2HtmlUtil.wordToHtml(docfile, htmlfile); } /** * WORD转HTML * * @param docfile * WORD文件全路径 * @param htmlfile * 转换后HTML存放路径 */ public static boolean wordToHtml(String inPath, String toPath) { // 启动word ActiveXComponent axc = new ActiveXComponent("Word.Application"); boolean flag = false; try { // 设置word不可见 axc.setProperty("Visible", new Variant(false)); Dispatch docs = axc.getProperty("Documents").toDispatch(); // 打开word文档 Dispatch doc = Dispatch.invoke(docs, "Open", Dispatch.Method, new Object[] { inPath, new Variant(false), new Variant(true) }, new int[1]).toDispatch(); // 作为html格式保存到临时文件 Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object[] { toPath, new Variant(8) }, new int[1]); Variant f = new Variant(false); Dispatch.call(doc, "Close", f); flag = true; return flag; } catch (Exception e) { e.printStackTrace(); return flag; } finally { axc.invoke("Quit", new Variant[] {}); } } }