做企业开发的同学,大概率都碰到过这类需求:
- 做知识库 / RAG 系统:要把用户上传的 PDF、Word、PPT、甚至扫描件全部扒成纯文本,切块丢向量库;
- 做全文检索:文件服务器上几十万份文档,要统一建索引,能按关键词搜到内容;
- 做内容审核 / 合规审计:员工上传的附件里有没有敏感词?合同里有没有不合规条款?
- 做元数据归档:一份合同的作者是谁、哪天创建的、最后谁改的、多少页?
这类需求的共同点是:格式杂、数量大、写解析代码非常痛苦——
- 写 Word 用 POI,
.doc 和 .docx 还不是一套 API; - 写 PDF 用 PDFBox,加密 PDF 还得绕一圈;
- 写 Excel 又得换 Fesod/POI;碰到 HTML、RTF、压缩包、图片 OCR?
- 每多一种格式,就得多学一套库、多写一套分支,维护起来就是噩梦。
今天的主角 Apache Tika 就是来解决这个痛点的。它把上千种文件格式的解析能力封装成一套统一的 API,你不用管底层是 POI 还是 PDFBox,丢文件进去 → 出来就是 文本内容 + 元数据 + MIME 类型。
配合上一篇 Spring Boot + Apache Fesod 生产级 Excel 组件,你的项目就能形成完整的 “Excel 精细化读写 + 全格式文档内容解析” 闭环。
0)Apache Tika 是什么 & 为什么选它
0.1 一句话定位
Apache Tika 是 Apache 基金会旗下的开源内容分析工具包,能够自动检测上千种文件格式,并从中统一提取文本内容、元数据、语言类型。
你可以把 Tika 理解成文档解析界的 Facade 模式——底层仍然使用 POI、PDFBox、HtmlParser、Tesseract 这些成熟解析器,但上层给你一套 10 分钟就能上手的统一门面。
0.2 Tika 能解析什么?(1000+ 格式部分代表)
| 类别 | 支持的格式 |
|---|
| 办公文档 | Word(.doc/.docx)、Excel(.xls/.xlsx,配合 Fesod/POI)、PowerPoint(.ppt/.pptx)、Visio、Outlook MSG、OpenDocument(ODT/ODS/ODP)、RTF |
| PDF | 标准 PDF、加密 PDF(需密码)、带表单 PDF、PDF/A 归档版 |
| 网页与标记 | HTML、XHTML、XML、JSON、YAML、Markdown |
| 纯文本 | .txt / .log / .csv(含自动编码识别) |
| 压缩包 | ZIP / TAR / GZIP / RAR / 7z(可递归解包提取内容) |
| 邮件 | .eml / .mbox / Outlook PST |
| 图像 & OCR | JPEG / PNG / TIFF / BMP(能取 EXIF;配合 Tesseract 可 OCR 图片文字) |
| 多媒体元数据 | MP3 / FLAC(ID3 标签)、MP4 / MOV(音视频元信息) |
0.3 核心三大能力
| 能力 | 说明 |
|---|
| 🔍 MIME 自动检测 | 不看后缀名,根据文件二进制 Magic Number + 内容特征判断真实类型,防改后缀名绕过 |
| 📝 内容提取 | 输出纯文本(也可输出 XHTML 结构化结果,保留标题、表格层次) |
| 🏷️ 元数据提取 | 作者、标题、创建/修改时间、页数、分辨率、EXIF、Creator Tool 等几十种属性 |
额外可选能力:🌏 语言检测(中英文混排自动识别)、🖼️ OCR(Tesseract 集成)、🔗 递归解析(ZIP 里的 Word 直接扒出来)。
0.4 和”挨个用解析器”对比
| 维度 | 手写”if PDF, if Word, if Excel” | Apache Tika |
|---|
| 支持格式 | 加一种格式加一套代码,维护爆炸 | 一套 API 通吃 1000+ |
| MIME 检测 | fileName.endsWith(".pdf") → 改后缀立刻翻车 | Magic Number + 内容特征,真实类型 99%+ 准确 |
| 学习成本 | POI、PDFBox、jsoup 每一套都要查文档 | 3 个核心类 + 2 个方法,10 分钟上手 |
| 升级兼容 | 每个解析器自己升版本,依赖冲突家常便饭 | Tika 团队已经帮你把依赖对齐、避过坑了 |
| 企业 RAG/知识库场景 | 一个月搭不完 + 后续持续踩坑 | 引入依赖 → 写几十行 Service → 上线 🚀 |
一句话结论:只要你的系统需要解析 2 种以上的文档格式,Tika 就是 ROI 最高的选择。
1)环境准备:3 种引入方式按需选
Tika 的发布体系非常清晰,按场景选就行。
1.1 版本怎么挑?(截至 2026 Q3)
| 系列 | 最新版本 | JDK 要求 | 推荐场景 |
|---|
| 2.9.x LTS | 2.9.4 | JDK 8+ | 生产环境首选,稳定、生态完善 |
| 3.3.x | 3.3.2 | JDK 11+ | 需要新特性,不追求极端稳定 |
| 4.0.0 | 4.0.0 | JDK 17+ | 尝鲜用,2026/8 刚发 GA |
✅ 本文示例统一用最稳的 2.9.4 + JDK 17,代码在 3.x 系列也完全兼容(只换版本号即可)。
1.2 方式一:极简依赖(核心 + 标准解析器,99% 项目用这个 ✅)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <properties> <tika.version>2.9.4</tika.version> </properties>
<dependencies> <dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-core</artifactId> <version>${tika.version}</version> </dependency>
<dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-parsers-standard-package</artifactId> <version>${tika.version}</version> <type>pom</type> </dependency>
<dependency> <groupId>org.apache.tika</groupId> <artifactId>tika-langdetect-optimaize</artifactId> <version>${tika.version}</version> </dependency>
</dependencies>
|
⚠️ 依赖冲突提示:如果你的项目已经有 POI / PDFBox,建议升级到 Tika 同版本(可以去 Maven 看 tika-parsers-standard-package 的 parent POM 里锁定的版本号),避免 NoSuchMethodError。
1.3 方式二:Tika Server(微服务 / 非 Java 项目用)
如果你的主语言不是 Java(Python/Go/Node.js),或者要做”解析中心”供多个微服务调用,推荐直接用 Tika 提供的 REST 服务:
1 2 3 4 5 6 7 8 9 10 11
| wget https://dlcdn.apache.org/tika/2.9.4/tika-server-standard-2.9.4.jar
java -Xmx2g -jar tika-server-standard-2.9.4.jar --port=9998
curl -T /path/to/report.pdf http://localhost:9998/tika
curl -T /path/to/report.pdf http://localhost:9998/meta
|
Docker 部署(生产推荐,含 Tesseract OCR 语言包):
1 2
| docker run -d -p 9998:9998 --name tika-server \ apache/tika:2.9.4.0-full
|
1.4 方式三:命令行 / GUI 工具(排错 & 手工解析)
Tika 还提供了一个开箱即用的 tika-app JAR,本地人肉调试神器:
1 2 3 4 5 6 7 8 9 10 11
| java -jar tika-app-2.9.4.jar -t report.pdf > report.txt
java -jar tika-app-2.9.4.jar -m report.pdf
java -jar tika-app-2.9.4.jar -x report.docx > report.xhtml
java -jar tika-app-2.9.4.jar -g
|
2)核心 API 速览:2 层用法,按需取用
Tika 设计了两层 API,简单场景 1 行搞定,复杂场景下到底层完全可控:
2.1 Facade 层(new Tika()):10 行以内搞定一切,首推 🌟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| Tika tika = new Tika();
String mime = tika.detect(new File("contract.pdf"));
String text = tika.parseToString(new File("contract.pdf"));
Metadata metadata = new Metadata(); try (InputStream in = new FileInputStream("contract.pdf")) { String text2 = tika.parseToString(in, metadata); String author = metadata.get("dc:creator"); String pages = metadata.get("xmpTPg:NPages"); }
|
2.2 Parser 层(AutoDetectParser):精细控制(大文件 / OCR / 加密 PDF)
Facade 层底层就是走的 Parser 层,当你需要控制字符限制、密码、OCR 参数、解析器白名单时就直接用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| AutoDetectParser parser = new AutoDetectParser(); BodyContentHandler handler = new BodyContentHandler(-1); Metadata metadata = new Metadata(); ParseContext context = new ParseContext();
try (InputStream in = TikaInputStream.get(new File("big.docx"))) { parser.parse(in, handler, metadata, context); String content = handler.toString(); }
|
⚠️ 巨坑提示:BodyContentHandler 默认构造器有 100,000 字符上限,超过就直接截断!大文档务必传 -1 或你想要的上限。这是新手最高频翻车点。
下面所有实战,两个 API 都会给示例。
3)实战一:一键提取各种格式的纯文本(PDF / Word / Excel / PPT / HTML)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @Slf4j public final class TikaUtil {
private static final Tika TIKA = new Tika();
private TikaUtil() {}
public static String extractText(File file) { try { return TIKA.parseToString(file); } catch (IOException | TikaException e) { log.error("提取文本失败: {}", file.getName(), e); throw new RuntimeException("文档解析失败", e); } }
public static String extractText(InputStream in, String fileName) { try { Metadata meta = new Metadata(); meta.set(Metadata.RESOURCE_NAME_KEY, fileName); return TIKA.parseToString(in, meta); } catch (IOException | TikaException e) { log.error("提取文本失败: {}", fileName, e); throw new RuntimeException("文档解析失败", e); } } }
|
3.2 一行用起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Demo1_BasicFormats { public static void main(String[] args) { Stream.of( "合同.pdf", "需求说明.docx", "年度预算.xlsx", "产品路演.pptx", "公司简介.html", "README.md" ).forEach(name -> { File f = new File("/docs/" + name); String text = TikaUtil.extractText(f); System.out.println("===== " + name + " 前 200 字 ====="); System.out.println(text.substring(0, Math.min(200, text.length()))); }); } }
|
对 Excel 特别说明:Tika 拿出来的是所有 Sheet 拼起来的纯文本,适合内容索引;如果你需要按行、按列、带公式的精细化读写,配合上一篇的 Apache Fesod,两者各司其职。
3.3 进阶:拿结构化 XHTML(保留标题/表格/段落)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public static String extractXhtml(File file) { AutoDetectParser parser = new AutoDetectParser(); ToXMLContentHandler handler = new ToXMLContentHandler(); Metadata metadata = new Metadata(); try (InputStream in = TikaInputStream.get(file)) { parser.parse(in, handler, metadata, new ParseContext()); return handler.toString(); } catch (SAXException | TikaException | IOException e) { throw new RuntimeException("结构化解析失败", e); } }
|
产出的 XHTML 交给 jsoup 或者直接正则切 </p>|<table>|</h\d>,做 RAG 的文档分块体验会好很多(不会把半句话切开)。
4)实战二:提取元数据(作者、页数、EXIF、创建时间……)
元数据在合规审计、文档管理系统里特别常用。Tika 把所有属性都放进 Metadata 这个 Map 里。
4.1 通用元数据提取 + 常用 Key 速查表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| @Data @Builder public class DocMetaInfo { private String mime; private String title; private String author; private String creatorTool; private LocalDateTime createdTime; private LocalDateTime modifiedTime; private Integer pageCount; private Long wordCount; private Map<String, String> raw; }
public class DocMetaExtractor {
private static final DateTimeFormatter FMT = DateTimeFormatter.ISO_DATE_TIME;
public static DocMetaInfo extract(File file) { Metadata meta = new Metadata(); try (InputStream in = TikaInputStream.get(file)) { new AutoDetectParser().parse(in, new DefaultHandler(), meta, new ParseContext()); } catch (Exception e) { throw new RuntimeException("元数据提取失败", e); }
DocMetaInfo.DocMetaInfoBuilder b = DocMetaInfo.builder() .mime(meta.get(Metadata.CONTENT_TYPE)) .title(meta.get(Metadata.TITLE)) .author(meta.get("dc:creator")) .creatorTool(meta.get("xmp:CreatorTool")) .pageCount(parseIntOrNull(meta.get("xmpTPg:NPages"))) .wordCount(parseLongOrNull(meta.get("meta:word-count"))) .raw(toMap(meta));
String created = meta.get("dcterms:created"); String modified = meta.get("dcterms:modified"); if (created != null) b.createdTime(safeParse(created)); if (modified != null) b.modifiedTime(safeParse(modified)); return b.build(); }
private static Map<String, String> toMap(Metadata meta) { Map<String, String> m = new LinkedHashMap<>(); for (String name : meta.names()) m.put(name, meta.get(name)); return m; }
private static LocalDateTime safeParse(String s) { try { return LocalDateTime.parse(s.replace("Z", ""), FMT); } catch (Exception ignore) { return null; } } private static Integer parseIntOrNull(String s) { try { return s == null ? null : Integer.parseInt(s); } catch (Exception ignore) { return null; } } private static Long parseLongOrNull(String s) { try { return s == null ? null : Long.parseLong(s); } catch (Exception ignore) { return null; } } }
|
4.2 常用元数据 Key 对照表(查资料省半天)
| 含义 | Key | 示例值 |
|---|
| MIME 类型 | Content-Type | application/pdf |
| 标题 | dc:title / title | 2026 Q3 采购合同 |
| 作者 | dc:creator / meta:author | 张三 |
| 最后修改者 | dc:contributor / meta:last-author | 李四 |
| 制作工具 | xmp:CreatorTool | Microsoft® Word 2021 |
| 创建时间 | dcterms:created | 2026-08-01T03:12:45Z |
| 修改时间 | dcterms:modified | 2026-09-15T08:05:10Z |
| 页数(PDF/PPT) | xmpTPg:NPages | 23 |
| 字数 | meta:word-count | 15320 |
| PDF 是否加密 | pdf:encrypted | false |
| 图片 EXIF 拍摄时间 | exif:DateTimeOriginal | 2026-05-01T14:30:00 |
| 图片宽高 | tiff:ImageWidth / tiff:ImageLength | 3840 / 2160 |
| 语言 | dc:language / Content-Language | zh-CN |
💡 小技巧:调试时直接把 metadata.names() 全打出来,因为不同格式的 Key 名不完全一致。PDF 一般 pdf: 前缀,Office 有 meta: / extended-properties:,EXIF 是 exif:。
5)实战三:MIME 类型检测(防改后缀绕过安全规则)
只靠 fileName.endsWith(".pdf") 判断格式是系统常见漏洞——把 evil.exe 改成 contract.pdf 上传就能混过检查。Tika 用文件头 Magic Number + 内容启发式判断,更靠谱。
5.1 一行检测,支持 3 种入参
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class MimeDetectDemo { private static final Tika TIKA = new Tika();
public static void main(String[] args) throws IOException { String mime1 = TIKA.detect(new File("/tmp/看起来像PDF其实是EXE.pdf")); System.out.println(mime1);
Metadata meta = new Metadata(); meta.set(Metadata.RESOURCE_NAME_KEY, "报表.xlsx"); try (InputStream in = new FileInputStream("file")) { String mime2 = TIKA.detect(in, meta); }
byte[] bytes = Files.readAllBytes(Path.of("a")); String mime3 = TIKA.detect(bytes);
} }
|
5.2 在 Spring MVC 上传里直接用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @PostMapping("/upload") public R<String> upload(@RequestParam("file") MultipartFile file) throws IOException { String realMime = new Tika().detect(file.getBytes(), file.getOriginalFilename());
Set<String> allow = Set.of( "application/pdf", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ); if (!allow.contains(realMime)) { return R.fail("文件类型非法,真实类型: " + realMime); }
return R.ok("ok"); }
|
这就把”改后缀名绕过”这条路堵死了,合规审查加分项 ✅。
6)实战四:OCR 识别扫描件 / 图片文字(Tesseract 集成)
现实中很多 PDF 本质是一堆扫描图片(比如合同扫描件、发票、票据),Tika 正常解析出来是空文本。这时候就需要 Tesseract OCR 引擎出马。
6.1 先装 Tesseract(Tika 只是调用它,不自带)
| OS | 命令 |
|---|
| macOS | brew install tesseract tesseract-lang(tesseract-lang 含中文包 chi_sim) |
| Ubuntu/Debian | sudo apt install tesseract-ocr tesseract-ocr-chi-sim |
| RHEL/CentOS | sudo yum install tesseract tesseract-langpack-chi-sim(先加 EPEL 源) |
| Windows | 去 UB-Mannheim 镜像 下载安装包,勾选”中文简体” |
验证是否装对:
1 2
| tesseract --version tesseract --list-langs
|
6.2 Java 端一行开启 OCR(Tika 2.x 自动发现 Tesseract)
Tika 会自动去 PATH 里找 tesseract 可执行文件,找到就会对图片/扫描 PDF 自动走 OCR。所以只要环境装好了,代码完全不用改 —— 还是之前那套 parseToString!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class OcrDemo { public static void main(String[] args) throws Exception { Tika tika = new Tika();
String text1 = tika.parseToString(new File("发票扫描件.jpg")); System.out.println(text1);
String text2 = tika.parseToString(new File("合同扫描件.pdf"));
TesseractOCRConfig ocrConfig = new TesseractOCRConfig(); ocrConfig.setTesseractPath("/opt/homebrew/bin"); ocrConfig.setLanguage("chi_sim+eng"); ParseContext ctx = new ParseContext(); ctx.set(TesseractOCRConfig.class, ocrConfig);
AutoDetectParser parser = new AutoDetectParser(); BodyContentHandler handler = new BodyContentHandler(-1); try (InputStream in = TikaInputStream.get(new File("中文合同扫描.pdf"))) { parser.parse(in, handler, new Metadata(), ctx); System.out.println(handler.toString()); } } }
|
6.3 OCR 常见坑
| 坑 | 解决 |
|---|
| OCR 出来全是乱码 | 没装中文语言包,tesseract --list-langs 看有没有 chi_sim |
| 识别特别慢 | 1) 图片先压缩到 150~200 DPI;2) 调 ocrConfig.setPageSegMode(6)(假设一页一个均匀文本块) |
| 表格识别错位 | OCR 对表格天然弱,建议配合 PaddleOCR / TableTransformer 做专门表格提取,Tika OCR 适合正文 |
| Tesseract 不是最新 | macOS brew 的版本经常落后,生产环境推荐用官方 Docker apache/tika:full,已经配好 |
7)实战五:Spring Boot 封装”文档解析服务”(直接搬到项目里)
前面的工具类 + 自动检测 + OCR,封装成一个 Spring Service,以后任何模块要解析文件就 @Autowired DocumentParserService 一行。
7.1 配置类:Tika Bean + 可选 OCR 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Configuration public class TikaAutoConfig {
@Bean public Tika tika() { return new Tika(); }
@Bean @ConditionalOnProperty(name = "tika.ocr.enabled", havingValue = "true") public TesseractOCRConfig ocrConfig( @Value("${tika.ocr.tesseract-path:}") String tesseractPath, @Value("${tika.ocr.language:chi_sim+eng}") String language) { TesseractOCRConfig cfg = new TesseractOCRConfig(); if (StrUtil.isNotBlank(tesseractPath)) cfg.setTesseractPath(tesseractPath); cfg.setLanguage(language); return cfg; } }
|
7.2 业务 Service:解析 + 入库 + 建索引一把梭
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| @Slf4j @Service @RequiredArgsConstructor public class DocumentParserService {
private final Tika tika; private final ObjectProvider<TesseractOCRConfig> ocrConfigProvider; private final DocIndexMapper docIndexMapper; private final ApplicationEventPublisher publisher;
private static final Set<String> ALLOW_MIME = Set.of( "application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "text/plain", "text/html", "text/markdown" );
@Async("docParseExecutor") public void parseAndSave(Long docId, MultipartFile file) throws IOException { String realMime = tika.detect(file.getBytes(), file.getOriginalFilename()); if (!ALLOW_MIME.contains(realMime)) { throw new IllegalArgumentException("不支持的文件类型: " + realMime); }
ParseContext ctx = new ParseContext(); ocrConfigProvider.ifAvailable(cfg -> ctx.set(TesseractOCRConfig.class, cfg));
AutoDetectParser parser = new AutoDetectParser(); BodyContentHandler handler = new BodyContentHandler(-1); Metadata meta = new Metadata(); meta.set(Metadata.RESOURCE_NAME_KEY, file.getOriginalFilename());
try (InputStream in = TikaInputStream.get(file.getBytes())) { parser.parse(in, handler, meta, ctx); } catch (SAXException | TikaException e) { throw new RuntimeException("文档解析失败", e); }
String content = handler.toString(); DocMetaInfo docMeta = DocMetaExtractor.extractFromMeta(meta);
if (StrUtil.isBlank(content) && realMime.startsWith("image/")) { log.warn("文档为空内容,可能是扫描件: docId={}", docId); }
docIndexMapper.updateParsed(docId, realMime, content.length(), docMeta, StrUtil.maxLength(content, 50_000));
publisher.publishEvent(new DocParsedEvent(docId, content, realMime, docMeta)); log.info("✅ 文档解析完成 docId={}, mime={}, 字符数={}", docId, realMime, content.length()); } }
|
7.3 application.yml 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| tika: ocr: enabled: true language: chi_sim+eng
spring: task: execution: pool: thread-name-prefix: doc-parse- core-size: 4 max-size: 8 queue-capacity: 200
|
8)生产环境避坑清单 ⚠️(踩一次调 3 天)
| 坑 | 现象 | 解决方案 |
|---|
| BodyContentHandler 默认截断 10w 字符 | 长文档后半段内容丢失 | 一定用 new BodyContentHandler(-1),不要用默认构造器 |
| Tika 实例反复 new | 性能差、GC 频繁、解析器重复初始化 | 全局单例 Bean,Tika 是线程安全的 |
| POI / PDFBox 版本冲突 | NoSuchMethodError / ClassNotFoundException | 引入 tika-parsers-standard-package 的 pom,把自己项目里老的 poi-ooxml / pdfbox 升到 Tika 对齐的版本,或直接 exclusions 排除 |
| 超大文件 OOM | 200MB+ PDF 解析到内存爆炸 | 1) 用 TikaInputStream 包装 File(不走 byte[]);2) 设置 BodyContentHandler 字符上限;3) 超过阈值的文件单独丢 Tika Server 集群处理 |
| 加密 PDF 直接抛异常 | EncryptedDocumentException | 先 metadata.set(PDFParser.PASSWORD, pwd) 再 parse;也可以在 catch 里友好提示”请先解密” |
| Excel 解析”丢数据” | 公式、图表、批注没出来 | Tika 对 Excel 是”全量文本抓取”,不负责公式计算和格式;精细化业务还是用 Fesod |
| 中文 OCR 全问号/乱码 | 扫描件出来一堆 ??? | 1) 没装 chi_sim 语言包;2) setLanguage("chi_sim+eng") |
| Zip 炸弹 / 超大压缩包 | recursive 解析时解压出几十 GB 塞满磁盘 | 配置 ZipParser 的 maxExtractSize、maxMemoryBytes,或干脆禁用递归解压 |
| Tika Server 连接超时 | 大文件 / OCR 跑几十秒 | 客户端把 readTimeout 调到 60s~300s;服务端 -Xmx 至少 2g |
9)总结 & 学习资源
9.1 能力全景回顾
本篇讲了 Tika 的 5 个核心实战能力 + 1 套 Spring 生产封装:
| 场景 | 核心代码入口 | 章节 |
|---|
| 任意格式 → 纯文本 | Tika.parseToString() | 实战一 |
| 任意格式 → 结构化 XHTML | ToXMLContentHandler | 实战一 3.3 |
| 元数据提取(作者/页数/时间…) | Metadata + 常用 Key 表 | 实战二 |
| MIME 真实类型检测(防改后缀) | Tika.detect() | 实战三 |
| 扫描件 / 图片 OCR | Tesseract 安装 + TesseractOCRConfig | 实战四 |
| Spring Boot 通用服务 | DocumentParserService + 异步 + 事件 | 实战五 |
9.2 和 Fesod 的分工配合(划重点)
很多同学纠结:Tika 能解析 Excel,那还要 Fesod 吗? 答案是 两者都要,分工不同:
| 维度 | Apache Tika | Apache Fesod |
|---|
| 定位 | 全格式内容索引(1000+ 种格式一把梭) | Excel 精细化读写(只专注电子表格) |
| Excel 输出 | 纯文本拼接、不带公式结果 | 按行按列、批注、合并单元格、样式全保留 |
| 写 Excel | ❌ 不支持 | ✅ 链式 API + 模板填充 + 多 Sheet |
| 大文件批量导入导出 | ❌ 不适合(没有分批入库监听器) | ✅ 流式读 + 分批写 + 错误报告 |
| 适用场景 | 知识库、全文搜索、合规审计、RAG 文档解析 | 业务系统的”用户导入/报表导出” |
配合起来就是:
- 用户上传一份 Excel → Fesod 做精细化导入(校验字段、分批入库、错误报告);
- 同时丢给 Tika 做全文索引(用户在搜索框输入关键词,能搜到这份 Excel 里的内容)。
9.3 官方学习资源
掌握本篇内容,以后再碰到**”把这堆各种格式的文档都给我解析了建索引”** 这种需求,再也不用熬夜写 if-else 了 🚀。下一篇打算讲 “Tika + Milvus + Spring AI 搭一套可落地的企业 RAG 知识库”,解析、切块、向量化、检索、问答全链路打通,欢迎关注~