jacob的简单使用

313 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

jacob的简单使用

前言

操作word文档的需求在工作中很常见, 我们之前也介绍了很多工具, 但是他们对更新目录等功能的支持都不是很友好 像poi-tl暂不支持, spire.doc免费版的有限制等, 我们来尝试下使用jacob操作word完成相关功能

ps: 其原理就是用代码调用word提供的api, 所以jocb只能在windows上使用

环境

下载 免费下载地址

结构 将jacob-1.20-x64.dll拷贝到C:\Windows\System32

maven 本地引入jacob.jar

 <dependency>
     <groupId>com.jacob</groupId>
     <artifactId>jacob</artifactId>
     <scope>system</scope>
     <systemPath>${project.basedir}/lib/jacob.jar</systemPath>
 </dependency>

代码

格式枚举

/**
 * word格式枚举
 */
@Getter
@AllArgsConstructor
public enum WordType {
    DOC(0, "doc"),
    DOCT(1, "dot"),
    TXT(2, "txt"),
    RTF(6, "rtf"),
    HTM(8, "htm"),
    MHT(9, "mht"),
    XML(11, "xml"),
    DOCX(12, "docx"),
    DOCM(13, "docm"),
    DOTX(14, "dotx"),
    DOTM(15, "dotm"),
    PDF(17, "pdf"),
    XPS(18, "xps"),
    ODT(23, "odt"),
    WTF(24, "wtf"),;
    private int code;
    private String type;
    public static String getTypeByCode(int code) {
        return Arrays.stream(values()).filter(e -> Objects.equals(code, e.getCode())).findFirst().map(WordType::getType).orElse(null);
    }
}

封装操作工具

public class WordUtil {

    /**
     * 源文件
     */
    private String docFile;
    /**
     * Word应用
     */
    private ActiveXComponent word;
    /**
     * 打开的文档
     */
    private Dispatch doc;

    /**
     * 构造
     */
    public WordUtil(String docFile) {
        this.docFile = docFile;
        ComThread.InitSTA();
	// 打开一个word应用
        word = new ActiveXComponent("Word.Application");
        word.setProperty("Visible", new Variant(false));
	// 打开一个word文档
        doc = Dispatch.invoke(word.getProperty("Documents").toDispatch(), "Open", Dispatch.Method,
                new Object[]{docFile, new Variant(false), new Variant(true)}, new int[1]).toDispatch();
    }

    /**
     * 更新目录并另存为
     */
    public void updateCatalogue(int fmt) {
        Dispatch activeDocument = word.getProperty("ActiveDocument").toDispatch();
        Dispatch tablesOfContents = Dispatch.get(activeDocument, "TablesOfContents").toDispatch();
        // 更新目录,有两个方法:Update 更新域,UpdatePageNumbers 只更新页码
        Dispatch toc = Dispatch.call(tablesOfContents, "Item", new Variant(1)).toDispatch();
        Dispatch.call(toc, "Update");
        convertDocFmt(fmt);
    }

    /**
     * 另存为
     *
     * @param fmt 另存为文档格式
     */
    public void convertDocFmt(int fmt) {
        String targetPath = StrUtil.replace(this.docFile, "." + FileUtil.getSuffix(this.docFile), "." + WordType.getTypeByCode(fmt));
        Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object[]{targetPath, new Variant(fmt)}, new int[1]);
        new File(targetPath);
    }


    /**
     * 封装一下调用, 方便关闭
     */
    public void call(VoidFunc0 voidFunc0) {
        try {
            voidFunc0.callWithRuntimeException();
        } finally {
            if (doc != null) {
		// 关闭文档
                Dispatch.call(doc, "Close", new Variant(false));
            }
            if (word != null) {
		// 退出word应用
                word.invoke("Quit", new Variant[]{});
            }
            ComThread.Release();
        }
    }
}

使用

 public static void main(String[] args) {
     String docFile = "F:\\ff.doc";
     WordUtil wordUtil = new WordUtil(docFile);
     // 另存为
     // wordUtil.call(() -> wordUtil.convertDocFmt(WordType.DOCX.getCode()));
     // 更新目录然后另存为
     wordUtil.call(() -> wordUtil.updateCatalogue(WordType.DOCX.getCode()));
 }