Impressão de Relatórios com Parametros no JSF passando varios registros e gerando varias Paginas

21/10/2009

Boa Noite,

 Estou com dificuldades de realizar impressão de varias paginas vindo de uma consulta.

 Eu tenho uma query que retorna uma lista de varios pedidos. veja:

 private String consultaPedidos() {
      
        String query = "SELECT t.desc_tppedido,p.fornecimento, p.data_forne,p.ord_venda,p.data_ordem," +
                " c.data_impr, u.nomeCli,u.logradouro,u.bairro,u.cidade, u.cep,p.isrisco,d.sigla_deposito," +
                " p.num_ped,p.obs_entrega,p.cod_ped, c.id_pickingimpr,c.isimpresso, p.cod_ped " +
                " FROM Pedido p JOIN p.deposito d JOIN p.pickingImpr c" +
                " JOIN p.tppedido t JOIN p.codCli u" +
                " WHERE p.data_forne BETWEEN :data1 AND :data2 " +
                " AND p.deposito = :cod_deposito AND c.isimpresso = false";

        return query;
    }

Tenho uma funcao que retorna um lista da query acima.




//separa a pesquisa do total encontrado
//possibilitando a utilização também no relatório
    private List<?> todosResultsPesq() {

        Deposito dep = depositoDao.pesquisarPorId(pedido.getDeposito().getCod_deposito());

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("data1", new Timestamp(data1.getTime()));
        params.put("data2", new Timestamp(dataConvertida()));
        params.put("cod_deposito", dep);

        return pedidoDao.listPesqParam(consultaPedidos(), params);
    }


O que preciso fazer agora é enviar para impressora todas as paginas vindas desse consulta. Estou fazendo dessa forma mas so me retorna no PDF o primeiro registro

   public void executarRelatorio() throws java.text.ParseException, ParseException, SQLException, IOException {


        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();

        //pega o caminho do arquivo .jasper da aplicação
        InputStream reportStream = context.getExternalContext().getResourceAsStream("/reporter/pedidos/picking_SubReporte.jasper");

        try {

            Connection connection = getConnection();

            ServletOutputStream servletOutputStream = response.getOutputStream();

            for (Iterator iterator = todosResultsPesq().iterator();
                    iterator.hasNext();) {

                Object[] o = (Object[]) iterator.next();
                HashMap<String, Integer> map = new HashMap<String, Integer>();

                map.put("PEDIDOID", Integer.parseInt(o[15].toString()));

                //envia a resposta com o MIME Type PDF
                response.setContentType("application/pdf");
                //envia para o navegador o PDF gerado
                JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, map, connection);

            }

            servletOutputStream.flush();
            servletOutputStream.close();

            connection.close();

        } catch (JRException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            //evita erro do JSF após completar
            //a geração do relatório
            //avisando o FacesContext que a resposta está completa
            context.responseComplete();

        }
    }


Apos clicar no link da pagina para imprimir, como ja havia falado, so retorna o primeiro registro da lista.

Agradeço desde ja.

Victor





Victor Lima

Victor Lima

Curtidas 0

Respostas

Henrique Weissmann

Henrique Weissmann

21/10/2009

Olá Victor,

há alguns pontos aqui que precisam ser observados:

Repare neste seu loop:

for (Iterator iterator = todosResultsPesq().iterator();
                    iterator.hasNext();) {

                Object[] o = (Object[]) iterator.next();
                HashMap<String, Integer> map = new HashMap<String, Integer>();

                map.put("PEDIDOID", Integer.parseInt(o[15].toString()));

                //envia a resposta com o MIME Type PDF
                response.setContentType("application/pdf");
                //envia para o navegador o PDF gerado
                JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, map, connection);

            }



Observe oq ue você está fazendo:
coloque as seguintes instruções fora do seu loop:

//envia a resposta com o MIME Type PDF
response.setContentType("application/pdf");
//envia para o navegador o PDF gerado
JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, map, connection);

Dentro deste, o que você est´fazendo é o seguinte: na primeira iteração do loop já está sendo enviado o stream de saída. Como resultado, somente o primeiro registro será exposto no seu relatório.
GOSTEI 0
Victor Lima

Victor Lima

21/10/2009

Boa tarde HENRIQUE,

