【Java处理word文档】


前言

这篇文章记录Java处理word的相关内容。
看完以下内容,word中的大多数甚至所有操作你都可以通过java代码实现。

注意:此篇文章处理的word格式为Microsoft Office Word 2007及之后的版本,也就是后缀为docx的word文件。


一、word是什么?

word其实是xml文件(格式为Microsoft Office Word 2007及之后的版本)。手动创建一个word文档,将后缀名改为zip,然后使用解压缩工具解压。在解压结果的word目录下有一个document.xml文件。这个文件就是word文档的主要内容。还有一个styles.xml文件,此文件定义word中的样式。

二、Java处理word

首先给一个通过java生成的word文档的示例。
在这里插入图片描述
将word文档后缀修改为zip,然后解压得到如下图中的文件:
在这里插入图片描述
打开word目录后,如下,其中的document.xml就是word文档的主要内容。
在这里插入图片描述
下来我们针对这个例子进行说明。

2.1、依赖包

以下依赖包中包含hutool相关的内容,此依赖包和处理word没有任何关系,只是其中的各种工具类用起来比较方便。

        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-JAXB-Internal</artifactId>
            <version>8.2.9</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.10</version>
        </dependency>

2.2、加载word样式

word的样式是存放在一个名为styles.xml的文件中,我们在处理word样式的时候为了方便,可以将想要的样式存放在代码的资源文件中,然后通过docx4j提供的api加载即可。以下为加载样式xml文件的代码。(样式xml文件后续在示例代码中给出源码)

InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("styles.xml");
Styles styles = (Styles) XmlUtils.unmarshal(resourceAsStream);

2.3、读入文件

通过docx4j依赖包提供的api加载文件(此文件如果不存在则会自动创建),返回WordprocessingMLPackage对象,后续处理都是在其基础上。

File outputFile = new File("C:\\Users\\admin\\Desktop\\test.docx");
// Create the package 建包
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
// 另存为新的文件 保存
// 如果原文件已存在的话,里面的内容会被清空
wordMLPackage.save(docxFile);
WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(outputFile);

2.4、单一样式段落

首先我们看一下word文档解压后的document.xml文件中的内容。
先看示例中的“标题1”。

		<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
			<w:pPr>
				<w:pStyle w:val="1"/>
			</w:pPr>
			<w:r>
				<w:t>标题</w:t>
			</w:r>
			<w:r>
				<w:t>1</w:t>
			</w:r>
		</w:p>

通过docx4j提供的ObjectFactory factory = Context.getWmlObjectFactory();对象工厂。ObjectFactory可以生成段落、表格、超链接等等与word相关的对象。
以下java代码生成一个单一样式的段落。
通过xml文件我们可以看到,首先我们需要创建一个段落P对象,同时设置段落的ppr。然后还需要创建一个R对象,将R对象通过P.getContent().add(R);与段落进行关联。

    /**
     * 根据样式ID获取段落对象P
     *
     * @param paragraphText
     * @param styleId
     * @return org.docx4j.wml.P
     */
    public static P getPByStyleId(String paragraphText, String styleId) {
        Style style = WordStylesUtil.getStyleById(styleId);
        ObjectFactory factory = Context.getWmlObjectFactory();
        P paragraph = factory.createP();
        R run = factory.createR();
        run.setRPr(style.getRPr());

        String[] split = paragraphText == null ? new String[0] : paragraphText.split("\n");
        if (split.length > 1) {
            List<Child> list = new ArrayList<>();
            for (String s : split) {
                Text text = factory.createText();
                text.setValue(s);
                // 保留前后空格
                text.setSpace(SchemaSymbols.ATTVAL_PRESERVE);
                // 将换行符进行处理为</Br>
                Br br = factory.createBr();
                list.add(text);
                list.add(br);
            }
            run.getContent().addAll(list);
        } else {
            Text text = factory.createText();
            text.setValue(paragraphText);
            run.getContent().add(text);
        }
        paragraph.getContent().add(run);
        paragraph.setPPr(style.getPPr());

        return paragraph;
    }

2.5、复合样式段落

示例中的“title:测试title”,其中“title:”进行了加粗处理。
先看word文档解压后的document.xml文件中的内容。

		<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
			<w:proofErr w:type="spellStart"/>
			<w:r>
				<w:rPr>
					<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
					<w:b/>
					<w:bCs/>
					<w:color w:val="000000"/>
					<w:sz w:val="24"/>
					<w:szCs w:val="24"/>
				</w:rPr>
				<w:t>title</w:t>
			</w:r>
			<w:r>
				<w:rPr>
					<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
					<w:b/>
					<w:bCs/>
					<w:color w:val="000000"/>
					<w:sz w:val="24"/>
					<w:szCs w:val="24"/>
				</w:rPr>
				<w:t></w:t>
			</w:r>
			<w:r>
				<w:rPr>
					<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
					<w:color w:val="000000"/>
					<w:sz w:val="24"/>
					<w:szCs w:val="24"/>
				</w:rPr>
				<w:t>测试</w:t>
			</w:r>
			<w:r>
				<w:rPr>
					<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
					<w:color w:val="000000"/>
					<w:sz w:val="24"/>
					<w:szCs w:val="24"/>
				</w:rPr>
				<w:t>title</w:t>
			</w:r>
			<w:proofErr w:type="spellEnd"/>
		</w:p>

