Uma das mais promissoras linguagens de programação ganhou mais força de uso com a criação de frameworks RAD, como é o exemplo do GXT que foi desenvolvido pelo Sencha e do outro lado está o GWT (Google Web Toolkit). Essas duas ferramentas permitem o desenvolvimento de aplicações web muito ricas de interface gráfica e garantem um bom desempenho.
A Aplicação
Para facilitar o desenvolvimento, a Google desenvolveu um plugin para o IDE Eclipse.

Após efetuar o donwload do plugin é preciso criar uma aplicação Web: File > New > Web Application Project.

É preciso informar o nome do projeto e um pacote padrão, no exemplo deste artigo não será utilizado o Google App Engine, ao clicar em Finish será criado o projeto com a estrutura padrão do projeto.

O GWT trabalha de forma assíncrona e como toda aplicação web precisa ser mapeado em um arquivo XML (web.xml). A separação das camadas dá-se pelos pacotes br.com, br.com.client, br.com.server e br.com.shared, tudo o que for referente à camada de visão da aplicação deverá ser colocado dentro do pacote br.com.client. Por padrão são gerados um arquivo HTML e um CSS, os dois são necessários para carregar o layout da aplicação juntamente com o código escrito em Java, que depois de compilado é transformado para JavaScript, o que aumenta ainda mais o desempenho da aplicação.
Para trabalhar com GXT é preciso além do projeto web, criar um projeto Java comum que irá conter o core da aplicação, dessa forma podemos dividir os interesses de negócios e a visão, obedecendo o padrão MVC. Dentro do projeto web deverão ser criadas as classes contendo os mesmos atributos das classes feitas no core da aplicação, essas classes deverão herdar da classe BaseModel, pois é o tipo aceito pelo GXT, ou seja todo objeto “bean” dentro do projeto web deverá ser um BaseModel.
Criando o Código
package br.com.client.domain;
import java.io.Serializable;
import com.extjs.gxt.ui.client.data.BaseModel;
public class PersonG extends BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code;
private String name;
private String phone;
private String cell;
private String email;
public Integer getCode() {
return get("code");
}
public void setCode(Integer code) {
set("code", code);
}
public String getName() {
return get("name");
}
public void setName(String name) {
set("name", name);
}
public String getPhone() {
return get("phone");
}
public void setPhone(String phone) {
set("phone", phone);
}
public String getCell() {
return get("cell");
}
public void setCell(String cell) {
set("cell", cell);
}
public String getEmail() {
return get("email");
}
public void setEmail(String email) {
set("email", email);
}
}
Não é preciso criar os atributos de referência de tipo primitivo, nem atributos do tipo String, porém os de outros tipos deverão ser explicitados dentro da classe. Os métodos Getters() e Setters() são um pouco diferentes dos que normalmente são utilizados em uma aplicação Java, justamente pelo fato de estender a classe BaseModel.
ASYNC Callback e mapeamento de Web.xml
O GXT é assíncrono, dessa forma é preciso criar elementos que suportem trabalhar dessa forma, boas práticas de programação aconselham que o desenvolvimento da aplicação seja feita orientada a interfaces. Seguindo essa ideia serão criadas duas interfaces que possibilitarão trabalhar de forma assíncrona.
package br.com.client.application;
import br.com.client.domain.PersonG;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
@RemoteServiceRelativePath ("personController")
public interface PersonApplication extends RemoteService{
public void save(PersonG person);
public void update(PersonG person);
public PersonG findById(int id);
public void delete(PersonG person);
}
package br.com.client.application;
import br.com.client.domain.PersonG;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface PersonApplicationAsync {
void save(PersonG person, AsyncCallback<Void> callback);
void update(PersonG person, AsyncCallback<Void> callback);
void delete(PersonG person, AsyncCallback<Void> callback);
void findById(int id, AsyncCallback<PersonG> callback);
}
Por padrão o projeto web cria o arquivo web.xml que permite o mapeamento dos servlets da aplicação (padrão em toda aplicação web). No arquivo web.xml será adicionado o servlet mapeado pela anotação @RemoteServiceRelativePath ("personController").
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee">
<!-- Servlets -->
<servlet>
<servlet-name>personService</servlet-name>
<servlet-class>br.com.server.PersonApplicationImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>personService</servlet-name>
<url-pattern>/gwtproj/personController</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>GWTProj.html</welcome-file>
</welcome-file-list>
</web-app>
O arquivo web.xml deverá estar contido do diretório WEB-INF contida na pasta war dentro do projeto.

