Dando continuidade na postagem: JasperReports 4.0.1: Utilizando JavaBean datasource, agora vamos usar o .jasper gerado no iReport, em um projeto Java EE 6.
Começando...
Para começar, no NetBeans crie uma nova Aplicação Web com o nome de PrimeiroRelatorio (seguindo os passos já vistos em postagens anteriores)...
Feito isso, vamos criar a estrutura que usamos para gerar o .jasper (postagem do link), então em pacotes de código-fonte crie um novo pacote com o nome de primeirorelatorio e dentro dele um pacote model, dentro desse pacote crie a classe Produto (lembrando que tem que ser idêntica à aquela usada no .jar para gerar o relatório), ficando com esta estrutura:
Relembrando a classe Produto:
public class Produto {
private int codigo;
private String nome;
private BigDecimal valor;
//gerar getters e setters
}
Agora dentro do WEB-INF, crie um novo diretório com o nome de relatorios, dentro dele coloque o arquivo .jasper, ficando assim:
Caso não tenha baixado as bibliotecas do JasperReports, baixe por aqui.
De todas as bibliotecas disponibilizadas no link, para este tipo de relatório iremos usar apenas algumas delas, acabei filtrando e chegando as que realmente precisavam, então adicione ao projeto as seguintes bibliotecas:
Depois disso assim como foi criado o pacote model, precisamos de um pacote controle, para armazenar nossos beans (nesse caso, teremos apenas um bean), então dentro do pacote primeirorelatorio, crie um novo pacote com o nome de controle, ficando assim: primeirorelatorio.controle, agora aqui dentro crie uma classe java com o nome de RelatorioBean.java, ela será assim (abaixo dela eu explico algumas coisas):
package primeirorelatorio.controle;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import primeirorelatorio.model.Produto;
/**
*
* @author andii
*/
@Named
@RequestScoped
public class RelatorioBean {
public void gerarRelatorio() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
ServletContext context = (ServletContext) externalContext.getContext();
String arquivo = context.getRealPath("WEB-INF/relatorios/PrimeiroRelatorio.jasper");
JRDataSource jrds = new JRBeanCollectionDataSource(listarProdutos());
gerarRelatorioWeb(jrds, null, arquivo);
}
private void gerarRelatorioWeb(JRDataSource jrds, Map<Object, Object> parametros, String arquivo) {
ServletOutputStream servletOutputStream = null;
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
try {
servletOutputStream = response.getOutputStream();
JasperRunManager.runReportToPdfStream(new FileInputStream(new File(arquivo)), response.getOutputStream(), parametros, jrds);
response.setContentType("application/pdf");
servletOutputStream.flush();
servletOutputStream.close();
context.renderResponse();
context.responseComplete();
} catch (Exception e) {
e.printStackTrace();
}
}
private List<Produto> listarProdutos() {
List<Produto> produtos = new ArrayList<Produto>();
Produto p1 = new Produto();
p1.setCodigo(1);
p1.setNome("Produto 1");
p1.setValor(new BigDecimal(1.99));
produtos.add(p1);
Produto p2 = new Produto();
p2.setCodigo(2);
p2.setNome("Produto 2");
p2.setValor(new BigDecimal(3000.50));
produtos.add(p2);
Produto p3 = new Produto();
p3.setCodigo(3);
p3.setNome("Produto 3");
p3.setValor(new BigDecimal(500.00));
produtos.add(p3);
return produtos;
}
}
Vamos ver o que esses métodos fazem:
public void gerarRelatorio()
Inicialmente este método será chamado pela nossa página JSF, nele nós precisamos pegar o caminho exato do nosso arquivo .jasper, que lá no começo da postagem colocamos dentro de WEB-INF/relatorios, para isso usamos o context.getRealPath.
Quanto ao jrds: por termos utilizado uma classe Java para gerar nosso .jasper, nos precisamos passar para nosso relatório um JRDataSource, que é formado por uma lista de Produto (pois o método listarProdutos(), retorna uma lista de produtos que poderia muito bem estar vindo de um banco de dados).
Ao chamar o gerarRelatorioWeb, estamos passando um parâmetro null, esse corresponderia a uma Map, que serviria para passarmos parâmetros(que vai ficar pra outra postagem) para o nosso relatório...
Agora vamos ver o que acontece no:
gerarRelatorioWeb(JRDataSource jrds, Map<Object, Object> parametros, String arquivo)
Neste método nós dependemos do response para mostrar o nosso relatório no navegador, quanto a essa parte não vou dar muitas explicações, pois sairia do nosso foco que é o JasperReports...
Bom, no final o responsável por gerar o que vai ser o nosso relatório, é essa linha aqui:
JasperRunManager.runReportToPdfStream...
esse método não cria um arquivo .pdf fisicamente no computador, apenas gera ele como se fosse um arquivo temporário, e quem decide se quer salvar o relatório ou não é o usuário, depois disso, o response entra em campo novamente dizendo ao navegador que o que será enviado é do tipo application/pdf, cada navegador reage de uma forma quando se trata de PDF, no caso do Google Chrome, mostra nele mesmo, se não me engano o Firefox, já dá a opção de fazer download do PDF...
e por fim o servletOutputStream, é quem manda o relatório para o navegador!
Depois de entendermos como funciona essa classe, vamos alterar nossa página index.xhtml, para que ela chame o método e mostre o relatório:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<h:form>
<h:commandButton value="Ver relatorio" actionListener="#{relatorioBean.gerarRelatorio}" onclick="this.form.target='_blank'" />
</h:form>
</h:body>
</html
Quanto ao onclick do commandButton, eu uso para poder abrir o relatório em outra aba do navegador. Visualmente a página index, fica assim:
Quem estiver usando o Google Chrome para fazer estes testes, terá o seguinte resultado ao clicar no botão:
E por fim... a estrutura completa do projeto é esta:
E por aqui finalizamos a postagem de hoje, logo logo posto como usar este mesmo relatório em um projeto desktop! =)