Primeiramente obrigado pela atencao.

 Eu refiz da forma que voce falou, e tambem ja havia tentado assim, mas tentei novamente para ter certeza.

 O resultado foi o mesmo, ele pega somente o primeiro registro, verifiquei a funcao todosResultsPesq() e esta ok, voce pode ver no print abaixo que o resultado me traz 2(dois) pedidos e cada pedido seus respectivos itens.





 Mas quando mando imprimir ele me retorna somente um, veja o resultado quando clico no link  Imprimir.





 Eu estarei tentando paralelamente usando uma conexão JRBeanCollectionDataSource, mas nao sei ao certo se vai funcionar. Pensei em pegar os dados e jogar em um ArrayList e depois imprimir, mas como sou iniciante estou lendo ainda sobre esse assunto, pois muitos exemplos ou tutoriais nao explicam utilizando um subrerport.

 Mas se esse metodo utilizando uma conexao desse certo seria melhor para nao refazer tudo.


vou postar todo codigo para voce ver se alem disso estou fazendo algo errado.

Obrigado pela ajuda.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.protracking.controller;

Import.*

/**
 *
 * @author victor
 */
@Controller("pickingImprController")
@Scope("session")
public class PickingImprController {

    private PickingImpr pickingImpr;
    private Deposito deposito;
    private Pedido pedido;
    @Resource
    private DaoGenerico<PickingImpr, Integer> pickingimprDao;
    @Resource
    private DaoGenerico<Pedido, Integer> pedidoDao;
    @Resource
    private DaoGenerico<ItensPedido, Integer> itenspedidoDao;
    @Resource
    private DaoGenerico<Deposito, Integer> depositoDao;
    private Map<String, Object> depositoItem = null;
    private Date data1;
    private Date data2;

    //atributos de paginação de resultados
    private int maxPorPagina = 40;
    private int paginaAtual = 0;
    private Integer cod_deposito;
    private DataModel model;
    private HashMap<String, Integer> map = new HashMap<String, Integer>();

  

    public PickingImprController() {
        this.pickingImpr = new PickingImpr();

    }

    public String novoPicking() {
        this.pickingImpr = new PickingImpr();
        this.pedido = new Pedido();
        this.pedido.setDeposito(new Deposito());
        this.getDepositos();

        return "imprimiPicking";

    }

    public Map<String, Object> getDepositos() {
        depositoItem = new LinkedHashMap<String, Object>();
        for (Iterator<?> iter = depositoDao.todos().iterator(); iter.hasNext();) {
            Deposito e = (Deposito) iter.next();
            depositoItem.put(e.getSigla_deposito(), e.getCod_deposito());// label,value
        }
        return depositoItem;
    }


    // mostra todos os Pedidos a serem impressos em um dataTable
    // mostra todos os produtos em um DataTable
    //comprados com os respectivos clientes
    //limitados pela paginação
    @SuppressWarnings("unchecked")
    public DataModel getPedidos() {


        String query = "SELECT t.desc_tppedido,p.fornecimento, p.data_forne,p.ord_venda,p.data_ordem," +
                " c.data_impr, u.nomeCli,u.logradouro,u.bairro,u.cidade, u.cep,p.isrisco,d.sigla_deposito," +
                " p.num_ped,p.obs_entrega,p.cod_ped, c.id_pickingimpr,c.isimpresso, p.cod_ped " +
                " FROM Pedido p JOIN p.deposito d JOIN p.pickingImpr c" +
                " JOIN p.tppedido t JOIN p.codCli u" +
                " WHERE p.data_forne BETWEEN :data1 AND :data2 " +
                " AND p.deposito = :cod_deposito AND c.isimpresso = false";

        Deposito dep = depositoDao.pesquisarPorId(pedido.getDeposito().getCod_deposito());


        Map<String, Object> params = new HashMap<String, Object>();
        params.put("data1", new Timestamp(data1.getTime()));
        params.put("data2", new Timestamp(dataConvertida()));
        params.put("cod_deposito", dep);

        //    return new ListDataModel(pedidoDao.listPesq(query));

        return new ListDataModel(pedidoDao.listPesqParam(query, params, maxPorPagina, paginaAtual));

    }

    private String consultaPedidos() {

        String query = "SELECT t.desc_tppedido,p.fornecimento, p.data_forne,p.ord_venda,p.data_ordem," +
                " c.data_impr, u.nomeCli,u.logradouro,u.bairro,u.cidade, u.cep,p.isrisco,d.sigla_deposito," +
                " p.num_ped,p.obs_entrega,p.cod_ped, c.id_pickingimpr,c.isimpresso, p.cod_ped " +
                " FROM Pedido p JOIN p.deposito d JOIN p.pickingImpr c" +
                " JOIN p.tppedido t JOIN p.codCli u" +
                " WHERE p.data_forne BETWEEN :data1 AND :data2 " +
                " AND p.deposito = :cod_deposito AND c.isimpresso = false";

        return query;
    }

