GWT – basico, mas funcional

setembro 2nd, 2008

O GWT é um tecnologia extraordinária. Ela possibilita que aplicações sejam criadas em java e após compilado, transformado em JavaScript gerando assim uma aplicação dinâmica e bastante flexível.
A internet está cheia de tutorias e o próprio site do GWT somado ao grupo oficial de usuário é uma fonte excelente de informação para tirar dúvidas e melhorar o conhecimento.

Um problema que é muito comum nos vários tutoriais que vemos pela internet é que eles não são completos o suficientes para o usuário mais iniciante ter um compreensão da tecnologia e muitas vezes até desmotiva a continuidade em busca de um maior entendimento ante os primeiros desafios.

Para quem está iniciando uma boa alternativa é utilizar o Netbeans com seu plugin gwt4nb para GWT pois ele permite criar uma aplicação completa inclusive fazer deploy para seu servidor de aplicação.
Para o Eclipse, entretanto, não existe nenhuma boa alternativa livre (que eu conheça) para se trabalhar com o GWT, mas isso pode ser contornado de forma simples. Vamos lá:

Faça o download:
wget http://google-web-toolkit.googlecode.com/files/gwt-linux-1.5.2.tar.bz2
veja opções para outras plataformas em http://code.google.com/webtoolkit/versions.html

Descompacte o arquivo:
tar -xjvf gwt-linux-1.5.2.tar.bz2

download

Edite suas variáveis de ambiente criando a variavel para GWT_HOME e atualizando a variável PATH.
Em sistemas no padrão Linux basta editar o arquivo oculto chamando .profile em sua pasta pessoal adicionando as seguintes linhas

export GWT_HOME=/home/paulo/gwt-linux-1.5.2
export PATH=$PATH:$GWT_HOME

Lógico que você precisará substituir /home/paulo/gwt-linux-1.5.2 pela pasta onde você descompactou o gwt.
Em sistemas Windows o procedimento é realizado editando-se as propriedades do sistema conforme imagem abaixo:

variaveisWin

Criando um projeto para teste

O objetivo do nosso teste é apenas criar um esqueleto de uma aplicação padrão, acrescentando a ela uma serviço RPC e por
fim fazer o deploy num conteiner web, no nosso caso, para simplificar, o Tomcat, mas não é preciso nenhuma mudança para que este rode no Glassfish

no console digite:

cd workspace/
applicationCreator -out gwtWebMode -eclipse gwtWebMode br.com.sample.client.GwtWebMode

o gwt criou uma estrutura básica para trabalharmos. Normalmente usaríamos um outro recurso do gwt que é criar um projeto para o eclipse, com o comando projectCreator importando-o em seguida mas não vamos fazê-lo pois o projeto criado não gera os artefatos para uma aplicação web coisa que uma aplicação gwt é por natureza.

applicationCreator

O que vamos fazer é pedir para o Eclipse criar um novo projeto web justamente na pasta recém criada, isso aproveitará os arquivos criados pelo applicationCreator e nos dará os artefatos adicionais.

Abra o Eclipse e escolha File/New/Other/Dynamic Web Project
newProject

Digite o nome do projeto igual ao nome ao informado ao applicationCreator.
nameApplication

Sua aplicação já deverá funcionar em hosted mode. Experimente executar GwtWebMode-shell (está na pasta recém criada).

hostmode

O hostmoded é uma opção rápida para utilização durante a fase de desenvolvimento, mas nem todos os recursos que sua aplicação irá precisar são suportados.

Executando em WebMode

O que vamos fazer é criar um mecanismo capaz de compilar nossa aplicação e fazer o deploy dela em nosso servidor web. A melhor opção ainda é utilizar um script Ant