可以看到段落P中存在多个R,每个R都有其自己特定的rPr。
以下java代码实现。

    /**
     * 给word中写入复合样式的段落信息
     *
     * @param wPackage
     * @param context   二维数组,二维中的数据只能有两个元素,第一个为段落内容,第二个为样式ID。例如:[["内容1","样式1"],["内容2","样式2"]]
     */
    public static void complexPWrite(WordprocessingMLPackage wPackage, String[][] context) {
        if (context.length <= 0) {
            return;
        }
        P complexP = WordUtil.getComplexP();
        for (int i = 0; i < context.length; i++) {
            String[] temp = context[i];
            if (temp.length != 2) {
                continue;
            }
            String paragraph = temp[0];
            String styleId = temp[1];
            Style style = WordStylesUtil.getStyleById(styleId);
            if (StringUtils.isBlank(paragraph) || style == null) {
                continue;
            }
            addRun(complexP, paragraph, style);
        }

        // 写入
        insertOneParagraph(wPackage, complexP);
    }

    /**
     * 复合段落某一段数据处理
     *
     * @param paragraph         整个段落
     * @param paragraphText     当前处理的某段数据
     * @param style             样式
     * @return void
     */
    public static void addRun(P paragraph, String paragraphText, Style style) {
        ObjectFactory factory = Context.getWmlObjectFactory();
        Text text = factory.createText();
        text.setValue(paragraphText);
        // 保留前后空格
        text.setSpace(SchemaSymbols.ATTVAL_PRESERVE);

        R run = factory.createR();
        run.getContent().add(text);
        run.setRPr(style.getRPr());

        paragraph.getContent().add(run);
    }

2.6、将段落写入word

    /**
     * 添加段落,可以是复合样式的段落
     *
     * @param wPackage
     * @param paragraph 用户自定义好的段落(包括样式与内容)
     * @return void
     */
    public static void insertOneParagraph(WordprocessingMLPackage wPackage, P paragraph) {
        wPackage.getMainDocumentPart().getContent().add(paragraph);
    }

2.7、word表格

先看word文档解压后的document.xml文件中的表格内容。
以下内容看着很长,其实总结下来就是表格tbl下嵌套行tr,行tr下嵌套单元格tc,单元格tc中示例中给的都是段落P。其他就是表格的样式处理。

		<w:tbl>
			<w:tblPr>
				<w:tblW w:w="0" w:type="auto"/>
				<w:tblBorders>
					<w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/>
					<w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/>
					<w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/>
					<w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/>
					<w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto"/>
					<w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto"/>
				</w:tblBorders>
				<w:tblLayout w:type="fixed"/>
				<w:tblLook w:val="04A0" w:firstRow="1" w:lastRow="0" w:firstColumn="1" w:lastColumn="0" w:noHBand="0" w:noVBand="1"/>
			</w:tblPr>
			<w:tblGrid>
				<w:gridCol w:w="2312"/>
				<w:gridCol w:w="1386"/>
				<w:gridCol w:w="1386"/>
				<w:gridCol w:w="4159"/>
			</w:tblGrid>
			<w:tr w:rsidR="001272E8">
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="25" w:type="pct"/>
						<w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>1</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
						<w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>2</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
						<w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>3</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="45" w:type="pct"/>
						<w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:b/>
								<w:bCs/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>4</w:t>
						</w:r>
					</w:p>
				</w:tc>
			</w:tr>
			<w:tr w:rsidR="001272E8">
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="25" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>1</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>2</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t></w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="45" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>4</w:t>
						</w:r>
					</w:p>
				</w:tc>
			</w:tr>
			<w:tr w:rsidR="001272E8">
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="25" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>1</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>2</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t></w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="45" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>4</w:t>
						</w:r>
					</w:p>
				</w:tc>
			</w:tr>
			<w:tr w:rsidR="001272E8">
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="25" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>1</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>2</w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="15" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
							<w:jc w:val="center"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t></w:t>
						</w:r>
					</w:p>
				</w:tc>
				<w:tc>
					<w:tcPr>
						<w:tcW w:w="45" w:type="pct"/>
					</w:tcPr>
					<w:p w:rsidR="001272E8" w:rsidRDefault="00EC6803">
						<w:pPr>
							<w:spacing w:before="130" w:after="50"/>
						</w:pPr>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>单元格</w:t>
						</w:r>
						<w:r>
							<w:rPr>
								<w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
								<w:color w:val="000000"/>
								<w:sz w:val="24"/>
								<w:szCs w:val="24"/>
							</w:rPr>
							<w:t>4</w:t>
						</w:r>
					</w:p>
				</w:tc>
			</w:tr>
		</w:tbl>

然后看java的实现。
通过ObjectFactory生成Tbl、Tr、Tc等对象,然后将这些对象进行关联,最后将表格Tbl对象写入到word中。

    public static void wordTable(WordprocessingMLPackage wPackage) {
        // 生成参数表格
        ObjectFactory objectFactory = Context.getWmlObjectFactory();
        Tbl table = objectFactory.createTbl();

        // 标题行 处理
        Tr tr = objectFactory.createTr();
        wordTc(tr, WordUtil.getPByStyleId("单元格1", WHQ_3), A41);
        wordTc(tr, WordUtil.getPByStyleId("单元格2", WHQ_3), A42);
        wordTc(tr, WordUtil.getPByStyleId("单元格3", WHQ_3), A43);
        wordTc(tr, WordUtil.getPByStyleId("单元格4", WHQ_3), A44);
        table.getContent().add(tr);

        // 数据行 处理,测试添加3条数据
        for (int i = 0; i < 3; i++) {
            Tr trTemp = objectFactory.createTr();
            wordTc(trTemp, WordUtil.getPByStyleId("单元格1", WHQ_4), A51);
            wordTc(trTemp, WordUtil.getPByStyleId("单元格2", WHQ_4), A52);
            wordTc(trTemp, WordUtil.getPByStyleId("是", WHQ_5), A53);
            wordTc(trTemp, WordUtil.getPByStyleId("单元格4", WHQ_4), A54);
            table.getContent().add(trTemp);
        }

        // 表格整体样式
        Style tabStyle3 = WordStylesUtil.getStyleById(A3);
        table.setTblPr(new TblPr());
        // 边框线处理
        table.getTblPr().setTblBorders(tabStyle3.getTblPr().getTblBorders());
        // 表格列长度固定不可变
        table.getTblPr().setTblLayout(tabStyle3.getTblPr().getTblLayout());

        // 表格写入word文件
        wPackage.getMainDocumentPart().getContent().add(table);
    }

    public static void wordTc(Tr tr, P p, String tcStyleId) {
        ObjectFactory objectFactory = Context.getWmlObjectFactory();
        Tc tc = objectFactory.createTc();
        tc.setTcPr(WordStylesUtil.getStyleById(tcStyleId).getTcPr());
        tc.getContent().add(p);
        tr.getContent().add(tc);
    }

