Olá pessoal. Sempre quando começo um novo projeto que tenho que usar relatórios, eu procuro sempre automatizar o processo de compilação dos mesmos. Para quem não sabe, o NetBeans utiliza o Apache Ant (parecido com o make do C/C++) para executar o build do projeto, ou seja, é o Ant que faz a mágica de compilar os arquivos .java, copiar determinados arquivos para algum diretório, criar o pacote de distribuição e assim por diante. Além do comportamento padrão do Ant para cada tipo de projeto, podemos inserir trechos de código no arquivo de build para que tarefas personalizadas possam ser executadas durante o processo de build.
Sendo assim, hoje vou ensinar como personalizar esse arquivo de build de forma a fazer com que sempre que nosso projeto for executado, sejam compilados os arquivos de código fonte dos relatórios (.jrxml), fazendo com que nosso projeto SEMPRE contenha a versão compilada que corresponde a última versão da definição dos relatórios. Com isso, evitamos ter que ficar compilando manualmente os relatórios a cada vez que alterarmos um arquivo.
Vou usar como base o projeto finalizado na Parte 4 do tutorial sobre relatórios. Clique aqui para fazer o download do projeto. Como nosso projeto é desktop, vou abordar com mais detalhes a personalização do arquivo de build para esse tipo de projeto, mas no final do tutorial eu vou postar o trecho de código para o arquivo de build de um projeto Web. Então vamos lá!
Primeiramente, abra o projeto no NetBeans. Ao abri-lo, verifique que por padrão a aba “Projects” tomará o foco. Ao lado desta aba, existe a aba “Files”. Nessa aba é mostrada a estrutura real do projeto, ou seja, a estrutura de diretórios e arquivos que ficam armazenada no seu computador, enquanto na aba “Projects” é mostrada uma estrutura abstrata do projeto que esconde os detalhes da estrutura real. Veja a Figura abaixo.
Note que destaquei dois arquivos na estrutura. O arquivo build-impl.xml é gerado automaticamente pela IDE, então mesmo que você o altere ela vai regerá-lo sempre. Sendo assim, nunca mexa nesse arquivo. Use-o para ver como o início do processo de build padrão funciona. O outro arquivo destacado, o build.xml, é o arquivo que podemos alterar para inserir nossas tarefas de build personalizadas. Durante o processo de build, o Ant copia os targets configurados no build-impl.xml para o build.xml, para então executar o arquivo de build.
Recomendo que vocês leiam todos os comentários que são criados dentro do build.xml. Neles vocês terão uma ideia de como o processo funciona. Notem que logo no início, são listados vários targets que podemos personalizar: -pre-init, -post-init, -pre-compile, etc. O nome de cada target é auto-explicativo, além é claro de ter o comentário explicando quanto eles são executados. Falei dos targets várias vezes, mas ainda não expliquei o que eles são. Um target é como se fosse um “passo” no processo de build. Você pode ter um ou vários passos durante o processo de build e cada passo pode depender de um ou vários passos que foram executados anteriormente. Por exemplo, um target que faz o empacotamento do projeto em um .jar, depende do target que faz a compilação dos arquivos .java.
No nosso arquivo de build, nós vamos inserir tarefas dentro do target “-post-compile”, ou seja, o target que é executado depois que os arquivos .java do projeto são compilados. Segue o código do build.xml comentado.
build.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- Documentação (omitida) --> <project name="TutorialRelatorios" default="default" basedir="."> <description>Builds, tests, and runs the project TutorialRelatorios.</description> <import file="nbproject/build-impl.xml"/> <!-- Documentação (omitida) --> <!-- configurando o target -post-compile, que é executado depois da compilação dos arquivos .java do projeto--> <target name="-post-compile"> <!-- Compilação das definições dos relatórios --> <!-- a tarefa "echo" do Ant mostra uma mensagem na saída --> <echo>Iniciando compilação das definições de relatórios...</echo> <!-- Define o classpath usado para a compilação dos relatórios --> <!-- A tarefa "path" do Ant define um caminho com id de "jrc.classpath" que indica um conjunto de arquivos (fileset) que correspondem a todos os .jars (que serão usados na compilação) localizados no diretório ${build.dir}/../lib/JasperReports-3.7.5. Quando o build for executado, a propriedade ${build.dir} será substituida por C:\<caminho>\TutorialRelatorios\build, sendo assim estamos acessando o diretório C:\<caminho>\TutorialRelatorios\lib\JasperReports-3.7.5, que no nosso projeto armazena todos os .jars utilizados pelo JasperReports. Para entender o que está acontecendo, sempre verifique a estrutura do projeto (na aba File). --> <path id="jrc.classpath"> <fileset dir="${build.dir}/../lib/JasperReports-3.7.5" includes="*.jar"/> </path> <!-- Definimos então uma tarefa customizada do Ant, chamada "jrc", que é implementada na classe net.sf.jasperreports.ant.JRAntCompileTask, que por sua vez é usada para compilar arquivos .jrxml Note que é necessário configurar o classpath para o Ant saber onde a classe está definida, além das possíveis dependências que ela utiliza. O classpath vem da tarefa "path" que configuramos anteriormente, ou seja, todos os .jars do diretório C:\<caminho>\TutorialRelatorios\lib\JasperReports-3.7.5 --> <taskdef name="jrc" classname="net.sf.jasperreports.ant.JRAntCompileTask"> <classpath refid="jrc.classpath"/> </taskdef> <!-- Quando testamos nossos relatórios, eles são compilados, gerando arquivos .jasper. O problema é as vezes nós alteramos o arquivo fonte e esquecemos de compilar. Sendo assim, caso existam definições de relatórios compiladas (que podem corresponder à versões antigas dos .jrxml's), a tarefa "delete" do Ant (definida abaixo) apaga todos os arquivos .jasper do diretório ${build.classes.dir} (C:\<caminho>\TutorialRelatorios\build\classes), ou seja, onde os arquivos .jasper são copiados durante o processo de build normal. --> <delete> <fileset dir="${build.classes.dir}" includes="*.jasper"/> </delete> <!-- Por fim, compilamos as definições de relatórios (.jrxmls contidos no diretório "relatorios") do nosso projeto, sendo que os arquivos compilados (.jasper) são gerados no diretório ${build.classes.dir}, ou seja, em C:\<caminho>\TutorialRelatorios\build\classes. Note que usamos a tarefa "jrc" que definimos acima e precisamos passar novamente o classpath definido na tarefa "path". --> <jrc srcdir="relatorios" destdir="${build.classes.dir}"> <classpath refid="jrc.classpath"/> <include name="*.jrxml"/> </jrc> <!-- Legal, terminou o processo, definições compiladas --> <echo>Compilação das definições de relatórios finalizada!</echo> </target> </project>
Sendo assim, copie o target listado acima para dentro do seu build.xml e salve o arquivo. Dê um “Clean and Build” no projeto (volte para a aba “Projects”, botão direito no projeto, “Clean and Build”), ou então clique no botão com um martelo e uma vassoura na barra de tarefas. Se tudo deu certo, a saída do NetBeans vai ser essa aqui:
init: deps-clean: Updating property file: C:\<caminho>\TutorialRelatorios\build\built-clean.properties Deleting directory C:\<caminho>\TutorialRelatorios\build clean: init: deps-jar: Created dir: C:\<caminho>\TutorialRelatorios\build Updating property file: C:\<caminho>\TutorialRelatorios\build\built-jar.properties Created dir: C:\<caminho>\TutorialRelatorios\build\classes Created dir: C:\<caminho>\TutorialRelatorios\build\empty Compiling 4 source files to C:\<caminho>\TutorialRelatorios\build\classes Copying 5 files to C:\<caminho>\TutorialRelatorios\build\classes Iniciando compilação das definições de relatórios... Compiling 5 report design files. log4j:WARN No appenders could be found for logger (net.sf.jasperreports.engine.xml.JRXmlDigesterFactory). log4j:WARN Please initialize the log4j system properly. File : C:\<caminho>\TutorialRelatorios\relatorios\ClientesPorNome.jrxml ... OK. File : C:\<caminho>\TutorialRelatorios\relatorios\ClientesCollectionDS.jrxml ... OK. File : C:\<caminho>\TutorialRelatorios\relatorios\LocacoesPorClientes_Locacoes.jrxml ... OK. File : C:\<caminho>\TutorialRelatorios\relatorios\LocacoesPorClientes.jrxml ... OK. File : C:\<caminho>\TutorialRelatorios\relatorios\Clientes.jrxml ... OK. Compilação das definições de relatórios finalizada! compile: Created dir: C:\<caminho>\TutorialRelatorios\dist Copy libraries to C:\<caminho>\TutorialRelatorios\dist\lib. Building jar: C:\<caminho>\TutorialRelatorios\dist\TutorialRelatorios.jar To run this application from the command line without Ant, try: java -jar "C:\<caminho>\TutorialRelatorios\dist\TutorialRelatorios.jar" jar: BUILD SUCCESSFUL (total time: 7 seconds)
Ou seja, ao executar o build no projeto, os arquivos .java são compilados e então cada arquivo .jrxml é compilado, gerando um .jasper em “C:\<caminho>\TutorialRelatorios\build\classes”, que no caso é a raiz do pacote do nosso projeto. Note que desta forma, sempre teremos os arquivos .jasper que correspondem às ultimas versões das definições dos relatórios. A seguir está listado o target que faz o mesmo processo para o nosso projeto Web feito na Parte 5 do tutorial. Caso queira, clique aqui para fazer o download do projeto.
build.xml (projeto Web)
<target name="-pre-dist"> <!-- Compilação das definições dos relatórios --> <echo>Iniciando compilação das definições de relatórios...</echo> <!-- Define o classpath usado para a compilação dos relatórios --> <path id="jrc.classpath"> <fileset dir="${build.classes.dir}/../lib" includes="*.jar"/> </path> <!-- Define a tarefa customizada do Ant que compila as definições dos relatórios--> <taskdef name="jrc" classname="net.sf.jasperreports.ant.JRAntCompileTask"> <classpath refid="jrc.classpath"/> </taskdef> <!-- Compila as definições .jrxml ==> .jasper --> <jrc srcdir="relatorios" destdir="${build.classes.dir}"> <classpath refid="jrc.classpath"/> <include name="*.jrxml"/> </jrc> <echo>Compilação das definições de relatórios finalizada!</echo> </target>
Note que o target listado acima difere um pouco do primeiro que listei (tipo do target e parte do classpath). Como exercício, tente entender porque o código é diferente e se ele pode ficar igual ou mais parecido ao primeiro target que foi mostrado. Faça mudanças no arquivo para poder entender melhor o que acontece. Os scripts que mostrei são apenas uma sugestão. Se você quiser inserir outras tarefas do Ant no build do seu projeto, dê uma olhada no manual: http://ant.apache.org/manual/index.html. Outro detalhe é que vocês conseguirão adaptar esse script para qualquer projeto, mesmo que a estrutura dele seja diferente dos projetos que criamos no tutorial.
Então é isso pessoal, espero que tenham gostado. No próximo tutorial vamos aprender os primeiros passos para trabalhar com a biblioteca JavaScript jQuery. Abraço!