Relatorio com EJB 3 e iReport

14 respostas
71C4700

Não consegui construir o relatorio utilizando a Unidade de Percistencia !
Alguma situação parecida ?

Já tentei colocar no classpath do iReport mas mesmo assim não funcionou, nem cria a conexão pra reaalizar as consultas !

Desde já agradeço !

14 Respostas

71C4700

Alguem ?

71C4700

Desculpe o up !!

Mas ninguem ?

faelcavalcanti

colega, esqueça comunicação com relatório a partir do contexto de persistência.
seus métodos de serviços devem ser suficientemente inteligentes e capazes de obterem informações a respeito do que o relatório deve visualizar.

eu sempre recomendo criar uma camada que faça este trabalho, o de montar este conjunto de informações a partir de um datasource, você pode criar uma camada intermediaria, em caso de relatorios, para guiar o controlador e que não possua acoplamentos das classes do JasperReports, afinal, você não iria querer classes do EntityManager na camada de serviço, assim como você não iria querer classes do Jasper na classe do seu Bean de sessão.

você também poderia criar uma implementação de seu DAO genérico, que também implemente uma interface com comportamento de suporte a um datasource JRDataSource.

recomendo leitura:
http://www.hibernate.org/79.html
http://www.hibernate.org/387.html
http://www.hibernate.org/389.html

71C4700

Não entendi bem a questao. Uma camada so para Relatorios é isso ?

Tenho um DAO generico, como poderia fazê-lo com os relatorios ?

Agradeço

faelcavalcanti

isto, na verdade uma camada que você possa encapsular todo o tratamento de montagem e configuração do seu relatório obtido do seu controlador que acaba de receber as informações da camada de serviço.

71C4700:
Tenho um DAO generico, como poderia fazê-lo com os relatorios ?

Agradeço


já ter isto ajuda bastante. imagine que você teria o mesmo sendo que para implementação de um datasource para o jasper reports. fiz um esboço rapidamente desta visão, conforme abaixo (não ligue para os detalhes e fiz rapidamente, e me esqueci de elaborar no aspecto de ter uma camada distribuida por voce mencionar estar usando EJB3. bem o objetivo foi mencionar o fluxo, mas me passe seu feedback que elaboro melhor em proxima vez):

Lembre-se que o controlador não deve conter lógica de negócio, e que esta deve estar na camada de serviço!

Veja do ponto de vista de interfaces. Coloquei como ServiceJasper, mas deveria ser ServicoRelatorio com uma implementação para Jasper, bem como para o caso do datasource.

Foi a pressa e foi mal não ter mencionado informações mais detalhadas, mas conforme dúvidas aos poucos vamos nos entendendo.

71C4700

Desculpe, mas ainda estou iniciando em relatorios, apanhei bastante pra conseguir montar um…
Mas, consigo gera-los (.jasper), atraaves do iReport e passar os parametros por uma aplicação em Java.

Não consegui entender a implementação do datasource, parecido com O Delphi ? ja tinha visto exemplos com ele.

Consegui entender o diagrama, menos a parte do datasource.

Agradeço pela atençao prontuosa.

faelcavalcanti

71C4700:

Desculpe, mas ainda estou iniciando em relatorios, apanhei bastante pra conseguir montar um…
Mas, consigo gera-los (.jasper), atraaves do iReport e passar os parametros por uma aplicação em Java.

procure criar uma pasta resource de forma que vc armazene os arquivos binarios lá. não se preocupe com o .jasper e sim com o jrxml. a sua preocupação com o jasper seria se você modificasse a versão do arquivo .jar.

71C4700:

Não consegui entender a implementação do datasource, parecido com O Delphi ? ja tinha visto exemplos com ele.

parecido, mas no caso do delphi, ainda dispõe de suporte a eventos sobre o que você pode fazer antes e depois de determinada banda ou grupo do relatório.

quanto à questão do datasource, você sabe que o jasper necessita de um datasource, caso contrário esteja vazio ou não especificado, você deverá passar uma referência da classe JREmptyDataSource, senão ele virá em branco. mas, continuando, quando você obter por exemplo uma listagem de clientes, você irá associar esta listagem como base de informações a serem consumidas pelo relatório conforme comportamento do seu layout.

o que quero dizer na verdade é que a cada registro lido ele irá sempre consultar este datasource que contempla uma lista de objetos complexos que necessitam consumir os fields esperados pelo seu relatório. o relatório é composto por fields, variáveis e parâmetros.

o ideal é que para cada relatório você tenha uma classe que o represente, ou seja, o seu estado completo de seu conjunto de informações exibidas, de forma que você possa obter menor acoplamento entre os objetos e facilitar assim os seus testes, podendo popular da forma esperada em ambiente de produção.

