Parte 1 – Parte 2 – Parte 3 – Parte 4 – Parte 5
Olá! Hoje vamos aprender a trabalhar com subrelatórios no JasperReports, mas antes de começar quero explicar algumas coisas. Nos últimos posts, eu tenho tentado formatar os termos em inglês em itálico e colocar logo em seguida a tradução. Eu vou parar de fazer isso. Primeiro, pq os termos são simples, e qualquer pessoa que trabalhe com informática tem mais que obrigação de saber. Segundo, gasto muito tempo formatando cada parágrafo, revisando se está tudo ok, etc. Então, para agilizar o processo, estou deixando de lado essa prática. Tenho também tratado os leitores cada hora de um jeito. Uma hora escrevo na primeira pessoa do singular, na outra, escrevo na terceira do plural. Vou tentar manter a mesma narração, mas se eu cometer algum deslize, não se encomodem ok? Então, vamos começar!
Se você já tentou trabalhar com subrelatórios, provavelmente teve algumas frustrações até conseguir fazer funcionar. Se você nunca trabalhou, hoje vai aprender! Trabalhar com subrelatórios não é difícil, o problema é entender como as coisas funcionam, mas antes de falar disso, vamos nos situar no tema. O que é um subrelatório? Como o próprio nome diz é um relatório que fica dentro de um outro relatório, ou seja, é uma parte de um relatório maior, mais geral. Vamos entender por meio de um exemplo. Para isso, abra o diagrama da base de dados sakila clicando aqui e imagine a seguinte situação: você precisa criar um relatório, onde serão exibidos os dados de todos os clientes e de todos os filmes que cada um alugou. O layout do relatório teria que ficar mais ou menos assim:
Como criar um relatório com esse layout? Usando subrelatórios! A parte mais externa do layout representa o arquivo de relatório mais geral, onde serão listados os clientes e onde será inserido o subrelatório. O subrelatório, destacado em azul, será um outro arquivo de relatório que será utilizado dentro do relatório mais geral. Confuso? Calma, calma, logo vocês vão enteder. Antes disso, um pouquinho mais de teoria.
O funcionamento de um subrelatório é igual ao de um relatório normal, sendo que existe apenas uma diferença e é justamente aqui que as pessoas se confundem. Os parâmetros de um subrelatório não são enviados diretamente do código Java como é feito em um relatório normal. No caso dos subrelatórios, os parâmetros são enviados pelo relatório que os contém, para então serem passados ao subrelatório. Então, caso você passe um parâmetro para o relatório que deve ser usado apenas no subrelatório, o seu relatório vai ter que ter o “mesmo” parâmetro e você vai ter que criar essa ponte entre o relatório principal e o subrelatório. Veja a Figura abaixo.
Em vermelho é destacada a transmissão dos parâmetros a partir da aplicação em Java para o relatório. Esses parâmetros são enviados usando o mapa da parâmetros lembram? Em laranja é destacada a transmissão dos parâmetros para o subrelatório a partir do relatório. Veja então que o relatório vai servir de ponte entre os parâmetros desejados, além de poder criar novos parâmetros e os enviar para o subrelatório. Outro detalhe é que podem haver diversos níveis de relatórios, ou seja, um subrelatório pode enviar parâmetros para um subsubrelatório, um subsubrelatório pode enviar parâmetros para um subsubsubrelatório, e assim por diante.
Finalmente! Vamos à prática! Abra o NetBeans e o projeto que estamos usando (TutorialRelatorios). Se você não acompanhou a parte anterior do tutorial, ou mesmo que tenha acompanhado e não tenha feito o exemplo, você pode baixar a versão do projeto (finalizada na Parte 2) clicando aqui. Na pasta de definições de relatórios que criamos, crie um novo Empty Report e dê o nome de LocacoesPorClientes. O arquivo LocacoesPorClientes.jrxml vai ser criado. Caso ele não abra automaticamente no editor, clique duas vezes para ser carregado no iReport.
Com o arquivo aberto, vamos primeramente criar um relatório simples, que lista os clientes a partir de uma pesquisa pelo nome. A query deste relatório vai ser um pouco mais complexa que a do relatório “ClientesPorNome”, criado na Parte 2 do tutorial, pois nela iremos obter outros dados do cliente que não estão na tabela customer. Não se esqueça de escolher o datasource correto, o “Sakila – JDBC” ok? Crie também um parâmetro, do tipo String, com o nome de “nomeCliente”. Segue então a query que deve ser inserida no relatório:
SELECT c.customer_id idCliente, c.first_name nome, c.last_name sobrenome, c.email email, a.address endereco, a.phone telefone, ci.city nomeCidade, co.country nomePais FROM customer c, address a, city ci, country co WHERE /* junções */ c.address_id = a.address_id AND a.city_id = ci.city_id AND ci.country_id = co.country_id AND /* restrições */ c.first_name LIKE $P{nomeCliente} ORDER BY c.first_name;
Ao inserir a query, o iReport vai carregar os campos retornados por ela. Ao clicar em OK, os campos carregados serão criados na definição do relatório. Os fields lembram? Expanda então o nó Fields do Report Inspector e arraste e organize esses campos na banda Detail do relatório. Veja como ficou o meu.
Note que coloquei campos estáticos na banda Detail, tirei as bandas Column Header, Column Footer e Summary. Criei um parâmetro chamado “nomeUsuario” para mostrar no cabeçalho da página o nome do usuário do “sistema” que gerou o relatório. Outra coisa que fiz foi colocar a data e hora que o relatório foi gerado na banda Page Header. Note que para o uso da data e do formato, foi usado um campo de texto dinâmico, com o tipo java.util.Date e a propriedade pattern alterada para “dd/MM/yyyy’, às’ HH:mm’hs'” (sem as aspas). Note também que o valor deste campo é gerado a partir de um código Java! Segue o fonte em XML do relatório. Basta copiar e colar no seu relatório (usando o botão XML).
LocacoesPorClientes.jrxml
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="report name" pageWidth="595" pageHeight="842" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <property name="ireport.zoom" value="1.0"/> <property name="ireport.x" value="0"/> <property name="ireport.y" value="0"/> <parameter name="nomeCliente" class="java.lang.String"/> <parameter name="nomeUsuario" class="java.lang.String"/> <queryString> <![CDATA[SELECT c.customer_id idCliente, c.first_name nome, c.last_name sobrenome, c.email email, a.address endereco, a.phone telefone, ci.city nomeCidade, co.country nomePais FROM customer c, address a, city ci, country co WHERE /* junções */ c.address_id = a.address_id AND a.city_id = ci.city_id AND ci.country_id = co.country_id AND /* restrições */ c.first_name LIKE $P{nomeCliente} ORDER BY c.first_name;]]> </queryString> <field name="idCliente" class="java.lang.Integer"/> <field name="nome" class="java.lang.String"/> <field name="sobrenome" class="java.lang.String"/> <field name="email" class="java.lang.String"/> <field name="endereco" class="java.lang.String"/> <field name="telefone" class="java.lang.String"/> <field name="nomeCidade" class="java.lang.String"/> <field name="nomePais" class="java.lang.String"/> <background> <band splitType="Stretch"/> </background> <title> <band height="75" splitType="Stretch"> <staticText> <reportElement x="0" y="18" width="555" height="40"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="25" isBold="true"/> </textElement> <text><![CDATA[Locações por Clientes]]></text> </staticText> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <line> <reportElement x="0" y="74" width="555" height="1"/> </line> </band> </title> <pageHeader> <band height="21" splitType="Stretch"> <staticText> <reportElement x="-1" y="0" width="51" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Usuário:]]></text> </staticText> <textField> <reportElement x="53" y="0" width="150" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$P{nomeUsuario}]]></textFieldExpression> </textField> <staticText> <reportElement x="360" y="0" width="68" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Gerado em:]]></text> </staticText> <textField pattern="dd/MM/yyyy', às' HH:mm'hs'"> <reportElement x="433" y="0" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.util.Date"><![CDATA[new Date()]]></textFieldExpression> </textField> </band> </pageHeader> <detail> <band height="110" splitType="Stretch"> <staticText> <reportElement x="0" y="3" width="50" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Nome:]]></text> </staticText> <textField> <reportElement x="0" y="23" width="99" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nome}]]></textFieldExpression> </textField> <staticText> <reportElement x="103" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Sobrenome:]]></text> </staticText> <textField> <reportElement x="103" y="23" width="136" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{sobrenome}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[E-mail:]]></text> </staticText> <textField> <reportElement x="242" y="23" width="228" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{email}]]></textFieldExpression> </textField> <staticText> <reportElement x="0" y="47" width="59" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Endereço:]]></text> </staticText> <textField> <reportElement x="62" y="47" width="177" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{endereco}]]></textFieldExpression> </textField> <staticText> <reportElement x="473" y="3" width="82" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Telefone:]]></text> </staticText> <textField> <reportElement x="473" y="23" width="82" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{telefone}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="47" width="42" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Cidade:]]></text> </staticText> <textField> <reportElement x="287" y="47" width="106" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomeCidade}]]></textFieldExpression> </textField> <staticText> <reportElement x="397" y="47" width="31" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[País:]]></text> </staticText> <textField> <reportElement x="433" y="47" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomePais}]]></textFieldExpression> </textField> <staticText> <reportElement x="167" y="82" width="226" height="20"/> <textElement textAlignment="Center" verticalAlignment="Middle" rotation="None"> <font size="12" isBold="true"/> </textElement> <text><![CDATA[O Subrelatório vai vir aqui....]]></text> </staticText> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> </band> </detail> <pageFooter> <band height="22" splitType="Stretch"> <textField> <reportElement x="455" y="2" width="100" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Integer"><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> </band> </pageFooter> </jasperReport>
Depois de colar, volte para o Designer e verifique o que foi feito em cada parte. Após atualizar o seu relatório, teste-o. O iReport vai pedir dois parâmetros, o nomeCliente que vai ser usado na query e o nomeUsuario que vai ser usado no pageHeader. Note que coloquei um campo de texto estático na banda detail, mostrando onde vai ficar o subrealtório. Vamos criá-lo então. Primeiro, remova o campo de texto estático que tem o valor “O Subrelatório vai vir aqui…” e aumente a banda detail na altura cerca de 120 pixels (depois iremos deixar do tamanho correto). Na paleta de componentes, procure por Subreport. Arraste m subreport para a banda Detail. Assim que arrastar e soltar, o assistente de criação de subrelatórios irá abrir. No primeiro passo, escolha “Create a new report” e clique em Next. Veja a Figura abaixo.
No segundo passo, escolha o layout como Blank A4 e clique em Next. Veja a Figura abaixo.
No terceiro passo, ele vai pedir para inserir uma query. Iremos colocar uma query provisória, só para poder continuar o assistente. Depois iremos mudá-la. Coloque “SELECT * FROM country” (sem as aspas) e clique em Next. Veja a Figura abaixo.
No quarto passo, ele vai perguntar os campos que queremos usar. Não adicione nenhum, pois não vamos usá-los, pois essa não é a query que queremos lembram? Veja a Figura abaixo.
No quinto passo, o assistente pergunta os grupos que serão usados. Nós não usaremos grupos, então, da mesma forma que fizemos no passo anterior, clique em Next sem fazer nada. Veja a Figura abaixo.
No próximo passo, configuramos o nome do arquivo de relatório que vai ser gerado (Report Name), onde ele vai ser armazenado e como ele vai ser obtido no relatório principal. Sendo assim, em Report Name insira “LocacoesPorClientes_Locacoes” (sem as aspas). Não mexa em Location, pq já deve estar apontanto para o diretório do relatório principal. Abaixo, escolha “Store the directory name in a parameter”. Isso vai ser útil depois, para informarmos onde está o subrelatório. Feito isso, clique em Next. Veja a Figura abaixo.
No sétimo e último passo é perguntado como os dados do subrelatório serão obtidos. Marque a opção “Use the same connection used to fill the master report”, ou seja, vamos usar o mesmo objeto Connection passado para executar a query do relatório principal. Clique em Finish. Veja a Figura abaixo.
Ao clicar em Finish, o novo arquivo de relatório será criado e aberto. Mas ainda não vamos mexer nele. Volte ao relatório principal. Você vai perceber que foi inserida uma caixa cinza no relatório. Essa caixa indica onde o subrelatório vai ser inserido. Note então que para cada cliente, teremos um subrelatório renderizado, afinal, estamos na banda Detail não é mesmo? Expanda a caixa na largura, para ocupar quase a totalidade do relatório e altere a largura da banda detail acomodar a caixa do subrealtório. Veja a Figura abaixo.
Ainda não teste o relatório! Como estamos obtendo todos os países para cada registro de cliente obtido, o iReport pode travar. Salve o relatório principal e vamos agora para o arquivo do subrelatório. Caso queria, segue o XML do relatório principal.
LocacoesPorClientes.jrxml
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="report name" pageWidth="595" pageHeight="842" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <property name="ireport.zoom" value="1.0"/> <property name="ireport.x" value="0"/> <property name="ireport.y" value="0"/> <parameter name="nomeCliente" class="java.lang.String"/> <parameter name="nomeUsuario" class="java.lang.String"/> <parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false"> <defaultValueExpression><![CDATA["C:\\Users\\David\\Documents\\Blog\\tutoriais\\TutorialRelatorios\\relatorios\\"]]></defaultValueExpression> </parameter> <queryString> <![CDATA[SELECT c.customer_id idCliente, c.first_name nome, c.last_name sobrenome, c.email email, a.address endereco, a.phone telefone, ci.city nomeCidade, co.country nomePais FROM customer c, address a, city ci, country co WHERE /* junções */ c.address_id = a.address_id AND a.city_id = ci.city_id AND ci.country_id = co.country_id AND /* restrições */ c.first_name LIKE $P{nomeCliente} ORDER BY c.first_name;]]> </queryString> <field name="idCliente" class="java.lang.Integer"/> <field name="nome" class="java.lang.String"/> <field name="sobrenome" class="java.lang.String"/> <field name="email" class="java.lang.String"/> <field name="endereco" class="java.lang.String"/> <field name="telefone" class="java.lang.String"/> <field name="nomeCidade" class="java.lang.String"/> <field name="nomePais" class="java.lang.String"/> <background> <band splitType="Stretch"/> </background> <title> <band height="75" splitType="Stretch"> <staticText> <reportElement x="0" y="18" width="555" height="40"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="25" isBold="true"/> </textElement> <text><![CDATA[Locações por Clientes]]></text> </staticText> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <line> <reportElement x="0" y="74" width="555" height="1"/> </line> </band> </title> <pageHeader> <band height="21" splitType="Stretch"> <staticText> <reportElement x="-1" y="0" width="51" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Usuário:]]></text> </staticText> <textField> <reportElement x="53" y="0" width="150" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$P{nomeUsuario}]]></textFieldExpression> </textField> <staticText> <reportElement x="360" y="0" width="68" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Gerado em:]]></text> </staticText> <textField pattern="dd/MM/yyyy', às' HH:mm'hs'"> <reportElement x="433" y="0" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.util.Date"><![CDATA[new Date()]]></textFieldExpression> </textField> </band> </pageHeader> <detail> <band height="175" splitType="Stretch"> <staticText> <reportElement x="0" y="3" width="50" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Nome:]]></text> </staticText> <textField> <reportElement x="0" y="23" width="99" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nome}]]></textFieldExpression> </textField> <staticText> <reportElement x="103" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Sobrenome:]]></text> </staticText> <textField> <reportElement x="103" y="23" width="136" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{sobrenome}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[E-mail:]]></text> </staticText> <textField> <reportElement x="242" y="23" width="228" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{email}]]></textFieldExpression> </textField> <staticText> <reportElement x="0" y="47" width="59" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Endereço:]]></text> </staticText> <textField> <reportElement x="62" y="47" width="177" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{endereco}]]></textFieldExpression> </textField> <staticText> <reportElement x="473" y="3" width="82" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Telefone:]]></text> </staticText> <textField> <reportElement x="473" y="23" width="82" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{telefone}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="47" width="42" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Cidade:]]></text> </staticText> <textField> <reportElement x="287" y="47" width="106" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomeCidade}]]></textFieldExpression> </textField> <staticText> <reportElement x="397" y="47" width="31" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[País:]]></text> </staticText> <textField> <reportElement x="433" y="47" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomePais}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <subreport> <reportElement x="7" y="71" width="544" height="100"/> <connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression> <subreportExpression class="java.lang.String"><![CDATA[$P{SUBREPORT_DIR} + "LocacoesPorClientes_Locacoes.jasper"]]></subreportExpression> </subreport> </band> </detail> <pageFooter> <band height="22" splitType="Stretch"> <textField> <reportElement x="455" y="2" width="100" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Integer"><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> </band> </pageFooter> </jasperReport>
A primeira coisa que vamos fazer no arquivo do subrelatório é excluir todas as bandas, exceto a Detail e a Column Header. Vamos agora criar um parâmetro chamado “idCliente”, que vai ser usado na nossa query para que possamos obter os filmes de um determinado cliente. O tipo deve deve ser Integer. Vamos agora editar a query do relatório, onde vamos obter o nome e o ano do filme alugado, além da data de devolução, sendo que iremos mostrar apenas os filmes que já foram alugados, ou seja, com data de devolução diferente de NULL. Teremos que fazer junções em algumas tabelas para podermos obter os filmes alugados por um determinado cliente. A query vai ficar assim:
SELECT f.title titulo, f.release_year anoLancamento, r.return_date dataDevolucao FROM customer c, rental r, inventory i, film f WHERE /* junções */ r.customer_id = c.customer_id AND r.inventory_id = i.inventory_id AND i.film_id = f.film_id AND /* restrições */ c.customer_id LIKE $P{idCliente} AND r.return_date IS NOT NULL ORDER BY r.return_date, f.title;
Ao clicar em OK, o iReport vai gerar os campos para podermos utilizar no subrelatório. Organize então os campos da mesma forma que mostrado na Figura abaixo.
Note que diminui a largura da página para 6,5 polegadas (6.5 inches). Para fazer isso, no Report Inspector, clique com o botão direito no nó raiz (deve estar com o nome do arquivo de relatório) e vá em Page Format (primeira opção) e altere a largura (Width) para 6.5 polegadas e clique em OK. Segue o código XML do subrelatório.
LocacoesPorClientes_Locacoes.jrxml
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="LocacoesPorClientes_Locacoes" language="groovy" pageWidth="468" pageHeight="802" columnWidth="468" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0"> <property name="ireport.zoom" value="1.0"/> <property name="ireport.x" value="0"/> <property name="ireport.y" value="0"/> <parameter name="idCliente" class="java.lang.Integer"/> <queryString> <![CDATA[SELECT f.title titulo, f.release_year anoLancamento, r.return_date dataDevolucao FROM customer c, rental r, inventory i, film f WHERE /* junções */ r.customer_id = c.customer_id AND r.inventory_id = i.inventory_id AND i.film_id = f.film_id AND /* restrições */ c.customer_id LIKE $P{idCliente} AND r.return_date IS NOT NULL ORDER BY r.return_date, f.title;]]> </queryString> <field name="titulo" class="java.lang.String"/> <field name="anoLancamento" class="java.sql.Date"/> <field name="dataDevolucao" class="java.sql.Timestamp"/> <background> <band splitType="Stretch"/> </background> <columnHeader> <band height="25"> <staticText> <reportElement x="0" y="0" width="100" height="20"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Devolvido em]]></text> </staticText> <staticText> <reportElement x="103" y="0" width="47" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Título]]></text> </staticText> <staticText> <reportElement x="326" y="0" width="117" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Ano de Lançamento]]></text> </staticText> <line> <reportElement x="0" y="24" width="468" height="1"/> </line> </band> </columnHeader> <detail> <band height="21" splitType="Stretch"> <textField pattern="dd/MM/yyyy"> <reportElement x="0" y="1" width="100" height="20"/> <textElement textAlignment="Center" verticalAlignment="Middle"/> <textFieldExpression class="java.sql.Timestamp"><![CDATA[$F{dataDevolucao}]]></textFieldExpression> </textField> <textField> <reportElement x="103" y="1" width="219" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{titulo}]]></textFieldExpression> </textField> <textField pattern="yyyy"> <reportElement x="326" y="1" width="117" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.util.Date"><![CDATA[$F{anoLancamento}]]></textFieldExpression> </textField> </band> </detail> </jasperReport>
Dê um preview no subreport, inserindo o valor “1” (sem as aspas) para o parâmetro idCliente. O preview deve ser parecido com o mostrado na Figura abaixo.
Engraçado notar que tem filmes que foram alugados pelo Cliente “1” antes de terem sido lançados 😀 Enfim, estamos quase lá. Falta agora nós fazermos os dois relatórios funcionarem juntos. Lembram que falei que os parâmetros do subrelatório teriam de ser enviados pelo relatório principal? No nosso caso, o nosso subrelatório espera pelo parâmetro “idCliente” ($P{idCliente}) para executar sua query. Então precisamos fazer com que o relatório principal passe este valor, que está sendo guardado do campo idCliente ($F{idCliente}) que é obtido na query do relatório principal.
Para isso, vá no relatório principal e selecione a caixa que vai conter o subrelatório. Ao selecioná-la, procure pela propriedade Parameters no painel de propriedades. O valor vai estar definido como “No parameter defined”. Clique no pequeno botão a direita e a janela mostrada na Figura abaixo vai ser exibida.
Esta janela é utilizada para criar um parâmetro de passagem (eu que inventei esse nome de “parâmetro de passagem”), que deve ter o mesmo nome do parâmetro esperado pelo subrelatório. Os parâmetros de passagem ficam na coluna destacada em roxo da tabela. O valor desse parâmetro é gerado pela expressão que for definida (coluna destacada em verde). Para criar o novo parâmetro de passagem, clique no botão Add. Ao clicar no botão, a janela mostrada na Figura abaixo é mostrada.
Preencha o campo “Subreport parameter name” com o valor idCliente (nome do parâmetro do subrelatório) e preencha o campo “Value expression” com o valor $F{idCliente}, ou seja, o campo idCliente da query do relatório principal e clique em OK. Veja a Figura abaixo.
Note que você pode usar o editor de expressões (Expression editor) clicando no botão destacado em laranja. Entendeu o que fizemos? Amarramos o parâmetro idCliente do subrelatório com o valor que vai ser inserido no campo idCliente ($F{idCliente}), ou seja, a cada vez que o subrelatório for chamado (para cada cliente) o valor do parâmetro idCliente vai ser configurado com o valor do campo idCliente. Note que o valor do parâmetro do subrelatório tem que ser do mesmo tipo que o valor gerado pela expressão de valor (value expression). É nesta mesma janela que você vai amarrar todos os parâmetros do subrelatório com valores gerados no relatório ou passados para ele. Por exemplo, o subrelatório tem um parâmetro chamado “paramSub1” e o valor deste parâmetro é passado ao relatório principal no parâmetro chamado “paramPrin1”. Então você teria que amarrar paramSub1 (coluna name, em verde) com a expressão $P{paramPrin1} (coluna expression, em roxo) entendeu? É como se estivéssemos chamando um método, passando parâmetros para ele. Segue então o código XML do relatório principal até o momento.
LocacoesPorClientes.jrxml
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="report name" pageWidth="595" pageHeight="842" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <property name="ireport.zoom" value="1.0"/> <property name="ireport.x" value="0"/> <property name="ireport.y" value="0"/> <parameter name="nomeCliente" class="java.lang.String"/> <parameter name="nomeUsuario" class="java.lang.String"/> <parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false"> <defaultValueExpression><![CDATA["C:\\Users\\David\\Documents\\Blog\\tutoriais\\TutorialRelatorios\\relatorios\\"]]></defaultValueExpression> </parameter> <queryString> <![CDATA[SELECT c.customer_id idCliente, c.first_name nome, c.last_name sobrenome, c.email email, a.address endereco, a.phone telefone, ci.city nomeCidade, co.country nomePais FROM customer c, address a, city ci, country co WHERE /* junções */ c.address_id = a.address_id AND a.city_id = ci.city_id AND ci.country_id = co.country_id AND /* restrições */ c.first_name LIKE $P{nomeCliente} ORDER BY c.first_name;]]> </queryString> <field name="idCliente" class="java.lang.Integer"/> <field name="nome" class="java.lang.String"/> <field name="sobrenome" class="java.lang.String"/> <field name="email" class="java.lang.String"/> <field name="endereco" class="java.lang.String"/> <field name="telefone" class="java.lang.String"/> <field name="nomeCidade" class="java.lang.String"/> <field name="nomePais" class="java.lang.String"/> <background> <band splitType="Stretch"/> </background> <title> <band height="75" splitType="Stretch"> <staticText> <reportElement x="0" y="18" width="555" height="40"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="25" isBold="true"/> </textElement> <text><![CDATA[Locações por Clientes]]></text> </staticText> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <line> <reportElement x="0" y="74" width="555" height="1"/> </line> </band> </title> <pageHeader> <band height="21" splitType="Stretch"> <staticText> <reportElement x="-1" y="0" width="51" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Usuário:]]></text> </staticText> <textField> <reportElement x="53" y="0" width="150" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$P{nomeUsuario}]]></textFieldExpression> </textField> <staticText> <reportElement x="360" y="0" width="68" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Gerado em:]]></text> </staticText> <textField pattern="dd/MM/yyyy', às' HH:mm'hs'"> <reportElement x="433" y="0" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.util.Date"><![CDATA[new Date()]]></textFieldExpression> </textField> </band> </pageHeader> <detail> <band height="175" splitType="Stretch"> <staticText> <reportElement x="0" y="3" width="50" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Nome:]]></text> </staticText> <textField> <reportElement x="0" y="23" width="99" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nome}]]></textFieldExpression> </textField> <staticText> <reportElement x="103" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Sobrenome:]]></text> </staticText> <textField> <reportElement x="103" y="23" width="136" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{sobrenome}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[E-mail:]]></text> </staticText> <textField> <reportElement x="242" y="23" width="228" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{email}]]></textFieldExpression> </textField> <staticText> <reportElement x="0" y="47" width="59" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Endereço:]]></text> </staticText> <textField> <reportElement x="62" y="47" width="177" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{endereco}]]></textFieldExpression> </textField> <staticText> <reportElement x="473" y="3" width="82" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Telefone:]]></text> </staticText> <textField> <reportElement x="473" y="23" width="82" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{telefone}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="47" width="42" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Cidade:]]></text> </staticText> <textField> <reportElement x="287" y="47" width="106" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomeCidade}]]></textFieldExpression> </textField> <staticText> <reportElement x="397" y="47" width="31" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[País:]]></text> </staticText> <textField> <reportElement x="433" y="47" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomePais}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <subreport> <reportElement x="7" y="71" width="544" height="100"/> <subreportParameter name="idCliente"> <subreportParameterExpression><![CDATA[$F{idCliente}]]></subreportParameterExpression> </subreportParameter> <connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression> <subreportExpression class="java.lang.String"><![CDATA[$P{SUBREPORT_DIR} + "LocacoesPorClientes_Locacoes.jasper"]]></subreportExpression> </subreport> </band> </detail> <pageFooter> <band height="22" splitType="Stretch"> <textField> <reportElement x="455" y="2" width="100" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Integer"><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> </band> </pageFooter> </jasperReport>
Teste o relatório e veja o que acontece. Você vai perceber que para cada cliente será gerado uma lista de filmes. Agora que está tudo pronto, organize o layout do subrelatório e personalize da forma que achar melhor. Eu coloquei a largura com 7,694 polegadas e expandi a linha para ocupar toda a largura. Note que se você mudar alguma coisa no subrelatório, vc precisará compilar apenas ele. Agora, para finalizar, vamos chamar este relatório a partir do nosso programa em Java, mas para isso ainda temos que fazer algumas pequenas modificações no arquivo de relatório principal.
Para entender o que vamos fazer, abra o arquivo LocacoesPorClientes.jrxml e selecione a caixa do subrelatório. Nas propriedades procure pela propriedade Subreport Expression. Essa expressão que é responsável em fazer o subrelatório ser carregado, ou seja, é ela que define para o relatório principal a localização do subrelatório. Por padrão – na verdade, pq definimos quando usamos o assistente de subrelatórios – ela vai conter o valor $P{SUBREPORT_DIR} + “LocacoesPorClientes_Locacoes.jasper”, ou seja, o caminho do subrelatório é formado pelo valor do parâmetro SUBREPORT_DIR concatenado com o nome do arquivo de Subrelatório. O problema é que o parâmetro SUBREPORT_DIR está configurado com um valor fixo, que corresponde ao caminho absoluto do relatório e isso não é bom… O que vamos fazer então é fazer com que tudo execute corretamente tanto no projeto, quanto no programa compilado e empacotado.
Primeiro, no Report Inspector, procure pelo parâmetro SUBREPORT_DIR. Ao selecioná-lo, verifique a propriedade “Default Value Expression”. Ela vai estar definida como o caminho absoluto do diretório onde está o subrelatório. Vamos mudar esse valor para “/” (com as aspas), ou seja, uma String que contém uma barra, que vai indicar a raiz do projeto. O tipo da classe do parâmetro ainda é String. Ok, aqui está pronto. Agora selecione novamente a caixa do subrelatório. Na propriedade Subreport expression entre com o seguinte código.
getClass().getResource( $P{SUBREPORT_DIR} + "LocacoesPorClientes_Locacoes.jasper" )
Note que o ponto e vírgula da instrução não é colocado. Essa linha de código vai retornar um objeto URL que aponta para o arquivo do subrelatório (“/LocacoesPorClientes_Locacoes.jasper”), sendo então carregado corretamente tanto no projeto, quanto no .jar. Note que poderíamos fixar esse valor sem precisar usar o parâmetro, mas caso haja a necessidade de mudar os diretórios dos subrelatórios, essa abordagem facilita o trabalho, tendo apenas que mudar o valor padrão do parâmetro. Como a expressão vai retornar um objeto URL, ainda nas propriedades da caixa do subrelatório, mude a Expression Class (logo abaixo da Subreport Expression) para java.net.URL.
Feito isso, salve o relatório e dê um preview. Na aba iReport output vai ser acusado um warning, dizendo que não é possível encontrar o relatório, no entando o relatório vai ser renderizado direitinho. Agora não precisamos mais nos preocupar, pois tanto no iReport, quanto no .jar que for ser gerado do projeto, o relatório vai abrir corretamente com o subrelatório.
O código do método abrirRelatorioClientes() da classe Main foi alterado para:
public void abrirRelatorioClientes() { InputStream inputStream = getClass().getResourceAsStream( "/LocacoesPorClientes.jasper" ); Map<String, Object> parametros = new HashMap<String, Object>(); parametros.put( "nomeCliente", "F%" ); try { ReportUtils.openReport( "Locações por Clientes", inputStream, parametros, ConnectionFactory.getSakilaConnection() ); } catch ( SQLException exc ) { exc.printStackTrace(); } catch ( JRException exc ) { exc.printStackTrace(); } }
O código das versões finais tanto do arquivo de relatório principal, quanto do subrelatório estão listadas a seguir.
LocacoesPorClientes.jrxml
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="report name" pageWidth="595" pageHeight="842" columnWidth="535" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <property name="ireport.zoom" value="1.0"/> <property name="ireport.x" value="0"/> <property name="ireport.y" value="0"/> <parameter name="nomeCliente" class="java.lang.String"/> <parameter name="nomeUsuario" class="java.lang.String"/> <parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false"> <defaultValueExpression><![CDATA["/"]]></defaultValueExpression> </parameter> <queryString> <![CDATA[SELECT c.customer_id idCliente, c.first_name nome, c.last_name sobrenome, c.email email, a.address endereco, a.phone telefone, ci.city nomeCidade, co.country nomePais FROM customer c, address a, city ci, country co WHERE /* junções */ c.address_id = a.address_id AND a.city_id = ci.city_id AND ci.country_id = co.country_id AND /* restrições */ c.first_name LIKE $P{nomeCliente} ORDER BY c.first_name;]]> </queryString> <field name="idCliente" class="java.lang.Integer"/> <field name="nome" class="java.lang.String"/> <field name="sobrenome" class="java.lang.String"/> <field name="email" class="java.lang.String"/> <field name="endereco" class="java.lang.String"/> <field name="telefone" class="java.lang.String"/> <field name="nomeCidade" class="java.lang.String"/> <field name="nomePais" class="java.lang.String"/> <background> <band splitType="Stretch"/> </background> <title> <band height="75" splitType="Stretch"> <staticText> <reportElement x="0" y="18" width="555" height="40"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="25" isBold="true"/> </textElement> <text><![CDATA[Locações por Clientes]]></text> </staticText> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <line> <reportElement x="0" y="74" width="555" height="1"/> </line> </band> </title> <pageHeader> <band height="21" splitType="Stretch"> <staticText> <reportElement x="-1" y="0" width="51" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Usuário:]]></text> </staticText> <textField> <reportElement x="53" y="0" width="150" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$P{nomeUsuario}]]></textFieldExpression> </textField> <staticText> <reportElement x="360" y="0" width="68" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Gerado em:]]></text> </staticText> <textField pattern="dd/MM/yyyy', às' HH:mm'hs'"> <reportElement x="433" y="0" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.util.Date"><![CDATA[new Date()]]></textFieldExpression> </textField> </band> </pageHeader> <detail> <band height="196" splitType="Stretch"> <staticText> <reportElement x="0" y="3" width="50" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Nome:]]></text> </staticText> <textField> <reportElement x="0" y="23" width="99" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nome}]]></textFieldExpression> </textField> <staticText> <reportElement x="103" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Sobrenome:]]></text> </staticText> <textField> <reportElement x="103" y="23" width="136" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{sobrenome}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="3" width="70" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[E-mail:]]></text> </staticText> <textField> <reportElement x="242" y="23" width="228" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{email}]]></textFieldExpression> </textField> <staticText> <reportElement x="0" y="47" width="59" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Endereço:]]></text> </staticText> <textField> <reportElement x="62" y="47" width="177" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{endereco}]]></textFieldExpression> </textField> <staticText> <reportElement x="473" y="3" width="82" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Telefone:]]></text> </staticText> <textField> <reportElement x="473" y="23" width="82" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{telefone}]]></textFieldExpression> </textField> <staticText> <reportElement x="242" y="47" width="42" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Cidade:]]></text> </staticText> <textField> <reportElement x="287" y="47" width="106" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomeCidade}]]></textFieldExpression> </textField> <staticText> <reportElement x="397" y="47" width="31" height="20"/> <textElement textAlignment="Left" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[País:]]></text> </staticText> <textField> <reportElement x="433" y="47" width="122" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{nomePais}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> <subreport> <reportElement x="0" y="96" width="555" height="100"/> <subreportParameter name="idCliente"> <subreportParameterExpression><![CDATA[$F{idCliente}]]></subreportParameterExpression> </subreportParameter> <connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression> <subreportExpression class="java.net.URL"><![CDATA[getClass().getResource( $P{SUBREPORT_DIR} + "LocacoesPorClientes_Locacoes.jasper" )]]></subreportExpression> </subreport> <staticText> <reportElement x="0" y="72" width="555" height="20"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font size="12" isBold="true"/> </textElement> <text><![CDATA[Filmes alugados]]></text> </staticText> <line> <reportElement x="0" y="71" width="555" height="1"/> </line> <line> <reportElement x="0" y="92" width="555" height="1"/> </line> </band> </detail> <pageFooter> <band height="22" splitType="Stretch"> <textField> <reportElement x="455" y="2" width="100" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.lang.Integer"><![CDATA[$V{PAGE_NUMBER}]]></textFieldExpression> </textField> <line> <reportElement x="0" y="1" width="555" height="1"/> </line> </band> </pageFooter> </jasperReport>
LocacoesPorClientes_Locacoes.jrxml
<?xml version="1.0" encoding="UTF-8"?> <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="LocacoesPorClientes_Locacoes" language="groovy" pageWidth="554" pageHeight="802" columnWidth="554" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0"> <property name="ireport.zoom" value="1.0"/> <property name="ireport.x" value="0"/> <property name="ireport.y" value="0"/> <parameter name="idCliente" class="java.lang.Integer"/> <queryString> <![CDATA[SELECT f.title titulo, f.release_year anoLancamento, r.return_date dataDevolucao FROM customer c, rental r, inventory i, film f WHERE /* junções */ r.customer_id = c.customer_id AND r.inventory_id = i.inventory_id AND i.film_id = f.film_id AND /* restrições */ c.customer_id LIKE $P{idCliente} AND r.return_date IS NOT NULL ORDER BY r.return_date, f.title;]]> </queryString> <field name="titulo" class="java.lang.String"/> <field name="anoLancamento" class="java.sql.Date"/> <field name="dataDevolucao" class="java.sql.Timestamp"/> <background> <band splitType="Stretch"/> </background> <columnHeader> <band height="25"> <staticText> <reportElement x="0" y="0" width="100" height="20"/> <textElement textAlignment="Center" verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Devolvido em]]></text> </staticText> <staticText> <reportElement x="103" y="0" width="47" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Título]]></text> </staticText> <staticText> <reportElement x="326" y="0" width="117" height="20"/> <textElement verticalAlignment="Middle"> <font isBold="true"/> </textElement> <text><![CDATA[Ano de Lançamento]]></text> </staticText> <line> <reportElement x="0" y="24" width="554" height="1"/> </line> </band> </columnHeader> <detail> <band height="21" splitType="Stretch"> <textField pattern="dd/MM/yyyy"> <reportElement x="0" y="1" width="100" height="20"/> <textElement textAlignment="Center" verticalAlignment="Middle"/> <textFieldExpression class="java.sql.Timestamp"><![CDATA[$F{dataDevolucao}]]></textFieldExpression> </textField> <textField> <reportElement x="103" y="1" width="219" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.lang.String"><![CDATA[$F{titulo}]]></textFieldExpression> </textField> <textField pattern="yyyy"> <reportElement x="326" y="1" width="117" height="20"/> <textElement verticalAlignment="Middle"/> <textFieldExpression class="java.util.Date"><![CDATA[$F{anoLancamento}]]></textFieldExpression> </textField> </band> </detail> </jasperReport>
O preview da versão final do meu relatório ficou assim:
Então é isso! Terminamos mais uma parte do tutorial! Espero que tenham gostado e que tenha auxiliado quem ainda tinha dificuldade com os subrelatórios. O projeto finalizado desta parte do tutorial pode ser obtido neste link. Na próxima parte do tutorial iremos aprender a trabalhar com outros tipos de datasources além das conexões que estamos usando até agora.
Grande abraço a todos! Até a próxima parte 😉
ótimo tuto bem explicado, nunca havia usado dessa forma sempre faço relatorios com DataSource JRBeanCollectionDataSource pois sempre utilizo JPA mas esse tuto que voce passou é uma otima escolha para se trabalhar com JDBC
Oi Diogo,
Obrigado! Na próxima parte eu vou falar dos diferentes tipos de datasources.
[]´s
Cara Parabensss… to fazendo meu TCC em Java.. seus Relatorios salvaram minha vida
Muito bom!
Mas o que não encontrei em lugar nenhum para aprender é como imprimir apenas a consulta atual feito no java.
Tipo assim, tenho uma aplicação java e uma tela com campo de pesquisa onde localizo um cliente por exemplo cliente Ricardo que por sua vez preenche automaticamente os outros campos do cliente com endereço, telefone e etc.
Como faço para o ireport gerar o relatório dessa tela do cliente que selecionei com seus dados e não um relatório de todo o banco de dados.
Não acho em lugar nenhum um tutorial explicando como se faz isso.
Oi Ulysses.
Que bom que gostou!
Você pode fazer isso de duas formas:
Primeira: criar um relatório sem a banda detail e sem uma query.
Os dados do relatório serão passados todos via parâmetros (os valores que você quer mostrar) e então você usa alguma outra banda para exibir cada parâmetro.
Segunda: Você pode usar um datasource ao invés de usar uma query, e passar para o datasource apenas o objeto que você quer mostrar, e então, dentro do relatório, na banda detail, vc mostra o valor. Como só vai ter um objeto, a banda detail vai mostrar apenas o objeto passado.
Eu ainda não ensinei como usar outros tipos de datasource. Ainda não tive tempo de escrever essa parte do tutorial. Acho que na próxima semana eu vou ter tempo para escrever.
[]´s
Cara…excelente tutorial. Depois de muita briga com o iReport e milhares de buscas em vão, este passo a passo funcionou “quase” perfeitamente. O que não tira os teus méritos, pois tenho certeza que deixei algo passar desapercebido.
Ocorre o seguinte…o meu sub-relatório está aparecendo em branco quando publicado, embora ele tenha sido preenchido de forma correta no preview do iReport.
Tens alguma idéia?
Desde já, agradeço e meus parabéns pelo artigo.
Oi Túlio,
Primeiramente, obrigado. Quanto à sua dúvida, realmente fica complicado falar o que é sem ter alguma mensagem de erro. Sugiro que você dê uma repassada no tutorial, algum detalhe deve ter ficado apra trás.
[]´s
O que me parece, é que o “path” do sub-relatório está incorreto.
Nem mesmo colocando o caminho fisico funciona, ele me reporta um erro mais bizarro ainda.
Oi Túlio,
Se tanto o subrelatório quanto o relatório estão no mesmo diretório, verifique o valor padrão do parâmetro SUBREPORT_DIR do relatório base. Configure-o para “/” (com as aspas). Compile o relatório base e teste novamente.
[]´s
Estão sim, no mesmo diretório.
Compilando, o mesmo me retorna um “warning”, que aparentemente parece natural. Segue abaixo:
Unable to locate the subreport with expression: “getClass().getResource( $P{SUBREPORT_DIR} + “report_subreport1.jasper” )”
E se setar para o caminho físico do relatório, a aplicação me reporta o seguinte erro:
“cannot assign instance of [Lnet.sf.jasperreports.engine.JRBand; to field net.sf.jasperreports.engine.base.JRBaseSection.bands of type [Lnet.sf.jasperreports.engine.JRBand; in instance of net.sf.jasperreports.engine.base.JRBaseSection ” e mais milhares de outras linhas.
Oi Túlio,
Realmente, esse warning é normal. Como eu disse, vc precisa configurar o valor padrão do parâmetro SUBREPORT_DIR com o valor “/” (com as aspas).
[]´s
já repassei tudo por aqui, mas ainda nada.
o único detalhe diferente é que revendo os teus artigos anteriores, percebo que o exemplo lida com um ambiente desktop, diferente do que tenho por aqui (web). Mas continuarei tentando.
Valeu pela força aí.
David, vc já mexeu com Grupos de relatóris além de subrelatórios?
Já mexi com os 2, e eu gostava mais usar Grupo, pois ficava apenas um arquivo jrxml.
e como uso JPA para realizar a consulta, eu instanciava uma lista de uma classe, que todos os atributos eram strings, e não sei como, os Grupos faziam a quebra sozin.
Mas continue com os post! Estou reaprendendo a mexer com JasperReports, e aprendendo o Pentaho. E seu blog está ajudando muito!
Oi Daniel,
Realmente os grupos são uma mão na roda, mas o objetivo dos tutoriais não é esgotar totalmente as funcionalidades do JasperReports, mas sim mostrar o caminho 😉
Fica ai a dica para os outros leitores.
Abraço!
Ola David, parabéns pelo seu projeto estou aprendendo muito, se for lançar um livro serei a primeira em adquirir, sua didatica é muito boa.Deus abencoe e te acrescente sempre mais a sabedoria. Sou sua fã
Obrigado Andrea.
[]´s
Cara, muito bom o seu tutorial, parabéns pela iniciativa em compartilhar esse material. Me ajudou muito!
Oi Ronaldo,
Que bom que foi útil!
[]’s
David, parabéns mesmo pelo post, para mim foi muito util, muitas vezes fazemos coiss em programação sem ter noção porqe das coisas. Neste seu tutorial vc teve o cuidade em deixar bem claro cada passo que estava realizando o que além de solucionar o problema, ainda passa conhecimentos que vão ser uteis em outras condições. Deixo aqui meu agradecimentos.
Oi David… estava olhando seu post e a principio não me ajudou muito… nunca havia usado o ireport… e precisei usá-lo com java web.
Mas depois que vi essa parte de subrelatório….percebi que seu post é o mais completo de todos…e me ajudou muito.
Brigadão!!
😀
Legal Ana, que bom que ajudou!
Cara , o tutorial é fodástico!! (Desculpe o palavreado ) mais é como posso descrever melhor, me ajudou muito, obrigado pelo post
Oi David, estou usando o ireport e seu tutorial sempre me ajuda muito =) Obrigado!
Manow do céu um tempão tentando resolver isso, e esse tuto me ajudou muito.
Que bom! Grande abraço!