2.8、超链接

示例给出的超链接为word文档内部的超链接。而且是将整个段落作为超链接进行处理。
还是先看word文档解压后的document.xml文件中的超链接内容。
为了在word文档中看到超链接跳转的效果。此处加了一个分页。
从以下xml代码中可以看到。段落的超链接是嵌套在段落中的w:hyperlink标签控制的,w:hyperlink标签中的w:anchor属性为“锚点”。与跳转目标要匹配一致才可以成功跳转,可以看到锚点目标使用w:bookmarkStart标签,其中的w:name属性与w:hyperlink标签中的w:anchor属性一致。
w:hyperlink标签中的w:history属性也很重要,当我们跳转到目标地方后,如果想通过快捷键alt + ⬅返回上一次的位置,则此属性必须设置为true。

        <w:p>
            <w:pPr>
                <w:spacing w:before="130" w:after="50"/>
            </w:pPr>
            <w:hyperlink w:history="true" w:anchor="_8418a746ee1a10cd44e530fdbcee6469">
                <w:r>
                    <w:rPr>
                        <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
                        <w:color w:val="000000" w:themeColor="hyperlink"/>
                        <w:sz w:val="24"/>
                        <w:szCs w:val="24"/>
                    </w:rPr>
                    <w:t xml:space="preserve">超链接1</w:t>
                </w:r>
            </w:hyperlink>
        </w:p>
        <w:p>
            <w:r>
                <w:br w:type="page"/>
            </w:r>
        </w:p>
        <w:p>
            <w:pPr>
                <w:spacing w:after="50" w:line="312" w:lineRule="auto"/>
            </w:pPr>
            <w:r>
                <w:rPr>
                    <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
                    <w:b/>
                    <w:bCs/>
                    <w:color w:val="000000"/>
                    <w:sz w:val="24"/>
                    <w:szCs w:val="24"/>
                </w:rPr>
                <w:t>超链接2</w:t>
            </w:r>
            <w:bookmarkStart w:name="_8418a746ee1a10cd44e530fdbcee6469" w:id="1"/>
            <w:bookmarkEnd w:id="1"/>
        </w:p>

java代码实现。
超链接起始位置。

    /**
     * 生成超链接段落(调用锚点)。整个段落都是超链接。
     *
     * @param paragraphText
     * @param anchor        超链接跳转锚点标识
     * @param styleId
     * @return org.docx4j.wml.P
     */
    public static P createHyperlinkConsume(String paragraphText, String anchor, String styleId) {
        ObjectFactory factory = Context.getWmlObjectFactory();
        P p = factory.createP();
        P.Hyperlink pHyperlink = factory.createPHyperlink();
        pHyperlink.setAnchor("_" + getAnchor(anchor));
        // ctrl跳转后,按alt + ⬅ 可以跳转回来。以下参数必须为true,否则光标返回位置不对。
        pHyperlink.setHistory(true);

        Style style = WordStylesUtil.getStyleById(styleId);
        addRun(pHyperlink, paragraphText, style);
        p.getContent().add(pHyperlink);
        p.setPPr(style.getPPr());

        return p;
    }

超链接目标位置。

    /**
     * 生成超链接段落(锚点)
     *
     * @param paragraphText
     * @param anchor
     * @param styleId
     * @return org.docx4j.wml.P
     */
    public static P createHyperlinkProduce(String paragraphText, String anchor, String styleId) {
        P p = getPByStyleId(paragraphText, styleId);
        ObjectFactory objectFactory = Context.getWmlObjectFactory();
        // 创建一个超链接对象
        BigInteger hli = BigInteger.valueOf(getHyperlinkId());
        CTBookmark ctBookmark = new CTBookmark();
        ctBookmark.setId(hli);
        ctBookmark.setName("_" + getAnchor(anchor));
        JAXBElement<CTBookmark> pHyperlinkBookmarkStart = objectFactory.createPHyperlinkBookmarkStart(ctBookmark);
        p.getContent().add(pHyperlinkBookmarkStart);
        CTMarkupRange ctMarkupRange = new CTMarkupRange();
        ctMarkupRange.setId(hli);
        objectFactory.createPBookmarkEnd(ctMarkupRange);
        p.getContent().add(ctMarkupRange);

        return p;
    }

2.9、写入样式及文件保存

最后一定要将样式写入word文档,否则样式都不生效。

        // 写入word文档样式信息
        wPackage.getMainDocumentPart().getStyleDefinitionsPart().getJaxbElement().getStyle().addAll(WordStylesUtil.STYLES.values());
        wPackage.save(outputFile);

总结

此篇文章只是从word的使用中挑选了部分功能进行说明。如果以上功能没有你想要的结果。可以自己摸索实现。首先你要新建一个word文档,然后将你要的功能写进去,之后将word文档后缀重命名为zip并解压缩,最后你就得到了xml文件,打开xml文件查看其中的xml实现(word目录下的document.xml),或者你想要某种样式,可以查看word目录下的styles.xml。

最后给出示例中的所有java源码。

示例源码

在这里插入图片描述

样式xml