    private String consultaItens() {
        String query = "SELECT i.item,p.codproduct,p.descProduto,i.quant " +
                " FROM ItensPedido i JOIN i.produto p JOIN i.pedido d" +
                " WHERE d.cod_ped = :pedidoId" +
                " ORDER BY i.item";

        return query;
    }

    //converte adicionando hora, minuto e segundo
    private long dataConvertida() {
        //adiciona a hora que não foi colocada no
        //intervalo de pesquisa
        GregorianCalendar gc1 = new GregorianCalendar();
        gc1.setTime(data2);
        gc1.add(GregorianCalendar.HOUR_OF_DAY, 23);
        gc1.add(GregorianCalendar.MINUTE, 59);
        gc1.add(GregorianCalendar.SECOND, 59);

        return gc1.getTimeInMillis();
    }


    //navega para a primeira página
    public String primeiraPagina() {
        paginaAtual = 0;
        return null;
    }

    //navega para a última página
    public String ultimaPagina() {
        int rest = getTotal() % maxPorPagina;

        if (rest != 0) {
            paginaAtual = getTotal() - rest;
        } else {
            paginaAtual = getTotal() - maxPorPagina;
        }

        return null;
    }

    //acessor da página atual
    public int getPaginaAtual() {
        return paginaAtual;
    }

//total de resultados encontrados na consulta
    @SuppressWarnings("unchecked")
    public int getTotal() {

        int total = todosResultsPesq().size();
        return total;

    }

//separa a pesquisa do total encontrado
//possibilitando a utilização também no relatório
    private List<?> todosResultsPesq() {

        Deposito dep = depositoDao.pesquisarPorId(pedido.getDeposito().getCod_deposito());

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("data1", new Timestamp(data1.getTime()));
        params.put("data2", new Timestamp(dataConvertida()));
        params.put("cod_deposito", dep);

        return pedidoDao.listPesqParam(consultaPedidos(), params);
    }

    // lista os itens do Pedido Selecionados
    private List<?> todosResultItensPedidos(Long id) {

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("pedidoId", id);

        return itenspedidoDao.listPesqParam(consultaItens(), params);

    }

    public int getProximaPagina() {
        int total = getTotal();
        int soma = paginaAtual + maxPorPagina;
        int proxima = (soma > total) ? total : soma;
        return proxima;
    }

    public int getMaxPorPagina() {
        return maxPorPagina;
    }

    //navega para a próxima página
    public String proxima() {
        int soma = paginaAtual + maxPorPagina;
        if (soma < getTotal()) {
            paginaAtual += maxPorPagina;
        }

        return null;
    }

    //navega para a página anterior
    public String anterior() {
        paginaAtual -= maxPorPagina;

        if (paginaAtual < 0) {
            paginaAtual = 0;
        }

        return null;
    }

//converte uma string para Timestamp
    private Timestamp convertTimestamp(String t) throws ParseException, java.text.ParseException {
        // trata nanoseconds "yyyy-mm-dd hh:mm:ss.nanoseconds"
        SimpleDateFormat sdfIn =
                new SimpleDateFormat("yyyy-MM-dd");
        return new Timestamp(sdfIn.parse(t).getTime());
    }

    private Connection getConnection() {

        Connection connection = null;

        try {
            // Cria a conexao com o banco de dados

            Class.forName("org.postgresql.Driver");
            String db = "jdbc:postgresql://localhost:5432/webtracking";
            connection = DriverManager.getConnection(db, "postgres", "viclima");

        } catch (SQLException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }

        return connection;
    }


 

    //@SuppressWarnings("unchecked")
    //executa o relatório através do actionListener
    public void executarRelatorio() throws java.text.ParseException, ParseException, SQLException, IOException {


        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();

        //pega o caminho do arquivo .jasper da aplicação
        InputStream reportStream = context.getExternalContext().getResourceAsStream("/reporter/pedidos/picking_SubReporte.jasper");

        try {

            Connection connection = getConnection();
            ServletOutputStream servletOutputStream = response.getOutputStream();

            
             for (Iterator iterator = todosResultsPesq().iterator();
                    iterator.hasNext();) {

                Object[] o = (Object[]) iterator.next();

                map.put("PEDIDOID", Integer.parseInt(o[15].toString()));

             }   //envia a resposta com o MIME Type PDF
                response.setContentType("application/pdf");
                //envia para o navegador o PDF gerado
                JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, map, connection);



            servletOutputStream.flush();
            servletOutputStream.close();

            connection.close();

        } catch (JRException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            //evita erro do JSF após completar
            //a geração do relatório
            //avisando o FacesContext que a resposta está completa
            context.responseComplete();

        }

    }







