Usando JExcel API numa aplicação WEB Struts
Crie uma aplicação web que edita planilhas do Microsoft Excel.
Crie uma aplicação web que edita planilhas do Microsoft Excel
Hoje em dia as empresas usam planilhas Excel para organizar quase tudo que ainda não é organizado por um sistema. Muitas vezes, mesmo havendo um sistema específico para determinada tarefa (como o MS Project para gerenciamento de projetos ou JIRA para controle de Trouble Tickets), muitos ainda preferem usar planilhas Excel, por sua flexibilidade e facilidade de uso. Dessa forma, torna-se extremamente útil poder criar sistemas web que saibam manipular planilhas Excel, que é o que veremos nesse artigo.
É suporto que o leitor saiba usar a ferramenta ANT para empacotar a aplicação em um arquivo WAR (Web Archive). Também é suporto que o mesmo saiba usar algum IDE Java para trabalhar com o código fonte que criaremos e a usar um Web Server como o Apache Tomcat para rodar a aplicação criada.
É necessário também baixar a versão 1.3.8 do framework Struts, que pode ser encontrado no site http://struts.apache.org e a JExcel API, que pode ser encontrada no site http://jexcelapi.sourceforge.net/. Não se esqueça de ter o ANT instalado em sua máquina no PATH do sistema.
A aplicação que criaremos será bem simples, mas suficiente para os fins de demonstração ao qual esse artigo se propõe. Nossa aplicação terá uma página inicial que permite ao usuário escolher um arquivo Excel em sua máquina para formatação. Ao clicar no botão "Formatar", o arquivo será enviado ao servidor e será feita uma varredura em todas as células de cada planilha. Todas as células numéricas terão sua cor de fundo alterada para vermelho e todas as células com texto, para azul.
Crie uma pasta raiz para a aplicação em seu disco, com o nome de JExcelApiStrutsExample. Essa pasta pode ser a pasta de seu projeto no seu IDE predileto. Dentro dessa pasta, crie as seguintes subpastas:
src:para guardar os arquivos ".java"
lib:para guardar os arquivos ".jar" de dependência
build:para guardar o build do ANT
etc:para guardar arquivos .properties
web/jsp: para guardar os JSPs
web/WEB-INF:para guardar deployment descriptors.
web/tld:para guardar arquivos de Tag library, como os que vem com o Struts.
Copie os JARS necessários do struts e da JExcel API para a pasta libs. Isso inclui o arquivo jxl.jar da JExcel API e todos os JARs incluídos na pasta lib da distribuição do struts. Copie os arquivos TLD do struts para a pasta web/tld.
Crie um arquivo chamado index.jsp dentro da pasta web, conforme mostra a listagem 1. Esse é o único arquivo que ficará fora da pasta JSP. Coloque o seguinte conteúdo no mesmo:
Listagem 01. Arquivo web/index.jsp
Tudo o que esse JSP faz é redirecionar a página atual para o JSP definido como welcome na configuração do struts.
Como nossa aplicação é bem simples, usaremos só mais um JSP. Crie um arquivo chamado Welcome.jsp na pasta web/jsp e então coloque nele o conteúdo da listagem 2.
<title>Exemplo JExcel API</title>
<h3>Exemplo JExcel API</h3>
<p>Por favor, escolha o arquivo excel a ser analisdo</p>
<html:form action="/FormatExcelAction.do" method="post"
<html:file property="arquivo" title="Arquivo Excel" />
<html:submit title="Processar arquivo" />
Listagem 02. Arquivo web/jsp/Welcome.jsp
Esse JSP simplesmente usa algumas tag libs do Struts para renderizar um form HTML com um input do tipo arquivo e um botão submit. Perceba que o form foi configurado para ser enviado via método POST com a codificação de multipart. Isso fará com que arquivo selecionado seja enviado pelo próprio stream http (e não como parâmetro da URL) e também fará com que o arquivo binário seja transformado em texto para que possa ser enviado viu http, numa codificação MIME específica para esse fim. O importante disso tudo é que quando o arquivo for recebido no lado do servidor, será preciso codificá-lo de volta para binário.
Antes de complicarmos mais, vejamos como ficam o web.xml e o struts-config.xml, nas listagens 3 e 4, respectivamente.
<display-name>JExcel Api Struts Example</display-name>
Listagem 03. Arquivo web/WEB-INF/web.xml
<form-bean name="FormatExcelForm" type="FormatExcelForm" />
<action path="/Welcome" forward="/WEB-INF/jsp/Welcome.jsp" />
<action path="/FormatExcelAction" type="FormatExcelAction"
name="FormatExcelForm" scope="request" validate="false"
input="/WEB-INF/jsp/Welcome.jsp">
<forward name="sucesso" path="/WEB-INF/jsp/Welcome.jsp" />
Listagem 04. Arquivo web/WEB-INF/struts-config.xml
Nada demais, para quem já está acostumado com Struts, certo? Simplesmente configuramos o servlet controller do Struts no web.xml e indicamos as TLDS. No struts-config.xml, configuramos o forward welcome, que havíamos usado no index.jsp, para que redirecionasse para o Welcome.jsp que criamos. Como esse último fica dentro de WEB-INF, não podemos acessá-lo diretamente, tornando nossa aplicação mais bem feita em termos de segurança.
Também definimos uma action e um form. A action será chamada pelo botão submit de nosso formulário JSP e o form é um bean que conterá o arquivo transmitido. O forward "sucesso" é opcional, não vamos usá-lo em nosso exemplo, está aí somente para ficar claro que não vamos sair nunca dessa página.
Vejamos como ficou o bean Form que usamos na listagem 5.
public class FormatExcelForm extends ActionForm {
private static final long serialVersionUID = 4294242013432948993L;
private FormFile arquivo;
public FormFile getArquivo() {
public void setArquivo(FormFile arquivo) {
Listagem 05. Arquivo src/FormatExcelForm.java
O serial version UID existe somente pelo fato do arquivo implementar a interface Serializable. Perceba que usamos a classe FormFile do Struts. Essa classe faz parte do suporte que o Struts tem para upload de arquivos. Como temos uma propriedade desse tipo em nosso form com o mesmo nome do campo tipo "file" do formulário html (o nome da propriedade é "arquivo"), o Struts automaticamente irá decodificar o arquivo de volta para binário, colocar nessa propriedade através do método setter e fornecer o form como parâmetro para nossa action.
Vejamos como ficou a action na listagem 6:
public class FormatExcelAction extends Action {
FormatExcelForm uploadForm = (FormatExcelForm) form;
FormFile arquivo = uploadForm.getArquivo();
InputStream in = arquivo.getInputStream();
// Cria workbook novo a partir do recebido
WritableWorkbook w = Workbook.createWorkbook(response
.getOutputStream(), Workbook.getWorkbook(in));
for (int i = 0; i < w.getNumberOfSheets(); i++) {
for (int j = 0; j < w.getSheet(i).getColumns(); j++)
for (int k = 0; k < w.getSheet(i).getRows(); k++) {
Cell celula = w.getSheet(i).getCell(j, k);
System.out.println("celula sheet(" + i + ") [" + j
+ ", " + k + "] = " + celula);
if (celula.getType() == CellType.NUMBER) {
WritableCellFormat novoFormato = new WritableCellFormat(
celula.getCellFormat());
novoFormato.setBackground(Colour.RED);
WritableCell celulaModificavel = w.getSheet(i)
.getWritableCell(j, k);
celulaModificavel.setCellFormat(novoFormato);
} else if (celula.getType() == CellType.LABEL) {
novoFormato.setBackground(Colour.AQUA);
throw new Exception("Erro ao transformar o arquivo: ", e);
Listagem 06. Arquivo src/FormatExcelAction.java
Aqui é que começa a entrar a JExcel API. Através do FormFile que o Struts já nos forneceu prontinho, só precisamos conseguir um InputStream para ler os dados transmitidos. O que queremos fazer é: criar um novo arquivo Excel a partir desse, para que seja modificado e enviado como resposta.
Para tanto, obtemos também um OutputStream a partir do objeto response, usando o método Response.getOutputStream(). Dessa forma, usamos o InputStream para recuperar os dados transmitidos pela página e o OutputStream para transmitir os dados de volta.
Com a JExcel API, esse trabalho é facilitado. O comando
WritableWorkbook w = Workbook.createWorkbook(
response.getOutputStream(), Workbook.getWorkbook(in));
cria um novo objeto WorkBook modificável, que corresponde a uma planilha, no OutputStream, usando o arquivo transmitido como base. Então nós modificamos o Workbook e executamos os comandos
para escrever de fato o arquivo para a resposta http.
Perceba que setamos alguma propriedade importantes no objeto response:
O primeiro comando dirá ao browser que um arquivo Excel está sendo transmitido. A segunda linha indica que não estamos redirecionando para uma outra página, mas sim para um download, de forma que o browser mostrará uma tela ao usuário perguntando se ele deseja abrir ou salvar o arquivo sendo transmitido. Se escolher salvar, o arquivo terá o nome default de sampleName.xls.
Mas afinal, o que fizemos no arquivo Excel? Fizemos um loop (aliás, três loops) pelo arquivo, percorrendo cada uma de suas worksheets. Para cada worksheet, usamos os comandos w.getSheet(i).getColumns() e w.getSheet(i).getRows() para percorrer por todas as células de cada sheet. O tamanho de cada sheet é retornado dependendo do conteúdo existente em suas células.
Para cada célula, verificamos o tipo do conteúdo. Se for um número, pintamos a cor de vermelho e, se for texto estático (LABEL), pintamos de azul.
Foi muito importante criarmos um objeto do tipo WriteableCell para modificarmos o formato. A JExcel API faz distinção entre Cell e WriteableCell, de forma que o último herda do primeiro. Só conseguimos modificar o arquivo porque criamos um objeto WritableWorkbook a partir do arquivo de entrada no OutputStream do response. Não é possível criar um objeto desses apenas a partir de um InputStream, somente um Workbook simples, não modificável.
Por último, mas não menos importante, falta o arquivo de build, para construirmos nossa aplicação. Vejamos como ficou o nosso nas listagens 7 e 8:
tomcat_home=G:/dev_env/Tomcat5/
tomcatlib=${tomcat_home}/common/lib
tomcatapps=${tomcat_home}/webapps
debug_on=true
Listagem 07. Arquivo build/build.properties
<project name="JExcelApiStrutsExample" default="package" basedir="..">
<property name="webinf" value="web/WEB-INF" />
<property name="etc" value="etc" />
<property name="jsp" value="web/jsp" />
<property name="index.jsp" value="web/index.jsp" />
<property name="web.xml" value="${webinf}/web.xml" />
<property name="tld" value="web/tld" />
<property name="build" value="build/" />
<property name="appname" value="JExcelApiStrutsExample" />
<!-- generated folders -->
<property name="distbuild" value="${dist}/build" />
<property name="distwebinf" value="${distbuild}/WEB-INF" />
<property name="classes" value="${distwebinf}/classes" />
<property name="distjsp" value="${distwebinf}/jsp" />
<property name="disttld" value="${distwebinf}/tld" />
<property name="distlibs" value="${dist}/lib" />
<property name="warname" value="${dist}/${appname}.war" />
<mkdir dir="${distbuild}" />
<mkdir dir="${distwebinf}" />
<mkdir dir="${disttld}" />
<mkdir dir="${distjsp}" />
<!-- Create the directory for the jar files -->
<mkdir dir="${distlibs}" />
<javac srcdir="${src}" destdir="${classes}" debug="${debug_on}">
<fileset dir="${tomcatlib}">
<!-- Copy files to dist dir -->
<copy todir="${distlibs}/" flatten="true">
<copy todir="${classes}/">
<copy todir="${disttld}/">
<fileset dir="${tld}">
<copy todir="${distjsp}/">
<copy tofile="${distbuild}/index.jsp" file="${index.jsp}" />
<copy todir="${distwebinf}/">
<include name="**.xml" />
<!-- make a war file -->
<war destfile="${warname}" webxml="${web.xml}">
<fileset dir="${distbuild}">
<lib dir="${distlibs}">
<!-- Delete the ${dist} directory tree -->
<delete dir="${tomcatapps}/${appname}" />
<delete file="${tomcatapps}/${appname}.war" />
<copy todir="${tomcatapps}" file="${warname}" />
Listagem 08. Arquivo build/build.xml
O build.properties simplesmente configura algumas propriedades a serem usadas no build.xml, como a pasta onde se encontra instalado o tomcat, pastas onde se encontram as libs e opções de debug. O segundo tem os targets para construção. O target init simplesmente cria uma pasta dist dentro do projeto, o target compile compila os arquivos .Java e os joga para dentro de dist, o target package copie os arquivos do projeto para uma estrutura de pastas de um arquivo war dentro de DIST e gera o WAR a partir da mesma. Finalmente, existe um target deploy, que copia o WAR gerado para dentro da pasta webapps do Tomcat, apagando primeiro a versão anterior.
Vejamos como funciona a aplicação rodando:
Figura 01. Entrando na aplicação
Figura 02. Escolhendo um arquivo exemplo
Figura 03. Arquivo exemplo original
Figura 04. Clicando no botão submit
Figura 05. Arquivo exemplo depois do processamento
A última linha não foi modificada, pois era uma fórmula. Poderíamos tê-la modificado também, bastante verificar seu tipo.
Agora é sua vez! Baixe a JExcel API e manipule arquivos Excel a vontade em suas aplicações web! Até o próximo artigo.