Inicial > programação, programação JSF > Como passar a consulta dinamicamente para o JasperReports / iReport

Como passar a consulta dinamicamente para o JasperReports / iReport

Essa semana me deparei com um problema no trabalho que levei alguns minutos estudando a melhor solução. Eu tinha um relatório que deveria ser gerado com o JarperReports cuja consulta a ser realizada no banco poderia mudar constantemente, de acordo com o filtro que o usuário selecionasse na tela. Uma solução me veio à cabeça imediatamente: mandar um ArrayList para o JasperReports com o resultado da minha consulta para que ele preencha os dados. Essa solução é prática e fácil de implementar, mas esse ArrayList poderia ficar muito grande, visto que meu banco possuía muitas informações.

A melhor solução que encontrei foi passar a consulta inteira como parâmetro para o JasperReports fazer a consulta no banco. Para ilustrar como fazer isso, vamos aos passos abaixo:

  • Definir um parâmetro do tipo String que receberá a consulta vinda da aplicação java:
Parâmetros do Relatório

Parâmetros do Relatório

Observe que temos dois parâmetros definidos por mim: Filtro – servirá para receber uma descrição textual do filtro que o usuário aplicou na geração do relatório e consulta – receberá a consulta a ser executada no banco de dados pelo JasperReports.

  • Configurar a consulta do relatório como sendo o parâmetro recebido:
Consulta do Relatório

Consulta do Relatório

A consulta do relatório será exatamento o parâmetro consulta. Observe o símbolo de exclamação depois da letra P. Sem ele o iReport dá erro no momento de efetuar a compilação do relatório.

  • Passar a consulta para o relatório através da aplicação Java:

private String geraRelatorioEmPdfConsulta(String consulta, String jasper, String nomeRelatorio) {
	// Seto a variável saida como nulo
	saida = null;

	try {
		JasperPrint print = JasperFillManager.fillReport(jasper, getMapComFiltroEConsulta(filtroAplicado, consulta), getNovaConexao());
		saida = RelatorioUtil.getDiretorioReal("/relatorios/relatorio.pdf");
		JasperExportManager.exportReportToPdfFile(print, saida);
		saida = RelatorioUtil.getContextPath() + "/relatorios/relatorio.pdf";
	} catch (Exception e) {
		addErrorMessage("Formulario", "erro.geracao.relatorio", nomeRelatorio);
		e.printStackTrace();
	} finally {
		fechaConexao();
	}

	// mostro o erro ou o relatório na janela que abre
	return "geraRelatorio";
}

/*
 * Esse método retorna o map com o filtro e a consulta que o usuário gerou.
 */
public Map<String, String> getMapComFiltroEConsulta(String filtroAplicado, String consulta) {
	Map<String, String> map = new HashMap<String, String>();

	// Se o usuário não aplicou nada no filtro, retorno nulo para o relatório
	if (filtroAplicado == null)
		filtroAplicado = "";
	else
		filtroAplicado = "Você aplicou o seguinte filtro no relatório:\n" + filtroAplicado;

	map.put("Filtro", filtroAplicado);
	map.put("consulta", consulta);

	return map;
}

Observe, pelo código acima, que eu passo a consulta e o filtro que foram gerados para o relatório dentro de um HashMap, como o JasperReports exige. No final, o relatório com um campo do filtro fornecido ficou assim.

Relatório Gerado

Relatório Gerado

O campo marcado em vermelho foi o filtro aplicado pelo usuário que eu mandei para o relatório como um parâmetro chamado Filtro e que na verdade é apenas uma descrição textual.

Obs.: cada coluna retornada pela minha consulta deve ter o mesmo nome do field no relatório. Caso isso não ocorra, haverá um erro na geração.

É somente isso. Qualquer dúvida, deixe um comentário.