<?xml version="1.0" encoding="UTF-8"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
    <w:docDefaults>
        <w:rPrDefault>
            <w:rPr>
                <w:rFonts w:asciiTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:cstheme="minorBidi"/>
                <w:sz w:val="22"/>
                <w:szCs w:val="22"/>
                <w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA"/>
            </w:rPr>
        </w:rPrDefault>
        <w:pPrDefault>
            <w:pPr>
                <w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
            </w:pPr>
        </w:pPrDefault>
    </w:docDefaults>
    <w:latentStyles w:defLockedState="false" w:defUIPriority="99" w:defSemiHidden="true" w:defUnhideWhenUsed="true" w:defQFormat="false" w:count="267">
        <w:lsdException w:name="Normal" w:uiPriority="0" w:semiHidden="false" w:unhideWhenUsed="false" w:qFormat="true"/>
        <w:lsdException w:name="heading 1" w:uiPriority="9" w:semiHidden="false" w:unhideWhenUsed="false" w:qFormat="true"/>
        <w:lsdException w:name="heading 2" w:uiPriority="9" w:qFormat="true"/>
        <w:lsdException w:name="heading 3" w:uiPriority="9" w:qFormat="true"/>
        <w:lsdException w:name="heading 4" w:uiPriority="9" w:qFormat="true"/>
    </w:latentStyles>
    <w:style w:type="paragraph" w:styleId="Normal" w:default="true">
        <w:name w:val="Normal"/>
        <w:qFormat/>
        <w:rsid w:val="004A3277"/>
    </w:style>
    <w:style w:type="paragraph" w:styleId="Heading1">
        <w:name w:val="heading 1"/>
        <w:basedOn w:val="Normal"/>
        <w:next w:val="Normal"/>
        <w:link w:val="Heading1Char"/>
        <w:uiPriority w:val="9"/>
        <w:qFormat/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
            <w:keepNext/>
            <w:keepLines/>
            <w:spacing w:before="480"/>
            <w:outlineLvl w:val="0"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="42"/>
            <w:szCs w:val="28"/>
        </w:rPr>
    </w:style>
    <w:style w:type="paragraph" w:styleId="Heading2">
        <w:name w:val="heading 2"/>
        <w:basedOn w:val="Normal"/>
        <w:next w:val="Normal"/>
        <w:link w:val="Heading2Char"/>
        <w:uiPriority w:val="9"/>
        <w:unhideWhenUsed/>
        <w:qFormat/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:pStyle w:val="Heading2"/>
            <w:keepNext/>
            <w:keepLines/>
            <w:spacing w:before="200"/>
            <w:outlineLvl w:val="1"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="38"/>
            <w:szCs w:val="26"/>
        </w:rPr>
    </w:style>
    <w:style w:type="paragraph" w:styleId="Heading3">
        <w:name w:val="heading 3"/>
        <w:basedOn w:val="Normal"/>
        <w:next w:val="Normal"/>
        <w:link w:val="Heading3Char"/>
        <w:uiPriority w:val="9"/>
        <w:unhideWhenUsed/>
        <w:qFormat/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:keepNext/>
            <w:keepLines/>
            <w:spacing w:before="200"/>
            <w:outlineLvl w:val="2"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="34"/>
        </w:rPr>
    </w:style>
    <w:style w:type="paragraph" w:styleId="Heading4">
        <w:name w:val="heading 4"/>
        <w:basedOn w:val="Normal"/>
        <w:next w:val="Normal"/>
        <w:link w:val="Heading4Char"/>
        <w:uiPriority w:val="9"/>
        <w:unhideWhenUsed/>
        <w:qFormat/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:keepNext/>
            <w:keepLines/>
            <w:spacing w:before="200"/>
            <w:outlineLvl w:val="3"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="30"/>
        </w:rPr>
    </w:style>
    <w:style w:type="paragraph" w:styleId="Heading5">
        <w:name w:val="heading 5"/>
        <w:basedOn w:val="Normal"/>
        <w:next w:val="Normal"/>
        <w:link w:val="Heading5Char"/>
        <w:uiPriority w:val="9"/>
        <w:unhideWhenUsed/>
        <w:qFormat/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:keepNext/>
            <w:keepLines/>
            <w:spacing w:before="200"/>
            <w:outlineLvl w:val="4"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="28"/>
        </w:rPr>
    </w:style>

    <w:style w:type="paragraph" w:styleId="ne-codeblock"/>

    <!-- 正文段落 加粗 居左 -->
    <w:style w:type="paragraph" w:styleId="whq1" w:customStyle="true">
        <w:name w:val="whq1"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:spacing w:after="50" w:line="312" w:lineRule="auto"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
        </w:rPr>
    </w:style>

    <!-- 正文段落 不加粗 居左 -->
    <w:style w:type="paragraph" w:styleId="whq2" w:customStyle="true">
        <w:name w:val="whq2"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:spacing w:after="50" w:line="312" w:lineRule="auto"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:color w:val="000000"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
        </w:rPr>
    </w:style>

    <!-- 正文段落 加粗 居中,表格单元格,表头使用 -->
    <w:style w:type="paragraph" w:styleId="whq3" w:customStyle="true">
        <w:name w:val="whq3"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:spacing w:before="130" w:after="50"/>
            <w:jc w:val="center"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:b/>
            <w:bCs/>
            <w:color w:val="000000"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
        </w:rPr>
    </w:style>
    <!-- 正文段落 不加粗 居左 增加段前间距,表格单元格使用 -->
    <w:style w:type="paragraph" w:styleId="whq4" w:customStyle="true">
        <w:name w:val="whq4"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:spacing w:before="130" w:after="50"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:color w:val="000000"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
        </w:rPr>
    </w:style>
    <!-- 正文段落 不加粗 居左 增加段前间距,表格单元格使用 添加超链接样式 -->
    <w:style w:type="paragraph" w:styleId="whq41" w:customStyle="true">
        <w:name w:val="whq41"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:spacing w:before="130" w:after="50"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:color w:val="000000" w:themeColor="hyperlink"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
        </w:rPr>
    </w:style>

    <!-- 正文段落 不加粗 居中 增加段前间距,表格单元格使用 -->
    <w:style w:type="paragraph" w:styleId="whq5" w:customStyle="true">
        <w:name w:val="whq5"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="00841CD9"/>
        <w:pPr>
            <w:spacing w:before="130" w:after="50"/>
            <w:jc w:val="center"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="宋体" w:eastAsia="宋体"/>
            <w:color w:val="000000"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
        </w:rPr>
    </w:style>

    <w:style w:type="table" w:default="1" w:styleId="a1">
        <w:name w:val="Normal Table"/>
        <w:uiPriority w:val="99"/>
        <w:semiHidden/>
        <w:unhideWhenUsed/>
        <w:tblPr>
            <w:tblInd w:w="0" w:type="dxa"/>
            <w:tblCellMar>
                <w:top w:w="0" w:type="dxa"/>
                <w:left w:w="108" w:type="dxa"/>
                <w:bottom w:w="0" w:type="dxa"/>
                <w:right w:w="108" w:type="dxa"/>
            </w:tblCellMar>
        </w:tblPr>
    </w:style>

    <!-- 表格:边框线、列长度固定不可变-->
    <w:style w:type="table" w:styleId="a3">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a1"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:tblPr>
            <w:tblBorders>
                <w:top w:val="single" w:sz="4" w:space="0" w:color="auto"/>
                <w:left w:val="single" w:sz="4" w:space="0" w:color="auto"/>
                <w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto"/>
                <w:right w:val="single" w:sz="4" w:space="0" w:color="auto"/>
                <w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto"/>
                <w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto"/>
            </w:tblBorders>
            <w:tblCellMar>
                <w:top w:w="0" w:type="dxa"/>
                <w:left w:w="108" w:type="dxa"/>
                <w:bottom w:w="0" w:type="dxa"/>
                <w:right w:w="108" w:type="dxa"/>
            </w:tblCellMar>
            <w:tblW w:w="0" w:type="auto"/>
            <w:tblLayout w:type="fixed"/>
        </w:tblPr>
    </w:style>

    <!-- 表格:表头样式,添加背景色 -->
    <w:style w:type="table" w:styleId="a41">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="100"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="2376" w:type="dxa"/>-->
            <w:tcW w:w="25" w:type="pct"/>
            <w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
        </w:tcPr>
    </w:style>
    <w:style w:type="table" w:styleId="a42">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="100"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="1276" w:type="dxa"/>-->
            <w:tcW w:w="15" w:type="pct"/>
            <w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
        </w:tcPr>
    </w:style>
    <w:style w:type="table" w:styleId="a43">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="100"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="1276" w:type="dxa"/>-->
            <w:tcW w:w="15" w:type="pct"/>
            <w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
        </w:tcPr>
    </w:style>
    <w:style w:type="table" w:styleId="a44">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="100"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="4315" w:type="dxa"/>-->
            <w:tcW w:w="45" w:type="pct"/>
            <w:shd w:val="clear" w:color="auto" w:fill="9CC2E5" w:themeFill="accent1" w:themeFillTint="99"/>
        </w:tcPr>
    </w:style>

    <!-- 表格:其他单元格,默认样式 -->
    <w:style w:type="table" w:styleId="a51">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="416"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="2376" w:type="dxa"/>-->
            <w:tcW w:w="25" w:type="pct"/>
        </w:tcPr>
    </w:style>
    <w:style w:type="table" w:styleId="a52">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="416"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="1276" w:type="dxa"/>-->
            <w:tcW w:w="15" w:type="pct"/>
        </w:tcPr>
    </w:style>
    <w:style w:type="table" w:styleId="a53">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="416"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="1276" w:type="dxa"/>-->
            <w:tcW w:w="15" w:type="pct"/>
        </w:tcPr>
    </w:style>
    <w:style w:type="table" w:styleId="a54">
        <w:name w:val="Table Grid"/>
        <w:basedOn w:val="a3"/>
        <w:uiPriority w:val="39"/>
        <w:rsid w:val="00A76ABD"/>
        <w:trPr>
            <w:trHeight w:val="416"/>
        </w:trPr>
        <w:tcPr>
            <!--<w:tcW w:w="4315" w:type="dxa"/>-->
            <w:tcW w:w="45" w:type="pct"/>
        </w:tcPr>
    </w:style>
