Перейти к основному содержимому

Spring и Apache FileUpload

· 3 мин. чтения

1. Обзор

Библиотека загрузки файлов Apache Commons помогает нам загружать большие файлы по протоколу HTTP, используя тип содержимого multipart/form-data .

В этом кратком руководстве мы рассмотрим, как интегрировать его с Spring.

2. Зависимости Maven

Чтобы использовать библиотеку, нам понадобится артефакт commons-fileupload :

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

Последнюю версию можно найти на Maven Central .

3. Передача всего сразу

В демонстрационных целях мы собираемся создать контроллер , обрабатывающий запросы с файловой полезной нагрузкой:

@PostMapping("/upload")
public String handleUpload(HttpServletRequest request) throws Exception {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);

DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(
new File(System.getProperty("java.io.tmpdir")));
factory.setSizeThreshold(
DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
factory.setFileCleaningTracker(null);

ServletFileUpload upload = new ServletFileUpload(factory);

List items = upload.parseRequest(request);

Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next();

if (!item.isFormField()) {
try (
InputStream uploadedStream = item.getInputStream();
OutputStream out = new FileOutputStream("file.mov");) {

IOUtils.copy(uploadedStream, out);
}
}
}
return "success!";
}

В начале нам нужно проверить, содержит ли запрос составной контент , используя метод isMultipartContent , найденный в классе ServletFileUpload из библиотеки.

По умолчанию в Spring есть MultipartResolver , который нам нужно отключить, чтобы использовать эту библиотеку. В противном случае он прочитает содержимое запроса до того, как оно достигнет нашего контроллера.

Мы можем добиться этого, включив эту конфигурацию в наш файл application.properties :

spring.http.multipart.enabled=false

Теперь мы можем установить каталог, в котором будут сохранены наши файлы, порог, при котором библиотека решает записать на диск, и следует ли удалять файлы после завершения запроса.

Библиотека предоставляет класс DiskFileItemFactory , который берет на себя ответственность за настройку сохранения и очистки файла . Метод setRepository задает целевой каталог, в примере показано значение по умолчанию.

Затем setSizeThreshold устанавливает максимальный размер файла.

Затем у нас есть метод setFileCleaningTracker , который при значении null оставляет временные файлы нетронутыми. По умолчанию он удаляет их после завершения запроса .

Теперь мы можем перейти к фактической обработке файлов.

Во- первых, мы создаем наш ServletFileUpload , включая нашу ранее созданную фабрику; затем мы приступаем к разбору запроса и генерации списка FileItem , которые являются основной абстракцией библиотеки для полей формы.

Теперь, если мы знаем, что это не обычное поле формы, мы приступаем к извлечению InputStream и вызываем полезный метод копирования из IOUtils (дополнительные параметры вы можете посмотреть в этом руководстве) .

Теперь наш файл хранится в нужной папке. Обычно это более удобный способ справиться с этой ситуацией, поскольку он обеспечивает легкий доступ к файлам, но эффективность использования времени/памяти не оптимальна.

В следующем разделе мы рассмотрим потоковый API.

4. Потоковое API

Потоковый API прост в использовании, что делает его отличным способом обработки больших файлов, просто не копируя их во временное место:

ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterStream = upload.getItemIterator(request);
while (iterStream.hasNext()) {
FileItemStream item = iterStream.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
// Process the InputStream
} else {
String formFieldValue = Streams.asString(stream);
}
}

В предыдущем фрагменте кода мы видим, что мы больше не включаем DiskFileItemFactory . Это потому, что при использовании потокового API он нам не нужен .

Далее для обработки полей библиотека предоставляет FileItemIterator , который ничего не читает, пока мы не извлечем их из запроса с помощью метода next .

Наконец, мы можем увидеть, как получить значения других полей формы.

5. Вывод

В этой статье мы рассмотрели, как мы можем использовать библиотеку загрузки файлов Apache Commons с Spring для загрузки и обработки больших файлов.

Как всегда, полный исходный код можно найти на GitHub .