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());
    }
}
相关推荐
Lam Tang1 小时前
APS 系列文章 08
java·代理模式
萧瑟余晖2 小时前
Java深入解析篇三十三之消息队列
java·开发语言
码匠许师傅2 小时前
【C++ 面试真题】聊聊 C++ 的序列容器
java·c++·面试
IT爱学堂2 小时前
尚硅谷Java+AI大模型应用开发革新版本 2025年3月
java·开发语言·人工智能
不爱编程的小九九3 小时前
小九源码-springboot004-springboot智能阅读推荐系统
java·spring boot·后端
yuhulkjv3353 小时前
Gemini鸿蒙版导出word格式的终极解法:AI 导出鸭如何重构AI内容落地链路
人工智能·ai·word·harmonyos·ai导出鸭
SCandL1524 小时前
Docker的实战应用
java·docker·容器
AC赳赳老秦4 小时前
OpenClaw 多源采集公开行业数据:从原始信息到研究报告初稿的自动化实践
java·c语言·c++·python·php·deepseek·openclaw
Java成神之路-4 小时前
深入理解三大高频队列:ArrayDeque、LinkedList、PriorityQueue 方法、特性与场景选择
java
roman_日积跬步-终至千里4 小时前
【资源控制】自助查询的智能路由
java·大数据·数据库