</w:styles>

WordConstant

package com.demo.word;

public class WordConstant {
    public final static String NORMAL = "Normal";
    // 一级标题
    public final static String HEADING_1 = "Heading1";
    // 二级标题
    public final static String HEADING_2 = "Heading2";
    // 正文段落 加粗 居左
    public final static String WHQ_1 = "whq1";
    // 正文段落 不加粗 居左
    public final static String WHQ_2 = "whq2";
    // 正文段落 加粗 居中,表格单元格,表头使用
    public final static String WHQ_3 = "whq3";
    // 正文段落 不加粗 居左 增加段前间距,表格单元格使用
    public final static String WHQ_4 = "whq4";
    // 正文段落 不加粗 居左 增加段前间距,表格单元格使用,添加超链接样式
    public final static String WHQ_41 = "whq41";
    // 正文段落 不加粗 居中 增加段前间距,表格单元格使用
    public final static String WHQ_5 = "whq5";

    // 表格:边框线、列长度固定不可变
    public final static String A3 = "a3";


    // 表格:表头样式,添加背景色,宽度25
    public final static String A41 = "a41";
    // 表格:表头样式,添加背景色,宽度15
    public final static String A42 = "a42";
    // 表格:表头样式,添加背景色,宽度15
    public final static String A43 = "a43";
    // 表格:表头样式,添加背景色,宽度45
    public final static String A44 = "a44";

    // 表格:其他单元格,默认样式,宽度25
    public final static String A51 = "a51";
    // 表格:其他单元格,默认样式,宽度15
    public final static String A52 = "a52";
    // 表格:其他单元格,默认样式,宽度15
    public final static String A53 = "a53";
    // 表格:其他单元格,默认样式,宽度45
    public final static String A54 = "a54";
}

WordStylesUtil

package com.demo.word;

import cn.hutool.core.collection.CollectionUtil;
import org.docx4j.XmlUtils;
import org.docx4j.wml.Style;
import org.docx4j.wml.Styles;

import javax.xml.bind.JAXBException;
import java.io.InputStream;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class WordStylesUtil {

    // 正文样式ID
    public static final String NORMAL_STYLE = "Normal";

    private WordStylesUtil() {
        try {
            InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("styles.xml");
            Styles styles = (Styles) XmlUtils.unmarshal(resourceAsStream);
            if (styles != null && !CollectionUtil.isEmpty(styles.getStyle())) {
                STYLES = styles.getStyle().stream().collect(Collectors.toMap(Style::getStyleId, Function.identity(), (oldVal, newVal) -> newVal));
            }
        } catch (JAXBException e) {
            System.err.println("加载styles.xml异常!");
            System.err.println(e);
        }
    }

    private static WordStylesUtil wordStylesUtil = new WordStylesUtil();
    public static Map<String, Style> STYLES;

    private static WordStylesUtil getInstance() {
        if (wordStylesUtil == null) {
            wordStylesUtil = new WordStylesUtil();
        }
        return wordStylesUtil;
    }

    /**
     * 通过样式ID获取Style
     *
     * @param styleId
     * @return org.docx4j.wml.Style
     */
    public static Style getStyleById(String styleId) {
        getInstance();
        return STYLES.get(styleId);
    }
}

