java 使用 POI 为 word 文档自动生成书签

poi 版本:4.1.0

XML 复制代码
<properties>
	<java.version>1.8</java.version>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
	<poi.version>4.1.0</poi.version>
</properties>

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>${poi.version}</version>
	<scope>compile</scope>
	<optional>false</optional>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>${poi.version}</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml-schemas</artifactId>
	<version>${poi.version}</version>
</dependency>

代码示例中是为类似如下所示的接口文档自动生成书签:

XML 复制代码
			人员接口文档
1.新增人员
	1.1.请求url:http://127.0.0.1/addUser
	1.2.请求方式:POST
	1.3.请求参数说明:xxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxx
	1.4.响应参数说明:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2.删除人员
	2.1.请求url:http://127.0.0.1/removeUser
	2.2.请求方式:POST
	2.3.请求参数说明:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	2.4.响应参数说明:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3.查看人员详情
	3.1.请求url:http://127.0.0.1/userDetail
	3.2.请求方式:POST
	3.3.请求参数说明:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	3.4.响应参数说明:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
					xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

即读取文档的每一行内容,检测到该行文本以 "http://127.0.0.1" 开头则将其上一行设置为书签,请结合文档具体内容以及需求自行修改使用

例如原始文档如下所示:

输出文档如下所示:

java 复制代码
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;

public class WordBookmarkCreater {

    public static void main(String[] args) throws Exception {
        String inputFilePath = "D:\\xxx\\input.docx";
        String outputFilePath = "D:\\xxx\\output.docx";
        XWPFDocument doc = new XWPFDocument(new FileInputStream(inputFilePath));

        // 删除原本书签
        deleteAllBookmarks( doc );

        // 重新生成书签
        markHeadings(doc);

        // 保存文档
        FileOutputStream out = new FileOutputStream(outputFilePath);
        doc.write(out);
        out.close();
    }

    // 删除文档中的书签
    private static void deleteAllBookmarks(XWPFDocument doc) {
        // 普通段落
        for (XWPFParagraph p : doc.getParagraphs()) {
            clearBookmarks(p.getCTP());
        }

        // 表格中的段落
        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph p : cell.getParagraphs()) {
                        clearBookmarks(p.getCTP());
                    }
                }
            }
        }
    }

    private static void clearBookmarks(CTP ctp) {
        ctp.getBookmarkStartList().clear();
        ctp.getBookmarkEndList().clear();
    }


    private static void markHeadings(XWPFDocument doc) {
        XWPFParagraph paragraph_prev = null;
        int num = 1;
        for (XWPFParagraph paragraph : doc.getParagraphs()) {
            String text = paragraph.getText();
            if( text.toLowerCase().contains( "请求" ) &&
                text.toLowerCase().contains( "url" ) &&
                text.toLowerCase().contains( "http://127.0.0.1" )){
                System.out.println( text );
                if( paragraph_prev == null ){
                    // 可选:添加书签锚点
                    addBookmark( paragraph, num + ". " + text );
                }else {
                    // 可选:添加书签锚点
                    addBookmark( paragraph_prev, num + ". " + paragraph_prev.getText() );
                }
                num++;
            }
            paragraph_prev = paragraph;
        }
    }

    private static void addBookmark(XWPFParagraph paragraph,String bookmarkName) {
        CTP ctp = paragraph.getCTP();
        CTBookmark bookmark = ctp.addNewBookmarkStart();
        bookmark.setId(BigInteger.valueOf( ctp.sizeOfBookmarkStartArray() ));
        bookmark.setName(bookmarkName);
        ctp.addNewBookmarkEnd().setId(bookmark.getId());
    }
}
相关推荐
野生技术架构师5 小时前
2026 Java 面试全套总结,八股 + 场景 + AI 相关面试考点
java·人工智能·面试
香吧香6 小时前
java服务异常日志只打印异常类型,没有堆栈定位分析
java·jvm·异常
qq_2518364576 小时前
AI 疾病自查功能SpringbootAI项目实战 · 技术实现文档
java·ai·ai编程
逆境不可逃7 小时前
Pi Agent 学习笔记:对话太长以后,如何压缩上下文
java
MetaLite7 小时前
JDK 8~26 核心特性一览:从 Stream 到 Scoped Values
java
wno7047 小时前
Spring Boot WebFlux增删改查
java·spring boot·后端
君顾17 小时前
上海24小时自助健身房系统开发实战指南:从架构设计到落地部署
java·开发语言·健身房
SL_staff9 小时前
别急着买商业规则引擎:90%风控场景根本不需要全量编码能力
java·程序员·groovy
ManageEngineITSM9 小时前
DevOps和ITIL是什么关系?是替代还是互补一文讲清
java·服务器·资产管理·变更管理
SL_staff10 小时前
ERP排程总在纸上谈兵?JVS-APS如何用真实产能约束打通计划与执行闭环
java·人工智能·开源