Java / Spring: как определить MimeType для InputStream, не потребляя его - PullRequest
1 голос
/ 22 сентября 2019

ОСНОВЫ

Это приложение Java 1.8 Spring Boot 1.5.

В настоящее время он использует Apache Tika 1.22 для чтения информации Mime-Type, но это можно легко изменить.

РЕЗЮМЕ

Существует картограф, которыйПользователь использует для загрузки файлов.Эти файлы приходят из другого URL отдельно от приложения.Файл может быть разных типов (excel, PDF, text и т. Д.), И приложение не может знать, каким оно будет, пока не извлечет файл.

ISSUE

Чтобы вернуть пользователю файл с соответствующим названием, расширением и ContentType, приложение использует Apache Tika для извлечения этой информации.К сожалению, теперь, когда заголовок InputStream используется, когда приложение записывает InputStream в HttpServletResponse, файл является неполным.

Это означает, что для того, чтобы функционировать в настоящее время, приложение закрывает первый InputStream, а затем открывает второй InputStream для возврата пользователю.

Это нехорошо, потому что это означаетчто URL вызывается дважды, что приводит к потере системных ресурсов.

Как правильно использовать эту функцию?

ПРИМЕР КОДА

    @GetMapping("/My/Download/")
    public void doDownload(HttpServletResponse httpServletResponse) {

            String externalFileURL = "http://www.pdf995.com/samples/pdf.pdf";

            try {       
                InputStream firstStream = new URL(externalFileURL).openStream();        
                TikaConfig tikaConfig = new TikaConfig();
                MediaType mediaType = tikaConfig.getDetector().detect(TikaInputStream.get(firstStream), new Metadata());
                firstStream.close();

                InputStream secondStream = new URL(externalFileURL).openStream();   
                httpServletResponse.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", "DownloadMe." + mediaType.getSubtype()));
                httpServletResponse.setContentType(mediaType.getBaseType().toString());
                FileCopyUtils.copy(secondStream, httpServletResponse.getOutputStream());
                httpServletResponse.flushBuffer();
            } catch (Exception e) {

            }
    }

1 Ответ

2 голосов
/ 22 сентября 2019

Javadoc из detect() говорит:

Данный поток гарантированно поддерживает mark feature, и ожидается, что детектор mark поток перед чтением любых байтов из него и reset поток перед возвратом.

Javadoc из TikaInputStream говорит:

Созданный экземпляр TikaInputStream отслеживает исходный ресурс, использованный для его создания, и ведет себя иначе, как обычный буферизованный InputStream.Экземпляр TikaInputStream также гарантированно поддерживает функцию mark(int).

Это означает, что вы должны использовать TikaInputStream для чтения содержимого и пробовать с ресурсами для закрытияэто:

try (InputStream tikaStream = TikaInputStream.get(new URL(externalFileURL))) {
    TikaConfig tikaConfig = new TikaConfig();
    MediaType mediaType = tikaConfig.getDetector().detect(tikaStream, new Metadata());

    httpServletResponse.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", "DownloadMe." + mediaType.getSubtype()));
    httpServletResponse.setContentType(mediaType.getBaseType().toString());
    FileCopyUtils.copy(tikaStream, httpServletResponse.getOutputStream());
    httpServletResponse.flushBuffer();
}
...