WordUtil

package com.demo.word;

import cn.hutool.crypto.digest.MD5;
import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
import org.apache.commons.lang3.StringUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.jvnet.jaxb2_commons.ppp.Child;

import javax.xml.bind.JAXBElement;
import java.io.File;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

public class WordUtil {
    // word 超链接ID
    private static Integer hyperlinkId = 0;

    /**
     * 获取超链接ID,每次自增1
     *
     * @param
     * @return java.lang.Integer
     */
    public static Integer getHyperlinkId() {
        return ++hyperlinkId;
    }

    /**
     * 创建docx文档
     * 原文件如果已经存在的情况下,原文件中的内容会被清空
     * 在windows中,只要是相同后缀名且前缀也相同就是同一文件(不区分大小写),当是同一后缀名且大小写不一致时,已存在的文件后缀名大小写不会改动
     * 如果原文件已存在,则该word文件不能处于打开状态
     *
     * @param docxFile
     * @return void
     */
    public static void createDocx(File docxFile) throws Exception {
        // Create the package 建包
        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
        // 另存为新的文件 保存
        // 如果原文件已存在的话,里面的内容会被清空
        wordMLPackage.save(docxFile);
    }

    /**
     * 添加段落,整个段落使用同一种样式
     *
     * @param wPackage
     * @param paragraphText
     * @param styleId
     * @return void
     */
    public static void insertOneParagraph(WordprocessingMLPackage wPackage, String paragraphText, String styleId) {
        if (StringUtils.isBlank(paragraphText)) {
            return;
        }

        MainDocumentPart mdt = wPackage.getMainDocumentPart();

        Style style = WordStylesUtil.getStyleById(styleId);
        if (style == null) {
            // 未查询到样式,直接添加默认段落
            mdt.addParagraphOfText(paragraphText);
        } else {
            mdt.getContent().add(getPByStyleId(paragraphText, styleId));
        }
    }

    /**
     * 根据样式ID获取段落对象P
     *
     * @param paragraphText
     * @param styleId
     * @return org.docx4j.wml.P
     */
    public static P getPByStyleId(String paragraphText, String styleId) {
        Style style = WordStylesUtil.getStyleById(styleId);
        ObjectFactory factory = Context.getWmlObjectFactory();
        P paragraph = factory.createP();
        R run = factory.createR();
        run.setRPr(style.getRPr());

        String[] split = paragraphText == null ? new String[0] : paragraphText.split("\n");
        if (split.length > 1) {
            List<Child> list = new ArrayList<>();
            for (String s : split) {
                Text text = factory.createText();
                text.setValue(s);
                // 保留前后空格
                text.setSpace(SchemaSymbols.ATTVAL_PRESERVE);
                // 将换行符进行处理为</Br>
                Br br = factory.createBr();
                list.add(text);
                list.add(br);
            }
            run.getContent().addAll(list);
        } else {
            Text text = factory.createText();
            text.setValue(paragraphText);
            run.getContent().add(text);
        }
        paragraph.getContent().add(run);
        paragraph.setPPr(style.getPPr());

        return paragraph;
    }

    /**
     * 添加段落,可以是复合样式的段落
     *
     * @param wPackage
     * @param paragraph 用户自定义好的段落(包括样式与内容)
     * @return void
     */
    public static void insertOneParagraph(WordprocessingMLPackage wPackage, P paragraph) {
        wPackage.getMainDocumentPart().getContent().add(paragraph);
    }

    /**
     * 给word中写入复合样式的段落信息
     *
     * @param wPackage
     * @param context   二维数组,二维中的数据只能有两个元素,第一个为段落内容,第二个为样式ID。例如:[["内容1","样式1"],["内容2","样式2"]]
     */
    public static void complexPWrite(WordprocessingMLPackage wPackage, String[][] context) {
        if (context.length <= 0) {
            return;
        }
        P complexP = WordUtil.getComplexP();
        for (int i = 0; i < context.length; i++) {
            String[] temp = context[i];
            if (temp.length != 2) {
                continue;
            }
            String paragraph = temp[0];
            String styleId = temp[1];
            Style style = WordStylesUtil.getStyleById(styleId);
            if (StringUtils.isBlank(paragraph) || style == null) {
                continue;
            }
            addRun(complexP, paragraph, style);
        }

        // 写入
        insertOneParagraph(wPackage, complexP);
    }

    /**
     * 给word中写入复合样式的段落信息
     *
     * @param wPackage
     * @param prefix            前缀
     * @param prefixStyleId     正文段落 加粗 居左  样式ID
     * @param text              内容
     * @param textStyleId       正文段落 不加粗 居左 样式ID
     */
    public static void complexPWrite(WordprocessingMLPackage wPackage,  String prefix, String prefixStyleId,
                                     String text, String textStyleId) {
        String[][] context = new String[2][2];
        context[0][0] = prefix;
        context[0][1] = prefixStyleId;
        context[1][0] = text;
        context[1][1] = textStyleId;
        complexPWrite(wPackage, context);
    }

    /**
     * 复合段落某一段数据处理
     *
     * @param paragraph         整个段落
     * @param paragraphText     当前处理的某段数据
     * @param style             样式
     * @return void
     */
    public static void addRun(P paragraph, String paragraphText, Style style) {
        ObjectFactory factory = Context.getWmlObjectFactory();
        Text text = factory.createText();
        text.setValue(paragraphText);
        // 保留前后空格
        text.setSpace(SchemaSymbols.ATTVAL_PRESERVE);

        R run = factory.createR();
        run.getContent().add(text);
        run.setRPr(style.getRPr());

        paragraph.getContent().add(run);
    }

