Tika

官网:https://tika.apache.org/3.3.1/examples.html

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>3.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-package</artifactId>
<version>3.2.3</version>
<scope>compile</scope>
</dependency>

tika-core 提供 API 层,tika-parsers-standard-package 包含所有主流格式的解析器实现。

示例

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
67
68
69
70
71
72
73
/**
* 解析上传的文件,提取文本内容
*
* @param file 上传的文件(支持PDF、DOCX、DOC、TXT、MD等)
* @return 提取的文本内容
*/
public String parseContent(MultipartFile file) {
String fileName = file.getOriginalFilename();
log.info("开始解析文件: {}", fileName);

// 处理空文件
if (file.isEmpty() || file.getSize() == 0) {
log.warn("文件为空: {}", fileName);
return "";
}

try (InputStream inputStream = file.getInputStream()) {
String content = parseContent(inputStream);
String cleanedContent = textCleaningService.cleanText(content);// 通过正则清洗和规范化文本
log.info("文件解析成功,提取文本长度: {} 字符", cleanedContent.length());
return cleanedContent;
} catch (IOException | TikaException | SAXException e) {
log.error("文件解析失败: {}", e.getMessage(), e);
throw new BusinessException(ErrorCode.INTERNAL_ERROR, "文件解析失败: " + e.getMessage());
}
}
/**
* 核心解析方法:使用显式 Parser + Context 方式解析文档
* <p>
* 优化点:
* 1. 使用 BodyContentHandler 只提取正文内容
* 2. 禁用 EmbeddedDocumentExtractor,不解析嵌入资源(图片、附件)
* 3. 配置 PDFParserConfig,关闭图片和注释提取
* 4. 显式指定 Parser 到 Context,增强健壮性
*
* @param inputStream 文件输入流
* @return 提取的文本内容
* @throws IOException IO 异常
* @throws TikaException Tika 解析异常
* @throws SAXException SAX 解析异常
*/
private String parseContent(InputStream inputStream) throws IOException, TikaException, SAXException {
// 1. 创建自动检测解析器
AutoDetectParser parser = new AutoDetectParser();

// 2. 创建内容处理器,只接收正文,限制最大长度为 5MB
BodyContentHandler handler = new BodyContentHandler(MAX_TEXT_LENGTH);

// 3. 创建元数据对象
Metadata metadata = new Metadata();

// 4. 创建解析上下文
ParseContext context = new ParseContext();

// 5. 显式指定 Parser 到 Context(增强健壮性)
context.set(Parser.class, parser);

// 6. 禁用嵌入文档解析(关键:避免提取图片引用和临时文件路径)
context.set(EmbeddedDocumentExtractor.class, new NoOpEmbeddedDocumentExtractor());

// 7. PDF 专用配置:关闭图片提取,按位置排序文本
PDFParserConfig pdfConfig = new PDFParserConfig();
pdfConfig.setExtractInlineImages(false);
pdfConfig.setSortByPosition(true); // 按 x/y 坐标排序文本,改善多栏布局解析顺序
// 注意:Tika 2.9.2 中 setExtractAnnotations 方法可能不存在,关闭图片提取已足够
context.set(PDFParserConfig.class, pdfConfig);

// 8. 执行解析
parser.parse(inputStream, handler, metadata, context);

// 9. 返回提取的文本内容
return handler.toString();
}

一般文本提取之后,都需要进行二次清洗,比如通过正则表达式。