Tengo un requisito donde necesito descargar un PDF desde el sitio web. El PDF debe generarse dentro del código, que pensé que sería una combinación de freemarker y un marco de generación de PDF como iText. ¿Alguna mejor manera?
Sin embargo, mi problema principal es ¿cómo permito que el usuario descargue un archivo a través de un controlador Spring?
Respuestas:
En términos generales, cuando tienes
response.getOutputStream()
, puedes escribir cualquier cosa allí. Puede pasar esta secuencia de salida como un lugar para colocar el PDF generado en su generador. Además, si sabe qué tipo de archivo está enviando, puede configurarfuente
IOUtils
lugar de Spring'sFileCopyUtils
?Pude transmitir esta línea usando el soporte integrado en Spring con su ResourceHttpMessageConverter. Esto establecerá la longitud del contenido y el tipo de contenido si puede determinar el tipo mime
fuente
Content-Disposition
encabezado de esta manera?Debería poder escribir el archivo en la respuesta directamente. Algo como
y luego escribe el archivo como una secuencia binaria en
response.getOutputStream()
. Recuerde hacerresponse.flush()
al final y eso debería hacerlo.fuente
@RequestMapping(value = "/foo/bar", produces = "application/pdf")
Con Spring 3.0 puede usar el
HttpEntity
objeto de retorno. Si usa esto, entonces su controlador no necesita unHttpServletResponse
objeto y, por lo tanto, es más fácil de probar. Excepto esto, esta respuesta es relativamente igual a la de Infeligo .Si el valor de retorno de su marco pdf es una matriz de bytes (lea la segunda parte de mi respuesta para otros valores de retorno) :
Si el tipo de retorno de su PDF Framework (
documentBbody
) no es una matriz de bytes (y tampocoByteArrayInputStream
), entonces sería prudente NO convertirla primero en una matriz de bytes. En cambio, es mejor usar:InputStreamResource
,PathResource
(desde la primavera 4.0) oFileSystemResource
,ejemplo con
FileSystemResource
:fuente
return new ResponseEntity<byte[]>(documentBody, headers, HttpStatus.CREATED)
ResponseEntity
es una subclase deHttpEntity
(pero lo entiendo) 201 CREATED no es lo que usaría cuando devuelva solo una vista de los datos. (ver w3.org/Protocols/rfc2616/rfc2616-sec10.html para 201 CREATED)Si tu:
byte[]
antes de enviarlo a la respuesta;InputStream
;@ControllerAdvice
excepciones para usted (o no).El siguiente código es lo que necesita:
Acerca de la parte de la longitud del archivo :
File#length()
debería ser lo suficientemente bueno en el caso general, pero pensé que haría esta observación porque puede ser lenta , en cuyo caso debería tenerla almacenada previamente (por ejemplo, en la base de datos). Los casos en que puede ser lento incluyen: si el archivo es grande, especialmente si el archivo está en un sistema remoto o algo más elaborado como eso, una base de datos, tal vez.InputStreamResource
Si su recurso no es un archivo, por ejemplo, recoge los datos de la base de datos, debe usarlos
InputStreamResource
. Ejemplo:fuente
FileSystemResource
allí. Incluso es recomendable si su recurso es un archivo . En esta muestra,FileSystemResource
se puede usar dondeInputStreamResource
está.File#length()
debería ser lo suficientemente bueno en el caso general. Lo acabo de mencionar porque puede ser lento , especialmente si el archivo está en un sistema remoto o algo más elaborado, ¿una base de datos, tal vez? Pero solo preocúpese si se convierte en un problema (o si tiene pruebas sólidas de que se convertirá en uno), no antes. El punto principal es: está haciendo un esfuerzo para transmitir el archivo, si tiene que precargarlo todo antes, la transmisión termina sin hacer ninguna diferencia, ¿eh?Este código funciona bien para descargar un archivo automáticamente desde el controlador de Spring al hacer clic en un enlace en jsp.
fuente
El siguiente código funcionó para mí para generar y descargar un archivo de texto.
fuente
Lo que puedo pensar rápidamente es generar el pdf y almacenarlo en webapp / downloads / <RANDOM-FILENAME> .pdf desde el código y enviar un reenvío a este archivo utilizando HttpServletRequest
o si puede configurar su resolución de vista algo así como,
entonces solo regresa
fuente
La siguiente solución me funciona
fuente
algo como abajo
Puede mostrar PDF o descargarlo aquí.
fuente
Si ayuda a alguien. Puede hacer lo que sugiere la respuesta aceptada por Infeligo, pero solo ponga este bit extra en el código para una descarga forzada.
fuente
Esta puede ser una respuesta útil.
¿Está bien exportar datos en formato pdf en frontend?
Extendiéndose a esto, agregando disposición de contenido como un archivo adjunto (predeterminado) descargará el archivo. Si desea verlo, debe configurarlo en línea.
fuente
En mi caso, estoy generando algún archivo a pedido, por lo que también se debe generar la URL.
Para mí funciona algo así:
Muy importante es el tipo mime
produces
y también, ese nombre del archivo es parte del enlace, por lo que debe usarlo@PathVariable
.El código HTML se ve así:
Cuando
${file_name}
se genera por thymeleaf en el controlador y es decir: result_20200225.csv, de modo que enlace todo url behing es:example.com/aplication/dbreport/files/result_20200225.csv
.Después de hacer clic en el navegador de enlaces, me pregunta qué hacer con el archivo: guardar o abrir.
fuente