praticamente utilizando sua camada de serviço, você estará obtendo uma listagem específica(classe de VO para respresentar o relatório) para um datasource específico que lê a classe de VO).

fique a vontade em perguntar, assim que puder vamos nos entendendo. :wink:

71C4700

Grande faelcavalcanti

Tô postando um exemplo pra voce da uma olhada e ver como sou iniciante ainda. Por favor de uma olhada no projeto.
Tentei organizar de forma que ficase OO o maximo possivel.
Equanto a parte do relatorio tenho duvidas.

Agradeço pela atenção.

faelcavalcanti

sei que é apenas um teste, mas para evitar qualquer desfeche, lá vai:

1. fachada nao deve reconhecer o dao. caso voce ache necessario utilizar a fachada no projeto real, pelo menos crie uma camada de serviço para generalizar as operações de negócio que você vai querer unificar dentro da fachada.
2. Troque as assinaturas dos metodos para receber o tipo pessoa. Isto é necessário para efetivar o encapsulamento que as outras camadas intermediárias irão fazer/atuar com o objeto passado. A maior vantagem disto, também é ter uma assinatura unificada, impossibilitando modificação em todos os métodos. Com esta mudança o código abaixo do método [public void gravar(int id, String nome, String email)] por exemplo deverá ser migrado para camada de controller(no seu caso view -> TelaInicial)
Pessoa pessoaTeste = new Pessoa();
pessoaTeste.setId(id);
pessoaTeste.setEmail(email);
pessoaTeste.setNome(nome);
Ou seja, ele irá obter informações do cliente e posteriormente passar a referência para a fachada, e por aí vai. Lembre-se a fachada somente delega, ela não deverá efetuar qualquer validação ou operação posterior. Agora caso sua aplicação não tenha muitos módulos de sistema, ou seja, se você não tiver um subconjunto muito grande de operações/funcionalidades no sistema, não acharia necessário você utilizá-la para unificar isto. Sugestão: caso necessário existência do facade, coloque em um pacote facade. Para entender mais sobre o padrão Fachada/Facade, leia aqui.
3. Na Classe RelatorioPessoa.java, você poderia 3.1 Colocar o arquivo [relatorio/RelatorioTeste.jasper] em um pacote "resources" por exemplo, e obter o InputStream da mesma forma, somente para ter referências externas em um arquivo .properties 3.2 Você pode criar
4. Uma dica. Crie uma classe que represente os parâmetros e propriedades exigidas para processar o relatório. Desta forma você estaria também encapsulando informações para enviar a sua classe, como por exemplo: - Hashmap esperado pelo jasper, parâmetros de configuração do relatório - Tipo de Extensao, pode ser necessário para interpretar qual tipo de saída configurada pelo usuário: PDF, HTML, etc.
Seguem os passos abaixo mais ou menos da execução básica esperada, supondo que seja um relatório com filtros:
1. O Usuário preenche informações de filtro e clica em imprimir 2. O controlador da view será disparado e irá encapsular os filtros em uma classe(encapsula os filtros preenchidos apenas) que o represente e enviar a fachada 3. A fachada irá receber a batata quente(parametros) e irá delegar para camada de serviço 4. Na camada de serviço, ela realizará uma série de operações
4.1 Verificará se os parametros obrigatórios foram preenchidos corretamente, por exemplo 4.2 Irá repassar o filtro para camada de DAO processar a lista de pessoas, por exemplo 4.3 Ao receber a lista de pessoas, vazias ou não, ele irá chamar o Handler(gerenciador, no seu caso RelatorioPessoa) do relatório passando a listagem e os filtros informados 4.4 Camada handler de relatório
4.4.1 O handler irá obter as configurações padrão do comportamento do relatório, inputstream, etc. 4.4.2 O handler irá montar o datasource passando a lista de pessoas obtidas. Segue abaixo um exemplo padrão da classe de datasource, independente de DAO(não afetado, pois já recebeu da camada de serviço):
import java.util.Iterator;
import java.util.List;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;

/**
* Classe responsável para processamento e leitura das informações necessárias pelo relatório
*/
public class HibernateQueryResultDataSource implements JRDataSource {

	/**
	* lista de campos que serão exibidos no relatório
	* att: deverá ser os mesmos nomes dos fields configurados no seu arquivo .jrxml
	*/
	private String[] fields;

	private Iterator iterator;

	private Object currentValue;

	/**
	* Construtor que irá receber a lista de objetos e fields do relatório na mesma ORDEM
	*/
	public HibernateQueryResultDataSource(List list, String[] fields) {
		this.fields = fields;
		this.iterator = list.iterator();
	}

