0% acharam este documento útil (0 voto)
252 visualizações45 páginas

Relatórios em Java Com JasperReports e Ireport

O documento fornece instruções sobre como baixar e instalar o iReport e JasperReports para criar relatórios. Explica como configurar uma conexão com um banco de dados MySQL, definir um modelo de relatório e visualizar um relatório de exemplo contendo dados do banco. Também discute como organizar elementos no iReport e personalizar um relatório.

Enviado por

leo
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato DOCX, PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
252 visualizações45 páginas

Relatórios em Java Com JasperReports e Ireport

O documento fornece instruções sobre como baixar e instalar o iReport e JasperReports para criar relatórios. Explica como configurar uma conexão com um banco de dados MySQL, definir um modelo de relatório e visualizar um relatório de exemplo contendo dados do banco. Também discute como organizar elementos no iReport e personalizar um relatório.

Enviado por

leo
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato DOCX, PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 45

Explicação

Downloads
Você pode baixar a versão utilizada do iReport nesse link. Também vamos usar um
banco de dados no treinamento. Para facilitar a importação dos dados preparamos um
arquivo SQL disponível nesse link: financas.sql

Case queira usar a versão mais atual do iReport segue o link da Jaspersoft.

Relatórios em HTML e seus


problemas
Qualquer aplicação de negócio tem que se preocupar com a apresentação de dados. O
usuário final quer gerar relatórios com dados agrupados e bem formatados e tirar
conclusões sobre o que é apresentado.

A forma mais comum é o desenvolvedor gerar uma página HTML, por exemplo, com uma
tabela, formatando-a através de CSS. O problema é que isso nem sempre tem a qualidade
e precisão desejada após a impressão. Como, por exemplo, paginar este relatório?

Outra questão: o que fazer se a aplicação não é uma aplicação web? E se ainda
desejarmos numa aplicação web outras saídas, não só HTML com CSS, como também
PDF? Muitas vezes misturamos dados do relatório com sua visualização, sendo
necessário rescrever parte do código para outras saídas.

Isso também significa que estamos dependentes do desenvolvedor para criar um relatório.
Queremos uma abordagem mais simples, uma abordagem que permita criar relatórios
sofisticados sem termos que conhecer detalhes técnicos a fundo.

Report engine: JasperReports e


iReport
Para resolver essas questões foram criadas ferramentas específicas para a geração de
relatórios, que também são chamadas de report engines: são eles que assumem a
responsabilidade pela formatação e geração.

Uma ferramenta famosa do mundo Java é o iReport. Ele nos fornece uma interface gráfica
bem elaborada para definirmos o relatório e para exportá-lo em vários formatos como PDF,
PPT, OpenDocument, etc.

O iReport é apenas o report designer, a ferramenta que ajuda na construção de relatórios.


A definição é salva dentro de um XML com terminação jrxml. Este XML é independente
da saída concreta.

O responsável pela leitura do XML é o JasperReports - o report engine, que preenche o


relatório com os dados exportando-o para a saída desejada.
Instalação do iReport
Vamos começar a utilizar o report designer iReport com JasperReports, acessando a
página jasperforge.org.

Existem outros projetos relacionados ao JasperReports, mas o que nos interessa é o


report designer. Podemos baixar o programa clicando no link. Há um download para cada
sistema operacional específico (Windows, Mac e Linux) e também um ZIP genérico para
qualquer plataforma, inclusive há um plugin para o Netbeans.

Utilizaremos o ZIP genérico. Ao baixar o ZIP, será pedido um login e senha, basta clicar no
link logo abaixo que pulará esta etapa. Assim, chegamos na página de download.

Agora com o ZIP baixado, vamos extraí-lo. Temos a distribuição genérica do iReport com
os arquivos, plugin para Netbeans e uma pasta bin com os arquivos de inicialização do
iReport. Cada um dos arquivos destina-se a uma plataforma diferente (Windows, Mac e
Linux).

Definição da conexão e template


Temos a página inicial da ferramenta na qual podemos ver um assistente para criarmos
nosso primeiro relatório. Primeiro definiremos de onde virão nossos dados. A nossa
aplicação com iReport utilizará o MySQL. Nele teremos um banco já configurado chamado
finanças. Neste banco teremos uma tabela chamada movimentações e selecionaremos
todos os seus dados.

Dentro do iReport definiremos uma conexão com o nosso banco de dados ( jdbc
connection) que se chamará finanças. O driver é mysql e a nossa URL será finanças. O
login será root, sem senha. Após configurar, salvaremos e testaremos a conexão.

O próximo passo é selecionar através do assistente o layout, o template do nosso relatório.


Existem templates pré-definidos. Utilizaremos o template simple blue. Podemos fazer um
zoom para vermos mais detalhes sobre este template. Após inicializar, chamaremos o
relatório de finanças. No menu file, na parte admin, criaremos um arquivo chamado
financas.jrxml. Utilizaremos nosso datasource recém criado. Nossa query será um select
* from movimentacoes. Ele já fez o select, analisou nossa query e mostrou todos esses
fields. Adicionaremos o id, a data, a descrição e o tipo da movimentação, como também o
valor. O id da categoria e da conta não importam neste relatório. Na próxima tela não
agruparemos dados.

Organização do iReport
Estamos vendo a tela do nosso relatório e no centro o Designer.

O iReport criou colunas para nossos campos e logo abaixo de cada um deles uma espécie
de expression language, para indicar que teremos os valores.

No lado esquerdo temos o Report inspector, que mostra a estrutura do nosso relatório e
também as variáveis mais importantes como os parâmetros, os fields e as variáveis. Em
fields aparecem os campos que selecionamos no momento de criação do nosso relatório.
No lado direito temos as propriedades que mudam sempre quando selecionamos um
elemento dentro do relatório.

Visualizando o primeiro relatório


O primeiro passo é alterar o relatório, mas já podemos pré-visualizá-lo clicando em
Preview. O que o iReport faz é usar nosso relatório, acessar o banco de dados, gerando
um PDF com essas duas informações.

Várias páginas foram geradas com os dados das movimentações, mas como podemos
perceber, a data mostra um horário que não queremos apresentar. Voltando ao Designer e
selecionando a data, podemos, no lado direito, adicionar um pattern ( dd/MM/yyyy)
manualmente ou utilizar um assistente de data. Vamos formatar a data mostrando-a sem
horário.

Adicionaremos o título, movimentações, mudaremos o tamanho, apagaremos a descrição


e também colocaremos em maiúsculo o cabeçalho. Fazendo o preview novamente,
podemos ver o nosso atalho e também a data bem formatada.

Atividade 1 de 7
A funcionalidade de relatórios é um das tarefas mais rotineiras em sistemas
automatizados. Várias estratégias podem ser utilizadas para isso. Conte-nos se já foi
necessário essa tarefa em seus sistemas e como foi sua estratégia para realizá-lo.

Atividade 2 de 7
Por ser mais simples de ser criado, a estratégia de criar relatórios com HTML é bastante
adotada. Embora mais simples possui algumas limitações. Cite algumas dessas
limitações.

Atividade 3 de 7
Uma das alternativas para a criação de relatórios é usar uma Report Engine. No mundo
java existe duas ferramentas bastante difundidas: IReport e JasperReports. Para que
servem as duas ferramentas?

Atividade 4 de 7
Onde ficam salvas as definições do iReport?

17/12/2013 08:07

Elas ficam salvas num arquivo *.jrxml.


Elas ficam salvas num banco de dados.

Elas não ficam armazenadas em lugar algum.

Elas ficam salvas na pasta bin da própria ferramenta.

Atividade 5 de 7
Baixe o iReport aqui e escolha a versão ZIP (ou a extensão do seu sistema operacional).

Depois ter baixado, extraia o ZIP. Para rodar o iReport é preciso ter Java instalado.

Dentro da pasta bin se encontram os executáveis. Execute o arquivo do seu sistema


operacional (por exemplo, para window use o ireport.exe).