GOSTEI 0
Henrique Weissmann

Henrique Weissmann

21/10/2009

Olá Victor,

encontrei algo no seu código que talvez seja o problema:

 
             for (Iterator iterator = todosResultsPesq().iterator();
                    iterator.hasNext();) {

                Object[] o = (Object[]) iterator.next();

                map.put("PEDIDOID", Integer.parseInt(o[15].toString()));

             }   //envia a resposta com o MIME Type PDF
                response.setContentType("application/pdf");
                //envia para o navegador o PDF gerado
                JasperRunManager.r

Você está passando apenas o id do pedido. Será que não deveria passar para o relatório a própria instância do pedido?

Outro ponto, ainda sobre o mesmo loop: que tal se você ao invés de usar o Iterator, fizesse algo como no código abaixo:

Iterator iterator = todosResultsPesq().iterator();
while (iterator.hasNext()) {
      Object[] o = (Object[]) iterator.next()
   // restante do loop
}

Isto tornaria o seu código mais claro, e além disto, se bobear, pode ser que seja ai que o seu problema esteja.
GOSTEI 0
Victor Lima

Victor Lima

21/10/2009

Boa Tarde Henrique,

Utilizei a iteração com while mas nao deu certo,  voce falou que estou passando so o ID para o parametro e deveria passar tambem  o pedido , isso nao entendi,  porque no relatório iReport possui uma query dentro dele com um where cod_ped = $P   e no while eu passo o codigo , e o que ele deveria fazer é que quando passar a cada registro gravar no PDF a pagina, que no caso grava so a primeira e logo vai gerando o PDF,  eu nao sei bem mas acho que o PDF esta sendo gerado e fechado logo apos o primeiro registro e os outros estam ficando de fora, nao sei suposição minha. O que voce acha ?

bom de qualquer forma se vc encontrar algo mais ficarei grato.

obrigado

Victor

segue codigo abaixo:



 public void executarRelatorio() throws java.text.ParseException, ParseException, SQLException, IOException {


        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();

        //pega o caminho do arquivo .jasper da aplicação
        InputStream reportStream = context.getExternalContext().getResourceAsStream("/reporter/pedidos/picking_SubReporte.jasper");

        try {

            Connection connection = getConnection();

            ServletOutputStream servletOutputStream = response.getOutputStream();


            Iterator iterator = todosResultsPesq().iterator();
            while (iterator.hasNext()) {
                Object[] o = (Object[]) iterator.next(); // restante do loop
                map.put("PEDIDOID", Integer.parseInt(o[15].toString()));
               }
            //envia a resposta com o MIME Type PDF
            response.setContentType("application/pdf");
            //envia para o navegador o PDF gerado
            JasperRunManager.runReportToPdfStream(reportStream, servletOutputStream, map, connection);

        
            servletOutputStream.flush();
            servletOutputStream.close();

            connection.close();

        } catch (JRException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            //evita erro do JSF após completar
            //a geração do relatório
            //avisando o FacesContext que a resposta está completa
            context.responseComplete();

        }

    }
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

21/10/2009

Opa Victor,

não sabia desta consulta interna dentro do seu relatório. Sendo assim, o que você falou está correto.

Neste caso, será que não seria o caso de verificar esta consulta? As vezes ela pode estar configurada para retornar apenas um registro. Isto costuma acontecer.
GOSTEI 0
Victor Lima

Victor Lima

21/10/2009

Opa Henrique,

Está apontando para um parametro, que quando percorrido pela List do for deveria mudar o PEDIDOID e fazer a query.

Veja como esta minha query dentro do Mestre_detalhe do iReport:

SELECT
     deposito."sigla_deposito" AS deposito_sigla_deposito,
     tipo_pedido."desc_tppedido" AS tipo_pedido_desc_tppedido,
     modalidade."desc_modalidade" AS modalidade_desc_modalidade,
     cliente."nome_cli" AS cliente_nome_cli,
     cliente."logradouro" AS cliente_logradouro,
     cliente."cpf_cnpj" AS cliente_cpf_cnpj,
     cliente."bairro" AS cliente_bairro,
     cliente."cidade" AS cliente_cidade,
     cliente."cep" AS cliente_cep,
     pedido."isrisco" AS pedido_isrisco,
     pedido."ord_venda" AS pedido_ord_venda,
     pedido."data_forne" AS pedido_data_forne,
     pedido."data_ordem" AS pedido_data_ordem,
     pedido."num_ped" AS pedido_num_ped,
     pedido."fornecimento" AS pedido_fornecimento,
     pedido."textremessa" AS pedido_textremessa,
     pedido."obs_entrega" AS pedido_obs_entrega,
     picking_impr."data_impr" AS picking_impr_data_impr,
     pedido."cod_ped" AS pedido_cod_ped
