09/01/2018
por
FELIPE RODRIGUES DA SILVA em iMasters
Olá, caros leitores!
Este é o meu primeiro artigo no portal. Venho compartilhar algumas soluções técnicas que demorei pra encontrar em alguns cenários bem específicos.
Acredito que grande parte dos desenvolvedores
Java já conhecem a API de documentos Microsoft
Apache POI e já fizeram uso dela para gerar relatórios simples. Hoje venho apresentar uma das funcionalidades que a biblioteca também oferece, que é a criação de gráficos.
Para a exemplificação, criei um projeto maven com o spring boot, instalando a dependência WEB, um arquivo index.html para realizar a requisição do arquivo e um controlador responsável por gerar o arquivo, conforme a estrutura definida na imagem abaixo:
A versão escolhida do POI foi a 3.17 (suportada por versões mais antigas do Java) e para que a solução funcione, é preciso importar duas bibliotecas no arquivo pom.xml conforme abaixo:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
Nesta versão do POI temos algumas limitações sobre criar gráficos em um nível alto de representação (modo simples). Então, são “suportados” pelo apache poi, nesta versão, apenas gráficos de linhas e de dispersão, mas isso não quer dizer que só se pode gerar esses dois tipos de gráficos.
O POI oferece para os outros tipos presentes no Excel, a biblioteca poi-ooxml-schemas
, que disponibiliza objetos subjacentes baseados no xml gerado por arquivos xlsx.
Então, caso precise gerar outros tipos de gráficos na versão 3.17, será um pouco mais trabalhoso, mas não impossível (disponibilizarei posteriormente artigos ensinando a gerar outros tipos de gráficos nessa versão do poi).
Hoje já temos a versão 4.0, que oferece, em um nível alto de representação, suporte para outros tipos de gráficos. Porém, esta versão só pode ser utilizada em ambientes cuja versão mínima do Java é a 8 (assuntos para os próximos artigos).
Para que o código não ficasse muito extenso, utilizei uma planilha pronta como template, que exibe os gastos em determinadas categorias do primeiro semestre do ano de 2018. Nela, lemos os dados e geramos o gráfico do tipo linha conforme a imagem abaixo:
Os passos para gerar gráficos são simples – utilizamos classes e interfaces definidas nos pacotes.
· org.apache.poi.ss.usermodel
· org.apache.poi.xssf.usermodel
· org.apache.poi.ss.util
O principal é deixar bem claro o mapeamento dos dados dentro da planilha, para que ao selecionar as células que gerarão o gráfico, não ocorra erros (você só saberá se ocorreu erro de seleção de dados após abrir o arquivo gerado).
O código do controlador que gera o arquivo está abaixo, contendo comentários sobre os passos para criar o gráfico.
package com.teste.poi.testeExcel.controller;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.charts.AxisPosition;
import org.apache.poi.ss.usermodel.charts.ChartAxis;
import org.apache.poi.ss.usermodel.charts.ChartDataSource;
import org.apache.poi.ss.usermodel.charts.DataSources;
import org.apache.poi.ss.usermodel.charts.LegendPosition;
import org.apache.poi.ss.usermodel.charts.LineChartData;
import org.apache.poi.ss.usermodel.charts.LineChartSeries;
import org.apache.poi.ss.usermodel.charts.ValueAxis;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.charts.XSSFChartLegend;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("excel")
public class ExcelController {
@GetMapping("/grafico")
public ResponseEntity<String> exportExcelGrafico(HttpServletResponse response){
try{
InputStream input = ExcelController.class.getResourceAsStream("/templates/gastos.xlsx");
XSSFWorkbook book = getExcelFile(input);
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition",
"attachment; filename=\""
+ "Gerando Gráfico excel"
+ ".xlsx\"");
book.write(response.getOutputStream());
return new ResponseEntity<String>(HttpStatus.OK);
}
catch(Exception e){
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public XSSFWorkbook getExcelFile(InputStream fileTemplate) throws Exception{
try{
XSSFWorkbook book = new XSSFWorkbook(fileTemplate);
XSSFSheet abaSheet = book.getSheet("gastos");
int numRows = abaSheet.getPhysicalNumberOfRows();
XSSFDrawing designer = abaSheet.createDrawingPatriarch();
XSSFClientAnchor position = designer.createAnchor(0, 0, 0, 0, 0, numRows+1, 12, numRows +12);
XSSFChart graphic = designer.createChart(position);
XSSFChartLegend legend = graphic.getOrCreateLegend();
legend.setPosition(LegendPosition.BOTTOM);
graphic.setTitleText("Gastos do primeiro semestre de 2018");
LineChartData data = graphic.getChartDataFactory().createLineChartData();
ValueAxis yAxis = graphic.getChartAxisFactory().createValueAxis(AxisPosition.LEFT);
ChartAxis xAxis = graphic.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM);
yAxis.setMinimum(0);
ChartDataSource<String> columns = DataSources.fromStringCellRange(abaSheet, new CellRangeAddress(0,0,1,6));
for(int i = 1 ; i < numRows; i++){
ChartDataSource<Number> valueLinhas = DataSources.fromNumericCellRange(abaSheet, new CellRangeAddress(i,i,1,6));
LineChartSeries serie = data.addSeries(columns, valueLinhas);
CellReference titleSerie = new CellReference("gastos",i,0,false,false);
serie.setTitle(titleSerie);
}
graphic.plot(data, new ChartAxis[] { xAxis , yAxis });
return book;
}catch(IOException ex){
System.out.print("Erro ao carregar arquivo :" + ex.getMessage());
throw ex;
}
}
}
Temos o resultado como na imagem abaixo:
Como podem ver, não é muito difícil e também não é muito utilizado em vários cenários. Contudo, talvez um dia seja necessário.
Tendo em vista que a versão 4.0 do poi foi lançada no dia 07/09/2018, e foi retirado suporte para o Java 6 e 7, muitas aplicações que utilizam a biblioteca ainda não foram atualizados, ou – por restrição do Java – não podem atualizar.
Espero que tenha ajudado!