Depois de baixar e executar o iReport segue o Wizard na página inicial (Welcome Window)
para configurar a conexão. Define um conexão JDBC usando o banco MySQL (baseado
no database financas configurado no exercício). Chame a conexão financas. Escolhe o
Driver MySQL (com.mysql.jdbc.Driver) e o nome e senha do usuário. Cuidado para não
esquecer altera a URL do banco (por exemplo jdbc:mysql://localhost/financas).

No próximo passo escolhe o template, por exemplo Simple Blue e define o nome do
relatório.

Depois escrevemos a query. Nesse caso vamos definir um select simples: select * from
movimentacoes.

O campos (fields) são baseados na query. Escolhe todos os fields menos categoria_id e
conta_id. Assim pode finalizar o relatório e testar o preview

Para cada novo relatório é necessário 3 passos até verificar o esboço de um relatório.
Assinale a alternativa que descreve a ordem dos passos.

17/12/2013 08:08

definir relatório com template e query -> verifcar preview -> configurar datasource

configurar datasource -> definir relatório com template e query -> verificar preview

configurar datasource -> verificar preview -> definir relatório com template e query

verificar preview -> definir relatório com template e query -> configurar dasource

definir relatório com template e query -> configurar datasource ->verificar preview

Atividade 6 de 7
Para que se possa criar um relatório é necessário termos uma fonte de dados a serem
manipulados. Para que não seja necessário se preocupar com mais esse problema, vamos
usar dados já prontos.

Pegue o financas.sql e após isso crie um banco no MySQL com nome de financas.

Através do terminal importe seus dados com esse comando: mysql -u root -p -h
localhost --database=financas < financas.sql

Feito isso quantas tabelas foram criadas? E quais são os campos da tabela
movimentacoes?

Atividade 7 de 7
Qual a extensão do nosso recém-criado relatório financas?

17/12/2013 08:08

jar


java

hmtl

jrxml

xml

Explicação

Relatório sem template


Para esta aula veremos como o iReport organiza nosso relatório. Criaremos um novo
relatório, mas desta vez sem template, utilizaremos um blank letter, ou seja, um relatório
sem formatação. Este relatório ficará dentro da pasta relatório e terá o nome
gastos_por_mes. O próximo passo é definir a query através da nossa conexão com
MySQL que se chama financas.

Buscas customizadas com Query


Designer
O iReport oferece um designer, uma maneira visual para criação de query. Ele já detecta
as tabelas do nosso banco. Temos a tabela categorias que esta ligada à tabela
movimentacoes, que por sua vez liga-se à tabela contas. Os joins das tabelas são
representados visualmente através de links. Do lado esquerdo há o select
automaticamente gerado pelo iReport. Para cada tabela, selecionamos apenas os campos
de interesse. De categorias, queremos apenas o campo nome, de movimentacoes
ignoramos as chaves estrangeiras e de contas, apenas selecionamos o titular.

Além disso precisamos ordenar pelo titular e pela data da movimentação. Será
necessário filtrar a query, porque apenas saídas devem ser consideradas, isto é, estamos
interessados apenas nos gastos das movimentações. Simplificaremos o nome de alguns
campos e como resultado teremos: id, data, descricao, tipo, valor e categoria.

Com a query definida, o próximo passo é indicar os fields que utilizaremos, neste caso,
todos. Em seguida, agruparemos os dados pelo titular da conta. Após a finalização,
teremos como resultado a definição do relatório.
Seções e componentes de um
relatório
No lado esquerdo do report inspector, podemos ver as variáveis mais importantes da
estrutura do relatório. Por exemplo, temos os campos que definimos em nossa query.
Baseados nesses campos, criaremos o nosso relatório. O próximo passo agora é
escolhermos uma seção do nosso relatório para arrastarmos estes campos.

Podemos ver uma seção chamada detail. Este é o lugar onde ficam os dados que o
iReport utilizará, sendo assim, os campos do report inspector serão arrastados para esta
área. O iReport, além de criar automaticamente este campos, também adiciona o
cabeçalho para cada um deles.

Ao gerar o relatório, visualizamos os campos e seus cabeçalhos, mas com uma


formatação que deixa a desejar. O espaço da página é pouco utilizado, algo que pode ser
resolvido pelo próprio designer. Por ele, ajustaremos o espaço de cada dado e linha. A
mesma coisa para os cabeçalhos das colunas. Por uma questão estética, os cabeçalhos
ficarão em negrito. A visualização mostra um relatório mais apresentável.

Existem mais opções no relatório. Por exemplo, no cabeçalho da página, abrindo a paleta
com os componentes disponíveis, vamos utilizar o texto estático arrastando-o para a seção
page header definindo seu valor com Gastos por Contas. Ao visualizar novamente o
relatório, veremos o texto sendo repetido em cada página, mas queremos que ele seja
impresso apenas uma vez. Para isto, basta arrastá-lo para a seção title acima da seção
na qual ele se encontra. Além disso, ele será colocado em negrito e será impresso apenas
no início do relatório.

Ainda é possível mostrar no page footer, nosso rodapé, o número total de páginas,
inclusive a data atual. Basta visualizar mais uma vez para ver o resultado.

Agrupando e somando os gastos


da conta
Vamos também utilizar o rodapé da coluna e para isso arrastaremos o campo valor para a
seção column footer da coluna valor. Com esta ação, o iReport nos mostrará duas
opções: apenas manter o valor do campo ou aplicar uma função de soma. Com a opção
de soma selecionada, o iReport calculará o valor total das movimentações por página.

Faremos a mesma coisa para a seção sumary, nosso sumário. Novamente iremos
selecionar a opção soma para mostrar no final do relatório o valor total dos gastos.
Visualizando novamente o relatório vemos o total por página e no final o valor total de
todos os gastos.

Apesar do resultado, queremos saber os gastos por contas e uma conta em nosso
relatório é identificada através de um titular. Por isso agrupamos os dados no início do
relatório e olhando no report inspector temos um group header e um group footer para
titular, falta adicioná-los no relatório. Da mesma maneira que podemos adicionar seções,
podemos apagá-las do relatório. Apagaremos o column footer, porque não faz sentido
para o nosso relatório.
O processo é bem semelhante ao que já fizemos: arrastamos o campo, selecionamos a
função de soma e posicionamos o campo dentro do relatório. Verificando o resultado,
vemos que há o total de todos os gastos do titular João Souza e logo abaixo dele vem as
informações de outro titular.

Adicionando novos grupos ao


relatório
Queremos ver também a soma total de todos os gastos por mês. Por isso adicionaremos
um novo report group. Vamos chamá-lo de por_mes. Precisamos selecionar data, mas
excluiremos o dia e ano pois queremos apenas o seu mês. Utilizaremos novamente um
filtro por meio de uma expressão usando a data, mas agora selecionando apenas o mês.
Agora falta apenas posicioná-lo no rodapé.

Temos o nosso por_mes group footer. Nele adicionaremos o valor, realizaremos a soma
e apagaremos o que não estamos utilizando. Finalmente, temos um agrupamento do mês
de janeiro e mais a frente um agrupamento do mês de maio.

Atividade 1 de 5
Para criarmos um novo relatório sem template, escolheremos a seguinte opção

(quer uma dica?) (ver próxima dica)

 Blank significa "em branco"!

17/12/2013 08:09

Simple Blue

Blank Letter

Flower

Cherry
Atividade 2 de 5
No iReport existe um modo visual para criação de queries durante a criação do relatório.
Nesse modo, podemos simplificar os nomes de alguns campos. Que que propriedade
devemos alterar para isso?

17/12/2013 08:09

GROUP

ROOTQUERY

identifier

alias

Atividade 3 de 5
Para usarmos os campos definidos na query, podemos arrasta-los do report inspector para
que seção do relatório?

17/12/2013 08:09

Column Footer

Page Header


Title

Detail

Atividade 4 de 5
Podemos utilizar diversos componentes em nosso relatório. Para isso, podemos abrir o
menu Janela > Paleta. Se quisermos enumerar as páginas de nosso relatório, o que
devemos fazer?

17/12/2013 08:10

Arrastamos o elemento Crosstab para a seção Page Header

Arrastamos o elemento Page X of Y para a seção Page Footer

Arrastamos o elemento Static Text para a seção Title

Arrastamos o elemento Table para a seção Detail

Atividade 5 de 5
O iReport nos permite também saber o valor total da soma de algum campo. Por exemplo,
saber o total de gastos do mês. De que forma podemos utilizar a seção Summary para
saber o total de gastos apresentados no relatório?

(quer uma dica?) (ver próxima dica)

 Utilize a opção "The result of an aggregation function"!

Explicação
Melhorar o design do relatório
Olá! Vamos continuar com o nosso relatório Gastos por conta. Ele é funcional, mas ao
visualizá-lo, é possível perceber que está mal formatado. Vamos melhorar o seu design e
aumentar o zoom nos ajudará. Atacaremos inicialmente a primeira seção, o title. Podemos
selecionar o elemento diretamente no Designer ou navegar através do Report inspector.

A primeira coisa que faremos é selecionar um retângulo que servirá como background e
escolher uma cor para ele nas propriedades do componente. Ele não terá um traço e será
adaptado levando em consideração o tamanho do seu parent, a seção no qual ele está
incluído. Para tal, usaremos os Formatting Tools - adapt to parent. Agora só falta colocar o
componente para trás com send to back e centralizar o elemento dentro da seção title.

Nosso próximo passo é deixar todos os cabeçalhos com letra maiúscula. Depois disso
vamos alinhar os nomes do cabeçalho, bastando selecionar todos ao mesmo tempo e
aplicar alinhamento pelo centro. Já podemos visualizar o resultado pelo iReport.

Formatar e concatenar campos


de texto
Ainda falta trabalhar a parte do titular do relatório, pois queremos ele também em letra
maiúscula. O problema é que o titular é um campo que veio do banco de dados, fora do
padrão desejado. O campo dentro do relatório é uma expressão apresentada através do $
{}. Podemos manipular essa expressão através do Expression Editor. Repare que o tipo
do campo é java.lang.String, sendo assim, utilizaremos os próprios recursos desta
classe para colocarmos a informação em letra maiúscula. No editor da expressão, na lista
de métodos, aparece o método toUpperCase(). Além disso, queremos concatenar a
informação CONTA DE com o titular usando o operador + da linguagem Java.

O tamanho do campo não é suficiente, sendo necessário adaptá-lo ao seu parent, como
fizemos com nosso background. Na visualização, vemos a nova informação e tudo
centralizado, mas ainda falta o background na cor azul. Voltando ao Designer, ao
selecionar o componente de texto com o titular, podemos alterar a cor de fundo nas
propriedades dos componentes.

Formatando a data e os valores


numéricos
A próxima etapa é formatar os dados das colunas valor e data. Com o campo valor
selecionado, na opção field pattern, escolhemos a opção currency, para apresentar o valor
monetário. A mesma coisa será feita com o campo data, usando a opção field pattern,
mas escolheremos a opção date, mostrando apenas a data(sem a hora).

Resultados condicionais
As modificações são aplicadas, mas ao visualizarmos mais uma vez o relatório, vemos que
em alguns casos o campo descrição não se posiciona conforme o esperado quando o
mesmo não existe. É apresentado o valor null, que não faz sentido para o leitor do
relatório.

Para resolvermos este problema, basta selecionar o campo descricao e marcar a opção
Blank When Null. Com a opção marcada e visualizando, vemos que o resultado ainda não
é o esperado. Mais uma vez sobre o campo, marcamos a opção Stretch with overflow.
Esta opção organizará a informação mesmo quando não há espaço disponível, sempre
mostrando todas as informações do campo.

Diminuir o campo de texto


Há situações onde é necessário diminuir o tamanho da coluna, por exemplo, mostrar
apenas a letra S, para indicar que a movimentação é de SAÍDA. Com o campo
selecionado e editando a expressão, podemos recorrer ao método substring() e
selecionar apenas a primeira letra. Por fim, centralizaremos alguns campos. Agora é só
visualizar. Aparece apenas a letra S na coluna Tipo .

Mais formatações
Falta ainda lidar com os campos ou variáveis que agrupam o valor total do mês e da conta.
Primeiro, alinharemos o resultado e cada grupo à direita e definiremos o pattern currency
para eles. Depois do pattern definido, criaremos outro retângulo na cor azul que ocupará
todo o espaço de seu parent, produzindo um efeito que já fizemos.

No lugar de criarmos mais um retângulo, o copiaremos para o próximo grupo. Por fim,
jogaremos os retângulos para trás com send to back. Visualizando outra vez, vemos o
resultado esperado. Os agrupamentos aparecem na cor azul para se destacarem no
relatório.

Mas ainda há um problema: o texto do número da página está em inglês. Editando o


elemento e selecionando a expressão, podemos modificar o texto original page para
página. Novamente visualizando para verificar o resultado. Em cada página aparece o
rodapé em português. Por último, trocaremos a cor de todos os retângulos de azul para
cinza, basta selecionar todos os retângulos com control + shift e mudar o background color
para cinza. Agora, em nosso relatório, as seções serão apresentadas em cinza.

Passando parâmetros para o


relatório
Temos um total de 33 páginas, que pode ser demais para quem deseja retirar alguma
informação do relatório. Para o usuário final seria mais fácil se ele pudesse filtrar os
gastos. Por exemplo, pela data, selecionando um período. A ideia é renderizar apenas os
gastos entre duas datas definidas.

Para esta situação, o iReport oferece parâmetros. Os parâmetros são valores passados da
aplicação para o JasperReport, o responsável pela renderização do relatório. Já existem
parâmetros pré-definidos, por exemplo, de localização visível no Report Inspector.
Podemos adicionar nossos parâmetros através do menu, e uma vez feito isso, podemos
alterar as suas propriedades pelo editor. O nome do nosso parâmetro será DATA_INI e seu
tipo java.util.Date. Criaremos outro parâmetro que representa a data final, novamente
no Report Inspector. O nome dele será DATA_FIM, também do tipo Date.

Filtrando o relatório pelos


parâmetros
Como resultado, temos os dois parâmetros disponíveis para usar dentro do Report
Inspector. Podemos agora utilizá-los arrastando para o nosso relatório, mas não faremos
isto porque modificaremos nossa query com base nestes parâmetros.

Ao abrir o editor da query, alteraremos a cláusula where utilizando a data e filtrando-a


pelos dois parâmetros que podem ser arrastados para a query. A data da movimentação
deve estar entre DATA_INI e DATA_FIM. Vamos confirmar o diálogo e pré-visualizar o
relatório. Quando o relatório for renderizado, o iReport mostrará automaticamente um
prompt solicitando um valor, pois as datas são necessárias para executar a query. Vamos
filtrar as movimentações pelo mês de agosto. O relatório mostrará apenas as
movimentações desse mês.

Para não termos que definir toda vez a data, podemos definir um valor padrão. Nos
parâmetros criados, desmarcamos a opção Use as a prompt e editamos Default Value
Expression. Utilizaremos a classe SimpleDateFormat, que receberá um pattern com o
formato da data desejada e que realizará um parse da 01/08/2012.

Veja o código:

new java.util.SimpleDateFormat("dd/MM/yyyy").parse("01/08/2012");

Faremos a mesma coisa para DATA_FIM, desabilitando o prompt e alterando o valor que
sofrerá o parse, neste caso, final de agosto. Renderizando novamente, percebemos que o
prompt não aparece mais e mesmo assim tivemos nosso relatório filtrado.

Atividade 1 de 6
Muitas vezes precisamos formatar um elemento fazendo com que ele ocupe toda a área
do elemento pai no qual esta inserido. Isso é possível através do iReport acessando:

17/12/2013 08:11

Formatting Tools > send to back

Report inspector > Expression Editor


Formatting Tools > adapt to parent

Report inspector > adapt to parent

Atividade 2 de 6
Há situações em que é necessário formatar o conteúdo de algum campo (field) que
arrastamos para dentro do nosso relatório. Realizamos esta tarefa através do:

17/12/2013 08:13

Report inspector

Formatting Tools

Expression Editor

Stretch with overflow

Atividade 3 de 6
Para cada campo no relatório é possível definir um padrão. Cada padrão permite
configurações específicas, por exemplo, se o padrão for numérico, podemos escolher o
número de casas decimais. Qual é o nome da opção que permite escolher um padrão e
qual o padrão para campos que representam dinheiro?

17/12/2013 08:13


Expression Editor, currency

field pattern, number

field pattern, currency

Formatting tools, number

Atividade 4 de 6
Não faz sentido apresentar no relatório "null" para os campos sem valor. Podemos resolver
facilmente isto clicando no campo, e marcando a propriedade:

17/12/2013 08:14

Send to back

Blank When Null

Stretch with overflow

Atividade 5 de 6
É comum abreviarmos o texto de alguns campos para liberarmos espaço para outros,
sendo assim, como imprimir apenas a primeira letra do campo "Tipo" do nosso relatório?

Atividade 6 de 6
Parâmetros são valores passados da aplicação para o JasperReport e existem vários
parâmetros pré-definidos.
Quais são os passos que devemos seguir para criar nossos parâmetros?

Explicação

Gráficos para o iReport


Para esta aula queremos visualizar gráficamente os gastos agrupando por titular. Na
paleta de componentes existe o elemento chart, que arrastaremos para a seção sumary.

O iReport já vem com vários charts disponíveis nesta janela. O chart que queremos é o
Stack Chart(uma pilha de cores). Queremos visualizar os gastos agrupados por titular,
portanto, cada pilha representará um titular de uma conta, e cada cor fará referência à
soma de um tipo de gasto.

Na próxima página podemos selecionar qual fonte ou dataSet o chart utilizará. O iReport
oferece o dataSet do relatório principal, o main report dataset. O problema é que a query
do dataSet não agrupa os gastos por titular, sendo necessário alterá-la.

Observando a query, percebemos que qualquer alteração impactará no relatório existente.


Não queremos alterar os dados, apenas gerar um gráfico adicional no fim do relatório.

Um novo dataSet para o gráfico


Para resolver este problema, adicionaremos um segundo dataSet ao relatório com o nome
chartDataSet. Nesse dataSet utilizaremos novamente a conexão financas. Definiremos a
query através do query designer, clicando no botão Design Query. No designer,
selecionamos as tabelas categorias, contas e movimentacoes. O iReport
automaticamente realiza um join entre as tabelas. Os únicos campos que queremos na
query são: titular da conta, nome da categoria e o valor da movimentação. Para isso,
vamos desmarcar os outros. No caso do valor, somaremos os valores através de uma
função.

Depois de ajustar as janelas, renomearemos os campos para simplificar o trabalho. Os


campos ficam como titular, categoria e soma. No final agruparemos a query pelo titular
da conta e categoria, mas como queremos apenas os gastos, adicionaremos uma
condição na cláusula where para receber apenas as movimentações com o tipo SAIDA.

Após confirmarmos, podemos seguir para o próximo passo e adicionar todos os campos
no dataSet. Não haverá nenhum agrupamento. Finalizando a definição do dataSet,
aparece o novo elemento no report inspector.

Criação do gráfico
Com o dataSet definido, voltaremos para criação do gráfico. Para simplificar, ajustaremos
primeiro o tamanho da seção. Novamente arrastaremos o elemento chart para a seção
sumary, e na próxima tela escolheremos o Stack Chart. O dataSet será o chartDataSet.

O primeiro passo é definir a série, o valor da cada cor dentro de uma pilha. Cada cor é
uma categoria de gastos. Consequentemente escolheremos o campo categoria. Na tela
seguinte, a legenda estará definida abaixo do eixo X. Cada pilha é relacionada com um
titular, e os valores das categorias são representados pela soma dos gastos. Podemos
confirmar o gráfico e ajustá-lo na seção sumary, ocupando todo o espaço.

Podemos visualizar o relatório clicando no botão preview. No fim do relatório aparecerá o


gráfico que agrupa a soma dos gastos por categoria e titular. O gráfico visualiza bem os
gastos no sumário do relatório, mas é difícil tirar um valor exato dessa forma.

Resumindo e agrupando valores


através de crosstable
Claro que podemos encontrar todos os valores dentro do relatórios, mas as informações
estão espalhadas pelas páginas. Pode ser muito útil apresentar um sumário no final do
relatório, depois do gráfico, que mostra os valores mais importantes dentro de uma tabela.
Para isto existe o componente crosstable(ou pivotable). O objetivo é mostrar os gastos por
mês de cada titular. Arrastaremos este componente para a seção sumário, aumentando
um pouco o seu espaçamento.

Nesse caso, usaremos o dataSet do relatório principal. Na próxima tela definiremos o que
queremos mostrar em cada linha. Neste caso, o nome do titular. Depois, definiremos o que
usar no cabeçalho da coluna, que será o campo data(apenas o mes). O próximo passo é
decidir qual valor aparecerá em cada célula.

Queremos a soma dos gastos por mês deste titular, então, escolheremos o campo valor
com a função sum.

Na última tela podemos mudar o layout padrão da tabela. Usaremos a cor bege. Depois de
confirmado, o iReport criará automaticamente uma nova aba para mostrar o design da
tabela. Nesta tabela podemos ver os dados dos cabeçalhos e células. Além disso, também
foram criados campos para somar cada linha e coluna.

No relatório principal, precisamos ajustar o layout que está em conflito com o gráfico,
diminuindo o espaço da tabela. Depois disso podemos visualizar o relatório. Indo para a
última página do relatório, aparece a tabela, com os titulares em cada linha e a soma do
mês na coluna. Porém, a tabela foi criada baseada em apenas um mês porque nossa
query principal a utilizou num período muito pequeno.

A tarefa agora é aumentar este período, mas antes vamos inserir quebras de páginas
entre o gráfico e a tabela para melhorar o design. Já existe um componente pronto na
paleta. Para aumentar o período é preciso alterar o parâmetro DATA_INI. Podemos
acessá-lo pelo report inspector, selecionado a opção para editar a expressão, mostrando
os meses junho, julho e agosto. Novamente, usando o preview e indo para a última página,
percebemos que a tabela foi criada com os três meses.

Usando sub-relatórios
O gráfico e a crosstable são opções para visualizar as informações, diferente do relatório
principal. Existem casos aos quais queremos integrar dados complexos, nesse caso, é
preciso um novo relatório em anexo ao relatório principal. Com o iReport, podemos criar e
integrar um novo relatório através do elemento subreport, que se encontra na paleta.
Arrastando este elemento na seção title, um wizard de criação de relatórios aparecerá
automaticamente.

Na primeira tela, definiremos se vamos criar um novo relatório ou integrar um já existente.


Neste caso criaremos um novo, mas precisamos também escolher um layout para ele.
Usaremos o template Blank Letter com a mesma conexão financas.

A query será bem simples para ilustrar a funcionalidade de um sub-relatório.


Pesquisaremos todas as contas executando select * from contas. Na próxima tela,
selecionaremos todos os campos da query. Não haverá agrupamento e manteremos o
nome padrão fornecido pelo iReport ao salvar o subreport. Na última tela, confirmamos o
uso da conexão do relatório mestre.

O iReport abre uma nova aba para o design do relatório. O sub-relatório é um relatório
comum, então existem as mesmas seções e variáveis disponíveis. Também
encontraremos parâmetros, campos e variáveis no report inspector.

Para definir os dados do relatório, colocaremos todos os campos na seção e também


apagaremos as seções sem uso, como por exemplo: column footer, page footer, sumary,
page header e title. Por último, diminuiremos o tamanho das seções column header e
detail para otimizar o espaço. Falta visualizar e testar o relatório, clicando no botão
preview.

Integração do sub-relatório e
relatório mestre
Vamos voltar ao relatório mestre. O nosso sub-relatório deve ficar no início, na seção title.
É preciso ajustá-lo para o sub-relatório ter espaço suficiente.

Como queremos na primeira página apenas os dados das contas e titulares,


adicionaremos uma quebra de pagina após do sub-relatório. Visualizando o relatório,
aparecem os dados da conta e titulares na primeira página. Nas próximas páginas, os
dados principais do relatório mestre e no final, o gráfico seguido pelo crosstable.

Atividade 1 de 6
De onde vêm os dados que serão representados no gráfico?

17/12/2013 08:16

dataSet

dataComponent

data

source

dataSource

Atividade 2 de 6
Qual é o componente que utilizamos caso seja necessário resumir e agrupar os dados de
um relatório?

17/12/2013 08:16

groupData

grouper

crosstable

dataSumary

sumary
Atividade 3 de 6
Quando queremos integrar dados complexos em nossos relatórios utilizamos o seguinte
elemento:

17/12/2013 08:16

dataset

Stack Chart

crosstable

subreport

Atividade 5 de 6
É possível fazer um Gráfico de Linha utilizando o Stack Chart? Por quê?

false 1180 222 38 17/12/2013 08:17

38
Explicação

Downloads
A versão utilizada do JasperReports Library se encontra nesse link. Também preparamos
um projeto com todas as bibliotecas necessárias que vem preconfigurado para Eclipse.
O projeto pode ser baixado pelo link: cap5-movimentacoes.zip

A versão mais atual do JasperReports Library se encontra aqui. Caso queira baixar o
driver do MySQL (Connector J) separado segue também o link.
Introdução ao Report Engine
JasperReports
Vimos como criar e exportar relatórios usando o designer iReport. Para esta aula
focaremos na utilização do nosso relatório dentro de uma aplicação Java.

Utilizamos o iReport para definir os componentes do relatório. A definição foi salva dentro
de um arquivo XML com a extensão jrxml. Os dados vieram do banco MySQL e no final
tudo foi exportado em PDF para podemos visualizar.

Com a definição do relatório pronta podemos usar diretamente o Report Engine, o


JasperReport. O iReport nada mais é do que o designer que define o jrxml, mas é o
JasperReports o responsável pela geração e exportação de relatórios.

Antes de exportar com o Report Engine é preciso realizar um passo intermediário, que
consiste na compilação do jrxml para um arquivo com a extensão jasper. O iReport
sempre compilava e gerava o arquivo durante as exportações. O relatório compilado será
passado para o Report Engine com os parâmetros da aplicação e a conexão que define a
fonte de dados. Com todos esses informações, poderemos gerar o relatório e exportá-lo,
por exemplo, no formato PDF.

Preparação do projeto
Vamos gerar o relatório programaticamente usando o Eclipse como IDE. Já temos um
projeto preparado chamado gastos. A pasta lib é para as nossas bibliotecas e possui o
driver do MySQL, que já foi definido em nosso classpath. Na pasta src já temos a classe
ConnectionFactory para obter conexões com o banco MySQL
(jdbc:mysql://localhost/financas).

Além disso, temos uma classe de testes que abre uma conexão através da Report Engine.
Vamos chamar uma vez o método main. Executou sem problemas.

O próximo passo é copiar as definições dos relatórios, ou seja os arquivos jrxml. Vamos
copiar os dois arquivos (o relatório principal e o sub-relatório) para a raiz do projeto.

Configuração das bibliotecas


Como vimos na introdução é preciso compilar esses dois arquivos em jasper, mas antes
baixaremos os JARs do projeto JasperReports. Vamos acessar o site
http://jasperforge.org, escolhendo o projeto JasperReports Library, clicando no botão
download - sem logar no sistema. Na lista vamos escolher a versão mais recente, no
nosso caso 4.7.0, usando a extensão ZIP.

Na pasta apresentada já temos o ZIP baixado, então vamos extrair os arquivos. Entrando
na pasta extraída encontramos o JAR principal na sub-pasta dist, o arquivo
jasperreports-4.7.0.jar. Esse JAR ficará na pasta lib do projeto no Eclipse, vamos
arrastá-lo realizando uma cópia.
Além do JAR principal há mais dependências que estão na pasta lib da distribuição do
JasperReport. Nessa pasta encontramos diversos JARs. Queremos gerar o PDF em nosso
projeto e para isso esses JARs serão necessários: o primeiro é o itext, que o JasperReport
utiliza para gerar PDF. Como nosso relatório também gera um gráfico, utilizaremos o
jfreechart e jcommon. Por último, utilizaremos alguns JARs dos Apache Commons.

Falta adicionar os JARs no classpath do projeto. Selecionando e usando add to buildpath


dentro do Eclipse.

Compilação programática
Com as bibliotecas e com o classpath configurado podemos começar a implementar. Para
compilar o arquivo jrxml usaremos a classe JasperCompileManager. Ela possui vários
métodos estáticos para compilar o XML. Nós utilizaremos o método compileTofile que
recebe o nome do XML. É preciso tratar a exceção checked JRException.

Vejo o código:

public class TesteRelatorio {

public static void main(String[] args) throws SQLException, JRException {

JasperCompileManager.compileReport("gasto_por_mes.jrxml");
}
}

Alterando a linguagem de script


A chamada do método main lança uma exceção, acusando um problema de compilação
relacionada com a linguagem Groovy. É possível embutir scripts de Groovy dentro do
relatório, mas não utilizaremos esse recurso. No relatório utilizaremos apenas a linguagem
Java.

O problema é que o nosso relatório ainda está configurado para utilizar Groovy como
linguagem padrão. Podemos alterar este padrão para a linguagem Java abrindo o arquivo
jrxml no iReport e selecionando o elemento raiz no Report Inspector.

Em nosso caso, abriremos o jrxml diretamente no Eclipse e buscaremos pelo elemento


language. Nesta opção, basta trocar de Groovy para Java. Isso deve ser feito nos dois
arquivos jrxml.

<jasperReport ... name="gasto_por_mes" language="java" pageWidth="572"


pageHeight="752" ...>

Com esta alteração, compilaremos o relatório mais uma vez. Agora temos o arquivo
jasper gerado.
Preenchendo o relatório
Falta agora carregar este arquivo e preencher o relatório com os dados com base na
conexão e os parâmetros da aplicação. Para essa tarefa existe uma classe
JasperFillManager que possui o método fillReport que é sobrecarregado. Utilizaremos
a versão que recebe o nome do arquivo jasper, o mapa de parâmetros e a conexão. Só
falta inicializar o mapa de parâmetros. Criaremos um HashMap sem nenhum elemento, por
enquanto:
public class TesteRelatorio {

public static void main(String[] args) throws SQLException, JRException,


FileNotFoundException {

JasperCompileManager.compileReport("gasto_por_mes.jrxml");

Map<String, Object> parametros = new HashMap<String, Object>();


Connection connexao = new ConnectionFactory().getConnection();

JasperFillManager.fillReport("gasto_por_mes.jasper", parametros,
connexao);

connexao.close();
}
}

O código compila, mas ao executá-lo recebemos uma exceção. O JasperReports acusa a


falta do sub-relatório. É preciso compilar o sub-relatório também.

Alteraremos o nome do arquivo jrxml no código Java e chamaremos novamente o método


main para gerar o arquivo jasper do sub-relatório. Atualizando o projeto, dois arquivos
jasper aparecerão.

Com isso, preencheremos mais uma vez o relatório com o JasperFillManager, mas
primeiro comentaremos a linha que gerou o arquivo jasper, já que não há a necessidade
de recriá-lo.

Trabalhando com o objeto


JasperPrint e várias saídas
Durante a execução nenhuma exceção foi lançada, mas também não vimos nenhum
resultado. Olhando para assinatura do método fillReport(..) percebemos que ele
devolve um objeto do tipo JasperPrint. Este objeto representa o relatório preenchido, mas
é genérico, independente da saída concreta.
Agora só falta exportar o JasperPrint, mas isso é a responsabilidade de outra classe. Por
esta razão existem JRExporters. JRExporter é uma interface e suas implementações
definem a saída concreta. Há implementações para HTML, ODF, RTF, PDF entre várias
outras.

Veja também o link para a documentação:


http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/JRExporter.html

Exportando o relatório para PDF


Em nosso caso, exportaremos para PDF, usando a classe JRPdfExporter. O
JRPdfExporter recebe como parâmetro o objeto JasperPrint (usando o método
setParameter(... , ...)).

Além disso, através do mesmo método, definimos o OutputStream para configurar o nome
do arquivo PDF. Nesse exemplo usamos um FileOutputStream como fluxo de saída e o
arquivo se chamará gasto_por_mes.pdf.

Esse OutputStream também exige o tratamento da exceção FileNotFoundException. Por


último é preciso chamar o método export().

public class TesteRelatorio {

public static void main(String[] args) throws SQLException, JRException,


FileNotFoundException {

JasperCompileManager.compileReport("gasto_por_mes.jrxml");

Map<String, Object> parametros = new HashMap<String, Object>();


Connection connexao = new ConnectionFactory().getConnection();

JasperPrint print = JasperFillManager.fillReport("gasto_por_mes.jasper",


parametros, connexao);

JRExporter exporter = new JRPdfExporter();


exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, new
FileOutputStream("gasto_por_mes.pdf"));
exporter.exportReport();

connexao.close();
}
}
Após a chamada do main e depois de atualizar, aparecerá o PDF gerado na raiz do
projeto. Abrindo o relatório podemos visualizar os dados das contas seguidas pelas
movimentações. Como esperado, as informações encontram-se nas últimas páginas: o
gráfico e o crosstable.

Atividade 1 de 8
Qual é a extensão da definição do relatório (não compilado)?

17/12/2013 08:19

java

xml

jasper

ixml

jrxml

Atividade 2 de 8
Como se chama a classe que compila o arquivo jrxml?

17/12/2013 08:19

ReportCompiler

JrxmlToJasperCompiler

JasperCompiler

JasperCompileManager

CompileJrxml

Atividade 3 de 8
Qual é a extensão do relatório compilado?

17/12/2013 08:19

java

jasper

class

jrxml

bin

Atividade 4 de 8
Qual é a responsabilidade da classe JasperFillManager?

17/12/2013 08:20

Exportar o relatório

Alterar propriedades do relatório

Preencher o relatório com parâmetros e os dados

Compilar o relatório

Atividade 5 de 8
Queremos exportar o relatório para HTML. Dado o código abaixo, qual implementação
deverá ser escolhida no lugar de XXXXX?

Map<String, Object> parametros = new HashMap<String, Object>();


Connection conexao = new ConnectionFactory().getConnection();

JasperPrint print = JasperFillManager.fillReport("financas.jasper",


parametros, conexao);
OutputStream stream = new FileOutputStream("financas.html");

JRExporter exporter = new XXXXX();


exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, stream);
exporter.exportReport();

