package jnpf.dmsService.search.extract;
|
|
import jnpf.dmsService.search.DmsSearchProperties;
|
import lombok.RequiredArgsConstructor;
|
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.text.PDFTextStripper;
|
import org.apache.poi.hwpf.HWPFDocument;
|
import org.apache.poi.hwpf.extractor.WordExtractor;
|
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
|
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
import org.springframework.stereotype.Service;
|
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.util.Locale;
|
|
@Service
|
@RequiredArgsConstructor
|
public class DmsTextExtractionService {
|
private final DmsSearchProperties properties;
|
|
public DmsTextExtractionResult extract(Path file, String fileName) throws IOException {
|
if (Files.size(file) > properties.getMaxFileBytes()) {
|
throw new IOException("文件超过全文检索解析大小限制");
|
}
|
String extension = extension(fileName);
|
String text;
|
boolean ocrRequired = false;
|
switch (extension) {
|
case "doc":
|
text = readDoc(file);
|
break;
|
case "docx":
|
text = readDocx(file);
|
break;
|
case "pdf":
|
PdfText pdf = readPdf(file);
|
text = pdf.text;
|
ocrRequired = pdf.ocrRequired;
|
break;
|
default:
|
throw new IOException("全文检索仅支持 doc、docx、pdf 文件");
|
}
|
return new DmsTextExtractionResult(limit(normalize(text)), ocrRequired);
|
}
|
|
private String readDoc(Path file) throws IOException {
|
try (InputStream input = Files.newInputStream(file);
|
HWPFDocument document = new HWPFDocument(input);
|
WordExtractor extractor = new WordExtractor(document)) {
|
return extractor.getText();
|
}
|
}
|
|
private String readDocx(Path file) throws IOException {
|
try (InputStream input = Files.newInputStream(file);
|
XWPFDocument document = new XWPFDocument(input);
|
XWPFWordExtractor extractor = new XWPFWordExtractor(document)) {
|
return extractor.getText();
|
}
|
}
|
|
private PdfText readPdf(Path file) throws IOException {
|
StringBuilder text = new StringBuilder();
|
boolean ocrRequired = false;
|
try (PDDocument document = Loader.loadPDF(file.toFile())) {
|
PDFTextStripper stripper = new PDFTextStripper();
|
stripper.setSortByPosition(true);
|
for (int page = 1; page <= document.getNumberOfPages(); page++) {
|
stripper.setStartPage(page);
|
stripper.setEndPage(page);
|
String pageText = normalize(stripper.getText(document));
|
if (visibleCharacters(pageText) < properties.getMinPdfTextCharsPerPage()) {
|
ocrRequired = true;
|
}
|
if (text.length() > 0) {
|
text.append('\n');
|
}
|
text.append(pageText);
|
}
|
}
|
return new PdfText(text.toString(), ocrRequired);
|
}
|
|
private String extension(String fileName) {
|
int separator = fileName == null ? -1 : fileName.lastIndexOf('.');
|
return separator < 0 ? "" : fileName.substring(separator + 1).toLowerCase(Locale.ROOT);
|
}
|
|
private String normalize(String value) {
|
return value == null ? "" : value.replace("\u0000", "").trim();
|
}
|
|
private int visibleCharacters(String value) {
|
return value == null ? 0 : value.replaceAll("\\s+", "").length();
|
}
|
|
private String limit(String value) {
|
int max = Math.max(0, properties.getMaxTextChars());
|
return value.length() <= max ? value : value.substring(0, max);
|
}
|
|
private static final class PdfText {
|
private final String text;
|
private final boolean ocrRequired;
|
|
private PdfText(String text, boolean ocrRequired) {
|
this.text = text;
|
this.ocrRequired = ocrRequired;
|
}
|
}
|
}
|