Mam wymaganie, aby pobrać plik PDF ze strony internetowej. PDF musi zostać wygenerowany w kodzie, który, jak sądzę, będzie kombinacją freemarkera i frameworka generowania PDF, takiego jak iText. Czy jest lepszy sposób?
Jednak moim głównym problemem jest to, jak mogę pozwolić użytkownikowi na pobranie pliku za pomocą kontrolera Spring?
Odpowiedzi:
Mówiąc ogólnie, kiedy masz
response.getOutputStream()
, możesz tam napisać wszystko. Możesz przekazać ten strumień wyjściowy jako miejsce do umieszczenia wygenerowanego pliku PDF w generatorze. Ponadto, jeśli wiesz, jaki typ pliku wysyłasz, możesz ustawićźródło
IOUtils
zamiast SpringFileCopyUtils
?Byłem w stanie przesłać strumieniowo ten wiersz, używając wbudowanej obsługi wiosną z ResourceHttpMessageConverter. Spowoduje to ustawienie długości i typu zawartości, jeśli będzie w stanie określić typ MIME
źródło
Content-Disposition
nagłówka w ten sposób?Powinieneś być w stanie zapisać plik bezpośrednio w odpowiedzi. Coś jak
a następnie zapisz plik jako strumień binarny
response.getOutputStream()
. Pamiętaj, aby zrobićresponse.flush()
na końcu i to powinno wystarczyć.źródło
@RequestMapping(value = "/foo/bar", produces = "application/pdf")
W Spring 3.0 możesz użyć
HttpEntity
obiektu zwracanego. Jeśli tego użyjesz, twój kontroler nie potrzebujeHttpServletResponse
obiektu, dlatego łatwiej go przetestować. Poza tym, ta odpowiedź jest względna równa tej z Infeligo .Jeśli zwracaną wartością twojego frameworka pdf jest tablica bajtów (przeczytaj drugą część mojej odpowiedzi dla innych zwracanych wartości) :
Jeśli typ zwracany przez Framework PDF (
documentBbody
) nie jest już tablicą bajtów (a także nieByteArrayInputStream
), rozsądnie byłoby NIE uczynić go najpierw tablicą bajtów. Zamiast tego lepiej jest użyć:InputStreamResource
,PathResource
(od wiosny 4.0) lubFileSystemResource
,przykład z
FileSystemResource
:źródło
return new ResponseEntity<byte[]>(documentBody, headers, HttpStatus.CREATED)
ResponseEntity
jest podklasąHttpEntity
(ale rozumiem), z drugiej strony 201 CREATED nie jest tym, czego używałbym, gdy zwracam tylko widok danych. (patrz w3.org/Protocols/rfc2616/rfc2616-sec10.html dla 201 TWORZONY )Jeśli ty:
byte[]
przed wysłaniem do odpowiedzi;InputStream
;@ControllerAdvice
dla ciebie inne wyjątki związane z odbiorem (lub nie).Poniższy kod jest tym, czego potrzebujesz:
O części dotyczącej długości pliku :
File#length()
powinno być wystarczająco dobre w ogólnym przypadku, ale pomyślałem, że dokonam tej obserwacji, ponieważ może być powolna , w którym to przypadku powinieneś ją wcześniej zapisać (np. W DB). Przypadki mogą być powolne obejmują: jeśli plik jest duży, szczególnie jeśli plik jest w systemie zdalnym lub coś bardziej skomplikowanego - może to być baza danych.InputStreamResource
Jeśli Twój zasób nie jest plikiem, np. Pobierasz dane z bazy danych, powinieneś użyć
InputStreamResource
. Przykład:źródło
FileSystemResource
. Wskazane jest nawet, jeśli Twój zasób jest plikiem . W tej próbceFileSystemResource
można użyć gdzieInputStreamResource
jest.File#length()
powinno być wystarczająco dobre w ogólnym przypadku. Właśnie wspomniałem o tym, ponieważ może być powolny , szczególnie jeśli plik znajduje się w systemie zdalnym lub coś bardziej skomplikowanego - może baza danych? Ale martw się tylko, jeśli stanie się to problemem (lub jeśli masz twarde dowody, że stanie się jednym), a nie wcześniej. Chodzi o to, że: starasz się przesyłać strumieniowo plik, jeśli musisz wcześniej go wstępnie załadować, to strumieniowanie kończy się bez różnicy, prawda?Ten kod działa dobrze, aby automatycznie pobrać plik ze sterownika wiosennego po kliknięciu łącza w jsp.
źródło
Poniższy kod działał dla mnie w celu wygenerowania i pobrania pliku tekstowego.
źródło
To, co mogę szybko wymyślić, to wygenerować pdf i zapisać go w aplikacji internetowej / download / <RANDOM-FILENAME> .pdf z kodu i wysłać dalej do tego pliku za pomocą HttpServletRequest
lub jeśli możesz skonfigurować swój przelicznik widoków w taki sposób,
to po prostu wróć
źródło
Poniższe rozwiązanie działa dla mnie
źródło
coś jak poniżej
Możesz wyświetlić plik PDF lub pobrać przykłady tutaj
źródło
Jeśli to pomoże komukolwiek. Możesz zrobić to, co sugeruje zaakceptowana odpowiedź Infeligo, ale po prostu włóż ten dodatkowy fragment do kodu, aby wymusić pobranie.
źródło
To może być przydatna odpowiedź.
Czy można eksportować dane do formatu frontend w formacie pdf?
Rozszerzając to, dodanie dyspozycji treści jako załącznika (domyślnie) spowoduje pobranie pliku. Jeśli chcesz go zobaczyć, musisz ustawić go w linii.
źródło
W moim przypadku generuję jakiś plik na żądanie, więc trzeba też wygenerować adres URL.
Dla mnie działa coś takiego:
Bardzo ważny jest typ MIME,
produces
a także, że nazwa pliku jest częścią linku, więc musisz go użyć@PathVariable
.Kod HTML wygląda następująco:
Gdzie
${file_name}
są generowane przez Thymeleaf w sterowniku i jest tzn result_20200225.csv, więc linkujące cały url behing jest:example.com/aplication/dbreport/files/result_20200225.csv
.Po kliknięciu w link przeglądarka pyta mnie, co zrobić z plikiem - zapisz lub otwórz.
źródło