salve o arquivo abaixo na raiz de seu projeto com o nome build.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project name="gwtWebMode" default="deploy" basedir=".">
  3.  
  4.     <property environment="env" />
  5.     <property file="build.properties" />
  6.  
  7.     <path id="classpath">
  8.         <pathelement location="build" />
  9.         <pathelement location="src" />
  10.         <pathelement location="${gwt.dir}/gwt-user.jar" />
  11.         <pathelement location="${gwt.dir}/gwt-dev-linux.jar" />
  12.         <pathelement location="${gwt.dir}/gwt-servlet.jar" />
  13.         <fileset dir="${web.dir}/WEB-INF/lib/">
  14.             <include name="*.jar" />
  15.         </fileset>
  16.  
  17.     </path>
  18.  
  19.     <target name="clean" depends="clean.test" description="deletes all generated files">
  20.         <delete dir=".gwt-cache" />
  21.         <delete dir="build" />
  22.         <delete dir="dist" />
  23.         <delete dir="log" />
  24.  
  25.         <delete dir="container" />
  26.     </target>
  27.  
  28.     <target name="clean.test" description="deletes all generated test files">
  29.         <delete dir="test" />
  30.     </target>
  31.  
  32.     <target name="compile" depends="prepare" description="compiles Java source files to bytecode">
  33.         <javac srcdir="src" destdir="build" classpathref="classpath" debug="false">
  34.         </javac>
  35.     </target>
  36.  
  37.     <target name="compile.gwt" depends="compile" description="compiles Java source files to JavaScript">
  38.         <!-- Consider adding -Xms256m -Xmx512m to improve performance. -->
  39.         <java classname="com.google.gwt.dev.GWTCompiler" classpathref="classpath" fork="true" maxmemory="768m">
  40.             <arg line="-out build/www" />
  41.             <arg line="-style ${gwt-security}" />
  42.             <arg value="${package}.${module}" />
  43.         </java>
  44.         <move todir="build/www">
  45.             <fileset dir="build/www/${package}.${module}" />
  46.         </move>
  47.     </target>
  48.  
  49.     <target name="clean_www">
  50.         <delete dir="build/www" />
  51.     </target>
  52.  
  53.     <target name="hosted" depends="compile" description="runs the application in hosted mode">
  54.         <java classname="com.google.gwt.dev.GWTShell" classpathref="classpath" fork="true">
  55.             <jvmarg value="-XstartOnFirstThread" />
  56.             <arg line="-out ./www" />
  57.             <arg line="${package}.${module}/${module}.html" />
  58.         </java>
  59.     </target>
  60.  
  61.     <target name="prepare" depends="clean" description="creates output directories">
  62.         <mkdir dir="build" />
  63.         <mkdir dir="dist" />
  64.         <mkdir dir="log" />
  65.     </target>
  66.  
  67.     <target name="test" depends="clean.test,compile" description="runs all JUnit tests">
  68.         <mkdir dir="test" />
  69.         <junit fork="yes" printsummary="yes">
  70.             <!-- next line is only for Mac OS X -->
  71.             <jvmarg value="-XstartOnFirstThread" />
  72.             <classpath refid="classpath" />
  73.             <batchtest todir="test">
  74.                 <fileset dir="src" includes="**/${test}Test.java" />
  75.             </batchtest>
  76.             <formatter type="xml" />
  77.         </junit>
  78.         <junitreport toDir="test">
  79.             <fileset dir="test" />
  80.             <report format="frames" todir="test" />
  81.         </junitreport>
  82.         <exec os="Windows" executable="cmd.exe">
  83.             <arg line="/c start test/index.html" />
  84.         </exec>
  85.  
  86.  
  87.  
  88.  
  89.         <exec os="Mac OS X" executable="open">
  90.             <arg line="-a /Applications/Safari.app test/index.html" />
  91.         </exec>
  92.     </target>
  93.  
  94.     <target name="deploy" depends="clean_www, war,undeploy" description="deploys the war file to Tomcat">
  95.         <copy file="dist/${war}" todir="${app.server.deploy.dir}" />
  96.     </target>
  97.  
  98.     <target name="undeploy" description="undeploys the web app. from Tomcat">
  99.         <delete file="${app.server.deploy.dir}/${war}" />
  100.     </target>
  101.  
  102.     <target name="war" depends="compile, compile.gwt" description="builds the war file">
  103.         <delete file="dist/${war}" />
  104.        
  105.         <war destfile="dist/${war}" webxml="${web.dir}/WEB-INF/web.xml">
  106.  
  107.             <!-- bytecode from your Java code -->
  108.             <classes dir="build" includes="**/*.class" />
  109.            
  110.             <classes dir="src" includes="**/*.properties" />
  111.             <classes file="log4j.properties" />
  112.  
  113.             <manifest>
  114.                 <attribute name="Created-By" value="${user.name}" />
  115.                 <attribute name="Manifest-Version" value="1.0" />
  116.                 <attribute name="Ant-Version" value="${ant.version}" />
  117.             </manifest>
  118.  
  119.             <!-- generated HTML/JavaScript plus your CSS -->
  120.             <fileset dir="build/www"/>
  121.             <!-- supplied JAR -->
  122.             <lib dir="${web.dir}/WEB-INF/lib"/>
  123.             <lib file="${gwt.dir}/gwt-servlet.jar"/>
  124.         </war>
  125.     </target>
  126.  
  127. </project>

