• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Java Spring - wyświetlenie plików po uploadzie w działającej aplikacji

Object Storage Arubacloud
0 głosów
710 wizyt
pytanie zadane 8 lutego 2019 w Java przez niezalogowany
edycja 8 lutego 2019
Hej.

Mamy pewną aplikację, która umożliwia dodanie zdjęcia. Dodajemy zdjęcie i... nie wyświetla się, bo aplikacja ładuje zasoby przy starcie, a potem już nie ;] Jak sprawić, żeby dodane zasoby się zaktualizowały w działającej aplikacji? I czy w ogóle jest to potrzebne w "domowym" projekcie, czy zostawić jak jest? :)

Wykorzystuję spring boot, gradle + thymeleaf
komentarz 9 lutego 2019 przez mbabane Szeryf (79,280 p.)
A gdzie zapisujesz te pliki?
komentarz 9 lutego 2019 przez niezalogowany
Lokalnie na dysku - bo to ma być póki co prowizorka, żeby tylko działało. Domyślam się, że w prawdziwej aplikacji zdjęcia są zapisywane gdzieś w chmurze, na serwerze...
komentarz 9 lutego 2019 przez mbabane Szeryf (79,280 p.)
Serwer to tez ostatecznie dysk. Gdzie dokładnie i jak to potem odczytujesz?
komentarz 9 lutego 2019 przez niezalogowany

Zapisuję to tak:

 

private String rootLocation= "C:\\Users\\Tomek\\Documents\\Projekty\\IntelliJ\\shelter\\src\\main\\resources\\static\\images";
public void store(MultipartFile file, AnimalEntity animalEntity) {
    String filename = animalEntity.getNameString() + animalEntity.getAge() + ".jpg";
    try {
        try (InputStream inputStream = file.getInputStream()) {
            Files.copy(inputStream, this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
        }
    } catch (IOException e) {
        throw new StorageException("Failed to store file " + filename, e);
    }
}

A ładuję tak:

 

<img th:src="@{'/images/' + ${dog.getNameString()} + ${dog.getAge()} + '.jpg'}"/>

 

2 odpowiedzi

0 głosów
odpowiedź 8 lutego 2019 przez Paweł Nąckiewicz Nałogowiec (48,990 p.)
Coś więcej o tej aplikacji... (Spring/Spring Boot, Mavaen/Gradle)

Jakis fragment kodu cokolwiek... ?
komentarz 8 lutego 2019 przez niezalogowany
Ok, edytowałem pytanie. Założyłem, że rozwiązanie jest javowe bez znaczenia na framework ;)
0 głosów
odpowiedź 9 lutego 2019 przez mbabane Szeryf (79,280 p.)
Zapis robisz na podstawie ścieżki absolutnej, a odczyt na podstawie względnej. Kod odpowiadający za ładowanie obrazka szuka tego obrazka w lokalizacji pewnie tomcata /webapps/nazwa_aplikacji/... . Spróbuj zapisywać pliki również za pomocą ścieżki względnej.

Zerknij na to:

https://stackoverflow.com/questions/10847994/spring-mvc-save-uploaded-multipartfile-to-specific-folder
komentarz 9 lutego 2019 przez niezalogowany

OK, edytowałem nieco metodę, która wygląda teraz tak: 

 

public void store(MultipartFile file, AnimalEntity animalEntity, String path) {
        String filename = animalEntity.getNameString() + animalEntity.getAge() + ".jpg";

        try {
            file.transferTo(new File(path + "resources\\static\\images\\" + filename));
        } catch (IOException e) {
            throw new RuntimeException("Niepowodzenie ", e);
        }
    }

I kontroler wyglądający tak:

 

@PostMapping("/processNewAnimal")
	public String processNewAnimalForm(@Valid @ModelAttribute("newAnimal") AnimalEntity newAnimal, BindingResult result, @RequestParam("file") MultipartFile file,
									   RedirectAttributes redirectAttributes, HttpServletRequest request) {
		String rootDirectory = request.getSession().getServletContext().getRealPath("/");
		if (result.hasErrors()) {
			System.out.println(result.getAllErrors());
			return "addAnimal";
		}
		taskExecutor.execute(() -> sendingEmailToWorkersService.checkIfEmailCanBeSent(howManyPlaceLeft.existsFreePlaces(), numberOfFreePlacesToSendEmails));
		addAnimalsService.addAnimalToDb(newAnimal);
		storageService.store(file, newAnimal, rootDirectory);
		redirectAttributes.addFlashAttribute("flash.message", "Animal has been added!");
		return "redirect:/addAnimal";
	}
}