FROM
     "public"."pedido" pedido INNER JOIN "public"."deposito" deposito ON pedido."cod_deposito" = deposito."cod_deposito"
     INNER JOIN "public"."tipo_pedido" tipo_pedido ON pedido."id_tppedido" = tipo_pedido."id_tppedido"
     INNER JOIN "public"."modalidade" modalidade ON pedido."id_modalidade" = modalidade."id_modalidade"
     INNER JOIN "public"."cliente" cliente ON pedido."cod_cli" = cliente."cod_cli"
     INNER JOIN "public"."picking_impr" picking_impr ON pedido."cod_ped" = picking_impr."cod_ped"
WHERE
     pedido."cod_ped" = $P




Agora veja como esta meu Sub-Report o  Detalhe:

SELECT
     itens_pedido."item" AS itens_pedido_item,
     itens_pedido."quant" AS itens_pedido_quant,
     produto."codproduct" AS produto_codproduct,
     produto."desc_produto" AS produto_desc_produto,
     itens_pedido."cod_ped" AS itens_pedido_cod_ped
FROM
     "public"."produto" produto INNER JOIN "public"."itens_pedido" itens_pedido ON produto."idprod" = itens_pedido."idprod"
WHERE
     itens_pedido."cod_ped" = $P
ORDER BY
     itens_pedido."item" ASC




 Neste caso o que estou tentando fazer é jogar essa consulta dentro do for, e a cada registro passado pela List com o:
                 Object[] o = (Object[]) iterator.next(); // restante do loop
                map.put("PEDIDOID", Integer.parseInt(o[15].toString())); 
deveria pegar a posicao 15 onde se encontra o campo cod_ped do Pedido e gerar o relatório, nao sei se é assim.

Eu tenho outros modulos do sistema que realmente passa somente um registro, mas isso é que o usuario imprimi somente um mesmo.  Mas neste caso ele vai selecionar varios checkbox como vc viu na tela, e gerar em 1 PDF todos os pedidos marcados  Mestre_detalhe.

Voce acha que devo alterar a forma ou tem outra maneira ?


Valeuu

Victor










GOSTEI 0
Victor Lima

Victor Lima

21/10/2009

Ok, eu identifiquei que está chamando somente o primeiro pedido, pois a minha consulta tinha a seguinte sintaxe WHERE pedido."cod_ped" IN ( $P ), quando eu tento colocar o meu  $P para ser do tipo List, é apresentado um erro, informando que a minha query não aceita este tipo lista, como eu faco para que a minha query aceite esse tipo de comando, eu vi algo na internet do tipo $X{ in,  pedido."cod_ped",  $P }, a query funcionou, mas na hora de gerar o relatório deu um erro.

Abracos

victor
GOSTEI 0
Henrique Weissmann

Henrique Weissmann

21/10/2009

Victor,

no caso de instruções SQL que incluam o operador in, nem sempre as coisas funcionam tão bem. Nestes casos, quando enfrento problemas, costumo fazer uma gambiarra (sim, as vezes gambiarras são inevitáveis).

Eu passo como string para o PreparedStatement um texto formado pelos valores de id separados por virgula. Costuma funcionar bem desta maneira. No entanto, se não houverem itens na lista, será emitida uma excessão. Neste caso, você precisa fazer algum tratamento (passar um id inválido por exemplo funciona).
GOSTEI 0
Victor Lima

Victor Lima

21/10/2009

Obrigado Henrique,

Fiz o seguinte:

Percebi que as coisas estavam se complicando para meu lado e resolvi mudar a pesquisa, ao invez de buscar pelo id do pedido mandei buscar por uma faixa de data e por um paramtro que traria somente um deposito, como mostra a tela de pesquisa.

Seleciono todos na tela e mando para impressora. Ai imprimiu todos em um PDF só.

Deu certo e vou deixar assim, tenho mil coisas para fazer ainda.

Valeu pela força.

Obrigado

Victor
GOSTEI 0
POSTAR