salve também esse arquivo de propriedades na mesma pasta com o nome build.properties

  1. gwt.dir=/home/paulo/gwt
  2. web.dir=${basedir}/WebContent
  3. module=GwtWebMode
  4. package=br.com.sample
  5. url=http://localhost:8080/${ant.project.name}/${package}.${module}/${module}.html
  6. war=${ant.project.name}.war
  7.  
  8. app.server.dir = /home/paulo/bin/apache-tomcat
  9. app.server.deploy.dir = ${app.server.dir}/webapps
  10. app.server.lib.dir = ${app.server.dir}/lib
  11. gwt-security=OBFUSCATE

Não vou entrar nos detalhes dos arquivos.
O Eclipse deve está se "queixando" que não conhece as classes do GWT. Para resolver este problema copie os arquivos
$GWT_HOME/gwt-user.jar
$GWT_HOME/gwt-dev-linux.jar
$GWT_HOME/gwt-servlet.jar

para a pasta: gwtWebMode/WebContent/WEB-INF/lib e dê um refresh em seu projeto.

Certifique-se que o Tomcat esteja instalado e em execução.
Abra o arquivo build.properties e altere as variáveis gwt.dir e app.server.dir para refletir sua instalação
gwt.dir=/home/paulo/gwt-linux-1.5.2
app.server.dir = /home/paulo/bin/apache-tomcat

Edite seu arquivo web.xml modificando a tag welcome-file

welcome

Clique com botão direito no arquivo build.xml e escolha Run As/Ant Build. Após concluindo abra o browse no seguinte endereço:

http://localhost:8080/gwtWebMode/

webmode

Incluindo um Serviço RPC

Um outro importante recurso do GWT é a possibilidade de executar serviços remotos. Esses serviços são servlets especiais que fazem ponte entre o javascript gerado e a parte servidora, possibilitando assim um completa integração com outras aplicações e os mais variados frameworks que somos dependentes.

O nosso serviço apenas receberá uma String e retornará a quantidade de caracteres deste.
inicie criando a interface StringLengthService. Ela precisa estender a interface RemoteService.

interface

  1. package br.com.sample.client;
  2.  
  3. import com.google.gwt.user.client.rpc.RemoteService;
  4.  
  5. public interface StringLengthService extends RemoteService {
  6.       public Integer length(String string);
  7. }

Em seguida você precisa de uma outra interface que permitirá invocar os serviços de forma assíncrona, ou seja ele será executado em background e comunicado assim que houver uma "resposta" da execução do serviço.

  1. package br.com.sample.client;
  2.  
  3. import com.google.gwt.user.client.rpc.AsyncCallback;
  4.  
  5. public interface StringLengthServiceAsync {
  6.       void length(String string, AsyncCallback async);
  7. }

Por fim criaremos a classe responsável por implementar o serviço: Ela deve estender RemoteServiceServlet, implementar a interface StringLengthService anteriormente criada e deve ficar no

  1. package br.com.sample.server

serviceimpl

  1. package br.com.sample.server;
  2.  
  3. import br.com.sample.client.StringLengthService;
  4.  
  5. import com.google.gwt.user.server.rpc.RemoteServiceServlet;
  6.  
  7. public class StringLengthServiceImpl extends RemoteServiceServlet implements
  8.         StringLengthService {
  9.  
  10.     @Override
  11.     public Integer length(String string) {
  12.         if (string != null)
  13.             return string.length();
  14.         return 0;
  15.     }
  16.  
  17. }