Jednak po wysłaniu formularza metodą post, konsola zgłasza błąd:

"java.io.FileNotFoundException: C:\Users\Tomek\AppData\Local\Temp\tomcat-docbase.12533877630182209167.8080\resources\static\images\NowyPiesek12.jpg (System nie może odnaleźć określonej ścieżki)"

Zatem wracam do czytania API i znajduję tam opis działania konstruktora klasy File:

File​(String pathname)

Creates a new File instance by converting the given pathname string into an abstract pathname.

Dla mnie znaczy to, że tworzy nowy plik, przekształcając wskazany string w abstrakcyjną ścieżkę dostępu do pliku, więc powinno działać? 

komentarz 9 lutego 2019 przez mbabane Szeryf (79,280 p.)

Creates a new File instance

Tworzenie nowej instancji klasy File. 

Sam zapis pliku możesz robić tak jak wcześniej tylko ścieżkę dobrą ustaw, żeby potem aplikacja była wstanie go odczytać.

komentarz 9 lutego 2019 przez niezalogowany
Przyznam, że się pogubiłem ;] Wcześniej aplikacja znajdowała pliki i wszystko działało, ale po wciśnięciu shift + f10, a chciałem, żeby zmiany były widoczne live bez konieczności restartowania serwera.
komentarz 9 lutego 2019 przez mbabane Szeryf (79,280 p.)

Spróbuj na początek zrobić tak jak miałeś wyjściowo tylko zmień ścieżkę:

private String rootLocation=

tak, żeby była budowana tak jak na stacku. Nic więcej. 

komentarz 10 lutego 2019 przez niezalogowany

Niby działa, a jednak nie działa. Po zmianie metody na:

 

@Override
    public void store(MultipartFile file, AnimalEntity animalEntity) {
        String filename = animalEntity.getNameString() + animalEntity.getAge() + ".jpg";
        String uploadsDir = "/images/";
        String realPathToUploads = request.getServletContext().getRealPath(uploadsDir);
        if (!new File(realPathToUploads).exists()) {
            new File(realPathToUploads).mkdir();
        }
        Path root = Paths.get(realPathToUploads);
        try {
            if (filename.contains("..")) {
                throw new StorageException("Cannot store file with relative path outside current directory " + filename);
            }
            try (InputStream inputStream = file.getInputStream()) {
                Files.copy(inputStream, root.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
            }
        } catch (IOException e) {
            throw new StorageException("Failed to store file " + filename, e);
        }
    }

Oczywiście plik znika po restarcie serwera :D Więc teraz plik pojawia się na żywo po dodaniu, ale znika po restarcie aplikacji :D

komentarz 10 lutego 2019 przez mbabane Szeryf (79,280 p.)
Spring pewnie wszystko czyści przed restartem aplikacji. Musiał byś zapisywać te obrazki gdzieś poza kontekst tomcata-embeded.
komentarz 10 lutego 2019 przez niezalogowany

Tak. Pierwszym moim odruchem było ctrl+d i skopiowanie linijki: 
 

Files.copy(inputStream, this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING);

tym razem z zapisem fizycznym na dysku. Plik się pojawia w strukturze projektu, ale nie można go otworzyć :D

Masz może pojęcie, jak to wygląda w realnej aplikacji? Gdzie najczęściej zapisywane są zdjęcia (bo pewnie nie w bazie danych)?

komentarz 10 lutego 2019 przez mbabane Szeryf (79,280 p.)
Jeśli chodzi o bazę danych to jest możliwy zapis. Istnieje taki typ jak BLOB. Nie wiem jak jest z tym w praktyce.

A jeśli chodzi o nie bazę danych to po prostu gdzieś na dysku można zrobić dowolny folder. Prawdopodobnie i tak nie będzie to hostwane na windowsie tylko na linuxie. Najważniejszym jest aby taki folder miał ustawione odpowiednie prawa dostępu.

Podobne pytania

0 głosów
0 odpowiedzi 313 wizyt
0 głosów
3 odpowiedzi 420 wizyt
pytanie zadane 8 kwietnia 2020 w Java przez JuniorPL Użytkownik (770 p.)
+1 głos
1 odpowiedź 628 wizyt

92,555 zapytań

141,404 odpowiedzi

319,559 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...