POI操作word2010实现多级标题结构

一、 问题背景:

项目中会生成word的报告,但是直接io流写的报告都是“正文”,没有生成标题,也就没法在大纲结构中方便的查看章节内容了。搜了很多资料也请教了一些同事,终于把这个目录结构的问题搞定了,在此和大家分享一下。

目前我们用的是office2010,因为word2010(2010版本word结构和2007差不多,应该也适用于2007)与word2003的巨大差异,本方法可能不适用过低版本(主要是装卸office太耗时了),有低版本office的同学可以试试这个方法是否可行。

二、 准备工作:

1. JDK1.6或以上(1.8也试过是可以的,1.5的没试过了)。

2. 用的是maven管理配置,pom文件引入:

		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-excelant</artifactId>
			<version>3.9</version>
		</dependency>

三、 具体实现

1. 构建模板word。

创建一个word文档,例如D:/format.docx 。打开此文档,随便输入一行字符,例如输入: a 。 然后选中这一行,将其设置为“标题1”(或者大纲视图下的“1级”大纲)。保存,关闭format.docx。

2. 代码实现解析format.docx并新建word文档,写入标题到新建文档中。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;

public class WordTitle {
    /**
     * word整体样式
     */
    private static CTStyles wordStyles = null;

    /**
     * Word整体样式
     */
    static {
        XWPFDocument template;
        try {
            // 读取模板文档
            template = new XWPFDocument(new FileInputStream("D:/format.docx"));
            // 获得模板文档的整体样式
            wordStyles = template.getStyle();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        // 新建的word文档对象
        XWPFDocument doc = new XWPFDocument();
        // 获取新建文档对象的样式
        XWPFStyles newStyles = doc.createStyles();
        // 关键行// 修改设置文档样式为静态块中读取到的样式
        newStyles.setStyles(wordStyles);

        // 开始内容输入
        // 标题1,1级大纲
        XWPFParagraph para1 = doc.createParagraph();
        // 关键行// 1级大纲
        para1.setStyle("1");
        XWPFRun run1 = para1.createRun();
        // 标题内容
        run1.setText("标题 1");

        // 标题2
        XWPFParagraph para2 = doc.createParagraph();
        // 关键行// 2级大纲
        para2.setStyle("2");
        XWPFRun run2 = para2.createRun();
        // 标题内容
        run2.setText("标题 2");

        // 正文
        XWPFParagraph paraX = doc.createParagraph();
        XWPFRun runX = paraX.createRun();
        // 正文内容
        runX.setText("正文");

        // word写入到文件
        FileOutputStream fos = new FileOutputStream("D:/myDoc.docx");
        doc.write(fos);
        fos.close();
    }
}

四、 特别说明

1. format.docx中只有标题1,虽然代码中设置了标题2(2级大纲),但是没有生效,“标题2”仍然是正文格式。如果想生效,需要在format.docx中新增一行,并设置为标题2(2级大纲)。

2. 一个奇怪的现象:设置完标题2,解析一次之后,再次将标题2设置为正文格式,或者删除,读取的wordStyles格式仍然能够设置标题2。

3. 大家可以打印下wordStyles,看看“标题1”附近的一些参数值,有助于理解和记忆。

五、 参考资料

参考了stackoverflow一篇关于POI的问题

最终解决问题,是这个链接给了灵感。老外用的是英文版的word,最终实现上还是和中文版的略有不同。

此外,大家往下看会发现一段代码,没有依赖模板,直接正向实现的。这种方式的实现,需要自己调整标题的字体大小、是否加粗等,个人感觉挺繁琐的。

具体实现如下(注意包的引入):

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFStyle;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;

public class WordTitle {
    /**
     * word整体样式
     */
    private static CTStyles wordStyles = null;

    /**
     * Word整体样式
     */
    static {
        XWPFDocument template;
        try {
            // 读取模板文档
            template = new XWPFDocument(new FileInputStream("D:/format.docx"));
            // 获得模板文档的整体样式
            wordStyles = template.getStyle();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlException e) {
            e.printStackTrace();
        }
    }

