Czy wiesz, jak działa mechanizm uploadu plików w Springu?
Upload plików w Springu to temat, który na pierwszy rzut oka wygląda prosto, ale kilka ustawień potrafi mocno wpłynąć na działanie aplikacji.
W tym wpisie przejdziemy przez najważniejsze parametry spring.servlet.multipart i pokażemy,
jak bezpiecznie oraz praktycznie obsłużyć plik po stronie serwera.
Konfiguracja obsługi plików
Spring umożliwia skonfigurowanie następujących parametrów (prefix spring.servlet.multipart):
enabled- czy obsługa żądań typumultipart/form-datama zostać obsłużona przez Springa (domyślnie true),max-file-size- określa maksymalny rozmiar pliku, który zostanie obsłużony przez serwer (domyślnie 1 MB),max-request-size- określa maksymalny rodzaj żądania typumultipart/form-data(domyślnie 10 MB),file-size-threshold- określa rozmiar, po którym pliki zostaną zapisane na dysku (domyślnie 0),location- określa tymczasową lokalizację plików obsługiwanych przez serwer (domyślnie katalog tymczasowy systemu),resolve-lazily- odpowiada za sposób przetwarzania żądań multipart. Działanie w zależności od wartości:false- Spring od razu analizuje (resolve) i przetwarza dane multipart przy odbieraniu żądania (domyślna wartość),true- Przetwarzanie multipart jest opóźnione (lazy), czyli wykonywane dopiero w momencie, gdy aplikacja rzeczywiście potrzebuje dostępu do plików (np. wywołaniarequest.getPart()lubrequest.getParameter()),
strict-servlet-compilance- w Spring Boot określa, czy Spring ma przestrzegać ścisłej zgodności ze specyfikacją Servlet API podczas obsługi żądań multipart. W zależności od wartości:true- przetwarza tylko żądania typumultipart/form-data, pozostałe muszą zostać przetworzone ręcznie,false- próbuje przetworzyć każde żądanie typumultipart/*(domyślna wartość).
Jak wysłać plik na serwer?
Po stronie serwera należy przygotować kontroler, który ma zdefiniowany parametr żądania jako obiekt MultipartFile.
package com.example.uploadfiles;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Slf4j
@Controller
public class FileUploadController {
@PostMapping("/")
public void handleFileUpload(@RequestParam("file") MultipartFile file) {
LOGGER.info("Geting new file. [fileName={}]", file.getOriginalFileName());
}
}
Tak przygotowany kontroler oczekuje pod parametrem file pliku, na którym będzie mógł wykonać operację.
Co dzieje się z plikiem po stronie serwera?
Plik zostaje zapisany na serwerze w katalogu tymczasowym na czas przetwarzania żądania - po jego zakończeniu zostaje automatycznie usunięty.
Jak zatrzymać plik dłużej niż na czas obsługi żądania?
Możemy zrealizować to na dwa sposoby:
-
Ustawiając parametr
file-size-thresholdna większą wartość niż domyślnaNa przykład ustawienie wartości
file-size-thresholdna 5 MB spowoduje zapisanie się wszystkich plików poniżej 5 MB w pamięci aplikacji. Pliki te zostaną usunięte w momencie, w którym aplikacja nie będzie wykorzystywała referencji na nie.Jest to prostszy sposób, jednak trzeba liczyć się z tym, żeby monitorować pamięć aplikacji, gdyż jej zużycie może wzrosnąć.
-
Zapisując plik w momencie obsługi żądania na nośniku w bazie danych lub w systemie
Poniżej zaprezentuję przykład Controllera, który w momencie otrzymania pliku zapisuje go w katalogu tymczasowym systemu operacyjnego.
package com.example.uploadfiles; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; @Slf4j @Controller public class FileUploadWithSaveController { @PostMapping("/") public void handleFileUpload(@RequestParam("file") MultipartFile file) { File systemFile = new File(Paths.get(System.getProperty("java.io.tmpdir"), file.getOriginalFilename()).toString()); file.transferTo(systemFile); } }Tak przygotowany kontroler zapisze otrzymany plik w katalogu oznaczonym w zmiennej systemowej
java.io.tmpdir.Co ważne, od momentu wywołania metody
transferTo()należy posługiwać się plikiem zapisanym w systemie, ponieważ obiektMultipartFileod tego momentu nie posiada już strumienia danych zapisanych w pliku.
W takim rozwiązaniu plik będzie się znajdował w katalogu tymczasowym do momentu jawnego usunięcia go przez aplikacje. Należy więc pamiętać o przygotowaniu mechanizmu, który zarządzałby czyszczeniem katalogu z nieużywanych plików.
Żródła
-
SENIOR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 14 900 - 20 590 PLN brutto
B2B 19 680 - 27 220 PLN netto -
REGULAR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 11 300 - 15 900 PLN brutto
B2B 14 950 - 21 000 PLN netto -
ZOBACZ WSZYSTKIE OGŁOSZENIA
-
SENIOR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 14 900 - 20 590 PLN brutto
B2B 19 680 - 27 220 PLN netto -
REGULAR FULLSTACK DEVELOPER (JAVA + ANGULAR) Poznań (hybrydowo) lub zdalnie UoP 11 300 - 15 900 PLN brutto
B2B 14 950 - 21 000 PLN netto -
ZOBACZ WSZYSTKIE OGŁOSZENIA