Para utilizar o GWT é preciso criar classes que servirão de conversor das classes do projeto Java para o projeto web. Esse conversor será utilizado tanto para as transações de persistência quanto para as transações de busca entre a aplicação web e a aplicação core.
package br.com.client.converter;
import br.com.client.domain.PersonG;
import br.com.domain.Person;
public class PersonConverter {
private Person person;
private PersonG personG;
public Person personConverterG(PersonG personG){
person = new Person();
person.setCode(personG.getCode());
person.setName(personG.getName());
person.setEmail(personG.getEmail());
person.setPhone(personG.getPhone());
person.setCell(personG.getCell());
return person;
}
public PersonG personConverter(Person person){
personG = new PersonG();
personG.setCode(person.getCode());
personG.setName(person.getName());
personG.setPhone(person.getPhone());
personG.setCell(person.getCell());
personG.setEmail(person.getEmail());
return personG;
}
}
Para este artigo utilizamos o conversor construído de forma manual, porém já existem artefatos como por exemplo o Jazon utilizado para efetuar o papel de conversão dos objetos de forma automática.
package br.com.server;
import br.com.client.application.PersonApplication;
import br.com.client.converter.PersonConverter;
import br.com.client.domain.PersonG;
import br.com.database.impl.PersonRepositoryImpl;
import br.com.domain.Person;
import br.com.domain.PersonRepository;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class PersonApplicationImpl extends RemoteServiceServlet
implements PersonApplication{
private static final long serialVersionUID = 1L;
private PersonConverter pConverter;
private PersonRepository pRep;
private Person person;
public PersonApplicationImpl() {
pConverter = new PersonConverter();
pRep = new PersonRepositoryImpl();
}
@Override
public void save(PersonG personG) {
person = pConverter.personConverterG(personG);
pRep.save(person);
}
@Override
public void update(PersonG person) {
// TODO Auto-generated method stub
}
@Override
public PersonG findById(int id) {
// TODO Auto-generated method stub
return null;
}
@Override
public void delete(PersonG person) {
// TODO Auto-generated method stub
}
}
Para este artigo será mostrado somente como persistir um objeto em um banco de dados, porém a lógica para as demais funções podem ser implementadas seguindo a mesma estrutura lógica.
Domínio da Aplicação
A aplicação Java Project será utilizada para receber os objetos convertidos da aplicação web e efetuar a lógica de persistência no banco. Para o exemplo deste artigo foi utilizado o framework JPA.
package br.com.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
@Entity (name="tb_person")
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator (initialValue = 1, allocationSize=1,
sequenceName="person_seq", name="person_seq")
@GeneratedValue (generator="person_seq", strategy=GenerationType.AUTO)
@Column (nullable=false)
private Integer code;
private String name;
private String email;
private String phone;
private String cell;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getCell() {
return cell;
}
public void setCell(String cell) {
this.cell = cell;
}
}
Para efetuar as funcionalidades de transação com o banco de dados, será utilizada a interface PersonRepository contendo as assinaturas dos métodos de transação.
package br.com.domain;
public interface PersonRepository {
public void save(Person person);
public void update(Person person);
public Person findById(int id);
public void delete(Person person);
}
O JPA utilizado na aplicação contém o arquivo persistence.xml obrigatoriamente contido na pasta WEB-INF dentro de SRC do projeto.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JPAUnit">
<class>br.com.domain.Person</class>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.connection.url"
value="jdbc:postgresql://localhost:5432/persondb"/>
<property name="hibernate.connection.driver_class"
value="org.postgresql.Driver"/>
<property name="hibernate.connection.password" value="123456"/>
<property name="hibernate.connection.username" value="postgres"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
Para efetuar a conexão com o banco de dados é preciso criar uma fábrica de conexões que inicia a transação com o banco.
package br.com.database;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.hibernate.Session;
public class ConnectionFactory {
private static EntityManagerFactory emf = Persistence
.createEntityManagerFactory("JPAUnit");
private static EntityManager entityManager;
public static EntityManager getEntityManager() {
entityManager = emf.createEntityManager();
return entityManager;
}
public static Session getSession() {
return (Session) entityManager.getDelegate();
}
}
Para implementar a interface que contém as assinaturas dos métodos de persistência e utilizar a fábrica de transações, será preciso criar a classe que implementa a interface PersonRepository, que irá conter a lógica de persistência.
package br.com.database.impl;
import javax.persistence.EntityManager;
import br.com.database.ConnectionFactory;
import br.com.domain.Person;
import br.com.domain.PersonRepository;
public class PersonRepositoryImpl implements PersonRepository{
private EntityManager em;
public PersonRepositoryImpl() {
em = ConnectionFactory.getEntityManager();
}
@Override
public void save(Person person) {
em.getTransaction().begin();
em.persist(person);
em.getTransaction().commit();
em.close();
}
@Override
public void update(Person person) {
// TODO Auto-generated method stub
}
@Override
public Person findById(int id) {
// TODO Auto-generated method stub
return null;
}
@Override
public void delete(Person person) {
// TODO Auto-generated method stub
}
}
O métod save() recebe um objeto Person, inicia a transação com o banco de dados e persiste o objeto, logo após a transação com o banco é finalizada.
Criação de tela de cadastro com o GXT
Após toda a lógica de negócios estar criada, é preciso exportar a aplicação de domínio para dentro da pasta lib da aplicação web, a pasta lib pode ser encontrada dentro da pasta WEB-INF contida na pasta war do projeto.

