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

如何用Apache POI获取.docx单页内容及段落所属页码

实现docx分页内容添加<hr/>标签的方案

Apache POI的XWPF模块本身不直接存储段落的页码信息(因为docx的页码是渲染时动态计算的,而非文档结构的固有属性),以下两种可行方案可以满足你的需求:

方案一:借助docx4j实现精准页码计算

docx4j带有布局引擎,可以准确计算每个段落所属的页码,步骤如下:

  1. 添加docx4j相关依赖(根据你的构建工具调整,比如Maven)
  2. 加载文档并使用LayoutManager获取段落页码
  3. 遍历段落时记录当前页码,页码变化时插入<hr/>标签

示例代码:

import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.model.layout.LayoutManager;
import org.docx4j.wml.P;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

// 读取docx文件并处理分页
public String[] processDocxWithPageBreaks(String absolutePath) throws Exception {
    WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(absolutePath));
    LayoutManager layoutManager = new LayoutManager(wordMLPackage);
    
    List<String> textList = new ArrayList<>();
    int currentPage = 0;

    for (Object contentObj : wordMLPackage.getMainDocumentPart().getContent()) {
        if (contentObj instanceof P) {
            P docx4jPara = (P) contentObj;
            // 转换为POI的XWPFParagraph,适配你现有的parseParagraph方法
            XWPFParagraph paragraph = new XWPFParagraph(docx4jPara, new XWPFDocument());
            String textToAdd = parseParagraph(paragraph);
            
            int paraPageNum = layoutManager.getPageNumber(docx4jPara);
            if (paraPageNum > currentPage) {
                if (currentPage != 0) {
                    textList.add("<hr/>");
                }
                currentPage = paraPageNum;
            }
            textList.add(textToAdd);
        }
    }
    // 最后一页末尾添加分隔线
    textList.add("<hr/>");
    
    return textList.toArray(new String[0]);
}

优缺点:精准度高,能处理复杂排版(如图片、表格、不同页面设置),但需要额外引入docx4j依赖,代码复杂度稍高。

方案二:基于POI的近似分页计算

如果不需要绝对精准的页码,可通过估算段落高度、累计页面高度的方式实现近似分页,无需额外依赖:

  1. 定义页面可用高度(根据纸张大小、边距计算)
  2. 遍历段落时计算段落高度,累计超过页面高度时插入<hr/>标签

示例代码:

import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

public String[] processDocxApproximatePageBreaks(String absolutePath) throws Exception {
    FileInputStream fis = new FileInputStream(absolutePath);
    XWPFDocument document = new XWPFDocument(fis);
    List<IBodyElement> bodyElements = document.getBodyElements();
    List<String> textList = new ArrayList<>();

    // A4纸默认可用高度(单位:磅):页面总高793.7磅,上下边距各72磅
    final double PAGE_AVAILABLE_HEIGHT = 649.7;
    double currentPageHeight = 0;

    for (IBodyElement bodyElement : bodyElements) {
        if (bodyElement.getElementType() == BodyElementType.PARAGRAPH) {
            XWPFParagraph paragraph = (XWPFParagraph) bodyElement;
            String textToAdd = parseParagraph(paragraph);
            
            double paraHeight = calculateParagraphHeight(paragraph);
            // 判断是否需要分页
            if (currentPageHeight + paraHeight > PAGE_AVAILABLE_HEIGHT) {
                textList.add("<hr/>");
                currentPageHeight = paraHeight;
            } else {
                currentPageHeight += paraHeight;
            }
            
            textList.add(textToAdd);
        }
    }
    // 最后一页末尾添加分隔线
    textList.add("<hr/>");
    
    document.close();
    return textList.toArray(new String[0]);
}

// 估算段落高度的辅助方法
private double calculateParagraphHeight(XWPFParagraph paragraph) {
    // 默认字体大小11磅
    int fontSize = 11;
    for (XWPFRun run : paragraph.getRuns()) {
        if (run.getFontSize() != -1) {
            fontSize = run.getFontSize();
            break;
        }
    }

    // 默认行间距1.5倍
    double lineSpacing = 1.5;
    CTPPr pPr = paragraph.getCTP().getPPr();
    if (pPr != null && pPr.getSpacing() != null && pPr.getSpacing().getLine() != null) {
        // Word中行间距存储单位是1/20磅,转换为倍数
        lineSpacing = pPr.getSpacing().getLine().doubleValue() / 20 / fontSize;
    }

    // 估算段落行数:假设每行约40个字符
    String paraText = paragraph.getText();
    int lines = paraText.isEmpty() ? 1 : (int) Math.ceil(paraText.length() / 40.0);

    // 段落总高度 = 行数 × 字体大小 × 行间距
    return lines * fontSize * lineSpacing;
}

优缺点:轻量无需额外依赖,实现简单,但属于近似计算,对于包含图片、表格或特殊排版的文档,分页精度会受影响,适合对分页精度要求不高的场景。

内容的提问来源于stack exchange,提问作者Adnan Bin Zahir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 17:05:29