[RESOLVIDO]Ireport - Relatório via JRDataSouce com listas

6 respostas
M

Pessoal, boa tarde.

Seguinte, preciso fazer um relatório de Vendas Detalhadas no período. Vou fazê-lo via JrDataSource.

A lógica é:

  • uma lista de venda.
  • cada item dessa lista de venda é uma venda, e contém: uma lista de produtos e uma lista de formas de pagamento.

A nível de Classe Bean para servir de base para o JrDataSouce como eu poderia fazer ?

6 Respostas

D

A nível de a nível de não existe.
Basta que você crie uma classe que contenha a venda e as listas que precisa (produtos e formas de pagamento). Qual a dificuldade nisso?

E

drsmachado:
A nível de a nível de não existe.
Basta que você crie uma classe que contenha a venda e as listas que precisa (produtos e formas de pagamento). Qual a dificuldade nisso?

E então no iReport, para passar para o sub-relatório escolha a opção de usar um DataSource próprio e passe as suas listas…

M

Certo, mas na Classe que implementa JRDataSource, como fica o método getFieldValue, normal, eu dou uma descrição para a lista, por exemplo:

public Object getFieldValue(JRField campo) throws JRException {
        Object valor = null;
        MovimentoSaidaDetalhado movimentoSaidaDetalhe = (MovimentoSaidaDetalhado) valorAtual;

        if ("codigoVenda".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getCodigoVenda();
        } else if ("nomeCliente".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getNomeCliente();
        } else if ("dataVenda".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getDataVenda();
        } else if ("subTotal".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getSubTotal();
        } else if ("desconto".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getDesconto();
        } else if ("acrescimo".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getAcrescimo();
        } else if ("frete".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getFrete();
        } else if ("valorTotal".equals(campo.getName())) {
            valor = movimentoSaidaDetalhe.getValorTotal();
        }else if("listaProdutos".equals(campo.getName())){
            valor = movimentoSaidaDetalhe.getListaProdutos();
        }else if("listaFormasPagamento".equals(campo.getName())){
            valor = movimentoSaidaDetalhe.getListaFormasPagamento();
        }
        
        return valor;
    }

E a Classe bean dele, ficaria assim?

public class MovimentoSaidaDetalhado implements Serializable {
    
    private int codigoVenda;
    private String nomeCliente;
    private Date dataVenda;
    private BigDecimal subTotal;
    private BigDecimal desconto;
    private BigDecimal acrescimo;
    private BigDecimal frete;
    private BigDecimal valorTotal;    
	private ArrayList listaProdutos;
	private ArrayList listaFormasPagamento;

E no Relatório, no master, aparecerá as informações da venda, na banda detalhe, porque pode ser mais de uma venda, e para cada item desse detalhe (que é uma venda), haverá um subrelatório que mostrará os itens, então do relatório master para o subrelatório eu passo:

  • Connection type: use a datasource expression
  • DataSourceExpression eu passo o $F{listaProdutos}

Aí no subrelatório de produtos, é só eu criar fields com mesmo nome da classe.
Até aí eu consegui descobrir um pouco aqui e um pouco em outros lugares.

Uma questão que tenho é: o subreport de formas de pagamentos, teria que vir abaixo do subreport dos produtos, como eu faço para quando o subreport de produtos aumentar de tamanho, leve junto o subreport de formas de pagamento?

E

Confesso que não entendi o porquê de você implementar JRDataSource, ainda mais do jeito que fez…

Como falei antes, isso é simples de fazer… basta você pegar a sua lista e passar para o sub-relatório encapsulado em um JRBeanCollecionDataSource (veja que este já é uma implementação de JRDataSource)

Use a posição “Flutuante”

M

Eu vou tentar de novo, com mais calma.
Qualquer coisa eu posto.

Obrigado até agora pela ajuda.

M

Olá. Boa noite.

Estou tentando agora implementar como me foi passado, vejam se estou no caminho correto.

1) Eu tenho uma Classe Produto, normal.

public class Produto {
    
    private int codigo;
    private String nomeProduto;
    private String tamanho;
    private String cor;
    private Double quantidade;
    private BigDecimal valor;

    //Construtor vazio, Setts e Getts omitidos
2) Eu tenho uma Classe Venda.
public class Venda {
    
    private int codigo;
    private String nomeCliente;
    private BigDecimal valorTotal;
    private Date dataVenda;
    private List produtos;
    
    //Construtor vazio, Setts e Getts omitidos

Então na Classe Venda, eu teria uma lista de Produtos.

No Relatório Master, eu apontei o ClassPath do iReport para a pasta: build/classes criado no meu projeto. (no caso: C:\Users\Marcos\Desktop\Relatorios\build\classes)
Dessa forma, ao criar o relatório, eu consigo mapear os Fields de forma automática, na Tela Report Query, na Aba JavaBean Datasource. Lá eu digito o package.nomeDaClasse e clico no botão Read Attributes e ele me relaciona os Atributos dessa minha classe. E dessa classe ele mapeou minha lista de produtos, como List, mesmo.

Então, eu adicionei os Field mapeados na Banda Detalhe, normalmente. Criei um Novo Relatório, com Empty DataSource. Nele, eu apontei o mapeamento da mesma forma como no anterior, só que para a Classe Produto.
E, voltando no Relatório Master, selecionei o Subrelatório criado e adicionado, fui na propriedade Connection type e selecionei "Use a datasource expression" e na propriedade Datasource expression coloquei a expressão:

new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{produtos})