A criação da interface gráfica no GXT pode ser feita utilizando códgio Java, para isso serão necessários a biblioteca do GXT, o “gxt-2.2.5-gwt22.jar” e o “gwt-servlet.jar”. Ao criar o projeto exemplo do GXT, a classe conhecida como EntryPoint é criada automaticamente, essa classe é utilizada para ser o ponto de partida da aplicação, é uma espécie de main da aplicação, essa classe implementa a interface EntryPoint, que contém o método onModuleLoad(), é necessário também criar pelo menos um módulo para que a aplicação seja executada com sucesso, o módulo é um arquivo xml criado no pacote principal do projeto, onde contém o link das bibliotecas que serão utilizadas na aplicação.
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='gwtproj'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<!-- Inherit the default GWT style sheet. You can change -->
<!-- the theme of your GWT application by uncommenting -->
<!-- any one of the following lines. -->
<inherits name='com.google.gwt.user.theme.clean.Clean'/>
<inherits name="com.google.gwt.resources.Resources" />
<inherits name="com.google.gwt.http.HTTP" />
<inherits name="com.extjs.gxt.ui.GXT" />
<!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
<!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
<!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> -->
<!-- Other module inherits -->
<!-- Specify the app entry point class. -->
<entry-point class='br.com.client.GWTProj'/>
<!-- Specify the paths for translatable code -->
<source path='client'/>
<source path='shared'/>
</module>
package br.com.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GWTProj implements EntryPoint {
@Override
public void onModuleLoad() {
RootPanel.get().add(new PessoaView());
}
}
A classe RootPanel contém os métodos get() e add() estáticos e são utilizados para receber uma instância de qualquer objeto que estenda um UIObject, e assim poder renderizar a tela.
package br.com.client;
import br.com.client.application.PersonApplication;
import br.com.client.application.PersonApplicationAsync;
import br.com.client.domain.PersonG;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.Window;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
public class PessoaView extends Window{
private PersonApplicationAsync app = GWT.create(PersonApplication.class);
private TextField<String> fieldName = new TextField<String>();
private TextField<String> fieldEmail = new TextField<String>();
private TextField<String> fieldPhone = new TextField<String>();
private TextField<String> fieldCell = new TextField<String>();
private PersonG person;
private Button btSave = new Button("Salvar");
private FormPanel fp = new FormPanel();
public PessoaView() {
setHeading("Incluir Pessoa");
setMinimizable(false);
setSize(350, 175);
configure();
configureBtSave();
}
private void configure(){
fp.setHeaderVisible(false);
fieldName.setFieldLabel("Nome");
fp.add(fieldName);
fieldEmail.setFieldLabel("Email");
fp.add(fieldEmail);
fieldPhone.setFieldLabel("Fixo");
fp.add(fieldPhone);
fieldCell.setFieldLabel("Celular");
fp.add(fieldCell);
add(fp);
fp.add(btSave);
add(fp);
layout();
}
private PersonG getPerson(){
person = new PersonG();
person.setName(fieldName.getValue());
person.setEmail(fieldEmail.getValue());
person.setPhone(fieldPhone.getValue());
person.setCell(fieldCell.getValue());
return person;
}
private void configureBtSave(){
btSave.addListener(Events.OnClick, new Listener<ButtonEvent>() {
@Override
public void handleEvent(ButtonEvent be) {
app.save(getPerson(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
Info.display("Sucesso","");
}
@Override
public void onFailure(Throwable caught) {
Info.display("Falha","");
}
});
}
});
}
}
Por fim a interface gráfica será criada utilizando os componentes da biblioteca do GXT, componentes como TxtField, que cria uma caixa de texto contendo um Label e um Button, que cria um botão que receberá as ações da tela. O FormPanel é utilizado para alinhar os componentes dentro de um formulário, contendo um tamanho configurável em pixels e uma barra de títulos, por a classe estender de Window, o método setHeading() inclui um título na janela.
Após executar a aplicação a tela de cadastro será exibida e estará pronta para persistir um objeto do tipo Person. Após mandar executar a aplicação um link será gerado.


Conclusão
Desenvolver aplicações utilizando o framework GXT foi um salto e tanto para o desenvolvimento utilizando a linguagem Java, dessa forma podem ser utilizado vários outros frameworks para auxiliar na execução de uma aplicação robusta como por exemplo o Spring, dessa forma pode-se construir aplicações ricas para a web diminuindo o esforço e seguindo todos os padrões de engenharia de software.