使用POI生成文章标题

生成文章标题有两种方式,一种是自定义标题,还有一种是使用现有样式来生成,现在网上大部分是第一种方式,但这种方式有很多弊端,我们先来看第一种

第一步,引入依赖

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

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

代码如下:

/**
 * 自定义样式方式写word,参考statckoverflow的源码
 *
 * @throws IOException
 */
@Test
public void writeSimpleDocxFile() throws IOException {
    XWPFDocument docxDocument = new XWPFDocument();
    // 自定义标题1和标题2
    addCustomHeadingStyle(docxDocument, "标题 1", 1);
    addCustomHeadingStyle(docxDocument, "标题 2", 2);

    // 标题1
    XWPFParagraph paragraph = docxDocument.createParagraph();
    XWPFRun run = paragraph.createRun();
    run.setText("标题 1");
    run.setFontFamily("宋体");
    run.setBold(true);
    run.setFontSize(22);
    paragraph.setStyle("标题 1");

    // 标题2
    XWPFParagraph paragraph2 = docxDocument.createParagraph();
    XWPFRun run2 = paragraph2.createRun();
    run2.setText("标题 2");
    run2.setFontFamily("宋体");
    run2.setBold(true);
    run2.setFontSize(18);
    paragraph2.setStyle("标题 2");

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

    // word写入到文件
    FileOutputStream fos = new FileOutputStream("D:/myDoc.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);
}

 生成的word文档WPS打开如下,发现目录栏新增了两个自定义目录,这样就没法用内置的标题1,2,3了否则层级会乱掉

 再看word打开的效果,发现虽然用了内置标题,但是内置标题的样式被覆盖了

 所以第一种方案我们不会采用,问题太多,接下去看方案二。

首先新建一个format.docx,内容空白的也没事,我们所有的标题样式都取自这个文档

/**
 * 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();
    }
}

// 模板方式实现
@Test
public 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("2");
    XWPFRun run1 = para1.createRun();
    // 标题内容
    run1.setText("标题 1");

    // 标题2
    XWPFParagraph para2 = doc.createParagraph();
    // 关键行// 2级大纲
    para2.setStyle("3");
    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();
}

来看关键代码newStyles.setStyles(wordStyles);这行代码的意思是使用format.docx的样式

再来看一个关键代码para1.setStyle("2");这行代码的意思是设置为标题1样式,关键是2是什么意思呢?2其实就是styleId,如何查看format.docx的styleId呢?

我们打开format.docx,另存为,保存成xml格式

打开保存的xml,找styleId

可以看到heading 1对应的styleId是1,heading 2对应的styleId是2,heading 1和heading2又是什么鬼?

其实就是对应的目录栏,heading 1是正文,heading 2是标题1

 那如果修改标题1的样式呢?那就很简单了,右击标题1,点击修改样式就行了

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值