Introdução
ReportBuilder
Para a utilização da API de relatórios temos a classe ReportBuilder que através de sua interface fluente facilita a construção do relatório, segue abaixo um exemplo de um relatório simples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public StreamedContent relatorioSimples() { List<ProdutoEntity> listaProduto = criaListaProduto(); ReportBuilder reportBuilder = ReportBuilder .createInstance() .setTitle("Relatório de Produtos") .setSubtitle("Período: 01/2017 até 12/2017") .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class) .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class) .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class) .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false) .withListData(listaProduto); try { return reportBuilder.exportPdf("relatorioProdutoSimples"); } catch (JRException | IOException ex) { LogUtils.generate(ex); } return null; } private List<ProdutoEntity> criaListaProduto() { List<ProdutoEntity> listaProduto = new ArrayList<>(); listaProduto.add(criaProduto("001", "Caneta", UnidadeType.UNIDADE, "1.39")); listaProduto.add(criaProduto("002", "Borracha", UnidadeType.UNIDADE, "3.27")); listaProduto.add(criaProduto("003", "Mouse", UnidadeType.UNIDADE, "10.50")); listaProduto.add(criaProduto("004", "Teclado", UnidadeType.UNIDADE, "45.60")); listaProduto.add(criaProduto("005", "Monitor", UnidadeType.UNIDADE, "109.99")); return listaProduto; } private ProdutoEntity criaProduto(String codigo, String descricao, TipoType tipo, String valor){ ProdutoEntity produtoEntity = new ProdutoEntity(); produtoEntity.setCodigo(codigo); produtoEntity.setDescricao(descricao); produtoEntity.setTipo(tipo); produtoEntity.setValor(new BigDecimal(valor)); return produtoEntity; } |
Na linha 2 criamos uma lista simples para a saída do relatório. A partir da linha 4 começa a construção, segue um exemplo da saída acima:
Estilizando o cabeçalho da página com um template:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public StreamedContent relatorioComTemplate() { List<ProdutoEntity> listaProduto = criaListaProduto(); ReportBuilder reportBuilder = ReportBuilder .createInstance() .setTitle("Relatório de Produtos") .setSubtitle("Período: 01/2017 até 12/2017") .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class) .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class) .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class) .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false) .withListData(listaProduto) .addParameter("emissor", "Bruno Araujo") .addParameter("sistema", BundleUtils.messageBundle("label.siglaSistema")) .addParameter("tituloPrefeitura", BundleUtils.messageBundle("label.titulo1")) .addParameter("tituloSecretaria", BundleUtils.messageBundle("label.titulo2")) .addParameter("imagemTopo",JsfUtils.getPath("resources/images/logo-menu.png")) .setTemplateFile(JsfUtils.getPath("relatorios/templates/") + "templateReportLandscape.jrxml") .withLandscapeOrientation(); try { return reportBuilder.exportPdf("relatorioProdutoSimples"); } catch (JRException | IOException ex) { LogUtils.generate(ex); } return null; } |
Saída:
ReportGroupBuilder
Para criar agrupamento no relatório utilizamos em conjunto com o ReportBuilder a classe ReportGroupBuilder conforme abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public StreamedContent relatorioComGrupo() { List<ProdutoEntity> listaProduto = criaListaProduto(); ReportBuilder reportBuilder = ReportBuilder .createInstance() .setTitle("Relatório de Produtos") .setSubtitle("Período: 01/2017 até 12/2017") .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class) .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class) .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class) .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false) .withListData(listaProduto); try { return reportBuilder .addGroup(ReportGroupBuilder.createInstance(reportBuilder, "tipo") .addFooterVariable("SubTotal","codigo", DJCalculation.COUNT) .addFooterVariable("valor", DJCalculation.SUM) .build()) .addGrandTotalLegend(BundleUtils.messageBundle("label.total")) .addGlobalFooterVariable("valor", DJCalculation.SUM) .exportPdf("relatorioProdutoGrupo"); } catch (JRException | IOException e) { LogUtils.generate(); } return null; } |
Na linha 15 criamos um agrupamento para o atributo tipo da classe que esta na lista, conforme o valor desse atributo muda é gerado um totalizador no atributo valor e um totalizador geral, conforme abaixo.
Obs: para o agrupamento funcionar conforme o esperado a lista deve estar ordenada conforme a necessidade:
Com um agrupamento mais elaborado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public StreamedContent relatorioComGrupoHeaderEFooter() { List<ProdutoEntity> listaProduto = criaListaProduto(); ReportBuilder reportBuilder = ReportBuilder .createInstance() .setTitle("Relatório de Produtos") .setSubtitle("Período: 01/2017 até 12/2017") .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class) .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class) .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class) .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false) .withListData(listaProduto); try { return reportBuilder .addGroup(ReportGroupBuilder.createInstance(reportBuilder, "tipo") .setGroupLayout(GroupLayout.VALUE_FOR_EACH) .addHeaderVariable("tipo", DJCalculation.FIRST) .addFooterVariable("SubTotal","codigo", DJCalculation.SYSTEM) .addFooterVariable("descricao", DJCalculation.COUNT) .addFooterVariable("valor", DJCalculation.SUM) .build()) .addGrandTotalLegend(BundleUtils.messageBundle("label.total")) .addGlobalFooterVariable("descricao", DJCalculation.COUNT) .addGlobalFooterVariable("tipo", DJCalculation.SYSTEM) .addGlobalFooterVariable("valor", DJCalculation.SUM) .exportPdf("relatorioProdutoGrupo"); } catch (JRException | IOException e) { LogUtils.generate(); } return null; } |
ReportSubReportBuilder
Com um subrelatório é possível colocar uma lista no meio do detalhe do relatório, usaremos em conjunto com o ReportBuilder e ReportGroupBuilder, conforme abaixo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | public StreamedContent relatorioComSubRelatorio() { List<ProdutoEntity> listaProduto = criaListaProduto(); ReportBuilder reportBuilder = ReportBuilder .createInstance() .setTitle("Relatório de Produtos") .setSubtitle("Período: 01/2017 até 12/2017") .addField(BundleUtils.messageBundle("label.codigo"), "codigo", 100, String.class) .addField(BundleUtils.messageBundle("label.descricao"), "descricao", 200, String.class) .addField(BundleUtils.messageBundle("label.tipo"), "tipo", 400, TipoType.class) .addFieldNumber(BundleUtils.messageBundle("label.valor"), "valor", 100, BigDecimal.class, true, false) .addField("listaMateriaPrima", List.class) .withListData(listaProduto); try { return reportBuilder .addGroup(ReportGroupBuilder.createInstance(reportBuilder, "codigo").build()) .addSubReport(ReportSubReportBuilder .createInstance() .addField(BundleUtils.messageBundle("label.nome"), "nome", 300, String.class) .addField(BundleUtils.messageBundle("label.quantidade"), "quantidade", 200, Long.class) .build(), "listaMateriaPrima", 1) .exportPdf("relatorioProdutoSubRelatorio"); } catch (JRException | IOException ex) { LogUtils.generate(ex); } return null; } |
Saída:
Conclusão
Nesse post mostrei alguns exemplos de como implementar relatórios de forma dinâmica (Relatório simples, com template, com agrupamento e/ou subrelatório), sem muita complexidade na criação e manutenção.
Até mais,
Nenhum comentário:
Postar um comentário