    /**
     * 某一段数据处理-添加超链接
     *
     * @param pHyperlink
     * @param paragraphText
     * @param style
     * @return void
     */
    public static void addRun(P.Hyperlink pHyperlink, String paragraphText, Style style) {
        ObjectFactory factory = Context.getWmlObjectFactory();
        Text text = factory.createText();
        text.setValue(paragraphText);
        // 保留前后空格
        text.setSpace(SchemaSymbols.ATTVAL_PRESERVE);

        R run = factory.createR();
        run.getContent().add(text);
        run.setRPr(style.getRPr());

        pHyperlink.getContent().add(run);
    }

    /**
     * 复合段落使用正文pPr(Previous Paragraph Properties)
     *
     * @param
     * @return org.docx4j.wml.P
     */
    public static P getComplexP() {
        ObjectFactory factory = Context.getWmlObjectFactory();
        P paragraph = factory.createP();
        Style style = WordStylesUtil.getStyleById(WordStylesUtil.NORMAL_STYLE);
        paragraph.setPPr(style.getPPr());
        return paragraph;
    }

    /**
     * 生成超链接段落(锚点)
     *
     * @param paragraphText
     * @param anchor
     * @param styleId
     * @return org.docx4j.wml.P
     */
    public static P createHyperlinkProduce(String paragraphText, String anchor, String styleId) {
        P p = getPByStyleId(paragraphText, styleId);
        ObjectFactory objectFactory = Context.getWmlObjectFactory();
        // 创建一个超链接对象
        BigInteger hli = BigInteger.valueOf(getHyperlinkId());
        CTBookmark ctBookmark = new CTBookmark();
        ctBookmark.setId(hli);
        ctBookmark.setName("_" + getAnchor(anchor));
        JAXBElement<CTBookmark> pHyperlinkBookmarkStart = objectFactory.createPHyperlinkBookmarkStart(ctBookmark);
        p.getContent().add(pHyperlinkBookmarkStart);
        CTMarkupRange ctMarkupRange = new CTMarkupRange();
        ctMarkupRange.setId(hli);
        objectFactory.createPBookmarkEnd(ctMarkupRange);
        p.getContent().add(ctMarkupRange);

        return p;
    }

    /**
     * 生成超链接段落(锚点)并写入word。整个段落都是超链接。
     * 超链接锚点anchor自定义
     *
     * @param wPackage
     * @param paragraphText     超链接段落
     * @param anchor            超链接锚点
     * @param styleId
     * @return void
     */
    public static void createHyperlinkProduce(WordprocessingMLPackage wPackage, String paragraphText, String anchor, String styleId) {
        insertOneParagraph(wPackage, createHyperlinkProduce(paragraphText, anchor, styleId));
    }

    /**
     * 生成超链接段落(锚点)并写入word。整个段落都是超链接。
     * 超链接锚点anchor与段落内容相同。
     *
     * @param wPackage
     * @param paragraphText
     * @param styleId
     * @return void
     */
    public static void createHyperlinkProduce(WordprocessingMLPackage wPackage, String paragraphText, String styleId) {
        insertOneParagraph(wPackage, createHyperlinkProduce(paragraphText, paragraphText, styleId));
    }

    /**
     * 生成超链接段落(调用锚点)。整个段落都是超链接。
     *
     * @param paragraphText
     * @param anchor        超链接跳转锚点标识
     * @param styleId
     * @return org.docx4j.wml.P
     */
    public static P createHyperlinkConsume(String paragraphText, String anchor, String styleId) {
        ObjectFactory factory = Context.getWmlObjectFactory();
        P p = factory.createP();
        P.Hyperlink pHyperlink = factory.createPHyperlink();
        pHyperlink.setAnchor("_" + getAnchor(anchor));
        // ctrl跳转后,按alt + ⬅ 可以跳转回来。以下参数必须为true,否则光标返回位置不对。
        pHyperlink.setHistory(true);

        Style style = WordStylesUtil.getStyleById(styleId);
        addRun(pHyperlink, paragraphText, style);
        p.getContent().add(pHyperlink);
        p.setPPr(style.getPPr());

        return p;
    }

    /**
     * 生成超链接段落(调用锚点)。整个段落都是超链接。
     * 超链接锚点anchor自定义
     *
     * @param wPackage
     * @param paragraphText
     * @param anchor
     * @param styleId
     * @return void
     */
    public static void createHyperlinkConsume(WordprocessingMLPackage wPackage, String paragraphText, String anchor, String styleId) {
        insertOneParagraph(wPackage, createHyperlinkConsume(paragraphText, anchor, styleId));
    }

    /**
     * 生成超链接段落(调用锚点)。整个段落都是超链接。
     * 超链接锚点anchor与段落内容相同。
     *
     * @param wPackage
     * @param paragraphText
     * @param styleId
     * @return void
     */
    public static void createHyperlinkConsume(WordprocessingMLPackage wPackage, String paragraphText, String styleId) {
        insertOneParagraph(wPackage, createHyperlinkConsume(paragraphText, paragraphText, styleId));
    }

    /**
     * 超链接锚点处理。
     * 锚点不能含有某些特殊字符,此处使用MD5进行转换。
     *
     * @param anchor
     * @return java.lang.String
     */
    public static String getAnchor(String anchor) {
        return MD5.create().digestHex(anchor, StandardCharsets.UTF_8);
    }

    /**
     * 分页
     *
     * @param wPackage
     * @return void
     */
    public static void setPage(WordprocessingMLPackage wPackage) {
        ObjectFactory factory = Context.getWmlObjectFactory();
        P paragraph = factory.createP();
        Style style = WordStylesUtil.getStyleById(WordStylesUtil.NORMAL_STYLE);
        paragraph.setPPr(style.getPPr());

        // 创建换行,且类型设置为分页
        Br br = factory.createBr();
        br.setType(STBrType.PAGE);
        R run = factory.createR();
        run.setRPr(style.getRPr());
        run.getContent().add(br);

        paragraph.getContent().add(run);

        insertOneParagraph(wPackage, paragraph);
    }
}

Main

package com.demo.word;


import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.*;

import java.io.File;