stream.close();
conexao.close();

false 1104 223 38 17/12/2013 08:20

38
Atividade 6 de 8
Baixe o projeto movimentacoes aqui . Importe-o no Eclipse (File -> Import -> General ->
Existing Project into Workspace -> Select Archive) e verifique se todas as bibliotecas da
pasta lib estão dentro do classpath.

Abra a classe TesteGeraRelatorio do pacote br.com.caelum.financas.relatorio . Ao


executar a classe é lançada uma exceção. Por que isso acontece? Como arrumar?

Atividade 7 de 8
Após a compilação do relatório, na raiz do projeto movimentacoes encontra-se o arquivo
financas.jasper.

Preencha o relatório com a conexão e os parâmetros da aplicação. Depois exporte o


relatório preenchido para PDF.

Atividade 8 de 8
Na classe TesteGeraRelatorio experimente outras saídas como HTML (JRHtmlExporter)
ou XLS (JRXlsExporter).

Explicação

Downloads
Para esta aula é preciso ter instalado Eclipse na versão Java EE. Você pode baixar o
Eclipse no link: http://www.eclipse.org/downloads. Além disso, usaremos o Apache
Tomcat 7 que se encontra no http://tomcat.apache.org. Também temos um projeto
preconfigurado com todas as bibliotecas necessárias disponível: aqui

