Tutorial: Tcnicas de Gerao de Relatrios com JasperReports Uma
abordagem utilizando a ferramenta de design iReportFortaleza CE,
fevereiro de 2009 http://pablonobrega.wordpress.com
2. CONFIGURANDO O IREPORT4
3. A APLICAO7
3.1 O Banco de Dados8
4. PREPARANDO OS RELATRIOS9
4.1 Mtodo passando conexo com o banco de dados9
4.1.1 Cdigo Java da Soluo18
4.2 Mtodo passando ResultSet18
4.2.1 Cdigo Java da Soluo20
4.3 Mtodo passando Lista de Objetos20
4.3.1 Cdigo Java da Soluo36
5. TESTES DE DOCUMENTOS COM SUBRELATRIOS37
6. CONFIGURAES TEIS40
6.1 Configuraes de textFields40
6.1.1 Campo deve ficar em branco quando for nulo40
6.1.2 Valor do campo no aparece quando ultrapassa o limite de
espao41
6.1.3 Campo deve crescer de acordo com o valor a ser
exibido41
1. INTRODUOPor diversas vezes tenho me deparado com pessoas
tendo dificuldades para gerar relatrios no JasperReports ou em
utilizar os recursos do iReport - a ferramenta de design para o
JasperReports e isso me incentivou a criar esse tutorial que mostra
trs tcnicas para gerao desses documentos to importantes em qualquer
sistema: passando uma conexo com o banco, passando um ResultSet
(encapsulado na classe JRResultSetDataSource) e passando uma lista
de objetos de qualquer tipo (encapsulada na classe
JRBeanCollectionDataSource).Duas outras caractersticas importantes
desse tutorial so: o emprego de subrelatrios - uma sada bastante
til em vrios casos, sobretudo em relatrios complexos, e a passagem
de parmetros para o relatrio atravs de um Map.Para finalizar,
disponibilizo o projeto do Eclipse no meu blog do WordPress
(http://pablonobrega.wordpress.com) a todos aqueles que desejam
entender a estrutura da aplicao finalizada. Na aplicao voc
encontrar os arquivos jrxml, os jasper, o script de criao do banco,
etc.Requisitos do Tutorial: IReport 3.0
(http://jasperforge.org/plugins/project/project_home.php?group_id=83);
JasperReports 3.0 (includo o JAR no diretrio do IReport); Eclipse
Europa 3.3, ou algum outro IDE que aceite JSF
http://www.eclipse.org/europa/ Apache Tomcat 6.0, ou algum outro
Servidor de Aplicao (http://tomcat.apache.org/); MySQL 5.0, ou
algum outro SGBD (http://dev.mysql.com/downloads/);2. CONFIGURANDO
O IREPORTComo toda boa ferramenta, o iReport precisa que sejam
feitas algumas configuraes aps a instalao na mquina. Abaixo dou o
exemplo de algumas que sempre uso para evitar a gerao de arquivos
que no me interessam e outras para que eu possa visualizar o
resultado da gerao de relatrios em PDF e em outros formatos (quando
necessito).
Clique no item Opes do menu Opes.
Na aba Programas Externos, configure os programas que o iReport
utilizar para abrir os arquivos gerados em outros formatos (para
efeito de testes internos). No exemplo acima, est configurado o
Adobe Acrobat Reader para abrir arquivos PDF.
Na aba Cpia, marque a opo Sem backup para evitar que o iReport
gere arquivos bak sempre que voc efetua alteraes no relatrio.
Na aba Compilador, marque a opo Usar o diretrio do relatrio para
os compilados. Isso far com que o iReport gere o arquivo jasper no
mesmo local onde est o jrxml. Alm disso, desmarque a opo manter
arquivo .java (se disponvel).3. A APLICAOO objetivo da aplicao
muito simples: gerar relatrio dos alunos cadastrados no banco e
seus respectivos professores. Alguns mtodos so utilizados pelos trs
modelos de gerao dos relatrios. So eles:Mtodo que retorna o caminho
completo de um arquivo ou pasta da aplicao.Mtodo para retornar o
nome da aplicao.Mtodo que gera o arquivo PDF.Mtodo que cria a
conexo com o banco de dados (chamado no construtor da classe).Mtodo
que retorna a conexo aberta.public Connection getConexao() { return
conexao; public void criaConexao() throws ClassNotFoundException,
SQLException {String endereco = "localhost"; String porta = "3306";
String banco = "academico"; String usuario = "root"; String senha =
""; try {Class.forName("com.mysql.jdbc.Driver"); conexao =
DriverManager.getConnection("jdbc:mysql://" + endereco + ":" +
porta + "/" + banco + "?user=" + usuario} catch
(ClassNotFoundException ex) { throw ex; } catch (SQLException ex) {
throw ex; private String getDiretorioReal(String diretorio)
{HttpSession session =
(HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
return session.getServletContext().getRealPath(diretorio); }
private String getContextPath() {HttpSession session =
(HttpSession)
FacesContext.getCurrentInstance().getExternalContext().getSession(false);
return session.getServletContext().getContextPath(); } private void
preenchePdf(JasperPrint print) throws JRException {// Pego o
caminho completo do PDF desde a raiz saida =
getDiretorioReal("/pdf/relatorio.pdf"); // Exporto para PDF
JasperExportManager.exportReportToPdfFile(print, saida); /* * Jogo
na varivel sada o nome da aplicao mais o* caminho para o PDF. Essa
varivel ser utilizada pela view*/ saida = getContextPath() +
"/pdf/relatorio.pdf"; }A pgina JSF que exibir os relatrios tem o
seguinte cdigo:Observe que se a varivel sada estiver vazia, uma
mensagem de erro ser exibida. Do contrrio, ser exibido o iFrame.
Utilizei essa tcnica para evitar que a tela fique em branco quando
o relatrio no foi gerado por algum motivo.3.1 O Banco de
DadosUtilizo o SGBD MySQL 5.0 para efetuar as demonstraes. O nome
do banco acadmico e o Diagrama Relacional ficou da seguinte
forma:
Dica: se sua fonte de dados ficar no MySQL, utilize o MySQL
Workbench (sucessor doDBDesigner) para criar seu Diagrama
Relacional. Foi com ele que gerei o modelo acima e o script de
criao do banco e a vantagem que o software totalmente gratuito.
Segue link para download:
http://dev.mysql.com/downloads/workbench/5.1.html 4. PREPARANDO OS
RELATRIOSPara fins de praticidade, utilizarei o Assistente de
Relatrio do prprio iReport para gerar o layout do relatrio e
algumas pequenas modificaes visuais sero feitas para que as
informaes fiquem melhor distribudas. claro que, medida que eu faa
essas alteraes, chamarei a ateno do leitor para o layout que
existia antes, como ficou e porque efetuei as mudanas.4.1 Mtodo
passando conexo com o banco de dadosNesse primeiro exemplo, vamos
preparar um relatrio que receber uma conexo com o banco de dados
aberta pela nossa aplicao Java para gerar um PDF.
Selecione a opo Assistente de relatrio.Como iremos passar uma
conexo com o banco de dados para o relatrio, vamos ter que
configurar qual a query a ser executada pelo banco, o banco de
dados, o schema (no caso de alguns SGBDs), etc. Clique em Novo, na
opo Conexes / Fonte de Dados para configurar.Selecione a opo Conexo
de Banco de Dados JDBC.Vamos agora configurar os parmetros da
conexo, como o driver JDBC, a URL de conexo, usurio, senha e o
banco a serem utilizados. Obs.: para alguns SGBDs (como o
Postgres), ser preciso colocar o jar do banco na pasta lib do
iReport. Clique em Salvar.Clique agora em Design query para
modelarmos graficamente a consulta a ser executada.
Do lado esquerdo selecionamos as tabelas a serem utilizadas.
Depois, em cada tabela, selecionamos os campos a serem exibidos ou
necessrios ao relatrio. Por ltimo - sendo esse o caso - podemos
modificar o tipo de JOIN que ser realizado entre as tabelas
clicando duas vezes nos quadradinhos vermelhos.
A consulta agora aparece no campo reservado a ela. Clique em
Prximo para continuar.Nessa tela, vamos selecionar os campos da
consulta que iro aparecer no relatrio. Nesse caso passe todos para
o select da direita.Nossa query vai retornar, em cada linha do
resultado da consulta, o nome e a matrcula do aluno, o nome do
professor, etc. lgico que no interessa para o usurio ver dados de
cada aluno repetidos diversas vezes em toda exibio de um professor
dele. Para que o aluno seja mostrado somente uma vez e logo em
seguida todos os seus professores, precisamos de um agrupamento
pelo id do aluno. Faa a configurao conforme a figura acima e clique
em Prximo.Escolhe o layout do relatrio. Na seleo acima (colunar)
cada dado fica abaixo do outro com seu label do lado esquerdo, como
veremos logo mais.Pronto. Processo concludo. Agora precisamos
somente clicar em Encerrar e fazer alguns ajustes.
Esse o resultado. A rea com o retngulo vermelho mostra onde est
o agrupamento (o iReport cria uma banda para ele). Isso significa
que, para cada aluno, ser exibido o seu id e logo abaixo cada um
dos seus professores, juntamente com o nome e a matrcula do aluno
(isso para cada professor, o que representa uma repetio
desnecessria de dados).
Para corrigir esse problema e tambm no mostrar o id do aluno,
aumentei a banda do agrupamento (rea marcada com fundo preto) e
coloquei l a matrcula e o nome do aluno, alm de apagar o label e o
textField com o id do aluno.
Vamos agora Compilar nosso relatrio para gerar o arquivo jasper
a ser utilizado pela nossa aplicao. Selecione a opo mostrada acima.
Obs.: para acompanhar o andamento, erros e outros detalhes,
consulte as abas Processos e Console de Sada (marcadas com o crculo
vermelho).
Como eu no havia salvo o arquivo, o iReport pede para que voc d
um nome para o arquivo e selecione seu local. Para aplicaes web
interessante usar nomes sem espao.
Vamos agora executar o relatrio para ver o resultado final. O
iReport vai conectar no banco, extrair as informaes e gerar o
resultado. O relatrio ser mostrado no JRViewer (conforma seleo
acima marcao em vermelho). Para gerar em outros formatos, selecione
outra opo de visualizao.
O resultado da gerao esse acima. Agora precisamos colocar o
arquivo jasper gerado na nossa aplicao e prepar-la para usar esse
arquivo.4.1.1 Cdigo Java da SoluoAo processarmos o mtodo
geraRelatorioPassandoConexao() do nosso Managed Bean, ser gerado o
relatrio em PDF e ento a navigation rule exibeRelatorio ser
chamada.4.2 Mtodo passando ResultSetPara efeitos de praticidade,
vamos utilizar o mesmo relatrio anterior, pois no precisamos fazer
nenhuma mudana na configurao de um documento quando passamos a
utilizar o ResultSet.Nesse tipo de abordagem, efetuamos a query no
banco a partir da nossa prpria aplicao e enviamos para o
JasperReports o ResultSet gerado encapsulado na classe
JRResultSetDataSource. O nico detalhe com o qual devemos nos
preocupar o fato de os nomes das colunas do ResultSet precisarem
ser idnticos aos textFields do relatrio. Para exemplificar, no
nosso caso, para o id do aluno, por exemplo, devemos usar o nome da
coluna aluno_id_aluno e para o nome do professor o nome da coluna
deve ser professor_nome (veja figura abaixo), pois os nomes dos
textFields no iReport devem ser iguais aos alias gerados pela
consulta ao banco.public String geraRelatorioPassandoConexao() {
saida = null;String jasper =
getDiretorioReal("/jasper/professores_por_aluno.jasper");
Connection conexao = null; try {// Abro a conexo com o banco que
ser passada para o JasperReports conexao = new
Conexao().getConexao();// Mando o jasper gerar o relatrio
JasperPrint print = JasperFillManager.fillReport(jasper, null,
conexao);// Gero o PDF preenchePdf(print); // VEJA O MTODO NO
CAPTULO 3 DO TUTORIAL} catch (Exception e) { e.printStackTrace(); }
finally { try {// Sempre mando fechar a conexo, mesmo que tenha
dado erro if (conexao != null) conexao.close(); } catch
(SQLException e) { return "exibeRelatorio"; }
Trecho da query configurada no iReport (marcado na cor
vermelha). Trecho da query configurada no iReport (marcado na cor
vermelha).4.2.1 Cdigo Java da SoluoObserve que o ResultSet deve
estar encapsulado pela classe JRResultSetDataSource.Mtodo que
retorna o ResultSet da query executada no banco.4.3 Mtodo passando
Lista de ObjetosEsse o mtodo mais interessante de gerao de
relatrios. Ele pode ser utilizado como uma alternativa aos dois
outros mtodos ou quando o relatrio muito complexo.Para facilitar,
novamente aproveitei o modelo anterior existente, fazendo apenas
algumas pequenas alteraes. No se esquea de salvar o novo relatrio
com outro nome. Coloquei ainda um subrelatrio que bastante til em
situaes complexas ou especficas. O legal dessa soluo que o relatrio
principal vai receber uma lista de objetos e o subrelatrio uma
conexo com o banco.private ResultSet getResultSet(Connection
conexao) throws SQLException, ClassNotFoundException {Statement
stmt = conexao.createStatement(); ResultSet rs =
stmt.executeQuery("SELECT aluno.nome AS aluno_nome, " +
"aluno.matricula AS aluno_matricula, professor.nome AS
professor_nome, " + "aluno.id_aluno AS aluno_id_aluno FROM aluno
aluno " + "INNER JOIN professores_alunos professores_alunos ON
aluno.id_aluno = " + "professores_alunos.id_aluno INNER JOIN
professor professor ON " + "professores_alunos.id_professor =
professor.id_professor"); return rs; } public String
geraRelatorioPassandoResultSet() { saida = null;String jasper =
getDiretorioReal("/jasper/professores_por_aluno.jasper");
Connection conexao = null; try {// Abro a conexo com o banco
conexao = new Conexao().getConexao();// Gero o ResultSet que ser
enviado a partir da conexo aberta JRResultSetDataSource jrsds =
newJRResultSetDataSource(getResultSet(conexao));// Mando o jasper
gerar o relatrio JasperPrint print =
JasperFillManager.fillReport(jasper, null, jrsds);// Gero o PDF
preenchePdf(print); } catch (Exception e) { e.printStackTrace(); }
finally { try {// Sempre mando fechar a conexo, mesmo que tenha
dado erro if (conexao != null) conexao.close(); } catch
(SQLException e) {} return "exibeRelatorio"; }
Esse relatrio no ter agrupamento de dados - vamos utilizar um
subrelatrio para os professores -, portanto, antes de excluirmos o
agrupamento, vamos mover todos os campos para a banda detail
(marcada na cor vermelha). Isso necessrio para que esses campos no
sejam perdidos.
Vamos agora tirar o agrupamento do relatrio. Entre na opo
Agrupamentos do Relatrio do menu Visualizar.
Selecione aluno_id_aluno e clique em Excluir. Pronto. O relatrio
deve ficar com a aparncia acima, j sem a banda de agrupamento por
id do aluno.
Como no teremos dados sobre os professores dos alunos nesse
relatrio isso ser tarefa do subrelatrio -, precisamos mudar a query
do banco. Entre em Query do Relatrio no menu Data. Essa query ser
modificada e configurada apenas para efeito de testes, j que iremos
passar uma lista de objetos para o relatrio e a query no ser
executada.Apague toda a query para podermos refazer tudo novamente
(o Query Designer tem um bug se quisermos tirar algumas tabelas ou
colunas da query anterior). Clique em Query Designer.
Selecione apenas a tabela aluno, marque todos os campos e clique
em OK. Podem observar que a idia que esse relatrio seja mais
detalhado.
A query do relatrio ficar como a mostrada acima.
Precisamos que os textFields do nosso relatrio batam com os
nomes dos atributos da classe que estar na lista do relatrio. Na
classe Aluno da minha aplicao, tenho os seguintes atributos: nome,
matricula, situacaoFrequencia e situacaoPagamento. Precisamos
renomear os alias das colunas (marcados na cor vermelha) para os
nomes acima.
Precisamos agora atualizar os textFields colocando o valor
correto para o que contm aluno_matrcula (ser agora $F{matricula}) e
para o que contm aluno_nome (ser agora $F{nome}). Vamos tambm
inserir os labels freqncia e pagamento e inserir os textFields
correpondentes com os valores $F{situacaoFrequencia} e
$F{situacaoPagamento}}. Para facilitar basta arrastar da estrutura,
onde tem o ns Campos (lado esquerdo, inferior da tela) para o
relatrio.
(Parte2de 2)
Precisamos excluir tambm os campos relacionados ao professor. Ao
final de tudo o relatrio ficar como est a imagem acima. Vamos agora
adicionar o subrelatrio. Clique no cone marcado em vermelho na
imagem acima para fazer essa operao.
Crie uma rea logo abaixo dos campos com o fundo preto (matrcula,
freqncia, etc), de preferncia utilizando a largura do relatrio por
inteiro. A tela acima mostrada. Deixe a conexo como est e entre com
a query a ser executada pelo subrelatrio. No exemplo acima coloquei
a id do aluno com o valor 1 apenas para o iReport deixar eu passar
dessa tela. Clique em Prximo.
Marque os campos que deseja que o iReport exiba. No nosso caso,
vamos selecionar todos. Clique em Finalizar.
Selecione o layout do relatrio. Decidi que o relatrio funcionar
com um cabealho superior e os valores abaixo (uma linha para cada
professor do aluno), ento selecionei o layout tabular.
Esse passo muito importante. Nele vamos indicar o nome do
subrelatrio e como ser referenciado pelo relatrio principal. Como
nosso relatrio e o subrelatrio podem mudar seus caminhos vamos
dizer para o iReport que o caminho para o subrelatrio ser passado
atravs de um parmetro chamado SUBREPORT_DIR.
O subrelatrio deve ter uma aparncia semelhante a que se encontra
na imagem acima. Fiz apenas alguma modificaes nas larguras dos
textFields.Observem como est a query do relatrio. Logo mais, o
nmero 1 ser modificado por um parmetro.
Voltando ao relatrio principal, vamos agora modificar algumas
configuraes do subrelatrio. Clique duas vezes em cima dele.
Na aba Sub-Relatrio (Outro) podemos observar que o iReport se
encarregou de configurar o caminho para o subrelatrio concatenando
o seu nome com o diretrio passado por parmetro ($P{SUBREPORT_DIR}).
Vamos agora passar um parmetro do relatrio principal para o
subrelatrio que servir para fazer a query listando os professores
de um determinado aluno. Clique no boto Adicionar.
Na janela a seguir, digite idAluno no Nome de Parmetro do
Sub-Relatrio. Depois clique no boto do lado direito (marcado na cor
vermelha).Na expresso, digite $F{idAluno}. Clique em Aplicar.
Com essa configurao, estamos dizendo para o JasperReports que
para cada aluno colocado na tela, ele vai gerar um subrelatrio que
receber como parmetro o id do aluno que foi processado. Clique em
OK.
A tela deve ficar como a que est acima.
Na aba Subrelatrio, mude a Expresso de Conexo/Fonte de Dados de
$P{subConnection} para $P{REPORT_CONNECTION}. Com isso voc est
dizendo para o JasperReports que a conexo com o banco de dados
utilizada pelo subrelatrio, est na chave REPORT_CONNECTION da lista
de parmetros.
Voltando para o subrelatrio, vamos agora mudar a Query do
Relatrio para poder receber o parmetro passado e mostrar somente os
professores do aluno correto. Entre novamente na opo Query do
Relatrio do menu Data.Mude o valor 1 que tinha antes para
$P{idAluno}, o parmetro que est vindo do relatrio principal. Clique
em OK.
Vamos agora preparar o subrelatrio para receber o parmetro do
relatrio principal. Entre na opo Parmetros do Relatrio, no menu
Visualizar.
Na aba Parmetros, clique no boto Novo.
Coloque o nome do parmetro idAluno e informe que do tipo
Integer. Clique em OK. Salve os dois relatrios e mande
compilar.4.3.1 Cdigo Java da SoluoObserve que no caso de passarmos
uma lista, devemos encapsul-la na classe
JRBeanCollectionDataSource.private ArrayList
getListaAlunos(Connection conexao) throws SQLException { return
(ArrayList) new AlunoDao().loadAll(conexao); } public String
geraRelatorioPassandoListaDeObjetos() { saida = null; String jasper
=
getDiretorioReal("/jasper/professores_por_aluno_com_lista.jasper");
Connection conexao = null; try {// Conexo com o banco para o
segundo relatrio conexao = new Conexao().getConexao();// criao dos
parametros Map map = new HashMap();// conexo com o banco que ser
utilizada pelo subrelatrio map.put("REPORT_CONNECTION", conexao);
// pego o caminho do diretrio onde se encontra o subrelatrio
map.put("SUBREPORT_DIR", getDiretorioReal("/jasper/") + "/");
ArrayList alunos =
getListaAlunos(conexao);JRBeanCollectionDataSource ds =
newJRBeanCollectionDataSource(alunos); /* * Mando o jasper gerar o
relatrio. Nesse caso passo o map,* j que ele tem dois parmetros que
sero utilizadosJasperPrint print =
JasperFillManager.fillReport(jasper, map, ds); // Gero o PDF
preenchePdf(print); } catch (Exception e) { e.printStackTrace(); }
return "exibeRelatorio"; }5. TESTES DE DOCUMENTOS COM
SUBRELATRIOSUm grande problema com o qual me deparei quando comecei
a usar o iReport foi o de realizar testes quando o relatrio
principal possua uma subrelatrio. Isso porque o subrelatrio
referenciado pelo JasperReports atravs do parmetro SUBREPORT_DIR e
quando mandamos executar o relatrio principal - caso voc no efetue
a configurao a seguir - o subrelatrio no encontrado. Para contornar
isso, realizaremos uma configurao adicional, conforme as telas a
seguir (o exemplo abaixo se aplica no exemplo de relatrio com
listas explicado no subcaptulo 4.3):
Entre nos parmetros do relatrio principal, escolha SUBREPORT_DIR
e clique em Modificar.
Em Valor Padro da Expresso, coloque o caminho para o diretrio
onde se encontra o arquivo jrxml do subrelatrio. Agora clique em
Executar relatrio (usar conexo ativa).
A tela a seguir ser exibida. Clique em Usar padro.
Pronto! O relatrio principal foi gerado executando a consulta no
banco e o subrelatrio funcionou com a mesma conexo utilizada pelo
relatrio principal. Observe que cada aluno tem sua lista de
professores.6. CONFIGURAES TEIS 6.1 Configuraes de textFieldsAs
configuraes a seguir se aplicam quando se faz a operao a
seguir:
Clique com o boto direito sobre o textField e escolha a opo
Propriedades 6.1.1 Campo deve ficar em branco quando for nulo
Marque a opo Em branco quando for nulo da aba Campo texto.6.1.2
Valor do campo no aparece quando ultrapassa o limite de espao
Marque a opo Imprimir quando detalhes excederem na aba Comum.
6.1.3 Campo deve crescer de acordo com o valor a ser exibido
Marque a opo Aumentar quando exceder na aba Campo texto.6.1.4
Campo deve ser exibido com formatao HTML Marque a opo HTML no item
Markup da aba Fonte.