Onde "produtos" é o nome da lista que está dentro da Classe Venda.

Compilando no iReport, ambos relatórios não apresentam erro algum.

Então, para abrir meu relatório, fiz uso de uma Classe que encontrei pela Internet, num tutorial:
public static void openReport(
            String titulo,
            InputStream inputStream,
            Map<String, Object> parametros,
            Connection conexao ) throws JRException {

        /*
         * Cria um JasperPrint, que é a versão preenchida do relatório,
         * usando uma conexão.
         */
        JasperPrint print = JasperFillManager.fillReport(
                inputStream, parametros, conexao );

        // abre o JasperPrint em um JFrame
        viewReportFrame( titulo, print );

    }

    
    public static void openReport(
            String titulo,
            InputStream inputStream,
            Map<String, Object> parametros,
            JRDataSource dataSource ) throws JRException {

        /*
         * Cria um JasperPrint, que é a versão preenchida do relatório,
         * usando um datasource genérico.
         */
        JasperPrint print = JasperFillManager.fillReport(
                inputStream, parametros, dataSource );

        // abre o JasperPrint em um JFrame
        viewReportFrame( titulo, print );

    }

    private static void viewReportFrame( String titulo, JasperPrint print ) {

        /*
         * Cria um JRViewer para exibir o relatório.
         * Um JRViewer é uma JPanel.
         */
        JRViewer viewer = new JRViewer( print );

        // cria o JFrame
        JFrame frameRelatorio = new JFrame( titulo );

        // adiciona o JRViewer no JFrame
        frameRelatorio.add( viewer, BorderLayout.CENTER );

        // configura o tamanho padrão do JFrame
        frameRelatorio.setSize( 500, 500 );

        // maximiza o JFrame para ocupar a tela toda.
        frameRelatorio.setExtendedState( JFrame.MAXIMIZED_BOTH );

        // configura a operação padrão quando o JFrame for fechado.
        frameRelatorio.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );

        // exibe o JFrame
        frameRelatorio.setVisible( true );

    }

}

E no meu método, escrevi da seguinte maneira:

public void abrirRelatorioClientesDS() {
        InputStream inputStream = getClass().getResourceAsStream( "relatorioVendaDetalhado.jasper" );
        
        Map parametros = new HashMap();
        
        List<Venda> dados = new ArrayList<Venda>(); 
        List<Produto> produtos = new ArrayList<Produto>(); 
        
        //Fake Dados Produto
        Produto p = new Produto();
        p.setCodigo(102);
        p.setCor("AZUL");
        p.setNomeProduto("VESTIDO DE FESTA");
        p.setQuantidade(1.0);
        p.setTamanho("M");
        p.setValor(new BigDecimal(90.0));
        produtos.add(p);
        
        //Fake Dados Venda
        Venda v1 = new Venda();
        v1.setCodigo(1);
        v1.setDataVenda(new Date());
        v1.setNomeCliente("MARCOS ROBERTO DA FONSECA");
        v1.setValorTotal(new BigDecimal(10.0));
        v1.setProdutos(produtos);
        dados.add(v1);
        
        // criando o datasource com os dados criados
        JRDataSource ds = new JRBeanArrayDataSource(dados.toArray()); 
        try {
            // passando o datasource para o método de criação e exibição do relatório
            ReportUtils.openReport( "Vendas - Bean Collection Data Source", inputStream, parametros,ds);
        } catch (JRException ex) {
            ex.printStackTrace();
        }

    }

Fiz então uma lista chamada DADOS, que seria minha lista de Vendas, e dentro de cada objeto venda há uma lista com seus respectivos produtos. Ainda teria que haver, dentro da Venda uma segunda lista, com as formas de pagamento, mas eu acredito que conseguindo fazer funcionar dessa maneira, a outra lista será tranquilo, pois em comentários anteriores, o usuário erico_kl me deu a dica de as formas de pagamento, serem colocadas num subrelatorio e colocar esse subrelatorio com a propriedade Position Type = Float.

Pra ficar mais organizado, visualmente falando, nos subrelatórios, você pode zerar as propriedades:
- Right Margin, que é a margem da direita
- Left MArgem que é a margem da esquerda
- Top Margin que é a margem do topo
- Bottom margin que é a margem do rodapé do relatórios
Basta selecionar, no relatório principal, o subrelatório, e na Aba Properties, alterar os valores.

Até o término da escrita desse post, eu consegui fazer o subrelatorio de formas de pagamento. E useu, como o usuário erico_kl me deu a dica de as formas de pagamento, serem colocadas num subrelatorio e colocar esse subrelatorio com a propriedade Position Type = Float.
Espero que essas informações tenham sido de boa serventia.

Agradeço e muito a ajuda dos usuários que me reponderam anteriormente. Muito obrigado!

Criado 7 de fevereiro de 2013
Ultima resposta 8 de fev. de 2013
Respostas 6
Participantes 3