Caso você tenha dúvidas sobre a instalação do Tomcat verifique a apostila aberta do
treinamento FJ-21.

Refatoração para simplificar a


geração do PDF
Na última aula vimos como um relatório pode ser gerado programaticamente a partir de
sua definição: o arquivo jrxml. Também preenchemos e exportamos o relatório utilizando
código Java.

Foi necessário definir a entrada, o mapa de parâmetros e estabelecer uma conexão com o
banco de dados, tudo como parâmetro do método fillReport(..) da classe
JasperFillManager, que lê e preenche o relatório.

O relatório preenchido é um objeto do tipo JasperPrint, que precisa ser processado por
um JRExporter. Escolhemos JRPdfExporter que transforma o objeto JasperPrint em
PDF.

Nesta aula já temos preparada a classe GeradorRelatorio que encapsula os detalhes de


geração de relatório. Essa classe recebe no construtor a entrada, ou seja, o nome do
arquivo jasper, os parâmetros e a conexão. Além disso, possui um método público
geraPDFParaOutputStream(..) que encapsula classes como JasperFillManager ou
JRPdfExporter.

O uso do GeradorRelatorio simplifica o trabalho. Uma vez estabelecida a entrada


podemos instanciar a classe e passar os parâmetros via construtor. Depois chamamos o
método geraPDFParaOutputStream passando um FileOutputStream.