import static com.demo.word.WordConstant.*;

public class Main {

    public static void main(String[] args) throws Exception {
        File outputFile = new File("C:\\Users\\admin\\Desktop\\test.docx");
        WordUtil.createDocx(outputFile);
        WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(outputFile);

        // 写入一级标题
        WordUtil.insertOneParagraph(wPackage,"标题1", HEADING_1);
        // 写入单一样式段落
        WordUtil.insertOneParagraph(wPackage, "这是一个正文段落", NORMAL);
        // 写入复合样式段落
        WordUtil.complexPWrite(wPackage, "title:", WHQ_1, "测试title", WHQ_2);
        // 写入一个表格
        wordTable(wPackage);
        // 写入一个超链接(文档内部的超链接) 跳转起始处
        WordUtil.createHyperlinkConsume(wPackage,"超链接1", "这个必须唯一且与跳转的地方一致", WHQ_41);
        // 分页
        WordUtil.setPage(wPackage);
        // 写入一个超链接(文档内部的超链接) 跳转目标处
        WordUtil.createHyperlinkProduce(wPackage, "超链接2", "这个必须唯一且与跳转的地方一致", WHQ_1);

        // 写入word文档样式信息
        wPackage.getMainDocumentPart().getStyleDefinitionsPart().getJaxbElement().getStyle().addAll(WordStylesUtil.STYLES.values());
        wPackage.save(outputFile);
    }

    public static void wordTable(WordprocessingMLPackage wPackage) {
        // 生成参数表格
        ObjectFactory objectFactory = Context.getWmlObjectFactory();
        Tbl table = objectFactory.createTbl();

        // 标题行 处理
        Tr tr = objectFactory.createTr();
        wordTc(tr, WordUtil.getPByStyleId("单元格1", WHQ_3), A41);
        wordTc(tr, WordUtil.getPByStyleId("单元格2", WHQ_3), A42);
        wordTc(tr, WordUtil.getPByStyleId("单元格3", WHQ_3), A43);
        wordTc(tr, WordUtil.getPByStyleId("单元格4", WHQ_3), A44);
        table.getContent().add(tr);

        // 数据行 处理,测试添加3条数据
        for (int i = 0; i < 3; i++) {
            Tr trTemp = objectFactory.createTr();
            wordTc(trTemp, WordUtil.getPByStyleId("单元格1", WHQ_4), A51);
            wordTc(trTemp, WordUtil.getPByStyleId("单元格2", WHQ_4), A52);
            wordTc(trTemp, WordUtil.getPByStyleId("是", WHQ_5), A53);
            wordTc(trTemp, WordUtil.getPByStyleId("单元格4", WHQ_4), A54);
            table.getContent().add(trTemp);
        }

        // 表格整体样式
        Style tabStyle3 = WordStylesUtil.getStyleById(A3);
        table.setTblPr(new TblPr());
        // 边框线处理
        table.getTblPr().setTblBorders(tabStyle3.getTblPr().getTblBorders());
        // 表格列长度固定不可变
        table.getTblPr().setTblLayout(tabStyle3.getTblPr().getTblLayout());

        // 表格写入word文件
        wPackage.getMainDocumentPart().getContent().add(table);
    }

    public static void wordTc(Tr tr, P p, String tcStyleId) {
        ObjectFactory objectFactory = Context.getWmlObjectFactory();
        Tc tc = objectFactory.createTc();
        tc.setTcPr(WordStylesUtil.getStyleById(tcStyleId).getTcPr());
        tc.getContent().add(p);
        tr.getContent().add(tc);
    }
}

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java可以使用Apache POI库来处理Word文档,包括表格和样式。以下是基本的步骤: 1. 导入POI库 ```java import org.apache.poi.xwpf.usermodel.*; ``` 2. 加载Word文档 ```java FileInputStream fis = new FileInputStream("example.docx"); XWPFDocument document = new XWPFDocument(fis); ``` 3. 处理表格 ```java // 获取所有表格 List<XWPFTable> tables = document.getTables(); // 遍历所有表格 for (XWPFTable table : tables) { // 获取表格的行数和列数 int rows = table.getNumberOfRows(); int cols = table.getRow(0).getTableCells().size(); // 遍历表格的每一行和每一列 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { // 获取单元格 XWPFTableCell cell = table.getRow(i).getCell(j); // 获取单元格的内容 String content = cell.getText(); // 处理单元格的样式 CTTc cttc = cell.getCTTc(); CTTcPr ctPr = cttc.getTcPr(); if (ctPr != null) { CTShd ctShd = ctPr.getShd(); if (ctShd != null) { String bgColor = ctShd.getFill().toString(); // 处理背景色 } } } } } ``` 4. 处理样式 ```java // 获取文本段落 List<XWPFParagraph> paragraphs = document.getParagraphs(); // 遍历所有段落 for (XWPFParagraph paragraph : paragraphs) { // 获取段落的样式 CTPPr ctPPr = paragraph.getCTP().getPPr(); if (ctPPr != null) { CTSpacing ctSpacing = ctPPr.getSpacing(); if (ctSpacing != null) { int lineSpacing = ctSpacing.getLine().intValue(); // 处理行间距 } } // 获取段落中的文本 String text = paragraph.getText(); // 处理文本的样式 List<XWPFRun> runs = paragraph.getRuns(); for (XWPFRun run : runs) { // 获取文本的样式 CTRPr ctrPr = run.getCTR().getRPr(); if (ctrPr != null) { CTColor ctColor = ctrPr.getColor(); if (ctColor != null) { String color = ctColor.getVal(); // 处理字体颜色 } CTFonts ctFonts = ctrPr.getRFonts(); if (ctFonts != null) { String fontName = ctFonts.getAscii(); // 处理字体名称 } CTOnOff ctOnOff = ctrPr.getB(); if (ctOnOff != null) { boolean bold = ctOnOff.getVal().intValue() == 1; // 处理加粗 } } } } ``` 5. 关闭文件流 ```java fis.close(); ``` 这是处理Word文档的基本步骤,如果还需要处理图片等内容,可以参考POI库的官方文档。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值