Fórum iReport + JSF classes para gerar relatório na página jsf #389723
30/10/2010
0
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionFactory {
private Connection conexao;
public ConnectionFactory() throws ClassNotFoundException, SQLException {
criaConexao();
}
public void criaConexao() throws ClassNotFoundException, SQLException {
String endereco = "localhost";
String porta = "5432";
String banco = "secretarias";
String usuario = "postgres";
String senha = "post";
try {
Class.forName("org.postgresql.Driver");
conexao = DriverManager.getConnection("jdbc:postgresql://" + endereco
+ ":" + porta + "/" + banco + "?user=" + usuario
+ "&password=" + senha);
} catch (ClassNotFoundException ex) {
throw ex;
} catch (SQLException ex) {
throw ex;
}
}
public void fechaConexao() throws SQLException {
conexao.close();
conexao = null;
}
public boolean isFechada() {
try {
return conexao.isClosed();
} catch (SQLException ex) {
return false;
}
}
public Connection getConexao() {
return conexao;
}
}
Roberto Rodrigues.
Curtir tópico
+ 0Posts
30/10/2010
Davi Costa
qual estratégia usar, se vai usar servlet ou um managedbean,
vai depender bastante da tua arquitetura. Mas não há necessidade alguma de nenhum dos dois.
Gosto bastante da estratégia de criar uma classe só para chamar relatório (por exemplo RelatorioUtils),
nela eu coloco métodos estáticos (para diminuir acoplamento e para reaproveitamento de código... pode haver mais de um caso de uso que utilize relatório) que recebem só os parâmetros necessários para executar o relatório. Essa classe utilitária pode ser chamada do seu bean ou do seu servlet dependendo do que vc estiver usando.
O código com uma pequena pesquisa vc acha rapidim alguns exemplos, posso até te passar depois caso vc não ache. Só complementando existem essencialmente duas formas de executar relatórios do jasper, um é passando a conexão e deixando o ireport executar a consulta no banco, mas vc também opde fazer a consulta nas próprias classes java e passar o datasource com os dados para executar o relátorio. Espero ter ajudado.
Att Davi
Gostei + 0
31/10/2010
Roberto Rodrigues.
Gostei + 0
31/10/2010
Davi Costa
public class ReportUtil {
private static String ERRO_MENSAGEM_REPORT = "Um erro ocorreu quando o relatório estava sendo executado.";
//executa o relatório através de um JRBeanCollectionDataSource
public static void executarRelatorio(String caminhoRelatorio, Map<String, Object> parametros, String nomeRel, JRBeanCollectionDataSource fonteDados) throws ReportException{
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
//pega o caminho do arquivo .jasper da aplicação
InputStream reportStream = context.getExternalContext().getResourceAsStream(caminhoRelatorio);
/*//envia a resposta com o MIME Type
if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.ACROBAT_PDF)){
response.setContentType("application/pdf");
}else if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.PAGINA_HTML)){
response.setContentType("application/html");
}
*/
response.setHeader("Content-Disposition", "attachment; filename="+ nomeRel +".pdf");
response.setContentType("application/download");
response.setHeader("Pragma", "no-cache");
try {
ServletOutputStream servletOutputStream = response.getOutputStream();
//envia parametros para o relatório
if (parametros == null){
parametros = new HashMap<String, Object>();
}
//envia para o navegador o PDF gerado
JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, parametros, fonteDados);
servletOutputStream.flush();
servletOutputStream.close();
} catch (JRException e) {
e.printStackTrace();
throw new ReportException(ERRO_MENSAGEM_REPORT);
} catch (IOException e) {
e.printStackTrace();
throw new ReportException(ERRO_MENSAGEM_REPORT);
}finally{
context.responseComplete();
}
}
//executa o relatorio através de uma Connection
public static void executarRelatorio(String caminhoRelatorio, Map<String, Object> parametros, TipoFormatoRelatorio tipoFormatoRelatorio, Connection conn) throws ReportException{
FacesContext context = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
//pega o caminho do arquivo .jasper da aplicação
InputStream reportStream = context.getExternalContext().getResourceAsStream(caminhoRelatorio);
//envia a resposta com o MIME Type
if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.ACROBAT_PDF)){
response.setContentType("application/pdf");
}else if(tipoFormatoRelatorio.equals(TipoFormatoRelatorio.PAGINA_HTML)){
response.setContentType("application/html");
}
try {
ServletOutputStream servletOutputStream = response.getOutputStream();
//envia parametros para o relatorio
if (parametros == null){
parametros = new HashMap<String, Object>();
}
//envia para o navegador o PDF gerado
JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, parametros, conn);
servletOutputStream.flush();
servletOutputStream.close();
} catch (JRException e) {
e.printStackTrace();
throw new ReportException(ERRO_MENSAGEM_REPORT);
} catch (IOException e) {
e.printStackTrace();
throw new ReportException(ERRO_MENSAGEM_REPORT);
}finally{
context.responseComplete();
}
}
}
Nesta classe, vai exemplo como havia citado antes, passando a conexão e já os resultados da consulta via JRBeanCollectionDataSource, esse TipoFormatoRelatorio, foi um enum que criei para dizer o tipode relatório, simplesmente só isso, como também o ReportException é só uma classe de exceção criada tb que tranquilamente vc pode adaptar para a sua necessidade.
Att Davi
Gostei + 0
01/11/2010
Roberto Rodrigues.
public static void executarRelatorio(String "/report/relatoriosecretaria.jasper" , Map parametros, String "relatoriosecretaria.jasper", JRBeanCollectionDataSource fonteDados) throws ReportException{ if (parametros == null){
parametros = new HashMap();
} JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, parametros, fonteDados);
public static void executarRelatorio(String caminhoRelatorio, Map parametros, TipoFormatoRelatorio tipoFormatoRelatorio, Connection conn) throws ReportException{ Gostei + 0
02/11/2010
Davi Costa
@SuppressWarnings("unchecked")
public void executarRelatorioUnidade() throws SgpException {
List dados = new ArrayList();
Map record = null;
//varre a consulta e separa os objetos
for (Unidade unidade : findAll()) {
record = new HashMap();
//coloca em um Map cada um dos campos criados
//manualmente pelo relatorio
record.put("cd_unidade", unidade.getId());
record.put("ds_unidade", unidade.getDescricao());
record.put("nm_gestor", unidade.getNomeGestor());
record.put("ds_email_gestor", unidade.getEmailGestor());
//adiciona o List dados
dados.add(record);
}
//cria uma fonte de dados para coleções
JRBeanCollectionDataSource fonteDados =
new JRBeanCollectionDataSource(dados);
Map<String, Object> parametros = new HashMap<String, Object>();
parametros.put("PARAMETRO_TITULO_RELATORIO", "RELATÓRIO DE UNIDADES");
ReportUtil.executarRelatorio("/relatorios/emitirUnidade/emitirUnidadesReport.jasper", parametros, TipoFormatoRelatorio.ACROBAT_PDF, fonteDados);
}
Agora o código que chama uma conexão vai depender do seu projeto, pq aí vc passa a conexão para o relatório ser executado, e se usar como esse que fiz acima vai ter que ter o campos (fields) no teu relatório conforme esse trecho de código entre aspas:
record.put("cd_unidade", unidade.getId());
record.put("ds_unidade", unidade.getDescricao());
record.put("nm_gestor", unidade.getNomeGestor());
record.put("ds_email_gestor", unidade.getEmailGestor());
Att Davi
Gostei + 0
02/11/2010
Roberto Rodrigues.
Gostei + 0
02/11/2010
Davi Costa
nesses exemplos que te passei, a classe utilitária junto com o enum para dizer tipo de relatório fica em um pacote util, junto com outras classes utilitária como uma DataUtil que faz formatações de data e moeda...
E no meu serviço é que chamo o relatório, deixando isso abstraído do meu bean, realmente a chamada do relatório fica no meu serviço, mas nada te impede de chamar teu relatório de dentro do próprio bean.
Eu particularmente não gosto, pois em uma das formas de chamar já podemos passar o resultado da pesquisa para o relatório e sempre envolve alguma regra de negócio, por isso gosto de fazer tudo em um serviço na minha regra de negócio.
Att Davi
Gostei + 0
02/11/2010
Roberto Rodrigues.
Gostei + 0
02/11/2010
Roberto Rodrigues.
Exception in thread "main" net.sf.jasperreports.engine.JRException: java.io.FileNotFoundException: relatoriosecretaria.jasper at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:84) at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:536) at jdbc.ConnectionFactory.gerarRelatorio(ConnectionFactory.java:63) at jdbc.ConnectionFactory.main(ConnectionFactory.java:71) Caused by: java.io.FileNotFoundException: relatoriosecretaria.jasper ... 4 more Java Result: 1 CONSTRUÍDO COM SUCESSO (tempo total: 3 segundos)
public class ConnectionFactory {
/* Driver do banco de dados, URL, usuário e senha do banco de dados */
static final String JDBC_DRIVER = "org.postgresql.Driver";
static final String DATABASE_URL = "jdbc:postgresql://localhost:5432/secretarias";//localhost:5432/secretarias”;
static final String USER = "postgres";
static final String PASSWORD = "post";
/* Conecta-se ao banco de dados e retorna o objeto da conexão */
private static Connection getConnection() throws
ClassNotFoundException, SQLException {
/* Carrega o driver do postgreSQL */
Class.forName(JDBC_DRIVER);
/* Cria um objeto de conexão */
Connection connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
return connection;
}
/* Gera relatório */
public void gerarRelatorio() throws
JRException, Exception {
/* Chama o método getConnection para obter um objeto Connection,
utiliza-o para obter um objeto Statement e realiza uma consulta
armazendo o resultado em um ResultSet
*/
Connection connection = getConnection();
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery("select *from cadsecretaria;");
/* Cria um JRResultSetDataSource com o resultado da consulta */
JRResultSetDataSource jrrs = new JRResultSetDataSource(result);
/* Cria um HashMap com parâmetros do relatório.
Caso não seja atribuído algum valor aos parâmetros estes
assumem o valor padrão.
*/
Map parametros = new HashMap();
/* Cria um arquivo .jrprint (relatório preenchido) utilizando o
Relatorio.jasper (design), os parâmetros e o
JRResultSetDataSource que é o resultado da consulta.
*/
JasperPrint jp = JasperFillManager.fillReport("relatoriosecretaria.jasper", parametros, jrrs);
/* Exibe o relatório */
JasperViewer.viewReport(jp);
}
public static void main(String[] args) throws
JRException, Exception {
new ConnectionFactory().gerarRelatorio();
}
}
Gostei + 0
02/11/2010
Davi Costa
Primeira coisa passa o caminho dele completo.... por exemplo "C:\.....",
se for uma aplicação web passa a pasta que deve estar em web-inf e coloca a hierarquia a partir dessa
pasta por exemplo: "reports\relatoriosecretaria.jasper".
E caso não tenha feito quando tiver usando o ireport ou o plugin na sua IDE tecla com o botão direito no arquivo e escolhe a opção compile, para compilar seu relatório e até bom que se seu relatório tiver algum problema na hr de compilar ele tb faz uma verificação.
Att Davi
Gostei + 0
03/11/2010
Dyego Carmo
Conseguiu resolver colega ?
ValeuZ !
Gostei + 0
03/11/2010
Roberto Rodrigues.
log4j:WARN No appenders could be found for logger (net.sf.jasperreports.extensions.ExtensionsEnvironment). log4j:WARN Please initialize the log4j system properly. Exception in thread "main" net.sf.jasperreports.engine.JRException: Unknown column name : cadsecretaria_codigosecretaria at net.sf.jasperreports.engine.JRResultSetDataSource.getColumnIndex(JRResultSetDataSource.java:355) at net.sf.jasperreports.engine.JRResultSetDataSource.getFieldValue(JRResultSetDataSource.java:112) at net.sf.jasperreports.engine.fill.JRFillDataset.setOldValues(JRFillDataset.java:821) at net.sf.jasperreports.engine.fill.JRFillDataset.next(JRFillDataset.java:785) at net.sf.jasperreports.engine.fill.JRBaseFiller.next(JRBaseFiller.java:1482) at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:126) at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:946) at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:864) at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:84) at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:624) at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:540) at jdbc.ConnectionFactory.gerarRelatorio(ConnectionFactory.java:64) at jdbc.ConnectionFactory.main(ConnectionFactory.java:74) Java Result: 1
public class ConnectionFactory {
/* Driver do banco de dados, URL, usuário e senha do banco de dados */
static final String JDBC_DRIVER = "org.postgresql.Driver";
static final String DATABASE_URL = "jdbc:postgresql://localhost:5432/secretarias";//localhost:5432/secretarias”;
static final String USER = "postgres";
static final String PASSWORD = "post";
/* Conecta-se ao banco de dados e retorna o objeto da conexão */
private static Connection getConnection() throws
ClassNotFoundException, SQLException {
/* Carrega o driver do postgreSQL */
Class.forName(JDBC_DRIVER);
/* Cria um objeto de conexão */
Connection connection = DriverManager.getConnection(DATABASE_URL, USER, PASSWORD);
return connection;
}
/* Gera relatório */
public void gerarRelatorio() throws
JRException, Exception {
/* Chama o método getConnection para obter um objeto Connection,
utiliza-o para obter um objeto Statement e realiza uma consulta
armazendo o resultado em um ResultSet
*/
Connection connection = getConnection();
Statement statement = connection.createStatement();
ResultSet result = statement.executeQuery("select *from cadsecretaria");
/* Cria um JRResultSetDataSource com o resultado da consulta */
JRResultSetDataSource jrrs = new JRResultSetDataSource(result);
/* Cria um HashMap com parâmetros do relatório.
Caso não seja atribuído algum valor aos parâmetros estes
assumem o valor padrão.
*/
Map parametros = new HashMap();
/* Cria um arquivo .jrprint (relatório preenchido) utilizando o
Relatorio.jasper (design), os parâmetros e o
JRResultSetDataSource que é o resultado da consulta.
*/
JasperPrint jp = JasperFillManager.fillReport("relatorios/report/relatoriosecretaria.jasper", parametros, jrrs);
JasperExportManager.exportReportToPdfFile(jp, "relatoriosecretaria.pdf");
/* Exibe o relatório */
// JasperViewer.viewReport(jp);
JasperViewer.viewReport( "relatoriosecretaria.pdf", false );
}
public static void main(String[] args) throws
JRException, Exception {
new ConnectionFactory().gerarRelatorio();
}
}
Gostei + 0
03/11/2010
Davi Costa
Esse erro que está dando aí é no ireport.
Dando uma olhada por cima, parece, que vc não tem esses campos no relatório (cadsecretaria_codigosecretaria).
Não sei se fez essa classe para testar, mas ela está muito acoplada, tenta rever akela estratégia de deixar uma clase que receba todos os parametros para vc passar para o relátório, pq da forma que está todos seus casos de uso que precisarem de relatório vai repetir bastante código.
Att Davi
Gostei + 0
03/11/2010
Roberto Rodrigues.
Gostei + 0
03/11/2010
Davi Costa
seu relatório executa só c om Ireport né?
Se funcionar, um teste que vc pode fazer é remover todos os seus fields que vem na consulta.
è criar os fields com os mesmos nomes do resultset, e dando para eles seus tipos corretos de retorno, String ou integer.. e por aí vai, testa primeiro só com uma coluna para quando vc deixar rodando tudo ok sem erro, adiciona os outros.
A respeito da estratégia já até te expliquei, vou tentar ser mais claro.
Caso vc tenha outro caso de uso que chame outro relatório vc vai ter que repetir meio mundo de código dnovo.
Vc pode criar uma classe utilitária como a que te passei, mas obviamente que atenda a sua necessidade. E nesa classe cria um método estático e passa como parâmtros todos os dados para montar o relátório, parecido com a classe que te passei. de cara um parâmetro é o caminho do relatório, outro pode ser o ResultSet outro os parâmetros.Dessa forma, vc tem um único método que chama os relatórios que atenda a todas a necessidades.
Caso vc tenha usar ese seu factory, é só passar para ele os parâmetros necessários para ele também para que ele chame essa classe c o método estático para gerar relatório que eu tenho tanto falado. de repente pode ter ummétodo na Factory, que receba o caminho do relatório, talvez a query a ser executada para gerar o ResulSet e os parametros do relatório. A respeito do parametro do relatorio percebi q está só dando um new, o Ireport precisa pq no relatório pode ter alguns parametros, mas se no seucaso não tiver não tem problema dá sempre um new nele.
Mas ainda acho melhor no próprio código desse método que fica na classe utilitária vc pode colocar:
if(parametros == null){
parametros = new HashMap();
}
Já diminui tb algumas linhas de código instanciando esse atributo desnecessariamente, se não me engano vc até havia me perguntando o pq desse trecho de código no método q te enviei.
att Davi
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)