Estou tentando adaptar seu codigo para mostrar relatorios no meu projeto de TCC, mas quando eu clico no botão Ver relatorio ele abre a mesma página em outra aba e não mostra o relatorio. O que pode ser? Você poderia me ajudar?
ResponderExcluirBoa tarde!!
ExcluirClaudinei, você conseguiu resolver o seu problema?
estou com o mesmo problema aqui, e não sei como resolver.
Claudinei, olha só vendo o codigo fonte para saber o que pode estar acontecendo, não tive nada parecido com isto.
ResponderExcluirOla, tudo bem ?
ResponderExcluirApenas uma dúvida, msm usando um projeto web preciso colocar o .jar no classpath ?
Olá Naldo! Vc quer dizer colocar no classpath do windows? se for isso não precisa não, já é suficiente adicioná-las no projeto apenas.
ResponderExcluirOlá, parabéns pela série de tutoriais, tentei este relatório e tive o seguinte erro
ResponderExcluirServlet.service() for servlet Faces Servlet threw exception...
java.lang.IllegalStateException: PWC3991: getOutputStream() has already been called for this response
Sabe o que pode ser?
Obrigado,
Diego
Oi, vc sabe como nao abrir em uma nova aba caso o relatorio nao seja gerado. Eu quero exibir uma mensagem de erro, mas com target blank, acaba gerando a mensagem na nova aba.
ResponderExcluirOlá Antonio! Para mostrar o relatório na mesma página basta tirar o onclick="this.form.target='_blank'"
ResponderExcluirDiego Moura, quando acontecem erros dessa forma, basta vc olhar o que diz no log do servidor de aplicação, ele geralmente diz exatamente o que está acontecendo
ResponderExcluirmeu deu esse erro:
ResponderExcluirjava.lang.IllegalStateException: getOutputStream() has already been called for this response.
o que pode ser??
Os problemas podem ser diversos, vc tem que ler o que erro aparece no console do seu servidor de aplicação.
ExcluirOlá andii.brunetta
ResponderExcluirEu também estou com o erro "java.lang.IllegalStateException: getOutputStream() has already been called for this response".
Pesquisando na internet parece ser porque o org.apache.catalina.connector.Response.getWriter é executado antes do getOutputStream(). Em páginas JSP, parece ser problema com espaços em branco no código java entre <% %>
Alguma dica sobre a solução desse problema?
Ketellin, qual o erro que aparece no glassfish???
ExcluirPor favor, pode me ajudar?
ResponderExcluirO unico tutorial que consegui fazer foi o seu, deu certinho.
Mas preciso de uma ajuda simples, acredito eu!
Eu monto meu DataSource desta forma: JRDataSource jrds = new JRBeanCollectionDataSource(lista);
Mas acontece que eu quero montar sem "LISTA", ou seja quero enviar:
String nome;
String cpf;
String telefone;
Sem que se repita através de uma lista.
Eu consigo enviar no DataSource somente o meu DTO?
Por exemplo:
JRDataSource jrds = new JRBeanCollectionDataSource(DTOCONTATOS);
Pode me ajudar?
Olá, já pensou em passar esses valores por parametro? veja essa postagem http://javasemcafe.blogspot.com.br/2011/06/jasperreports-401-utilizando-subreports.html talvez ela possa te ajudar.
ExcluirPoxa, show, tinha perdido a esperança da resposta.
ResponderExcluirIrei seguir este tutorial, muito obrigado!
Que bom que te ajudou :)
ExcluirObtive o seguinte erro:
ResponderExcluirThe method runReportToPdfStream(InputStream, OutputStream, Map, JRDataSource) in the type JasperRunManager is not applicable for the arguments (FileInputStream, ServletOutputStream, Map, JRDataSource)
Valeu! Ajudou muito!
ResponderExcluir