    // 模板方式实现
    public static void formatDoc() throws IOException {
        // 新建的word文档对象
        XWPFDocument doc = new XWPFDocument();
        // 获取新建文档对象的样式
        XWPFStyles newStyles = doc.createStyles();
        // 关键行// 修改设置文档样式为静态块中读取到的样式
        newStyles.setStyles(wordStyles);

        // 开始内容输入
        // 标题1,1级大纲
        XWPFParagraph para1 = doc.createParagraph();
        // 关键行// 1级大纲
        para1.setStyle("1");
        XWPFRun run1 = para1.createRun();
        // 标题内容
        run1.setText("标题 1");

        // 标题2
        XWPFParagraph para2 = doc.createParagraph();
        // 关键行// 2级大纲
        para2.setStyle("2");
        XWPFRun run2 = para2.createRun();
        // 标题内容
        run2.setText("标题 2");

        // 正文
        XWPFParagraph paraX = doc.createParagraph();
        XWPFRun runX = paraX.createRun();
        // 正文内容
        runX.setText("正文");

        // word写入到文件
        FileOutputStream fos = new FileOutputStream("D:/myDoc.docx");
        doc.write(fos);
        fos.close();
    }

    // main
    public static void main(String[] args) throws Exception {
        // 读取模板方式写word
        formatDoc();

        // 自定义样式方式写word
        writeSimpleDocxFile();
    }

    /**
     * 自定义样式方式写word,参考statckoverflow的源码
     *
     * @throws IOException
     */
    public static void writeSimpleDocxFile() throws IOException {
        XWPFDocument docxDocument = new XWPFDocument();

        // 老外自定义了一个名字,中文版的最好还是按照word给的标题名来,否则级别上可能会乱
        addCustomHeadingStyle(docxDocument, "标题 1", 1);
        addCustomHeadingStyle(docxDocument, "标题 2", 2);

        // 标题1
        XWPFParagraph paragraph = docxDocument.createParagraph();
        XWPFRun run = paragraph.createRun();
        run.setText("标题 1");
        paragraph.setStyle("标题 1");

        // 标题2
        XWPFParagraph paragraph2 = docxDocument.createParagraph();
        XWPFRun run2 = paragraph2.createRun();
        run2.setText("标题 2");
        paragraph2.setStyle("标题 2");

        // 正文
        XWPFParagraph paragraphX = docxDocument.createParagraph();
        XWPFRun runX = paragraphX.createRun();
        runX.setText("正文");

        // word写入到文件
        FileOutputStream fos = new FileOutputStream("D:/myDoc2.docx");
        docxDocument.write(fos);
        fos.close();
    }

