SpringBoot3使用Apache Tika實現(xiàn)多格式文件內(nèi)容提取
做后端開發(fā)久了,難免碰到這類剛需:用戶上傳Word、PDF、Excel、Txt各種文檔,后臺得自動扒出文本做內(nèi)容審核、全文檢索或者數(shù)據(jù)庫歸檔。要是挨個用POI、PDFBox適配格式,代碼寫得又碎又亂,后期維護、擴展全是坑。
本文使用 Apache Tika 搞定全格式解析,不用管底層解析差異,支持文件類型識別、元數(shù)據(jù)提取、格式校驗這幾個開發(fā)必用的高頻場景,完全貼合真實業(yè)務(wù)。
一、前期準(zhǔn)備:項目環(huán)境與核心依賴
先說明環(huán)境版本:
- JDK版本:17+
- SpringBoot版本:3.2.5
- Tika:3.2.3
在pom.xml文件引入相關(guān)依賴:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- Maven模型版本,固定4.0.0適配SpringBoot3 -->
<modelVersion>4.0.0</modelVersion>
<!-- SpringBoot3父依賴,統(tǒng)一版本管理,避免依賴沖突 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<!-- 項目基礎(chǔ)信息,可根據(jù)實際業(yè)務(wù)修改 -->
<groupId>com.example</groupId>
<artifactId>springboot3-tika-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot3-tika-demo</name>
<description>SpringBoot3集成Apache Tika文件解析實戰(zhàn)</description>
<!-- 全局版本屬性,統(tǒng)一管理依賴版本,方便后續(xù)升級 -->
<properties>
<java.version>17</java.version>
<tika.version>3.2.3</tika.version>
</properties>
<dependencies>
<!-- SpringBoot Web核心依賴,提供HTTP接口、MVC等能力 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Tika核心依賴,提供基礎(chǔ)文件解析API -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>${tika.version}</version>
</dependency>
<!-- Tika標(biāo)準(zhǔn)解析器池,覆蓋Office/PDF/TXT/Excel等主流辦公格式 -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-pooled</artifactId>
<version>${tika.version}</version>
<type>pom</type>
</dependency>
<!-- Apache通用工具包,簡化字符串、集合、IO操作 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.20.0</version>
</dependency>
<!-- Lombok注解工具,省略Getter/Setter/構(gòu)造器,簡化代碼 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- FastJSON2,高性能JSON序列化/反序列化,適配接口返回 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.32</version>
</dependency>
<!-- 單元測試依賴,本地調(diào)試、接口測試使用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- SpringBoot打包插件,打包可執(zhí)行JAR -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<!-- 打包時排除lombok,減小jar包體積 -->
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>二、實戰(zhàn)集成:三步寫完核心代碼
1. 單例配置:避免重復(fù)創(chuàng)建實例
AutoDetectParser自動解析器是線程安全的,沒必要每次解析都新建實例,交給Spring托管單例最劃算,既能節(jié)省內(nèi)存開銷,后續(xù)自定義解析規(guī)則、擴展配置也更方便。
import org.apache.tika.parser.AutoDetectParser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Tika解析器配置類
* 作用:將AutoDetectParser交給Spring管理單例,避免重復(fù)創(chuàng)建消耗資源
*/
@Configuration
public class FileDetectParserConfig {
/**
* 注冊自動解析器Bean
* AutoDetectParser:自動識別文件格式,無需手動指定解析器
* 線程安全,全局單例使用即可
*/
@Bean
public AutoDetectParser detectParser() {
// 默認(rèn)配置適配絕大多數(shù)場景,可自定義編碼、超時、解析規(guī)則
return new AutoDetectParser();
}
}2. 文件解析結(jié)果對象實體類封裝
新建文件信息實體類,統(tǒng)一封裝解析文本和元數(shù)據(jù),方便接口返回和業(yè)務(wù)層調(diào)用。
import lombok.Builder;
import lombok.Data;
import java.util.Map;
/**
* 文件解析結(jié)果實體
* 統(tǒng)一封裝:提取的文本內(nèi)容 + 文件元數(shù)據(jù),標(biāo)準(zhǔn)化返回格式
*/
@Data
@Builder
public class FileInfo {
/**
* 從文件中提取的純文本內(nèi)容
*/
private String fileText;
/**
* 文件元數(shù)據(jù)集合
* Key:元數(shù)據(jù)字段名(如Content-Type、Author、Creation-Date)
* Value:對應(yīng)字段值
*/
private Map<String,Object> metadata;
}3. 核心服務(wù)類:覆蓋高頻解析場景
封裝通用文件解析方法,內(nèi)置10MB緩沖區(qū)閾值,兼顧大文件解析和內(nèi)存控制。
import com.example.springboot3tikademo.entity.FileInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;
import org.springframework.stereotype.Service;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* 文件解析核心業(yè)務(wù)類
* 封裝統(tǒng)一解析邏輯,處理普通/大文件、元數(shù)據(jù)轉(zhuǎn)換、異常捕獲
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class FileDetectService {
/**
* 注入自動解析器單例
*/
private final AutoDetectParser detectParser;
/**
* 統(tǒng)一文件解析入口
* @param inputStream 文件輸入流(前端上傳/本地文件均可)
* @return FileInfo 封裝后的解析結(jié)果
*/
public FileInfo parseFile(InputStream inputStream) {
// 入?yún)⒎强招r灒乐箍罩羔?
if (inputStream == null) {
throw new IllegalArgumentException("文件輸入流不能為空,請檢查文件上傳狀態(tài)");
}
try {
// 設(shè)置10MB緩沖區(qū),平衡解析速度與內(nèi)存占用,防止OOM
ContentHandler handler = new BodyContentHandler(10 * 1024 * 1024);
// 元數(shù)據(jù)對象:存儲文件類型、作者、創(chuàng)建時間等屬性
Metadata metadata = new Metadata();
// 解析上下文:用于擴展自定義解析規(guī)則、傳參
ParseContext context = new ParseContext();
// 執(zhí)行文件解析核心邏輯
detectParser.parse(inputStream, handler, metadata, context);
// Metadata對象無法直接序列化,轉(zhuǎn)為HashMap適配接口返回
Map<String,Object> metadataMap = new HashMap<>();
for (String name : metadata.names()){
metadataMap.put(name, metadata.get(name));
}
// 構(gòu)建結(jié)果對象返回
return FileInfo.builder()
.fileText(handler.toString())
.metadata(metadataMap)
.build();
} catch (SAXException | TikaException | IOException e) {
// 打印詳細(xì)異常日志,方便線上排查問題
log.error("文件解析失敗,異常堆棧:", e);
return null;
}
}
}4. 接口開發(fā):場景化測試調(diào)用
編寫文件上傳解析接口,接收前端上傳文件,調(diào)用核心服務(wù)完成解析,返回結(jié)構(gòu)化JSON數(shù)據(jù),方便自測和前端對接;后續(xù)可在此基礎(chǔ)上擴展單獨的文件類型校驗接口。
import com.alibaba.fastjson2.JSONObject;
import com.example.springboot3tikademo.entity.FileInfo;
import com.example.springboot3tikademo.service.FileDetectService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
/**
* 文件解析接口控制器
* 對外提供HTTP接口,對接前端文件上傳與解析請求
*/
@Slf4j
@RestController
@RequestMapping("/api/file")
@RequiredArgsConstructor
public class FileController {
/**
* 注入文件解析服務(wù)
*/
private final FileDetectService fileDetectService;
/**
* 文件上傳 + 全量解析接口
* @param file 前端上傳的文件對象
* @return JSONObject 標(biāo)準(zhǔn)化響應(yīng)結(jié)果(狀態(tài)碼+提示+數(shù)據(jù))
*/
@PostMapping("/parse")
public JSONObject parseFile(@RequestParam("file") MultipartFile file) {
// 第一步:校驗文件是否為空
if (file.isEmpty()) {
return JSONObject.of("code", 500, "msg", "上傳文件不能為空,請選擇文件后重試");
}
// try-with-resources:自動關(guān)閉輸入流,避免資源泄漏
try (InputStream inputStream = file.getInputStream()) {
// 調(diào)用服務(wù)層執(zhí)行解析
FileInfo fileInfo = fileDetectService.parseFile(inputStream);
// 解析失敗返回友好提示
if (fileInfo == null) {
return JSONObject.of("code", 500, "msg", "文件解析失敗,請檢查文件格式是否支持或文件是否損壞");
}
// 封裝成功響應(yīng):拼接狀態(tài)碼、提示、文件名、解析數(shù)據(jù)
JSONObject result = JSONObject.from(fileInfo);
result.put("code", 200);
result.put("msg", "文件解析成功");
result.put("fileName", file.getOriginalFilename());
return result;
} catch (Exception e) {
// 打印異常日志,定位上傳/解析流程問題
log.error("文件上傳解析異常,文件名:{}", file.getOriginalFilename(), e);
return JSONObject.of("code", 500, "msg", "解析異常:" + e.getMessage());
}
}
}三、接口測試:驗證解析效果
項目啟動后,用Postman或者接口測試工具調(diào)用:
- 請求地址:POST localhost:8080/api/file/parse
- 請求方式:form-data,key設(shè)為file,選擇本地文檔(.doc/.docx/.pdf/.txt/.xlsx)
- 返回結(jié)果:結(jié)構(gòu)化JSON,包含文件名、響應(yīng)狀態(tài)、提取文本、元數(shù)據(jù)(作者、文件類型、創(chuàng)建時間等)
實測主流辦公格式都能正常解析,元數(shù)據(jù)完整不丟失,文本提取精準(zhǔn),不會出現(xiàn)亂碼、內(nèi)容截斷問題。