Introdução a aplicação Web


Neste vídeo mostraremos como gerar o relatório com uma aplicação web. A aplicação
chama-se gastos-web e já possui classes como ConnectionFactory e
GerenciadorRelatorio. Além disso, temos dentro da pasta WEB-INF/lib todas as
bibliotecas necessárias que vimos até agora.

O servlet-container Tomcat, na versão 7, já esta configurado no Eclipse. Para baixar o


Tomcat acesse: http://tomcat.apache.org

Criação da Servlet para gerar o


PDF
Nossa tarefa agora é criar uma página com um formulário para enviar uma requisição e
uma servlet que gera o PDF como resposta. Começaremos com a servlet. Selecionaremos
a pasta src do projeto usando o wizard para criar uma nova classe servlet dentro no
pacote br.com.caelum.relatorio.servlet.

A servlet terá o nome RelatorioServlet e estenderá a classe HttpServlet. Também


alteraremos o mapeamento padrão, usaremos a URL /gastos.

O único método que queremos gerar na servlet é o método doPost(..).

Segue o esboço da servlet:

@WebServlet("/gastos")
public class RelatorioServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {

}
}

A nossa servlet está preparada, mas antes de usar o GeradorRelatorio é preciso copiar o
arquivo jasper do projeto anterior. Para isso criaremos uma pasta jasper dentro da pasta
WEB-INF. Nesta pasta colocaremos os dois relatórios compilados, o principal e o sub-
report.