    /**
     * 增加自定义标题样式。这里用的是stackoverflow的源码
     *
     * @param docxDocument 目标文档
     * @param strStyleId 样式名称
     * @param headingLevel 样式级别
     */
    private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {

        CTStyle ctStyle = CTStyle.Factory.newInstance();
        ctStyle.setStyleId(strStyleId);

        CTString styleName = CTString.Factory.newInstance();
        styleName.setVal(strStyleId);
        ctStyle.setName(styleName);

        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
        indentNumber.setVal(BigInteger.valueOf(headingLevel));

        // lower number > style is more prominent in the formats bar
        ctStyle.setUiPriority(indentNumber);

        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
        ctStyle.setUnhideWhenUsed(onoffnull);

        // style shows up in the formats bar
        ctStyle.setQFormat(onoffnull);

        // style defines a heading of the given level
        CTPPr ppr = CTPPr.Factory.newInstance();
        ppr.setOutlineLvl(indentNumber);
        ctStyle.setPPr(ppr);

        XWPFStyle style = new XWPFStyle(ctStyle);

        // is a null op if already defined
        XWPFStyles styles = docxDocument.createStyles();

        style.setType(STStyleType.PARAGRAPH);
        styles.addStyle(style);

    }
}

六、 没了

欢迎大家提供新的解决方案!

时间: 2024-10-28 14:27:30

POI操作word2010实现多级标题结构的相关文章

java使用POI操作excel文件,实现批量导出,和导入

一.POI的定义 JAVA中操作Excel的有两种比较主流的工具包: JXL 和 POI .jxl 只能操作Excel 95, 97, 2000也即以.xls为后缀的excel.而poi可以操作Excel 95及以后的版本,即可操作后缀为 .xls 和 .xlsx两种格式的excel. POI全称 Poor Obfuscation Implementation,直译为"可怜的模糊实现",利用POI接口可以通过JAVA操作Microsoft office 套件工具的读写功能.官网:htt

Silverlight项目笔记7:xml/json数据解析、MVVM下实现多级树形结构TreeView、忽视引用类型导致数据绑定错误、通过流或动态空间加载图片、虚拟目录设置、silverlight安全机制引发的问题、WebClient缓存问题

涉及的内容主要有: 1.xml/json数据解析 2.多级树形结构TreeView 3.忽视引用类型导致数据绑定错误 4.通过流或动态空间加载图片 5.虚拟目录设置 6.silverlight安全机制引发的问题 7.webclient缓存问题 1.xml/json数据解析 (1)xml数据解析 使用WebClient获取数据,获取到的数据实例化为一个XDocument,使用XDocument的Descendants(XName)方法获得对应节点的数据集合,再通过Element这个方法对数据集合进

POI操作EXCEL之导出Excel(设置有效性,下拉列表引用)

本人使用的是poi-bin-3.10-FINAL-20140208.zip 版本的poi以下是程序关键代码: //需要引用的类 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import ja

Java 借助poi操作Wold工具类

? Apache封装的POI组件对Excel,Wold的操作已经非常的丰富了,在项目上也会经常用到一些POI的基本操作 这里就简单的阐述POI操作Wold的基本工具类,代码还是有点粗造的,但是不影响使用. 这个类包含了一些对文本进行换行,加粗,倾斜,字体颜色,大小,首行缩进,添加边框等方法.分享给大家学习下: Apache POI的组件: ApachePOI包含用于处理MS-Office的所有OLE2复合文档的类和方法.该API的组件列表如下 - POIFS(不良混淆实现文件系统) - 此组件是

(5) 如何用Apache POI操作Excel文件-----发现Apache的POI的Bug后,如何给Apache的POI报Bug?

在我上篇文章中,(4) 如何用Apache POI操作Excel文件-----发现了POI-3.12一个回归,通过测试POI-3.12的版本,我发现了一个bug,那么发现bug后,该如何处理.我们有2种处理方式,首先我们到Apache POI的bug库里面搜索,看别人有没有创建类似的bug,如果有创建的,这个是最好的结果,我们只需要关注这个bug什么时候被修复.如果没有搜索不到,这个时候我们就需要给Apache POI报bug了.那么,如何给Apache报Bug? 第一步: 打开https://

poi操作Excel工具类

在上一篇文章<使用poi读写Excel>中分享了一下poi操作Excel的简单示例,这次要分享一下我封装的一个Excel操作的工具类. 该工具类主要完成的功能是:读取Excel.写入Excel.合并Excel的功能.

利用POI操作不同版本word文档中的图片以及创建word文档

我们都知道要想利用java对office操作最常用的技术就应该是POI了,在这里本人就不多说究竟POI是什么和怎么用了.先说本人遇到的问题,不同于利用POI去向word文档以及excel文档去写入数据和向外导出数据并且保存到数据库中这些类似的操作,由于业务上的需要需要利用POI去读取word中的图片,并且去把图片去保存为一个file文件.查了Apache公司提供的api帮助文档,再网友的一些线索,本人也总结了几中对不同word版本(.doc或者是.docx结尾)对于文件中所含图片的操作方式,希望

JAVA使用POI操作excel

这里提一下,java操作excel的组件除了apache的poi,还有jexcelapi(jxl),其中poi组件的获取地址为poi.apache.org. poi组件中常用的类有HSSFworkbook表示一个完整的excel表格,HSSFsheet表示excel中的一个工作薄,HSSFRow表示工作薄中的一行,HSSFCell表示一个单元格 下面是一个简单的写入的demo public static void main(String [] args){ try { HSSFWorkbook

POI操作Excel详解,HSSF和XSSF两种方式

HSSF方式: package com.tools.poi.lesson1; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.