Anúncios
  1. Ythalo Rossy
    11/09/2009 às 20:29

    Tanto esse como o post anterior sobre IReport + Jasper estão bem interessantes, tem muita gente que precia utilizar geração de relátorios.

    nice =)

  2. 12/09/2009 às 09:55

    Boa Pablo, ficou muito bom. Parabéns!

  3. 12/09/2009 às 10:25

    Pablo,

    Muito útil sua dica! Ótimo post!

  4. 12/09/2009 às 11:25

    Bacana, esses posts técnicos são um canivente suiço quando procuramos soluções rápidas para problemas comuns do dia-a-dia, é uma consultoria especializada opensource 🙂
    Obrigado!

  5. 14/09/2009 às 09:52

    Dica útil e bem explicada. Boa iniciativa!

  6. Danilo
    01/10/2009 às 11:50

    Cara muito legal esse tutorial muito obrigado por disponibilizar seu conhecimento.

  7. Pedro Eugênio
    05/03/2010 às 15:14

    pq precisa da exclamação?

    • 05/03/2010 às 15:33

      Olá Pedro. O post fala exatamente sobre isso: como passar a consulta dinamicamente para o JasperReports. Imagine que você tenha um relatório que servirá para listar os estudante de um estado, mas que também servirá para listar os estudantes que nasceram a partir de uma determinada data. Os dados do relatório serão os mesmos, mas a consulta mudará bastante. Dessa forma, o melhor é passar a consulta dinamicamente, pois ela seria mais ou menos assim em cada um dos casos:
      Select nome, data_nascimento, endereco from estudante where estado = ‘CE’; — quero listar os estudantes do ceará
      Select nome, data_nascimento, endereco from estudante where data_nascimento >= ‘1980-01-01’; — quero listar os estudantes que nasceram a partir de 1980

      Assim vou ter o mesmo arquivo jrxml para gerar os dois tipos de relatórios e o ponto de exclamação serve exatamente para que eu passe a consulta, seja ela qualquer uma das duas acima, como um parâmetro.

  8. Pedro Eugênio
    05/03/2010 às 15:37

    sim, eu entendo o de passar a consulta, só queria entender a técnica do ireport, o que a exclamação faz com o parâmetro para o programa entender como uma consulta sql por exemplo, já que passando como uma String normal, não funciona. Obrigado pela atenção.

    • 21/03/2010 às 12:47

      Nesse caso realmente eu não sei. Acredito que seja algo que eles convencionaram.

  9. 21/03/2010 às 00:23

    Cara, sensacional a sua dica… Tinha lido varios tutoriais, mas nenhum deles era claro como este.

    Muito obrigado e meus parabens!

    Abraco!

  10. Thomas
    31/03/2010 às 00:11

    Olá Pablo… muito bacana esse exemplo!

    Existem outras formas bacanas de fazer isso ai que você fez.

    Quanto a mudar a consulta, já que os campos retornados são os mesmos (e muda apenas o tamanho do ArrayList do resultado), não seria mais fácil “enviar para o Jasper” apenas o “ArryList” com o resultado?

    No caso dos campos “serem os mesmos” e os filtros “serem dinamicos”, uma solução elegante seria usar o Jasper apenas para renderizar o relatório. Os dados da consulta poderiam vir filtrados dinamicamente através de um DAO/Service do Hibernate ou iBatis (usando um pool de conexões oferecido pelo proprio servidor de aplicações como no JBOSS ou WebSphere)…

    As vantagens de se fazer dessa forma são várias.
    Obviamente que cada caso é um caso, um universo diferente.

    No exemplo que citei (aplicado em um caso real em um aplicativo corporativo de uso crítico que consultava uma base de dados cabulosa…), ao separar dos relatórios a renderização (neste caso o Jasper não realizava a consulta) dos serviços que faziam as consultas e retornavam “apenas os dados”, tivemos um reuso muito bacana e um ganho significativo em produtividade.

    • Barbosa
      15/04/2010 às 06:17

      Bacana Thomas, manda um passo a passo de como se faz, pode ser ?

  11. Gustavo
    08/02/2011 às 09:03

    Bom dia. Como faço pra forçar uma quebra de linha? Vi que você simplesmente passou uma String com “\n” mas isso não funcionou comigo, o jasper imprime o caracter de escape literalmente …. “blablabla\nblablabla”
    Obrigado pela atenção.

    • 08/02/2011 às 09:27

      Gustavo, o campo é Static Text ou TextField? Se for Static Text você tem que colocar a quebra de linha normalmente mesmo, no valor do campo. Já a solução que eu mostro, com o “\n” funciona apenas em campos TextField.

      • Gustavo
        08/02/2011 às 10:16

        Olá Paulo. Eu descobri o que estava fazendo errado. Estava fazendo os testes usando um textfield e um parametro no próprio ireport, sem ligaçao nenhuma com minha aplicaçao… Na hora de compilar o formulario, o ireport pedia o parametro e eu digitava, usando \n mas era impresso literalmente. Coloquei o meu texto com o \n na propriedade default do parametro e aê funcionou… acho que se eu for passar o parametro pela minha aplicaçao tbm vai funcionar…

        Obrigado pela atenção

  12. wanderlei magri
    14/06/2011 às 14:34

    Otimo post Pablo, agora uma duvida como você trabalhou (abriu e fechou) a conexão com o banco de dados do relatorio?

    • 14/06/2011 às 14:46

      Wanderlei,

      Minhas gerações se dão através do código java. Nesse caso, abro uma conexão, passo para o relatório e fecho-a no bloco finally. Algo mais os menos assim:

      Connection conn = null;
      JasperPrint print;

      try {
      conn = getConnection();
      print = JasperFillManager.fillReport(reportStream, parametros, conn);
      JasperExportManager.exportReportToPdf(print, “C:\aux.pdf”);
      } catch (Exception e) {
      e.printStackTrace();
      throw new RelatorioException();
      } finally {
      try {
      if (conn != null && !conn.isClosed()) {
      conn.close();
      }
      } catch (SQLException e) {
      }
      }

      Abraço,

      Pablo.

      • wanderlei magri
        14/06/2011 às 15:12

        Então mas no caso de você passar a conexao e a sql como parametros, como você fecha a conexão depois?
        No seu outro tutorial(Tutorial: Técnicas de Geração de Relatórios com JasperReports / iReport) uqe por sinal é muito bom tambem eu vi como abrir mas não tem como fechar?

      • 14/06/2011 às 15:20

        Mas é o mesmo caso. Você está passando o objeto conexão e a consulta vai como parâmetro. Entretanto, a conexão – assim como a consulta sql – são usadas apenas no momento da geração, depois elas não são mais necessárias. Aí basta você fechar no finally.

  13. Lucas
    23/01/2012 às 18:33

    Olá….Muito bom o post, só uma dúvida, eu consigo passar duas consultas dinamicamente para o jasper ?

    • 24/01/2012 às 08:47

      Sim. Basta passar como outro parâmetro. Mas porque você quer fazer isso? Está usando um subrelatório?

      • Lucas
        24/01/2012 às 09:06

        Na verdade não gostaria de utilizar subrelatório, e gostaria de saber se teria como passar duas consultas via parametro (uma para cabeçalho e outra para detalhes dos produtos), mas enfim, acabei utilizando subrelatório mesmo…..até q ficou legal….

        Muito obrigado pela resposta e ótimo seu post tbm.

  14. Rodolfo Santiago
    15/08/2012 às 08:49

    Excelente tutorial amigo .

    Resolveu o meu problema , pois eu precisava mesmo passar a SQL montada para o relatório .

    Abraços e obrigado .

  1. 03/01/2011 às 23:29

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: