domingo, 31 de maio de 2020

JasperReports JRBeanCollectionDataSource Java Bean Complexos

Vamos direto ao ponto. Quando usamos beans dentro de um JRBeanCollectionDataSource  e como no meu caso apenas linquei a pasta do projeto dentro do Jaspersoft Studio, quando temos um objeto diferente dos padrões do JRE, costumo ter um problema na hora de gerar vamos ver o caso:

Tenho uma Class Chamada Condutor dentro dela tenho vários atributos dentre eles alguns são classes como CidadeIBGE, EstadoIBGE e alguns sao Enuns Status,TipoCondutor, conforme imagem:


É importante ser notado que foi detectado corretamente o Class Type, mas mesmo assim vamos acabar esbarrando no problema das seguintes exceçoes NoClassDefFoundError e ClassNotFoundException durante a tentativa de geraçao do relatório com os dados do bean.

Os Bens selecionados tem os seguintes atributos:

Class CidadeIBGE
Class CidadeIBGE

Class EstadoIBGE

Enum Status

Vou usar o enum como o exemplo pois os demais serão exatamente iguais, tem um unico metodo que me é interessante que se refere a descrição, para que ele funcione corretamente sera necesario modificar algumas informacoes:
  1. Class Type Tem de ser o dado dado final, neste caso sera um java.lang.String.
  2. Em description vamos seguir o padrão Bean como se eu quisesse navegar no objeto ate seus atributos, neste caso ficaria situacao.descricao.
  3. Para realizar essas alterações basta dar dois cliques em uma das linhas que deseje editar


Se existe uma forma  de acessar as propriedades dos beans eu nao consegui encontrar, em fim! fica a dica para quem precisar um dia

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.

sábado, 30 de maio de 2020

Jaspersoft Studio + Lombok Instalação


Devo dizer que foi uma tarefa bem chata de se fazer ainda mais que o lombok no ubuntu não conseguiu reconhecer nem o Eclipse comum quem dirá a versão modificada que é o Jasper Studio nossa maravilhosa IDE para criação de relatórios das Jaspersoft.

Problema: Não instala de forma automática.


Necessidade: devido estar usando lombok no projeto se faz necessário que a IDE de relatórios também seja capaz de compilar os beans gerando assim setters e getters usando as annotations do lombok.

Soluçao: Instalar manualmente. Após encontrar o diretório de instalação do seu Jaspersoft Studio dentro do sistema operacional no seu computador, que no meu caso estava no caminho "/opt/tibco/TIB_js-studiocomm_6.12.2"(Ubuntu 16.04).

Vamos seguir a complicada explicação descrita dentro do proprio jar clicando em Show me what this installer will do to my IDE installation.


Considerações nao teremos dentro da pasta de instalação do Jaspersoft Studio um arquivo chamado Eclipse.ini nas sim Jaspersoft Studio.ini, como pode ser visto a seguir:


Copie o arquivo jar do lombok para dentro deste diretório e caso não tenha permissão de escrever, como eu basta conceder essa permissão pelo terminal  :x.

Após o arquivo estar no diretório abra o arquivo .ini e adicione no final do arquivo o caminho para o jar  do lombok lembrando se seu jar tem de estar com o mesmo nome que você informar no arquivo de configuração caso contrário vai acontecer um erro e a IDE não deve abrir.


basta colar a seguinte instrução " -javaagent:lombok.jar  " - Sem as aspas por favor rs. O arquivo deve ficar como acima, e para ter certeza conseguiu instalar corretamente basta abrir a IDE  > Help > About TIBCO Jaspersoft Studio e como pode notar na imagem temos descrito a versão do lombok instalada descrita nesta janela.



Agora e so compilar seu projeto e Correr para o abraço