Declando os Serviços

Aqui está um ponto crucial na execução de serviços RPC. Caso seu interese seja apenas executar seu serviço em hosted mode basta editar o arquivo GwtWebMode.gwt.xml declando nele seu serviço:

  1. <servlet path="/StringLength/StringLengthService" class="br.com.sample.server.StringLengthServiceImpl" />

Só que não bastará isto para utiliza-lo em webmode. Você precisará declara-lo no arquivo web.xml como se faz com qualquer servlet.

servletmap

Utilizando o Serviço

Por fim faremos agora a utilização do serviço. Crie uma referência ao serviço da seguinte forma:

  1. this.lengthService = (StringLengthServiceAsync) GWT.create(StringLengthService.class);
  2.         ((ServiceDefTarget) lengthService).setServiceEntryPoint(GWT.getModuleBaseURL()+ "/StringLength/StringLengthService");

Veja o código completo: GwtWebMode.java

  1. package br.com.sample.client;
  2.  
  3. import com.google.gwt.core.client.EntryPoint;
  4. import com.google.gwt.core.client.GWT;
  5. import com.google.gwt.user.client.rpc.AsyncCallback;
  6. import com.google.gwt.user.client.rpc.ServiceDefTarget;
  7. import com.google.gwt.user.client.ui.Button;
  8. import com.google.gwt.user.client.ui.ClickListener;
  9. import com.google.gwt.user.client.ui.DialogBox;
  10. import com.google.gwt.user.client.ui.Image;
  11. import com.google.gwt.user.client.ui.Label;
  12. import com.google.gwt.user.client.ui.RootPanel;
  13. import com.google.gwt.user.client.ui.TextBox;
  14. import com.google.gwt.user.client.ui.VerticalPanel;
  15. import com.google.gwt.user.client.ui.Widget;
  16.  
  17. /**
  18. * Entry point classes define <code>onModuleLoad()</code>.
  19. */
  20. public class GwtWebMode implements EntryPoint {
  21.  
  22.     private StringLengthServiceAsync lengthService;
  23.  
  24.     /**
  25.      * This is the entry point method.
  26.      */
  27.     public void onModuleLoad() {
  28.  
  29.         // prepara o serviço
  30.         this.lengthService = (StringLengthServiceAsync) GWT.create(StringLengthService.class);
  31.         ((ServiceDefTarget) lengthService).setServiceEntryPoint(GWT.getModuleBaseURL()+ "/StringLength/StringLengthService");
  32.  
  33.         Image img = new Image("http://code.google.com/webtoolkit/logo-185x175.png");
  34.         Button button = new Button("length");
  35.         img.getElement().setId("pc-template-img");
  36.  
  37.         final TextBox textBox = new TextBox();
  38.         final Label lengthLabel = new Label();
  39.  
  40.         VerticalPanel vPanel = new VerticalPanel();
  41.         vPanel.setWidth("100%");
  42.         vPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
  43.         vPanel.add(img);
  44.         vPanel.add(textBox);
  45.         vPanel.add(button);
  46.         vPanel.add(lengthLabel);
  47.  
  48.         // Add image and button to the RootPanel
  49.         RootPanel.get().add(vPanel);
  50.  
  51.         button.addClickListener(new ClickListener() {
  52.             public void onClick(Widget sender) {
  53.                 lengthService.length(textBox.getText(),
  54.                         new AsyncCallback<integer>() {
  55.  
  56.                             public void onFailure(Throwable arg0) {
  57.                                 lengthLabel.setText("foi mal! deu erro!");
  58.                             }
  59.  
  60.                             public void onSuccess(Integer arg0) {
  61.                                 lengthLabel.setText("length = " + arg0.toString());
  62.                             }
  63.                         }
  64.  
  65.                 );
  66.             }
  67.         });
  68.     }
  69. }

final

Se deseja faça o download dos fontes gwtWebMode.zip

Entry Filed under: AJAX

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed