domingo, 31 de maio de 2020

Spring Boot + JasperReports exportando relatorios para PDF

É hoje temos algumas coisas interessantes para falar dentre elas a dificuldade de encontrar um bom e interessante codigo para gerar um simples pdf a partir de um JasperReport junto com uma aplicação Spring Boot.

Durante a pesquisa encontrei codigos muito parecidos com este a baixo e sim! Ele funciona perfeitamente.

@GetMapping
public void gerarPDF(@RequestParam Map parametros, HttpServletResponse response) throws IOException,JRException {
       
 if(parametros == null)
  parametros = new HashMap<>();          
           
 InputStream jasperStream = this.getClass().getResourceAsStream("../../../../reports/CondutorFicha.jasper")
 JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(Arrays.asList(condutores.findByCodigo(5)));
 JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parametros,dataSource);
        
 response.setContentType("application/pdf");
 response.setHeader("Content-Disposition", "inline; filename=Ficha.pdf");

 final OutputStream outputStream = response.getOutputStream();
 JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);            
       
}

Explicando em miúdos:
jasperStream -> Capturando o arquivo do relatório no meu classpath de modo hard( pois existe uma forma mais facil), na sua forma compilada .jasper vi em vários locais que pessoal compila na hora de exibir o relatorio, como nao tenho que trabalhar com múltiplos idiomas preferi trabalhar diretamente com o .jasper ao .jrxml.

dataSource -> linha seguinte criando um JRBeanCollectionDataSource com os BEANS devidamente populados no meu banco.

jasperPrint -> unificando o relatório com seus parametros e dados para daí poder gerar o pdf preenchido.

O objeto response esta informando no header da resposta que vamos devolver um pdf e informando que sera exibido no navegador com o nome de Ficha.pdf.

outputStream -> Capturando a Stream da resposta para ser usada no retorno ao navegador.

JasperExportManager -> tem uma serie de metodos uteis para exportar para uma serie de formatos distintos, que no caso informei qual o jasperprint e para qual saída de fluxo ele iria.

Então se este código funciona perfeitamente por que tentar fazer de outra forma ?.. Insatisfação, teimosia , seja la qual foi o motivo eu queria poder usar todas as partes que conheço do Spring Boot ate o dia de hoje, eis que decido deixar meu código desta forma:

 
@GetMapping(produces = {MediaType.APPLICATION_PDF_VALUE})
public @ResponseBody ResponseEntity gerarPDF(@RequestParam Map parametros){
 if (parametros == null)
     parametros = new HashMap<>();     
    
 try (InputStream jasperStream = applicationContext.getResource("classpath:reports/CondutorFicha.jasper").getInputStream()) {

     JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(Arrays.asList(condutores.findByCodigo(5)));
     JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parametros,dataSource);         
   
     return ResponseEntity.ok()
      .header(HttpHeaders.CONTENT_DISPOSITION,"inline; filename=Ficha.pdf")
      .body(JasperExportManager.exportReportToPdf(jasperPrint));
 }catch(JRException | IOException exception ){
     exception.printStackTrace();
 }
 return ResponseEntity.badRequest().body("Nao foi possivel gerar o pdf");
}
 
Vou descrever  apenas as diferenças do com relação ao primeiro código. Começando que agora ele tem um retorno diferente do primeiro que era um void teremos como retorno um ResponseEntity

@GetMapping -> Agora tem um argumento informando que será produzido um PDF, descartando a configuracao no Header.

@ResponseBody -> Indica que o valor de retorno deve ser vinculado ao corpo da resposta

jasperStream -> é instanciado pelo ApplicationContext do Spring de uma forma mais simples comparando com a anterior na minha opinião. Além de ter usado um TRY Resources para abrir e fechar o fluxo

ResponseEntity - > Builder para a resposta como um HttpServletResponse, nele informei uma parte do header anterior, e no body passei como parâmetro um byte[] pois é isso que este método estático do JasperExportManager nos devolve. Além de ter um pequeno tratamento caso não seja possível gerar o pdf por algum motivo.

Nenhum comentário:

Postar um comentário