• 采用jacob实现word转pdf


    网络上已经有很多这方面的内容,在用之前也是参考了好多别人的文章,下面记录下我自己的整合过程。整个过程都比较简单:

    开发环境: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

    其他的转换方法参考:

    http://feifei.im/archives/93

    一个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[] {});
            }
        }
    }
  • 相关阅读:
    设计模式中的多态——策略模式详解
    Spring IOC容器启动流程源码解析(一)——容器概念详解及源码初探
    并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)
    HNOI2020游记
    旧年之末,新年伊始
    退役V次后做题记录
    PKUWC2020 游记
    CSP2019退役记
    CTS/APIO2019游记
    HNOI2019游记
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/8193281.html
Copyright © 2020-2023  润新知