1.1、概述
首先,我是一名搞开发的,深受pdf没有目录的那种痛苦,假如你在网上寻找到一本pdf电子书,或者是在某宝上买的,发现都是没有目录,看起来真的很难受。我就想办法自己来使用程序制作目录,如果大家也同样遇到这样的困难,就一定要看看我的博客,创作不易,某宝上使用pdf去生成目录,几块钱一本,我这方法一劳永逸,授人以鱼不如授人以渔,请大家体谅一下,感谢。废话不多说,直接上教程。
1.2、使用IDEA创建工程
学java的都会使用idea,那么就创建一个java的maven工程
1.3、引入依赖
<dependencies>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
</dependencies>
1.4、定义书签实体
/**
* @desc 定义书签
*/
public class Bookmark {
//书签id
Integer id;
//页码
Integer page;
//标题
String title;
//层级
Integer level;
//父id
Integer pid;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
@Override
public String toString() {
return "BookTemp{" +
"id=" + id +
", page=" + page +
", title='" + title + '\'' +
", level=" + level +
", pid=" + pid +
'}';
}
}
1.5、制作书签
1.5.1、制作书签格式说明
封面 1
版权信息 2
内容简介 3
前言 4
第1章收银台业务 5
1.1现金收银台 5
1.2POS机收银台 7
1.3Web收银台 9
1.4融合收银台 12
1.4.1短信代收费 12
1.4.2充值卡 14
1.4.3银行卡 16
1.4.4WAP支付 20
1.4.5支付宝 22
1.4.6微信支付 26
1.4.7代金券 27
如上目录个数标题格式:
一级目录:书签+空格+页码 【第1章收银台业务 5】
二级目录:tab+书签+空格+页码 【1.1现金收银台 5】
三级目录:tab+tab+书签+空格+页码 【1.4.1短信代收费 12】
用tab判断是几级标签
用空格拆分书签和页码
注意事项:
书签名字千万不能有空格。
1.5.2、寻找pdf书籍的目录
根据你pdf书籍的名称去豆瓣上寻找书籍的目录,下面我就以《Kafka权威指南》的pdf为例子来演示。
书籍源目录:
序 xiii
前言 xv
第 1 章 初识Kafka 1
1.1 发布与订阅消息系统 1
1.1.1 如何开始 2
1.1.2 独立的队列系统 3
1.2 Kafka登场 4
1.2.1 消息和批次 4
1.2.2 模式 4
1.2.3 主题和分区 5
1.2.4 生产者和消费者 5
1.2.5 broker和集群 6
1.2.6 多集群 7
1.3 为什么选择Kafka 8
1.3.1 多个生产者 8
1.3.2 多个消费者 8
1.3.3 基于磁盘的数据存储 9
1.3.4 伸缩性 9
1.3.5 高性能 9
1.4 数据生态系统 9
1.5 起源故事 11
1.5.1 LinkedIn的问题 11
1.5.2 Kafka的诞生 12
1.5.3 走向开源 12
1.5.4 命名 13
1.6 开始Kafka之旅 13
第 2 章 安装Kafka 14
2.1 要事先行 14
2.1.1 选择操作系统 14
2.1.2 安装Java 14
2.1.3 安装Zookeeper 15
2.2 安装Kafka Broker 17
2.3 broker配置 18
2.3.1 常规配置 18
2.3.2 主题的默认配置 19
2.4 硬件的选择 23
2.4.1 磁盘吞吐量 23
2.4.2 磁盘容量 23
2.4.3 内存 23
2.4.4 网络 24
2.4.5 CPU 24
2.5 云端的Kafka 24
2.6 Kafka集群 24
2.6.1 需要多少个broker 25
2.6.2 broker 配置 25
2.6.3 操作系统调优 26
2.7 生产环境的注意事项 28
2.7.1 垃圾回收器选项 28
2.7.2 数据中心布局 29
2.7.3 共享Zookeeper 29
2.8 总结 30
第 3 章 Kafka生产者——向Kafka写入数据 31
3.1 生产者概览 32
3.2 创建Kafka生产者 33
3.3 发送消息到Kafka 34
3.3.1 同步发送消息 35
3.3.2 异步发送消息 35
3.4 生产者的配置 36
3.5 序列化器 39
3.5.1 自定义序列化器 39
3.5.2 使用Avro序列化 41
3.5.3 在Kafka里使用Avro 42
3.6 分区 45
3.7 旧版的生产者API 46
3.8 总结 47
第 4 章 Kafka消费者——从Kafka读取数据 48
4.1 KafkaConsumer概念 48
4.1.1 消费者和消费者群组 48
4.1.2 消费者群组和分区再均衡 51
4.2 创建Kafka消费者 52
4.3 订阅主题 53
4.4 轮询 53
4.5 消费者的配置 55
4.6 提交和偏移量 57
4.6.1 自动提交 58
4.6.2 提交当前偏移量 59
4.6.3 异步提交 59
4.6.4 同步和异步组合提交 61
4.6.5 提交特定的偏移量 61
4.7 再均衡监听器 62
4.8 从特定偏移量处开始处理记录 64
4.9 如何退出 66
4.10 反序列化器 67
4.11 独立消费者——为什么以及怎样使用没有群组的消费者 71
4.12 旧版的消费者API 71
4.13 总结 72
第 5 章 深入Kafka 73
5.1 集群成员关系 73
5.2 控制器 74
5.3 复制 74
5.4 处理请求 76
5.4.1 生产请求 78
5.4.2 获取请求 78
5.4.3 其他请求 80
5.5 物理存储 81
5.5.1 分区分配 81
5.5.2 文件管理 82
5.5.3 文件格式 83
5.5.4 索引 84
5.5.5 清理 84
5.5.6 清理的工作原理 84
5.5.7 被删除的事件 86
5.5.8 何时会清理主题 86
5.9 总结 86
第 6 章 可靠的数据传递 87
6.1 可靠性保证 87
6.2 复制 88
6.3 broker配置 89
6.3.1 复制系数 89
6.3.2 不完全的首领选举 90
6.3.3 最少同步副本 91
6.4 在可靠的系统里使用生产者 92
6.4.1 发送确认 92
6.4.2 配置生产者的重试参数 93
6.4.3 额外的错误处理 94
6.5 在可靠的系统里使用消费者 94
6.5.1 消费者的可靠性配置 95
6.5.2 显式提交偏移量 95
6.6 验证系统可靠性 97
6.6.1 配置验证 98
6.6.2 应用程序验证 98
6.6.3 在生产环境监控可靠性 99
6.7 总结 100
第 7 章 构建数据管道 101
7.1 构建数据管道时需要考虑的问题 102
7.1.1 及时性 102
7.1.2 可靠性 102
7.1.3 高吞吐量和动态吞吐量 103
7.1.4 数据格式 103
7.1.5 转换 104
7.1.6 安全性 104
7.1.7 故障处理能力 104
7.1.8 耦合性和灵活性 105
7.2 如何在Connect API和客户端API之间作出选择 105
7.3 Kafka Connect 106
7.3.1 运行Connect 106
7.3.2 连接器示例——文件数据源和文件数据池 107
7.3.3 连接器示例——从MySQL到ElasticSearch 109
7.3.4 深入理解Connect 114
7.4 Connect之外的选择 116
7.4.1 用于其他数据存储的摄入框架 116
7.4.2 基于图形界面的ETL工具 117
7.4.3 流式处理框架 117
7.5 总结 117
第 8 章 跨集群数据镜像 118
8.1 跨集群镜像的使用场景 118
8.2 多集群架构 119
8.2.1 跨数据中心通信的一些现实情况 119
8.2.2 Hub和Spoke架构 120
8.2.3 双活架构 121
8.2.4 主备架构 123
8.2.5 延展集群 127
8.3 Kafka的MirrorMaker 128
8.3.1 如何配置 129
8.3.2 在生产环境部署MirrorMaker 130
8.3.3 MirrorMaker调优 132
8.4 其他跨集群镜像方案 134
8.4.1 优步的uReplicator 134
8.4.2 Confluent的Replicator 135
8.5 总结 135
第 9 章 管理Kafka 136
9.1 主题操作 136
9.1.1 创建主题 137
9.1.2 增加分区 138
9.1.3 删除主题 138
9.1.4 列出集群里的所有主题 139
9.1.5 列出主题详细信息 139
9.2 消费者群组 140
9.2.1 列出并描述群组 140
9.2.2 删除群组 142
9.2.3 偏移量管理 142
9.3 动态配置变更 143
9.3.1 覆盖主题的默认配置 143
9.3.2 覆盖客户端的默认配置 145
9.3.3 列出被覆盖的配置 145
9.3.4 移除被覆盖的配置 146
9.4 分区管理 146
9.4.1 首选的首领选举 146
9.4.2 修改分区副本 147
9.4.3 修改复制系数 150
9.4.4 转储日志片段 151
9.4.5 副本验证 152
9.5 消费和生产 153
9.5.1 控制台消费者 153
9.5.2 控制台生产者 155
9.6 客户端ACL 157
9.7 不安全的操作 157
9.7.1 移动集群控制器 157
9.7.2 取消分区重分配 157
9.7.3 移除待删除的主题 158
9.7.4 手动删除主题 158
9.8 总结 159
第 10 章 监控Kafka 160
10.1 度量指标基础 160
10.1.1 度量指标在哪里 160
10.1.2 内部或外部度量 161
10.1.3 应用程序健康检测 161
10.1.4 度量指标的覆盖面 161
10.2 broker的度量指标 162
10.2.1 非同步分区 162
10.2.2 broker度量指标 166
10.2.3 主题和分区的度量指标 173
10.2.4 Java虚拟机监控 174
10.2.5 操作系统监控 175
10.2.6 日志 176
10.3 客户端监控 177
10.3.1 生产者度量指标 177
10.3.2 消费者度量指标 179
10.3.3 配额 181
10.4 延时监控 182
10.5 端到端监控 183
10.6 总结 183
第 11 章 流式处理 184
11.1 什么是流式处理 185
11.2 流式处理的一些概念 186
11.2.1 时间 187
11.2.2 状态 188
11.2.3 流和表的二元性 188
11.2.4 时间窗口 189
11.3 流式处理的设计模式 190
11.3.1 单个事件处理 191
11.3.2 使用本地状态 191
11.3.3 多阶段处理和重分区 193
11.3.4 使用外部查找——流和表的连接 193
11.3.5 流与流的连接 195
11.3.6 乱序的事件 195
11.3.7 重新处理 196
11.4 Streams示例 197
11.4.1 字数统计 197
11.4.2 股票市场统计 199
11.4.3 填充点击事件流 201
11.5 Kafka Streams的架构概览 202
11.5.1 构建拓扑 202
11.5.2 对拓扑进行伸缩 203
11.5.3 从故障中存活下来 205
11.6 流式处理使用场景 205
11.7 如何选择流式处理框架 206
11.8 总结 208
附录A 在其他操作系统上安装Kafka 209
作者介绍 214
封面介绍 214
1.5.3、制作书籍的新目录
可以去掉书籍一些不必要的目录,例如上面的目录可以去掉:
序 xiii
前言 xv
作者介绍 214
封面介绍 214
根据自己的需求删除不必要的目录。
制作后的目录:
第1章初识Kafka 1
1.1发布与订阅消息系统 1
1.1.1如何开始 2
1.1.2独立的队列系统 3
1.2Kafka登场 4
1.2.1消息和批次 4
1.2.2模式 4
1.2.3主题和分区 5
1.2.4生产者和消费者 5
1.2.5broker和集群 6
1.2.6多集群 7
1.3为什么选择Kafka 8
1.3.1多个生产者 8
1.3.2多个消费者 8
1.3.3基于磁盘的数据存储 9
1.3.4伸缩性 9
1.3.5高性能 9
1.4数据生态系统 9
1.5起源故事 11
1.5.1LinkedIn的问题 11
1.5.2Kafka的诞生 12
1.5.3走向开源 12
1.5.4命名 13
1.6开始Kafka之旅 13
第2章安装Kafka 14
2.1要事先行 14
2.1.1选择操作系统 14
2.1.2安装Java 14
2.1.3安装Zookeeper 15
2.2安装Kafka Broker 17
2.3broker配置 18
2.3.1常规配置 18
2.3.2主题的默认配置 19
2.4硬件的选择 23
2.4.1磁盘吞吐量 23
2.4.2磁盘容量 23
2.4.3内存 23
2.4.4网络 24
2.4.5CPU 24
2.5云端的Kafka 24
2.6Kafka集群 24
2.6.1需要多少个broker 25
2.6.2broker 配置 25
2.6.3操作系统调优 26
2.7生产环境的注意事项 28
2.7.1垃圾回收器选项 28
2.7.2数据中心布局 29
2.7.3共享Zookeeper 29
2.8总结 30
第3章Kafka生产者——向Kafka写入数据 31
3.1生产者概览 32
3.2创建Kafka生产者 33
3.3发送消息到Kafka 34
3.3.1同步发送消息 35
3.3.2异步发送消息 35
3.4生产者的配置 36
3.5序列化器 39
3.5.1自定义序列化器 39
3.5.2使用Avro序列化 41
3.5.3在Kafka里使用Avro 42
3.6分区 45
3.7旧版的生产者API 46
3.8总结 47
第4章Kafka消费者——从Kafka读取数据 48
4.1KafkaConsumer概念 48
4.1.1消费者和消费者群组 48
4.1.2消费者群组和分区再均衡 51
4.2创建Kafka消费者 52
4.3订阅主题 53
4.4轮询 53
4.5消费者的配置 55
4.6提交和偏移量 57
4.6.1自动提交 58
4.6.2提交当前偏移量 59
4.6.3异步提交 59
4.6.4同步和异步组合提交 61
4.6.5提交特定的偏移量 61
4.7再均衡监听器 62
4.8从特定偏移量处开始处理记录 64
4.9如何退出 66
4.10反序列化器 67
4.11独立消费者——为什么以及怎样使用没有群组的消费者 71
4.12旧版的消费者API 71
4.13总结 72
第5章深入Kafka 73
5.1集群成员关系 73
5.2控制器 74
5.3复制 74
5.4处理请求 76
5.4.1生产请求 78
5.4.2获取请求 78
5.4.3其他请求 80
5.5物理存储 81
5.5.1分区分配 81
5.5.2文件管理 82
5.5.3文件格式 83
5.5.4索引 84
5.5.5清理 84
5.5.6清理的工作原理 84
5.5.7被删除的事件 86
5.5.8何时会清理主题 86
5.9总结 86
第6章可靠的数据传递 87
6.1可靠性保证 87
6.2复制 88
6.3broker配置 89
6.3.1复制系数 89
6.3.2不完全的首领选举 90
6.3.3最少同步副本 91
6.4在可靠的系统里使用生产者 92
6.4.1发送确认 92
6.4.2配置生产者的重试参数 93
6.4.3额外的错误处理 94
6.5在可靠的系统里使用消费者 94
6.5.1消费者的可靠性配置 95
6.5.2显式提交偏移量 95
6.6验证系统可靠性 97
6.6.1配置验证 98
6.6.2应用程序验证 98
6.6.3在生产环境监控可靠性 99
6.7总结 100
第7章构建数据管道 101
7.1构建数据管道时需要考虑的问题 102
7.1.1及时性 102
7.1.2可靠性 102
7.1.3高吞吐量和动态吞吐量 103
7.1.4数据格式 103
7.1.5转换 104
7.1.6安全性 104
7.1.7故障处理能力 104
7.1.8耦合性和灵活性 105
7.2如何在Connect API和客户端API之间作出选择 105
7.3Kafka Connect 106
7.3.1运行Connect 106
7.3.2连接器示例——文件数据源和文件数据池 107
7.3.3连接器示例——从MySQL到ElasticSearch 109
7.3.4深入理解Connect 114
7.4Connect之外的选择 116
7.4.1用于其他数据存储的摄入框架 116
7.4.2基于图形界面的ETL工具 117
7.4.3流式处理框架 117
7.5总结 117
第8章跨集群数据镜像 118
8.1跨集群镜像的使用场景 118
8.2多集群架构 119
8.2.1跨数据中心通信的一些现实情况 119
8.2.2Hub和Spoke架构 120
8.2.3双活架构 121
8.2.4主备架构 123
8.2.5延展集群 127
8.3Kafka的MirrorMaker 128
8.3.1如何配置 129
8.3.2在生产环境部署MirrorMaker 130
8.3.3MirrorMaker调优 132
8.4其他跨集群镜像方案 134
8.4.1优步的uReplicator 134
8.4.2Confluent的Replicator 135
8.5总结 135
第9章管理Kafka 136
9.1主题操作 136
9.1.1创建主题 137
9.1.2增加分区 138
9.1.3删除主题 138
9.1.4列出集群里的所有主题 139
9.1.5列出主题详细信息 139
9.2消费者群组 140
9.2.1列出并描述群组 140
9.2.2删除群组 142
9.2.3偏移量管理 142
9.3动态配置变更 143
9.3.1覆盖主题的默认配置 143
9.3.2覆盖客户端的默认配置 145
9.3.3列出被覆盖的配置 145
9.3.4移除被覆盖的配置 146
9.4分区管理 146
9.4.1首选的首领选举 146
9.4.2修改分区副本 147
9.4.3修改复制系数 150
9.4.4转储日志片段 151
9.4.5副本验证 152
9.5消费和生产 153
9.5.1控制台消费者 153
9.5.2控制台生产者 155
9.6客户端ACL 157
9.7不安全的操作 157
9.7.1移动集群控制器 157
9.7.2取消分区重分配 157
9.7.3移除待删除的主题 158
9.7.4手动删除主题 158
9.8总结 159
第10章监控Kafka 160
10.1度量指标基础 160
10.1.1度量指标在哪里 160
10.1.2内部或外部度量 161
10.1.3应用程序健康检测 161
10.1.4度量指标的覆盖面 161
10.2broker的度量指标 162
10.2.1非同步分区 162
10.2.2broker度量指标 166
10.2.3主题和分区的度量指标 173
10.2.4Java虚拟机监控 174
10.2.5操作系统监控 175
10.2.6日志 176
10.3客户端监控 177
10.3.1生产者度量指标 177
10.3.2消费者度量指标 179
10.3.3配额 181
10.4延时监控 182
10.5端到端监控 183
10.6总结 183
第11章流式处理 184
11.1什么是流式处理 185
11.2流式处理的一些概念 186
11.2.1时间 187
11.2.2状态 188
11.2.3流和表的二元性 188
11.2.4时间窗口 189
11.3流式处理的设计模式 190
11.3.1单个事件处理 191
11.3.2使用本地状态 191
11.3.3多阶段处理和重分区 193
11.3.4使用外部查找——流和表的连接 193
11.3.5流与流的连接 195
11.3.6乱序的事件 195
11.3.7重新处理 196
11.4Streams示例 197
11.4.1字数统计 197
11.4.2股票市场统计 199
11.4.3填充点击事件流 201
11.5Kafka Streams的架构概览 202
11.5.1构建拓扑 202
11.5.2对拓扑进行伸缩 203
11.5.3从故障中存活下来 205
11.6流式处理使用场景 205
11.7如何选择流式处理框架 206
11.8总结 208
附录A在其他操作系统上安装Kafka 209
注意:一定要看我的制作目录的说明啊,很重要的。
1.6、编写程序
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.*;
import com.thingsgod.entity.Bookmark;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class JavaCreatePdfCatalogue {
/**
* 读取书签文本
* @param txt
* @param skip
* @return
* @throws Exception
*/
public static List<Bookmark> readTxt(String txt, Integer skip) throws Exception{
ArrayList<String> lines=new ArrayList<>();
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(txt),"UTF-8"));
String line = null;
while ((line = br.readLine()) != null) {
lines.add(line);
}
br.close();
//判断分别的级别
ArrayList<Bookmark> Bookmarks = new ArrayList<>();
for(int i =0;i<lines.size();i++){
try {
String[] r = lines.get(i).split(" ");
Bookmark temp = new Bookmark();
int len = emptyStrlen(r);
//一个tab开头为二级标题【一个tab是4个空格,截取出来就会产生4个空字符,就是要空字符来判断】
if(len == 4){
temp.setLevel(2);
}
//两个tab开头为三级标题【一个tab是4个空格,截取出来就会产生8个空字符】
else if(len == 8){
temp.setLevel(3);
}
//无tab开头为一级标题
else{
temp.setLevel(1);
}
temp.setId(i);
temp.setTitle(r[r.length-2].replace("\t",""));
temp.setPage(Integer.valueOf(r[r.length-1])+skip);
temp.setPid(-1);
Bookmarks.add(temp);
} catch (Exception e){
System.out.println("数据错误: 行数="+i+",数据:"+lines.get(i));
e.printStackTrace();
throw new RuntimeException();
}
}
//建立pid关联关系
int lastLevel1 = 0;//最近一次level1标签的下标
int lastLevel2 = 0;//最近一次level2标签下标
for(int i =0;i<Bookmarks.size() ;i++){
Bookmark bt = Bookmarks.get(i);
if(bt.getLevel() == 1){
lastLevel1 = i;
continue;
}
if(bt.getLevel() == 2){
lastLevel2 = i;
bt.setPid(lastLevel1);
continue;
}
if(bt.getLevel() == 3){
bt.setPid(lastLevel2);
}
}
Bookmarks.stream().forEach(n->{
System.out.println(n.toString());
});
return Bookmarks;
}
/**
* 添加多级书签
* @param sPdf pdf的文件所在目录,绝对路径
* @param bookTxt 书籍的目录结构,可以从当当网上去获取
* @param skip 跳过书籍前面的广告页数
* @throws Exception
*/
public static void addMultiLevelBookmark(String sPdf,String bookTxt,Integer skip) throws Exception{
//打开文档
Document document = new Document();
//新pdf名称
String[] a = sPdf.split("\\.pdf");
String dPdf = a[0]+"_new.pdf";
PdfCopy writer = new PdfCopy(document, new FileOutputStream(dPdf));
writer.setViewerPreferences(PdfWriter.PageModeUseOutlines);
document.open();
//打开源pdf复制到新pdf
PdfReader reader = new PdfReader(sPdf);
int n = reader.getNumberOfPages();
for (int i = 1; i <= n; i++) {
writer.addPage(writer.getImportedPage(reader, i));
}
//添加书签
writer.freeReader(reader);
PdfOutline root = writer.getRootOutline();
//书签文本转书签对象
List<Bookmark> bookTemps = readTxt(bookTxt,skip);
bookTemps.stream().forEach(filter1->{
if(filter1.getLevel().equals(1)){
//建立一级标签
PdfAction actionLevel1 = PdfAction.gotoLocalPage(filter1.getPage(),new PdfDestination(PdfDestination.FIT), writer);
PdfOutline outlineLevel1 = new PdfOutline(root, actionLevel1, filter1.getTitle(), false);
System.out.println("一级:"+filter1.getTitle()+" "+filter1.getPage());
bookTemps.stream().forEach(filter2->{
//建立二级标签,要挂载一级标签下面
if(filter2.getLevel().equals(2)&&filter1.getId().equals(filter2.getPid())){
System.out.println("二级:"+filter2.getTitle()+" "+filter2.getPage());
PdfAction action2 = PdfAction.gotoLocalPage(filter2.getPage(),new PdfDestination(PdfDestination.FIT), writer);
PdfOutline outlineLevel2 = new PdfOutline(outlineLevel1, action2, filter2.getTitle(), false);
bookTemps.stream().forEach(filter3->{
//建立三级标签,要挂载二级标签下面
if(filter3.getLevel().equals(3)&&filter2.getId().equals(filter3.getPid())){
PdfAction action3 = PdfAction.gotoLocalPage(filter3.getPage(),new PdfDestination(PdfDestination.FIT), writer);
PdfOutline outlineLevel3 = new PdfOutline(outlineLevel2, action3, filter3.getTitle(), false);
System.out.println("三级:"+filter3.getTitle()+" "+filter3.getPage());
}
});
}
});
}
});
document.close();
}
public static int emptyStrlen(String[] strArr){
int len = 0;
if(strArr != null && strArr.length > 0){
for (String str : strArr) {
if("".equals(str)){
len += 1;
}
}
}
return len;
}
public static void main(String[] args) throws Exception {
addMultiLevelBookmark("D:\\yuxinwei\\AE\\Ae-java-create-pdf-catalogue\\pdf\\Kafka权威指南.pdf",
"D:\\yuxinwei\\AE\\Ae-java-create-pdf-catalogue\\bookmark\\目录.txt",
19);
}
注意点:就是 addMultiLevelBookmark 方法的第三个参数就是看你的pdf前面不必要的内容进行跳过,你可以使用wps打开,数一下,我这边pdf就是需要跳过前面19页的不必要,从第20页开始进行来生成目录。
1.7、运行结果
1.8、地址
创作不易,请尊重版权,感谢大家
GitHub - AldirchEugene/Ae-java-create-pdf-catalogue: java代码创建pdf文档目录