四、常見問題與調(diào)優(yōu)
1. 大文件解析報錯:Write limit exceeded
當(dāng)前代碼已設(shè)置10MB緩沖區(qū),若需解析更大文件,直接調(diào)整BodyContentHandler數(shù)值即可;比如設(shè)置100MB閾值:new BodyContentHandler(100 * 1024 * 1024),不建議設(shè)為-1無限制,避免服務(wù)器OOM。
2. PDF中文亂碼
解析PDF出現(xiàn)中文亂碼,優(yōu)先排查兩點:一是服務(wù)器安裝對應(yīng)中文字體包,二是在解析前手動指定UTF-8編碼,在Metadata中添加配置:
// 解析前手動指定UTF-8編碼,解決PDF中文亂碼、字符集不兼容問題 metadata.set(Metadata.CONTENT_ENCODING, "UTF-8");
3. 文件類型安全校驗
嚴(yán)禁只靠文件名后綴判斷文件類型,惡意文件篡改后綴極易繞過校驗。可從元數(shù)據(jù)中提取真實MIME類型,做白名單校驗,攔截非法文件上傳:
// 1. 從元數(shù)據(jù)獲取文件真實MIME類型,不依賴文件名后綴
String mimeType = (String) metadataMap.get("Content-Type");
// 2. 定義允許上傳的文件白名單,可根據(jù)業(yè)務(wù)擴展(如Excel、PPT)
List<String> allowTypes = Arrays.asList(
"application/pdf", // PDF格式
"application/msword", // Doc舊版Word
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", // Docx新版Word
"text/plain" // TXT純文本
);
// 3. 白名單校驗,攔截非法文件,防止惡意上傳
if (!allowTypes.contains(mimeType)) {
throw new RuntimeException("不支持該文件類型,請上傳PDF/Word/TXT格式文檔");
}4. 生產(chǎn)性能優(yōu)化
- 超大文件(100MB+)建議采用異步解析,避免接口超時阻塞主線程
- 對重復(fù)上傳文件做MD5緩存,復(fù)用解析結(jié)果,減少重復(fù)計算
- 配置SpringBoot文件上傳大小限制,防止惡意大文件攻擊
- 文件流務(wù)必使用try-with-resources自動關(guān)閉,避免資源泄漏
五、總結(jié)
這套SpringBoot3集成方案,配置簡單,代碼量小、侵入性極低,通過單例注入、標(biāo)準(zhǔn)化封裝、統(tǒng)一解析,實現(xiàn)了多格式文件文本提取+元數(shù)據(jù)獲取一站式搞定,完美適配內(nèi)容審核、文檔管理、數(shù)據(jù)錄入、全文檢索等業(yè)務(wù)場景。
除了基礎(chǔ)的文檔解析,Apache Tika還支持音視頻文件元數(shù)據(jù)提取、圖片文本OCR識別、壓縮包內(nèi)容遍歷、加密文檔解密等擴展能力,后續(xù)想疊加這些高階功能,原有代碼結(jié)構(gòu)無需改動,直接擴展方法即可,兼容性和擴展性拉滿。
以上就是SpringBoot3使用Apache Tika實現(xiàn)多格式文件內(nèi)容提取的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot3多格式文件內(nèi)容提取的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot整合Redis實現(xiàn)高并發(fā)數(shù)據(jù)緩存的示例講解
這篇文章主要介紹了SpringBoot整合Redis實現(xiàn)高并發(fā)數(shù)據(jù)緩存,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
Spring Boot集成ShedLock分布式定時任務(wù)的實現(xiàn)示例
ShedLock確保您計劃的任務(wù)最多同時執(zhí)行一次。如果一個任務(wù)正在一個節(jié)點上執(zhí)行,則它會獲得一個鎖,該鎖將阻止從另一個節(jié)點(或線程)執(zhí)行同一任務(wù)。2021-05-05
Mybatis Mapper XML文件-插入,更新,刪除詳解(insert, updat
這篇文章主要介紹了MyBatis的Mapper XML文件中用于插入、更新和刪除數(shù)據(jù)的語句,包括這些語句的屬性和子元素的使用方法2025-02-02
Eclipse Debug模式的開啟與關(guān)閉問題簡析
這篇文章主要介紹了Eclipse Debug模式的開啟與關(guān)閉問題簡析,同時向大家介紹了一個簡單的debug模式啟動不起來的解決方法,希望對大家有所幫助。2017-10-10
詳解SpringBoot中5種類型參數(shù)傳遞和json數(shù)據(jù)傳參的操作
當(dāng)涉及到參數(shù)傳遞時,Spring?Boot遵循HTTP協(xié)議,并支持多種參數(shù)傳遞方式,這些參數(shù)傳遞方式可以根據(jù)請求的不同部分進行分類,2023-12-12
SpringBoot使用MyBatis-Flex實現(xiàn)靈活的數(shù)據(jù)庫訪問
MyBatisFlex是一款優(yōu)秀的持久層框架,本文主要介紹了SpringBoot使用MyBatis-Flex實現(xiàn)靈活的數(shù)據(jù)庫訪問,具有一定的參考價值,感興趣的可以了解一下2024-06-06

