刘光辉
4 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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;
        }
    }
}