Voltando para a servlet, também copiamos o código que representa a entrada do relatório,
ou seja, nome do relatório, parâmetros e a conexão. Já fecharemos a conexão. A
chamada do método close() exige um try-catch, pois estamos dentro de uma servlet.
Colocaremos todo o código relacionado com a geração do relatório nesse bloco try-
catch. Dentro do bloco catch lançaremos uma ServletException.

Finalmente podemos usar o GeradorRelatorio chamando o construtor e passando os


parâmetros. Depois usaremos o método geraPDFParaOutputStream(..) que recebe o
fluxo de saída.

Como estamos em um aplicação web, o fluxo de saída é ligado à resposta. Através dela
pegamos o OutputStream, um ServletOutputStream:

response.getOutputStream()

O problema é que o arquivo jasper está dentro da pasta /WEB-INF/jasper. Falta indicar o
caminho até esta pasta. Isso é feito através do ServletRequest que possui o método
getServletContext().getRealPath(..) que recebe o caminho que desejamos acessar.
Passando o caminho a partir da raiz da aplicação web:
/WEB-INF/jasper/gasto_por_mes.jasper .

Segue a Servlet completa:

@WebServlet("/gastos")
public class RelatorioServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doPost(HttpServletRequest request, HttpServletResponse


response) throws ServletException, IOException {

try {
String nome =
request.getServletContext().getRealPath("/WEB-INF/jasper/gasto_por_mes.jasper
");
Connection connection = new ConnectionFactory().getConnection();
Map<String, Object> parametros = new HashMap<String, Object>();
GeradorRelatorio gerador = new GeradorRelatorio(nome, parametros,
connection);
gerador.geraPDFParaOutputStream(response.getOutputStream());

connection.close();
} catch (SQLException e) {
throw new ServletException(e);
}
}
}

Definição do formulário JSP


Como a nossa servlet usa o método doPost(..) é preciso criar um formulário HTML, que
ficará dentro da pasta WebContent com o nome relatorio.jsp.

Dentro da tag body criaremos o formulário que já preparamos antes. Repare o atributo
action que chama a URL da Servlet através do método POST. Também temos um botão
para submeter o formulário.

Segue o formulário HTML:

<html>
<body>

<form action="gastos" method="POST">


<input type="submit" value="Gera PDF" />
</form>

</body>
</html>

Ao subir o Tomcat e ao chamar nossa aplicação no endereço


http://localhost:8080/gastos-web/relatorio.jsp aparece o formulário com o botão.
Submetendo o formulário recebemos o PDF gerado pela Servlet.

Podemos ver na segunda página do relatório que as movimentações foram geradas a


partir de Junho até o mês de Agosto. Aparecem apenas 3 meses de movimentações. O
problema é que em nosso relatório definimos valores padrões para as datas. Para esta
aplicação queremos que o usuário final defina pelo formulário a data inicial e final do
relatório.
Capturando as datas do relatório
pelo formulário
Vamos voltar para o Eclipse e alterar a página JSP. Adicionaremos dois inputs.
Novamente já temos o código preparado. O primeiro input define a data inicial e o
segundo a data final. Repare que o nome dos inputs: data_ini e data_fim:
<html>
<body>

<form action="gastos" method="POST">

Data inicial: <input type="text" name="data_ini"/> <br />

Data final: <input type="text" name="data_fim"/> <br />

<input type="submit" value="Gera PDF" />

</form>
</body>
</html>

Passando parâmetros da
requisição para o relatório
Em nossa servlet leremos esses parâmetros. Voltando para Eclipse e abrindo a classe
RelatorioServlet usaremos o método getParameter(..) do objeto request para receber
o parâmetro data_ini, a mesma coisa para o parâmetro data_fim, copiando a linha
anterior e renomeando as variáveis.
String dataIni = request.getParameter("data_ini");
String dataFim = request.getParameter("data_fim");

Os parâmetros são ainda do tipo String, porém o nosso relatório espera receber as datas
como java.util.Date. É preciso parsear os dois parâmetros usando a classe
SimpleDateFormat. Essa classe recebe um pattern no construtor que define o formato da
data, em nosso caso dd/MM/yyyy. Com o SimpleDateFormat podemos usar o método
parse(dataString) para criar um objeto Date a partir da String.

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");


Date dataInicial = sdf.parse(dataIni);
Date dataFinal = sdf.parse(dataFim);

Ao chamar o método parse(..) o compilador exige um tratamento de exceção. Vamos


adicionar mais um bloco catch para capturar ParseException.

Por último é preciso adicionar os dois objetos Date no mapa que foi passado para a classe
GeradorRelatorio. Chamaremos o método put( .. , .. ) do mapa que recebe dois
argumentos, uma chave e um valor. O valor é o objeto data que criamos pelo
SimpleDateFormat e a chave definda na fase de design do relatório. As chaves se
chamam DATA_INI para a data inicial e DATA_FIM para a data final:

Map<String, Object> parametros = new HashMap<String, Object>();


parametros.put("DATA_INI", dataInicial);
parametros.put("DATA_FIM", dataFinal);
GeradorRelatorio gerador = new GeradorRelatorio(nome, parametros,
connection);

Segue a servlet completo:

