You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Apache POI将HTML转换为Word文档:无法添加页眉页脚及@page CSS支持问题咨询

解决Apache POI转换HTML到Word时的页眉页脚问题

你好!针对你遇到的问题,我来逐一解答:

一、POI支持CSS的@page样式吗?

答案是不支持。你当前使用的POIFSFileSystem直接写入WordDocument的方式,是针对旧版.doc格式的底层二进制操作,这种方式完全没有实现CSS @page规则的解析能力——它只是简单把HTML内容打包成Word的底层格式,根本无法识别页面布局相关的CSS规则,所以自然没法通过@page来生成页眉页脚。而且这种方式的扩展性极差,几乎没法控制文档的页面元素。

二、怎么给生成的.doc文档添加页眉页脚?

别用那种底层的POIFS方式了,改用Apache POI专门处理.doc的HWPF组件(或者处理.docx的XWPF,推荐后者,支持更好)来实现。下面分两种格式给你具体方案:

方案1:针对.doc格式(HWPF)

首先要确保你引入了poi-scratchpad依赖(Maven示例):

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>5.2.5</version> <!-- 用你实际使用的POI版本 -->
</dependency>

然后修改你的转换逻辑,用HWPF来构建文档并添加页眉页脚:

import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.HeaderStories;
import org.apache.poi.hwpf.usermodel.Range;

import java.io.IOException;
import java.io.OutputStream;

public class HtmlToWordUtil {

    public void convertHtmlToWordWithHeaderFooter(String html, OutputStream outputStream) throws IOException {
        // 1. 创建一个空的.doc文档
        HWPFDocument doc = new HWPFDocument();
        Range contentRange = doc.getRange();

        // 2. 把HTML内容插入到文档主体
        // 注意:HWPF对复杂HTML样式支持有限,如果你的HTML有复杂样式,建议先用Jsoup预处理
        contentRange.insertAfter(html);

        // 3. 添加页眉
        HeaderStories headerStories = doc.getHeaderStories();
        headerStories.setHeader("这里是自定义页眉内容");

        // 4. 添加带页码的页脚
        // 用Word的域来实现自动页码,PAGE是当前页,NUMPAGES是总页数
        String footerText = "第 " + org.apache.poi.hwpf.usermodel.PageNumber.PAGE + " 页 / 共 " + org.apache.poi.hwpf.usermodel.PageNumber.NUMPAGES + " 页";
        headerStories.setFooter(footerText);

        // 5. 写入输出流并关闭资源
        doc.write(outputStream);
        doc.close();
        outputStream.close();
    }
}

方案2:推荐用.docx格式(XWPF)

HWPF对HTML的支持比较有限,如果你业务允许,强烈推荐用.docx格式,XWPF的功能更完善,HTML转换和页眉页脚控制都更靠谱。

依赖只需要标准的poi和poi-ooxml:

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

实现代码:

import org.apache.poi.xwpf.usermodel.*;
import org.w3c.dom.Document;

import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;

public class HtmlToDocxUtil {

    public void convertHtmlToDocxWithHeaderFooter(String html, OutputStream outputStream) throws Exception {
        // 1. 创建空的.docx文档
        XWPFDocument docx = new XWPFDocument();

        // 2. 把HTML转换为docx内容(先解析HTML为DOM文档)
        Document htmlDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
                .parse(new ByteArrayInputStream(html.getBytes()));
        org.apache.poi.xwpf.converter.xhtml.XHTMLConverter.getInstance().convert(htmlDoc, docx, null);

        // 3. 添加页眉
        XWPFHeader header = docx.createHeader(HeaderFooterType.DEFAULT);
        XWPFParagraph headerPara = header.createParagraph();
        XWPFRun headerRun = headerPara.createRun();
        headerRun.setText("这是Docx文档的自定义页眉");
        headerPara.setAlignment(ParagraphAlignment.CENTER); // 居中显示

        // 4. 添加带自动页码的页脚
        XWPFFooter footer = docx.createFooter(HeaderFooterType.DEFAULT);
        XWPFParagraph footerPara = footer.createParagraph();
        footerPara.setAlignment(ParagraphAlignment.CENTER);

        XWPFRun footerRun = footerPara.createRun();
        footerRun.setText("第 ");
        // 插入当前页码域
        footerRun.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.BEGIN);
        footerRun.getCTR().addNewInstrText().setStringValue(" PAGE ");
        footerRun.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.END);

        footerRun.setText(" 页 / 共 ");
        // 插入总页数域
        footerRun.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.BEGIN);
        footerRun.getCTR().addNewInstrText().setStringValue(" NUMPAGES ");
        footerRun.getCTR().addNewFldChar().setFldCharType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STFldCharType.END);
        footerRun.setText(" 页");

        // 5. 写入输出流并关闭资源
        docx.write(outputStream);
        docx.close();
        outputStream.close();
    }
}

几个关键提醒:

  • 你原来的POIFS方式太底层,完全没法控制页面元素,必须切换到HWPF/XWPF的高层API。
  • 如果HTML有复杂样式,比如表格、自定义字体,建议先用Jsoup把HTML转换成标准XHTML,再进行转换,避免样式丢失。
  • 页脚的页码必须用Word的域来实现,这样才能自动计算页码,而不是写死的文本。

内容的提问来源于stack exchange,提问作者Chanchal Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 04:18:14