Tenho um requisito no qual preciso fazer o download de um PDF no site. O PDF precisa ser gerado dentro do código, que eu pensei que seria uma combinação de freemarker e uma estrutura de geração de PDF como o iText. Alguma maneira melhor?
No entanto, meu principal problema é como permito que o usuário baixe um arquivo através de um Spring Controller?
Respostas:
De um modo geral, quando você tem
response.getOutputStream()
, pode escrever qualquer coisa lá. Você pode transmitir esse fluxo de saída como um local para colocar o PDF gerado no seu gerador. Além disso, se você souber que tipo de arquivo está enviando, poderá definirfonte
IOUtils
vez do SpringFileCopyUtils
?Consegui transmitir isso usando o suporte interno do Spring com o ResourceHttpMessageConverter. Isso definirá o comprimento e o tipo de conteúdo, se puder determinar o tipo mime
fonte
Content-Disposition
cabeçalho dessa maneira?Você deve poder escrever o arquivo diretamente na resposta. Algo como
e depois grave o arquivo como um fluxo binário
response.getOutputStream()
. Lembre-se de fazerresponse.flush()
no final e isso deve ser feito.fonte
@RequestMapping(value = "/foo/bar", produces = "application/pdf")
Com o Spring 3.0, você pode usar o
HttpEntity
objeto de retorno. Se você usar isso, seu controlador não precisará de umHttpServletResponse
objeto e, portanto, é mais fácil testar. Exceto isso, essa resposta é relativa igual à do infeligo .Se o valor de retorno da sua estrutura pdf for uma matriz de bytes (leia a segunda parte da minha resposta para outros valores de retorno) :
Se o tipo de retorno do seu PDF Framework (
documentBbody
) ainda não for uma matriz de bytes (e também nãoByteArrayInputStream
), seria sensato NÃO torná-la uma matriz de bytes primeiro. Em vez disso, é melhor usar:InputStreamResource
,PathResource
(desde a Primavera 4.0) ouFileSystemResource
,exemplo com
FileSystemResource
:fonte
return new ResponseEntity<byte[]>(documentBody, headers, HttpStatus.CREATED)
ResponseEntity
é uma subclasse deHttpEntity
(mas entendo), por outro lado, 201 CREATED não é o que eu usaria quando retornasse apenas uma visualização dos dados. (consulte w3.org/Protocols/rfc2616/rfc2616-sec10.html para 201 CREATED )Se vocês:
byte[]
antes de enviá-lo para a resposta;InputStream
;@ControllerAdvice
exceções para você (ou não).O código abaixo é o que você precisa:
Sobre a parte do tamanho do arquivo :
File#length()
deve ser boa o suficiente no caso geral, mas pensei em fazer essa observação porque ela pode ser lenta ; nesse caso, você deve armazená-la anteriormente (por exemplo, no DB). Os casos em que pode ser lento incluem: se o arquivo é grande, especialmente se o arquivo estiver em um sistema remoto ou algo mais elaborado como esse - um banco de dados, talvez.InputStreamResource
Se o seu recurso não for um arquivo, por exemplo, você coleta os dados do banco de dados, você deve usá-lo
InputStreamResource
. Exemplo:fonte
FileSystemResource
lá. É ainda aconselhável se o seu recurso for um arquivo . Nesta amostra,FileSystemResource
pode ser usado ondeInputStreamResource
está.File#length()
deve ser bom o suficiente no caso geral. Eu acabei de mencionar porque pode ser lento , especialmente se o arquivo estiver em um sistema remoto ou em algo mais elaborado assim - um banco de dados, talvez? Mas preocupe-se apenas se isso se tornar um problema (ou se você tiver provas concretas de que ele se tornará um), não antes. O ponto principal é: você está fazendo um esforço para transmitir o arquivo, se tiver que pré-carregar tudo antes, então o streaming acaba sem fazer diferença, não é?Este código está funcionando bem para baixar um arquivo automaticamente do spring controller clicando em um link no jsp.
fonte
O código abaixo funcionou para gerar e baixar um arquivo de texto.
fonte
O que consigo pensar rapidamente é: gerar o pdf e armazená-lo em webapp / downloads / <RANDOM-FILENAME> .pdf a partir do código e enviar um encaminhamento para este arquivo usando HttpServletRequest
ou se você pode configurar seu resolvedor de visualizações como,
então é só voltar
fonte
A seguinte solução funciona para mim
fonte
algo como abaixo
Você pode exibir PDF ou fazer o download de exemplos aqui
fonte
Se isso ajuda alguém. Você pode fazer o que a resposta aceita pelo Infeligo sugeriu, mas basta colocar esse bit extra no código para um download forçado.
fonte
Esta pode ser uma resposta útil.
É possível exportar dados como formato pdf no frontend?
Estendendo a isso, adicionar a disposição do conteúdo como um anexo (padrão) fará o download do arquivo. Se você quiser visualizá-lo, precisará configurá-lo para embutido.
fonte
No meu caso, estou gerando algum arquivo sob demanda, portanto também é necessário gerar um URL.
Para mim, funciona algo assim:
Muito importante é o tipo MIME
produces
e, além disso, esse nome do arquivo faz parte do link, portanto você deve usar@PathVariable
.O código HTML é assim:
Onde
${file_name}
é gerado por Thymeleaf no controlador e é isto: result_20200225.csv, de modo que apontam toda url behing é:example.com/aplication/dbreport/files/result_20200225.csv
.Depois de clicar no link, o navegador me pergunta o que fazer com o arquivo - salve ou abra.
fonte