@WebServlet("/gastos")
public class RelatorioServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doPost(HttpServletRequest request, HttpServletResponse


response) throws ServletException, IOException {

try {
String nome =
request.getServletContext().getRealPath("/WEB-INF/jasper/gasto_por_mes.jasper
");
Connection connection = new ConnectionFactory().getConnection();

String dataIni = request.getParameter("data_ini");


String dataFim = request.getParameter("data_fim");

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

Date dataInicial = sdf.parse(dataIni);


Date dataFinal = sdf.parse(dataFim);

Map<String, Object> parametros = new HashMap<String, Object>();


parametros.put("DATA_INI", dataInicial);
parametros.put("DATA_FIM", dataFinal);
GeradorRelatorio gerador = new GeradorRelatorio(nome, parametros,
connection);
gerador.geraPDFParaOutputStream(response.getOutputStream());

connection.close();
} catch (SQLException e) {
throw new ServletException(e);
} catch (ParseException e) {
throw new ServletException(e);
}
}
}

Com o formulário definido e a servlet preparados podemos testar a aplicação. Vamos


reiniciar o Tomcat e chamar no navegador a aplicação. No formulário aparecem os dois
inputs onde inserimos as datas, por exemplo 01/01/2012 e 31/12/2012. Gerando o PDF o
relatório aparece no navegador com a primeira movimentação em Janeiro seguida pelos
outros meses até Dezembro.

Atividade 1 de 7
Qual implementação do JRExporter nós utilizamos para transformar um objeto
JasperPrint em PDF?

17/12/2013 08:23

JROdtExporter

JRHtmlExporter

JRPdfExporter


JRXmlExporter

JRTextExporter

Atividade 2 de 7
Como estamos em um aplicação web, o fluxo de saída está ligado à resposta. Como,
através dela, pegamos o OutputStream?

17/12/2013 08:23

response.getWriter()

request.getOutputStream()

response.getOutputStream()

response.getContentType()

Atividade 3 de 7
Como indicamos para a Servlet que o arquivo jasper (gasto_por_mes.jasper) está dentro
da pasta /WEB-INF/jasper?

17/12/2013 08:23

request.getServletContext().getRealPath("/WEB-INF/jasper/gasto_por_mes.jasper")


request.getWriter().getRealPath("/WEB-INF/jasper/gasto_por_mes.jasper")

request.getServletContext("/WEB-INF/jasper/gasto_por_mes.jasper")

request.getContextPath("/WEB-INF/jasper/gasto_por_mes.jasper")

response.getServletContext().getRealPath("/WEB-INF/jasper/
gasto_por_mes.jasper")

Atividade 4 de 7
Porque foi preciso converter os parâmetros (parsing) da aplicação web?

Atividade 5 de 7
No vídeo, o usuário final preenche um formulário para filtrar o relatório pela data inicial e
final. Como foram passados os parâmetros para o relatório jasper?

17/12/2013 08:24

Através da conexão do banco de dados.

Através de um mapa (java.util.Map) que recebe todos os parâmetros da aplicação.

Através de uma lista (java.util.List) que recebe todos os parâmetros da aplicação.

Não é possível passar parâmetros.


Atividade 6 de 7
Baixe o projeto movimentacoes-web aqui. Importe o projeto no Eclipse (Versão Java EE).

É preciso ter instalado o Tomcat 7 no Eclipse. Você pode baixar a versão do Tomcat aqui.
Basta baixar o ZIP e configurar o server no Eclipse. Caso você tenha dúvidas sobre a
instalação do Tomcat verifique a apostila aberta do treinamento FJ-21 aqui (Capítulo 3).

Dentro do Eclipse associe o projeto movimentacoes-web com o server Tomcat. Inicie o


Tomcat e acesse o link: http://localhost:8080/movimentacoes-web/formulario.jsp pelo
navegador.

No navegador deve aparecer o formulário para gerar o relatório de movimentações, mas


falta implementar a servlet para criar o PDF. No Eclipse, abra a classe RelatorioServlet
e complete o código. Na servlet utilize a classe GeradorRelatorio. Cole código da servlet
no campo abaixo:

Explicação

Qualquer entrada de dados para


o relatório
Vimos nas vídeo aulas anteriores como usar o iReport, interface gráfica para criar a
definição do relatório que é salva dentro de um arquivo jrxml. Esse arquivo XML foi
compilado através do iReport ou programaticamente para um arquivo jasper. Depois
preenchemos este arquivo com os parâmetros da aplicação e a conexão com o banco,
resultando no objeto JasperPrint, que exportamos para PDF pelo JRPdfExporter.

Ainda há um pequeno problema nessa abordagem. Estamos amarrando o JasperPrint ao


banco de dados pois passamos a conexão ao método fillReport(..). Como existem
várias saídas para o relatório, também podem existir várias entradas. Alguns exemplos
disso são fontes de dados, como XML, JSON, CSV e muitas outras. Não queremos nos
acoplar ao banco de dados. Queremos maior flexibilidade. Para isso existe a interface
JRDataSource, que representa uma fonte de dados que abstrai da entrada concreta
utilizada.

Introdução ao projeto
Para esta aula, utilizaremos o relatório que foi criado na primeira aula, aquele que lista
movimentações. Nesse relatório configuramos a conexão com o banco MySQL
executando uma simples query que selecionava todos os dados da tabela movimentacoes.

No Eclipse, já temos um projeto Java preparado que se chama movimentacoes. Dentro da


pasta src, temos uma classe para gerar relatório. Na raiz do projeto encontra-se a
definição do relatório, o arquivo financas.jrxml. Nele verificaremos se a linguagem
padrão é Java.
Primeiro, analisamos a classe TesteGeraRelatorio, compilamos o arquivo .jrxml,
definimos a entrada da aplicação, preenchemos o relatório e exportamos para PDF.

public class TesteGeraRelatorio {


public static void main(String[] args) throws SQLException, JRException,
FileNotFoundException {

JasperCompileManager.compileReportToFile("financas.jrxml");

Map<String, Object> parametros = new HashMap<String, Object>();


Connection connexao = new ConnectionFactory().getConnection();

JasperPrint print = JasperFillManager.fillReport("financas.jasper",


parametros, conexao);

JRExporter exporter = new JRPdfExporter();


exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, new
FileOutputStream("financas.pdf"));
exporter.exportReport();

connexao.close();
}
}

Ao chamar o método main e atualizar o projeto, o arquivo financas.jasper e a saída


financas.pdf são criados. Abriremos mais uma vez o PDF para ver o resultado. Todas as
movimentações foram listadas. Para evitar a recompilação do relatório, comentaremos no
código a linha responsável.

Desacoplando os dados e a
interface JRDataSource
Ao investigar o método fillReport(..), podemos ver que foi passado a conexão.
Justamente nessa linha, amarramos o relatório ao banco de dados. Ao visualizar as
versões do método fillReport(..) no Eclipse, percebemos que ele é sobrecarregado.
Há uma versão que recebe um objeto do tipo JRDataSource no lugar da conexão. Essa
JRDataSource é a abstração da fonte de dados.

Para conhecer melhor esta classe, vamos procurar pelo seu Javadoc na Internet:

http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/JRDataSource.html
Ao seguir o link da API, estamos vendo todas as classes e packages disponíveis.
Procuraremos pelo JRDataSource para chegar em seu javadoc. Na documentação,
podemos ver que JRDataSource é uma interface que declara apenas dois métodos:
getFieldValue(..) e next() .

O JasperReport já disponibiliza várias implementações dessa interface, por exemplo, a


JRXmlDataSource para trabalhar com arquivos XML como fonte de dados,
JRCsvDataSource para trabalhar com CSV ou JRBeanCollectionDataSource para usar a
lista de java beans como datasource.

Usando uma lista como


datasource
Ao investigar o Javadoc da classe JRBeanCollectionDataSource, podemos ver que ela
recebe uma coleção de beans. Vamos voltar ao Eclipse. A primeira coisa que faremos é
tirar a conexão da método fillReport(..). Vamos passar uma dataSource. Como já
falamos, a dataSource será do tipo JRDataSource e a implementação é do tipo
JRBeanCollectionDataSource, que recebe no construtor uma lista de movimentações.

Vamos declarar a lista acima e carregar as movimentações usando o DAO que já está
preparado no projeto. A classe MovimentacaoDAO possui o método todos() que devolve
todas as movimentações do banco de dados.

Connection connexao = new ConnectionFactory().getConnection();


List<Movimentacao> movimentacoes = new MovimentacaoDAO(connexao).todos();
JRDataSource dataSource = new JRBeanCollectionDataSource(movimentacoes);

JasperPrint print = JasperFillManager.fillReport("financas.jasper",


parametros, dataSource);

