java 操作word(docx4j)

 

1.情景展示

  用java编辑word文档

2.准备工作

  通过docx4j实现 

  所需jar包

<!-- https://mvnrepository.com/artifact/org.docx4j/docx4j-JAXB-Internal -->
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-JAXB-Internal</artifactId>
    <version>8.2.9</version>
</dependency>

3.功能实现

  生成word文件

import org.docx4j.openpackaging.packages.WordprocessingMLPackage;  
/*
 * 创建docx文档
 * @attention:
 * 1.原文件如果已经存在的情况下,原文件中的内容会被清空
 * 2.在windows中无论后缀名的大小写问题,只要是相同后缀名且前缀也相同就是同一文件,
 * 当是同一后缀名且大小写不一致时,已存在的文件后缀名大小写不会改动
 * 3.如果原文件已存在,则该word文件不能处于打开状态(没有处在使用中)
 * @date: 2021-05-12 14:57
 * @param: fileSavePath
 * 文件保存所在路径
 * @param: fileSaveName
 * @return: boolean
 * Word创建成功、失败
 */
private static boolean createDocx(String fileSavePath, String fileSaveName) {
    try {
        // 确保文件的后缀名为".docx"
        if (!fileSaveName.substring(fileSaveName.indexOf(".")).equalsIgnoreCase(".docx")) fileSaveName += ".docx";

        // 确保文件的绝对路径
        if (fileSavePath.endsWith("/") || fileSavePath.endsWith("\\"))
            fileSavePath += fileSaveName;
        else
            fileSavePath += File.separator + fileSaveName;

        // Create the package 建包
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
        // 另存为新的文件 保存
        // 如果原文件已存在的话,里面的内容会被清空
        wordMLPackage.save(new File(fileSavePath));

        log.info("docx创建成功");
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        log.error("docx创建失败:", e.getMessage());
        return false;
    }
}

  追加内容

import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.jetbrains.annotations.NotNull;

import java.io.*;
import java.util.List;  
/*
 * 增加段落内容
 * @attention:
 * 1.原文件不能在的话,会报错
 * 2.原文件不能处于打开状态(没有处在使用中)
 * @date: 2021-05-12 15:28
 * @param: docxAbsolutePath
 * 文件的绝对(完整)路径,比如:C:\Users\Marydon\Desktop\aaaaa.docx
 * @param: textList
 * 要添加的段落集合
 * @return: void
 */
public static void insertParagraphs(String docxAbsolutePath, @NotNull List<String> textList) {
    try {
        // 加载word文件
        WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(new File(docxAbsolutePath));
        MainDocumentPart mdt = wPackage.getMainDocumentPart();
        // 添加段落内容(原文件内容会被覆盖掉)
        textList.forEach(simpleText -> {
            mdt.addParagraphOfText(simpleText);
            // mdt.addStyledParagraphOfText()可以指定段落的级别,如:标题使用Title,副标题使用Subtitle等
        });
        // 如果仅仅是想要实现换行的话,除了增加段落外,还可以使用换行符来实现
        // mdt.addParagraphOfText("张三\r\n李四");
        // 保存
        wPackage.save(new File(docxAbsolutePath));
        log.info("段落批量添加成功");
    } catch (Docx4JException e) {
        e.printStackTrace();
        log.error("段落添加失败:", e.getMessage());
    }
}

  插入图片

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.wml.Drawing;
import org.docx4j.wml.ObjectFactory;
import org.docx4j.wml.P;
import org.docx4j.wml.R;
import org.jetbrains.annotations.NotNull;

import java.io.File;
/*
 * 插入图片
 * @attention:
 * 1.需要确保文件的有效性(真实存在、路径完整)
 * 2.原文件不能处于打开状态(没有处在使用中)
 * @date: 2021-05-12 17:45
 * @param: docxCompleteRoute
 * word文档的绝对(完整)路径
 * @param: imgCompleteRoute
 * 图片的绝对(完整)路径
 * @return: boolean
 * 插入成功、失败
 */
public static boolean insertImg(String docxCompleteRoute, String imgCompleteRoute) {
    try {
        // 图片转byte[]
        byte[] bytes = FileUtils.readFileToByteArray(new File(imgCompleteRoute));
        // 加载word文档
        // 创建了一个包(package)来容纳文档
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(docxCompleteRoute));
        // 插入图片(将图片添加到包中)
        addImageToPackage(wordMLPackage, bytes);
        // 保存这个包
        wordMLPackage.save(new File(docxCompleteRoute));
        log.info("图片插入成功");
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        log.error("图片插入失败:" + e.getMessage());
        return false;
    }

}

/**
 * 将图片放到文档的包中
 *
 * Docx4j拥有一个由字节数组创建图片部件的工具方法, 随后将其添加到给定的包中. 为了能将图片添加 到一个段落中,
 * 我们需要将图片转换成内联对象. 这也有一个方法, 方法需要文件名提示, 替换文本, 两个id标识符和一个是嵌入还是链接到的指示作为参数.
 * 一个id用于文档中绘图对象不可见的属性, 另一个id用于图片本身不可见的绘制属性. 最后我们将内联 对象添加到段落中并将段落添加到包的主文档部件.
 *
 * @param wordMLPackage
 *            要添加图片的包
 * @param bytes
 *            图片对应的字节数组
 * @throws Exception
 *             不幸的createImageInline方法抛出一个异常(没有更多具体的异常类型)
 */
private static void addImageToPackage(WordprocessingMLPackage wordMLPackage, byte[] bytes) throws Exception {
    // 创建图片部件
    BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, bytes);
    // 创建内联对象
    Inline inline = imagePart.createImageInline("Filename hint","Alternative text", 1, 2, false);
    // 将内联对象添加到段落中
    // 实现方法在下方
    P paragraph = addInlineImageToParagraph(inline);
    // 将段落添加到文档中
    wordMLPackage.getMainDocumentPart().addObject(paragraph);
}

/**
 * 将内联对象添加到段落中
 *
 * 创建一个对象工厂并用它创建一个段落和一个可运行块R. 然后将可运行块添加到段落中. 接下来创建一个图画并将其添加到可运行块R中. 最后我们将内联
 * 对象添加到图画中并返回段落对象.
 *
 * @param inline
 *            包含图片的内联对象.
 * @return 包含图片的段落
 */
@NotNull
private static P addInlineImageToParagraph(Inline inline) {
    // 采用工厂类增加段落的方法
    ObjectFactory factory = new ObjectFactory();
    // 创建段落
    P paragraph = factory.createP();
    // R是一个运行块,负责便于将多个属性相同的Object对象统一操作,通过其内部的content成员变量可以添加内容
    R run = factory.createR();
    paragraph.getContent().add(run);

    Drawing drawing = factory.createDrawing();
    run.getContent().add(drawing);
    drawing.getAnchorOrInline().add(inline);
    return paragraph;
}

  

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

 

 
上一篇:2021-09-13 网安实验-PHP安全特性(Is_numeric,Hash,parse_str,switch,extract,strcmp)


下一篇:1094 The Largest Generation (25 分)