	public Object getFieldValue(JRField field) throws JRException {
		Object value = null;
		int index = getFieldIndex(field.getName());
		if (index > -1) {
			if ( currentValue instanceof Object[] ) {
				Object[] values = (Object[]) currentValue;
				value = values[index];
			} else
				value = currentValue;
		}
		return value;
	}

	public boolean next() throws JRException {
		currentValue = iterator.hasNext() ? iterator.next() : null;
		return (currentValue != null);
	}

	private int getFieldIndex(String field) {
		int index = -1;
		for (int i = 0; i < fields.length; i++) {
			if (fields[i].equals(field)) {
				index = i;
				break;
			}
		}
		return index;
	}
}
4.4.3 Caso lista esteja vazia irá montar o datasource JREmptyDataSource. Comportamento deve ser definido caso não exista registros. Por exemplo, mensagem via alert, via tela, via relatório impresso com data/hora informando que não existem dados 4.4.4 O hanlder oficialmente irá processar o reltório após tudo configurado e montado
5. Processamento das camadas posteriores são finalizadas e relatório será impresso

como você está utilizando JDBC, recomendo duas soluções(ou uma ou outra) para evitar tanta escrita de código JDBC desnecessário, e aproveitando que você está montando arquitetura do projeto:

1. Utilize iBATIS, preferencialmente com spring para facilitar sua vida se conseguir, a fim de evitar muita escrita de código JDBC 2. Utilize algum framework para mapeamento objeto/relacional dentro da especificação JPA como hibernate ou toplink.

bem espero que tenha ajudado e conforme tinha te avisado, assim que pudesse com certeza te ajudaria. :wink:

71C4700

Cara muito obrigado.

Eu consegui utilizar JPA para persistencia, tenho um DAO que grava,exclui,localiza e atualiza, atraves do EntityManager.

Gostaria de saber como a camada de serviço e o DAO se interagem, para a formaçao do Relatorio.

Cordialmente.

Job.

ps: Agradeço pela pronta ajuda e pelos conselhos no projeto.

faelcavalcanti

fala garoto. motivando neste aspecto, inclusive de outros post que o pessoal tinha me questionado, passei 1 hora criando este projeto chamado escribas que motiva principal uso sobre diversas formas para desenvolvimento de relatórios utilizando um determinado reuso, mantendo alguns exemplos, entre outras motivações que pretendo demonstrar.

pretendo em breve comprovar alguns mitos também utilizando design de TDD com dbuni, entre outros mais.

mais informações: projeto escribas : http://code.google.com/p/escribas/

71C4700

Bem, ainda não consegui integrar os dois Java+relatorio de uma forma que este não esteja ‘amarrado’ de certa forma as ferramentas e não da forma que eu desejava que ele fosse um reflexo do codigo java, montando algo como um template na ferramenta e dependendo da consulta ele montasse relatorio.

Mas, não entendi ainda dois pontos:

  1. a camada de serviço, como ela atuaria na geração dos relatorios;
  2. como integrar de forma concisa e com baixa coesão o codigo e a geração do relatorio;

cordialmente, agradeço novamente pela pronta ajuda.

faelcavalcanti
71C4700:
1. a camada de serviço, como ela atuaria na geração dos relatorios;
pense como um conjunto de serviços. imagine que existe o serviço de inserir, salvar e listar que existem em uma interface de serviço genérico, como por exemplo:
IServiçoGenerico
- inserir
- salvar
- listar
e
IPessoaServico extends IServiçoGenerico
- listarPorEstadoCivil ( estadoCivil )
para o caso do relatório seria parecido, onde toda infra-estrutura já está pronta, como por exemplo:
IRelatorioServico
- gerarRelatorio( param1, configs, etc )
o que você precisa se preocupar agora seria em passar os parâmetros e partir para o abraço que o relatório vai sair. pense como uma caixa preta, encapsulada, que vai fazer o serviço que você pediu.

a idéia seria esta, na classe que implementar IPessoaServico, ela chamar o servico IRelatorioServico passando os parametros e pronto, porque se trata de serviço para serviço, e nada disto deve estar em outra camada (lógica)a não ser de negócio/serviço.

71C4700:
2. como integrar de forma concisa e com baixa coesão o codigo e a geração do relatorio;
me envie uma MP que te passo meu e-mail com instruções de como baixar o fonte deste projeto. no código estou demonstrando justamente isto.

você topa participar deste projeto ? pretendo divulgar mais porque algumas coisas não ficaram claras e os objetivos também. em breve e logo logo! :D

71C4700

Rafa !

Seria um prazer participar do projeto.

Já tô por ai…

Criado 5 de novembro de 2008
Ultima resposta 19 de nov. de 2008
Respostas 14
Participantes 2