¡No te pierdas ninguna publicación! Suscríbete a The Softtek Blog
Para generar de formar rápida un informe PDF os presentamos la librería Flying Saucer que se integra fácilmente con Thymeleaf, que ya fue presentado en el post Thymeleaf como alternativa MVC de nuestro compañero Sebas.
De hecho, hemos realizado un fork de su proyecto para integrar su ejemplo con Flying Saucer PDF y añadir un pequeño informe.
Estos son los pasos que hemos seguido para conseguirlo:
<!-- Generacion pdf: flying saucer pdf -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
Este servicio utiliza el motor de plantillas de Thymeleaf para obtener de forma dinámica un HTML (que revisaremos más adelante) utilizando los parámetros recibidos.
Posteriormente se crea un objeto ITextRenderer a partir del HTML generado, que se encarga de generar el ByteArrayOutputStream de salida que se utilizará para generar nuestro PDF.
@Service
public class PdfGenarator {
private static final Logger logger = LoggerFactory.getLogger(PdfGenarator.class);
@Autowired
private TemplateEngine templateEngine;
@Autowired
private ApplicationContext context;
@Autowired
ServletContext servletContext;
String urlBase = "http://localhost:8080";
public ByteArrayOutputStream createPdf(final String templateName, final Map map, final HttpServletRequest request, final HttpServletResponse response)
throws DocumentException {
logger.debug("Generando informe pdf");
Assert.notNull(templateName, "The templateName can not be null");
IWebContext ctx = new SpringWebContext(request, response, servletContext, LocaleContextHolder.getLocale(), map, context);
String processedHtml = templateEngine.process(templateName, ctx);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(processedHtml, urlBase);
renderer.layout();
renderer.createPDF(bos, false);
renderer.finishPDF();
logger.info("PDF created correctamente");
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
logger.error("Error creando pdf", e);
}
}
}
return bos;
}
}
A continuación añadiremos la invocación al servicio que acabamos de implementar desde el controlador RaffleController, que es el encargado de obtener la lista de ganadores.
El objeto ByteArrayOutputStream obtenido se utiliza para generar la salida mediante ResponseEntity. Podéis observar que se establece la cabecera Content-Disposition como fichero adjunto, el Content-Type como application/pdf, el Content-Length con el tamaño en bytes del fichero y, por último, el body con los bytes del PDF.
@GetMapping("/raffle/pdf")
public ResponseEntity rafflePDF(@ModelAttribute final Raffle raffle, final HttpServletRequest request,
final HttpServletResponse response) throws DocumentException {
List winners = raffle.getWinners();
Map<String, Object> mapParameter = new HashMap<String, Object>();
mapParameter.put("name", "Softtekiano");
mapParameter.put("winners", winners);
ByteArrayOutputStream byteArrayOutputStreamPDF = pdfGenarator.createPdf(templateName, mapParameter, request, response);
ByteArrayResource inputStreamResourcePDF = new ByteArrayResource(byteArrayOutputStreamPDF.toByteArray());
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName).contentType(MediaType.APPLICATION_PDF)
.contentLength(inputStreamResourcePDF.contentLength()).body(inputStreamResourcePDF);
}
Podéis encontrar la fuente en esta ruta: src\main\resources\templates\templatePDF.html
La variable ${name} se debe establecer de forma dinámica al igual que la lista ${winers} de acuerdo al servicio de negocio previamente que se ejecutó para obtener la lista de ganadores.
A modo de ejemplo se muestra cómo incluir unos estilos e imágenes en el pdf que se generará. Estos recursos se encuentran en:
src\main\resources\public\css\styles.css
src/main/resources/public/images/softtek.png
Aquí podéis ver cómo queda en informe PDF
Nos encontramos otro modo de generar informes con Flying Saucer integrado con Thymeleaf.
En comparación con otros frameworks de generación de informes lo que nos encontramos es un modo muy visual y más sencillo desde el punto de vista del Front Developer, ya que la plantilla se define con XHTML.
La maquetación de dicho XHTML se puede realizar con CSS 2.1.
Todo el código fuente del ejemplo que os hemos mostrado los podéis encontrar aquí:
https://github.com/ejalarcon/thymeleafdemo