Antes de testar, vamos verificar o método todos() do DAO. Podemos ver o SQL e o uso
do PreparedStatement para executar o SQL. Depois, usaremos o resultado da query
(ResultSet) para criar em cada iteração uma nova movimentação. As movimentações
ficam guardadas em uma lista que representa o retorno do método todos().

Geração do relatório e as
primeiras incompatibilidades
Vamos fechar a classe MovimentacaoDAO e executar a classe TestGeraRelatorio para
testar a DataSource. Após a execução, é gerada uma exceção acusando um problema de
cast entre GergorianCalendar e java.sql.Date.

O problema está no arquivo jrxml. O field data foi declarado como java.sql.Date. Essa
definição ocorreu quando definimos o relatório com iReport. Usamos uma query SQL e o
iReport associou automaticamente tipos com campos da query. O mais correto é definir os
tipos, independentemente da fonte de dados. Ou seja, para a data, usando a classe
java.util.Date.
Vamos rodar novamente a classe Teste, só descomentando a linha que compila o jrxml,
pois alteramos o relatório. Novamente foi gerada uma exceção de cast, pois a
incompatibilidade entre os tipos GregorianCalendar e java.util.Date continua.

Adaptar o modelo para atender o


relatório
Uma opção possível é ajustar o arquivo jrxml para trabalhar com o tipo
java.util.Calendar, alterando a classe e as expressões utilizadas no relatório. Outra
possibilidade é ajustar o modelo. A classe Movimentacao para não fornecer a data do tipo
java.util.Calendar e sim java.util.Date. Essa alteração se reflete no método
getData() da classe, que deve devolver um Date chamando o método getTime() da
classe Calendar. Esta forma faz com que o nosso modelo forneça os tipos corretos para o
relatório funcionar.

Após outro teste, recebemos mais uma exceção, agora não mais relacionada com a data,
mas com a enumeração TipoMovimentacao que é incompatível com o tipo
java.lang.String.

Ao verificarmos o relatório podemos ver que o campo tipoMovimentacao realmente foi


mapeado para a classe String. No outro lado, na classe Movimentacao, há o método
getTipoMovimentacao() que devolve uma Enum. Alteramos o método para devolver uma
String usando um método name() da enumeração.

public String getTipoMovimentacao() {


return tipoMovimentacao.name();
}

Após executar, o PDF foi finalmente gerado.

Desacoplar o modelo do relatório


Conseguimos usar um outro DataSource para abstrair a fonte de dados utilizando uma lista
de beans para alimentar o relatório. Percebemos que alguns ajustes foram necessários. O
problema era que os tipos do relatório não combinavam com os tipos do nosso modelo.
Duas soluções eram possíveis: alterar a definição do relatório ou adaptar o modelo. Em
nosso caso, a classe Movimentacao.

Isso gera um acoplamento entre o relatório e o modelo. Queremos que os dois lados
evoluam separadamente. Ou seja, mudanças no relatório devem não influenciar o modelo
e vice-versa. Os ajustes realizados no modelo foram apenas um exemplo e não eram
necessários.

A ideia é continuar com a JRBeanCollectionDataSource que recebe uma lista de beans,


mas esses beans não serão mais objetos da classe Movimentacao. Vamos desfazer as
alterações na classe, devolvendo uma enumeração no método getTipoMovimentacao() e
no método getData(). Daremos uma data do tipo java.util.Calendar.
Para fornecer os dados corretos, criaremos uma nova lista com elementos do tipo
MovimentacaoRelatorio. Essa classe auxiliar é específica para o relatório, com a
responsabilidade de fornecer os dados com os tipos corretos.

Vamos criar a classe pelo Eclipse definindo o atributo Movimentacao. Vamos gerar também
um construtor que recebe a movimentação. Segue o primeiro esboço da classe:

public class MovimentacaoRelatorio {

private Movimentacao movimentacao;

public MovimentacaoRelatorio(Movimentacao movimentacao) {


this.movimentacao = movimentacao;
}

Dentro da classe MovimentacaoRelatorio, vamos delegar os getters, novamente


utilizando o Eclipse para gerar este código. Os método gerados são os que o relatório
utilizará. Ou seja, getData(), getDescricao(), getId(), getTipoMovimentacao() e
getValor(). Ao confirmar, o Eclipse criará todos os getters selecionados na classe.

As mudanças necessárias relacionadas com os tipos serão feitas nesta classe auxiliar e
não no modelo da aplicação. Sendo assim, alteraremos primeiro o retorno do método
getData(), novamente utilizando java.util.Date com o método getTime(). Vamos
mudar o método getTipoMovimentacao(), que retorna uma String utilizando o método
name() da enumeração.

Ao voltar à classe TesteGeraRelatorio, falta inicializar a listaRelatorio e depois copiar


os elementos da lista de movimentações para a lista nova. Utilizaremos um laço em cada
iteração, criando um objeto MovimentacaoRelatorio que guardamos na listaRelatorio.
Passaremos esta lista para o DataSource.

List<Movimentacao> movimentacoes = new MovimentacaoDAO(connexao).todos();


List<MovimentacaoRelatorio> listaRelatorio= new
ArrayList<MovimentacaoRelatorio>();

for (Movimentacao movimentacao : movimentacoes) {


listaRelatorio.add(new MovimentacaoRelatorio(movimentacao));
}

JRDataSource dataSource = new JRBeanCollectionDataSource(listaRelatorio);

Antes de testarmos novamente, comentaremos a linha que compila o arquivo jrxml. Após
a execução e atualizando o projeto, foi gerado o PDF. Vamos abrí-lo. Todos os dados
aparecem, como esperado.
Resumo da aula
Resumindo, vimos como podemos abstrair a fonte de dados usando a interface
JRDataSource. A implementação concreta que usamos foi a
JRBeanCollectionDataSource. Com ela podemos utilizar qualquer coleção de Java Beans
como fonte de dados. O objetivo era usar a lista de movimentações para o nosso relatório.
Carregamos a lista pelo DAO e passamos ela para a DataSource. Percebemos que era
preciso adaptar o relatório ou a classe Movimentação. Isso gerou um acoplamento que
resolvemos através de uma classe auxiliar MovimentacaoRelatorio, e que também serviu
como um adaptador entre o nosso modelo e o relatório.

Atividade 1 de 7
Como podemos abstrair com JasperReports a fonte de dados da entrada concreta
utilizada?

17/12/2013 08:25

Através da interface JRDataSource

Através da conexção JDBC

Através do mapa java.util.Map

Através da entrada java.io.InputStream

Atividade 2 de 7
Qual é o argumento que a classe JRBeanCollectionDataSource recebe no construtor?

Para verificar você pode utilizar o javadoc da classe: aqui

17/12/2013 08:25

java.util.Set

java.util.Map

java.util.Collection

java.sql.Connection

java.util.List

Atividade 3 de 7
Qual implementação da interface JRDataSource podemos utilizar para ler, por exemplo, um
arquivo CSV (ComaSeparatedValues)?

Veja também o seu javadoc na Internet: aqui

17/12/2013 08:25

JRXmlDataSource

JRBeanCollectionDataSource

JRXlsDataSource

JRCsvDataSource

Atividade 4 de 7
Por que não devemos utilizar o metodo fillReport recebendo a conexão como
parâmetro? Como podemos contornar esse problema?

(quer uma dica?) (ver próxima dica)

 Podemos usar uma outra versão do metodo fillReport

Atividade 5 de 7
Podemos usar uma implementação concreta para receber qualquer coleção de Java Bean
como fonte de dados. Por exemplo, se quisermos usar uma lista de movimentações em
nosso relatório. Que implementação é essa?

17/12/2013 08:26

JRBeanCollectionDataSource

JRResultSetDataSource

JRAbstractBeanDataSource

JRBeanArrayDataSource

Atividade 6 de 7
Baixe o projeto movimentacoes-csv aqui. Extraia e importe o projeto no Eclipse.

Dentro da pasta src no pacote br.com.caelum.relatorio.teste tem uma classe


TesteGeraRelatorioComCSVDataSource.
A classe compila e executa sem problemas, mas o PDF é gerado vazio. Analisando o
código percebemos que foi definida uma variável dataSource nula. Initialize a dataSource
para ler o arquivo movimentacoes.csv que se encontra na raiz do projeto.

Veja um exemplo como utilizar a dataSource aqui.

Dica: É preciso definir os nomes das colunas e o pattern da data.

(quer uma dica?) (ver próxima dica)

 dataSource.setDatePattern(

Atividade 7 de 7
No projeto movimentacoes-csv do exercício anterior se encontra a classe
GeradorRelatorio que recebe no construtor a conexão JDBC.

Refatore a classe GeradorRelatorio para trabalhar com qualquer datasource, não use mais
a conexão e sim a interface JRDataSource.

Você também pode gostar

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy