Neste artigo, você desenvolverá um aplicativo da Web centrado em dados usando algumas das tecnologias Java do lado do servidor mais recente e o Dojo Toolkit para criação de uma interface de usuário elaborada. Essas tecnologias reduzem significativamente a quantidade de código que se tem de escrever, em ambos os lados, servidor e cliente. Para tirar o máximo deste artigo, é recomendado ter familiaridade com Java e JavaScript. Será necessário ter um Java 1.6 JDK para compilar e executar o código; este artigo usou o JDK 1.6.0_20. Você também precisará de um contêiner de Web Java; este artigo usou o Apache Tomcat 6.0.14. Para a persistência de dados, pode ser usado qualquer banco de dados com um driver compatível com JDCB 2.0. Para manter as coisas simples, foi usado um banco de dados incorporado, o Apache Derby 10.6.1. Este artigo usa o Java API for RESTful Web Services (JAX-RS), com Jersey 1.3 para a implementação do JAX-RS. Será usado também o Java Persistence API (JPA) com Hibernate 3.5.3 para a implementação. Finalmente, este artigo também usou o Dojo Toolkit 1.4. Veja Recursos para obter os links para essas ferramentas.
Dados Durante a Execução com a Java Persistence API
Muitos aplicativos da Web são centrados em dados — eles apresentam dados persistentes e permitem que o usuário crie ou atualize seus dados. Parece bastante simples, mas mesmo quando se trata de algo tão básico como ler e escrever dados de um banco de dados, as coisas podem ficar feias. No entanto, a Java Persistence API (JPA) reduz grandemente a quantidade de código clichê, tedioso, que precisa ser escrito. Vamos ver um exemplo simples de como usar a JPA.
Neste artigo, será desenvolvido um aplicativo simples para gerenciamento
de uma liga de futebol jovem. Você começará desenvolvendo um modelo de
dados simples para manter controle das equipes na liga e dos jogadores
nessas equipes. Usará a JPA para todo o acesso a esses dados. Iniciará
com o primeiro dos dois modelos, uma Team. A Listagem 1 mostra essa classe.
Listagem 1. A classe de modelo de dados
Team
@Entity
public class Team {
....
....@Id
....@GeneratedValue(strategy = GenerationType.IDENTITY)
....private long id;
....
....private String name;
....
....@OneToMany
....private Collection<Player> players;
....
// getters and setters........
}
|
Essa é uma classe anotada JPA típica. Você usa a anotação
@Entity para declarar que essa classe será
mapeada a um banco de dados. É possível especificar o nome da tabela para
a classe ou implementar a convenção de onde usar o mesmo nome que a
classe. Em seguida, você anota o campo id da
classe. Você deseja que esta seja a primeira chave da tabela, assim usa a
anotação @Id para declarar isso. O id não é importante da perspectiva da lógica de negócios; é necessário fazer isso apenas para o banco de dados. Como você
deseja que o banco de dados se encarregue do que acontecerá com seus
valores, use a anotação @GeneratedValue.
Na listagem 1, também é declarado outro campo, name. Esse será o nome da equipe. Observe que não há nenhuma anotação da JPA nesse campo. Por padrão, ele estará
mapeado a uma coluna com o mesmo nome, e isso é o suficiente para os fins
deste artigo. Finalmente, cada equipe tem vários jogadores associados a
ela. Você usa a anotação @OneToMany para
permitir que o tempo de execução da JPA saiba que esta é uma relação
gerenciada com uma equipe que tem muitos jogadores. Na sua classe Java,
esse é apenas um objeto Player de
java.util.Collection do .A
listagem 2 mostra a classe
Player que está sendo referenciada.
Listagem 2. A classe de modelo de dados
Player
@Entity
public class Player {
....
....@Id
....@GeneratedValue(strategy = GenerationType.IDENTITY)
....private long id;
....
....private String firstName;
....
....private String lastName;
....
....private int age;
....
....@ManyToOne (cascade=CascadeType.ALL)
....private Team team;
....
// getters and setters
}
|
A classe Player mostrada na
listagem 2 é similar à classe Team
na listagem 1. Ela tem mais campos, mas, novamente, na
maioria dos casos, você não terá de se preocupar em anotá-los. A JPA fará a coisa certa para você. A única diferença entre as listagens
1 e 2 é o modo de especificação do
relacionamento entre as classes Player e
Team. Neste caso, você usa uma anotação
@ManyToOne, porque há muitos
Players em uma única Team.
Observe que você especificou uma política de cascata. Examine alguma
documentação da JPA para selecionar a política de cascata certa para o
seu aplicativo. Neste caso, com essa política, é possível criar uma nova
Team e um Player,
ao mesmo tempo, e a JPA salvará a ambos, o que é conveniente para o
aplicativo.
Agora que você declarou essas duas classes, precisará informar ao tempo de execução da JPA como se conectar ao seu banco de dados. Isso é possível criando um arquivo persistence.xml. O tempo de execução da JPA precisa localizar esse arquivo para usar os metadados nele. O modo mais fácil de fazer isso é colocá-lo em um diretório /META-INF que seja subdiretório do seu código de origem (ele deve estar na raiz do diretório de saída das classes compiladas). A listagem 3 mostra o arquivo persistence.xml file.
Listagem 3. O arquivo persistence.xml do aplicativo soccer
<persistence version="1.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_1_0.xsd">
....<persistence-unit name="soccer">
........<class>org.developerworks.soccer.model.Team</class>
........<class>org.developerworks.soccer.model.Player</class>
........<properties>
............<property name="hibernate.dialect"
value="org.hibernate.dialect.DerbyDialect" />
............<property name="hibernate.connection.driver_class"....
value="org.apache.derby.jdbc.EmbeddedDriver" />
............<property name="hibernate.connection.url"
value="jdbc:derby:soccerorgdb;create=true" />
............<property name="hibernate.hbm2ddl.auto" value="update" />
............<property name="hibernate.show_sql" value="true" />
............<property name="hibernate.connection.characterEncoding"
value="UTF-8" />
............<property name="hibernate.connection.useUnicode"
value="true" />
........</properties>
....</persistence-unit>
</persistence>
|
Olhando novamente as listagens 1 e 2, observe que todo o código é JPA genérico. Na verdade, tudo o que é usado são anotações da JPA e algumas de suas constantes. Não há nada que seja específico do seu banco de dados ou da implementação da JPA usada. Como é possível ver na listagem 3, o arquivo persistence.xml é onde as coisas específicas se encontram. Várias implementações de JPA excelentes estão disponíveis, inclusive OpenJPA e TopLink (veja Recursos). Você usou o venerável Hibernate, assim tem várias propriedades específicas do Hibernate especificadas por você. Essas são as coisas mais simples como o driver JDBC e a URL, e algumas coisas úteis como informar ao Hibernate para registrar o SQL em que ele está executando (algo que você definitivamente não desejará fazer em uma situação de produção, mas que é muito útil quando realizado para fins de depuração durante o desenvolvimento).
Também é possível observar na listagem 3 que está sendo
usado o banco de dados do Apache Derby. Na verdade, você está usando uma versão integrada do banco de dados. Assim, não é necessário inicializar o
banco de dados separadamente nem se preocupar com a sua configuração.
Adicionalmente, foi especificado na URL da conexão que o banco de dados
deve ser criado automaticamente, e se informou ao Hibernate para criar
automaticamente o esquema (essa é a propriedade
hibernate.hbm2ddl.auto). Assim, basta executar
seu aplicativo, para que o banco de dados e as tabelas sejam criados.
Isso é grande para o desenvolvimento, mas é evidente que você desejará
configurações diferentes em um sistema de produção. Agora que foi criado
todo o código do modelo de dados e o acesso à JPA já foi ativado, vamos
examinar a exposição desses dados, de modo que um aplicativo da Web possa
tirar proveito disso.
Acesso do RESTful aos Dados com JAX-RS
Se estivesse criando este aplicativo cinco anos atrás, agora seria o
momento de começar a criar algumas Java Server Pages (JSPs) ou Java
Server Faces (JSFs), ou alguma tecnologia de criação de modelos
semelhante. Em vez de criar a UI desse aplicativo no servidor, será usado
o Dojo para criá-la no cliente. Tudo o que é necessário fazer é fornecer
um modo para que o código do lado do cliente acesse esses dados usando
o Ajax. É possível ainda usar uma solução de modelos para fazer algo como
isso, mas é muito mais simples usar a API for RESTful Web Services
(JAX-RS). Vamos iniciar pela criação de uma classe para leitura de todas
as Teams no banco de dados e para criação de
novas Teams. A listagem 4
mostra essa classe.
Listagem 4. Classe de acesso a dados de
Teams
@Path("/teams")
public class TeamDao {
....
....private EntityManager mgr =
DaoHelper.getInstance().getEntityManager();
....
....@GET
....@Produces("application/json")....
....public Collection<Team> getAll(){
........TypedQuery<Team> query =
mgr.createQuery("SELECT t FROM Team t", Team.class);
........return query.getResultList();
....}
....
....@POST
....@Consumes("application/x-www-form-urlencoded")
....@Produces("application/json")
....public Team createTeam(@FormParam("teamName") String teamName){
........Team team = new Team();
........team.setName(teamName);
........EntityTransaction txn = mgr.getTransaction();
........txn.begin();
........mgr.persist(team);
........txn.commit();
........return team;
....}
}
|
A listagem 4 mostra uma classe de objeto de acesso a
dados de classe, daí o nome TeamDao. Nós vamos
chegar às anotações nessa classe em breve, mas deixe-me primeiro explicar
o acesso aos dados. A classe tem uma referência à classe
EntityManager da JPA. Essa é uma classe
central na JPA e fornece acesso ao banco de dados subjacente. Para o
primeiro método, que recupera todas as equipes na liga, use
EntityManager para criar uma consulta. A consulta usa a linguagem de consulta da JPA, que é muito similar à SQL.
Essa consulta simplesmente obtém tudo das Teams.
Para o segundo método, simplesmente crie uma nova
Team usando o nome da equipe informado, crie
uma transação, salve a nova equipe e confirme a transação usando a
classe EntityManager. Todo esse código é
código JPA baunilha, já que todas essas classes e interfaces são parte da
API básica.
Agora que a parte da JPA na listagem 4 está entendida,
vamos falar sobre os aspectos do JAX-RS. Primeiramente, é possível observar a anotação @Path que expõe isso para os
clientes baseados em HTTP. A cadeia de caractere /teams
especifica o caminho relativo para essa classe. O caminho completo da URL
será <host>/SoccerOrg/resources/teams.
/SoccerOrg especificará o caminho para o
aplicativo da Web (evidentemente, é possível configurá-lo para algo
diferente ou removê-lo por completo). A parte
/resources será usada para especificar um
terminal do JAX-RS. /teams corresponde à
anotação @Path e especifica quais classes do
JAX-RS usar.
Em seguida, o primeiro método, getAll, tem uma
anotação @GET nele. Isso especifica que esse
método deverá ser chamado se a solicitação GET
do HTTP for recebida. Em seguida, o método tem uma anotação
@Produces. Essa declara o tipo MIME da resposta. Neste caso, você deseja produzir JSON, visto ser a coisa mais
fácil de usar com o cliente baseado em JavaScript.
Isso é tudo o que é necessário fazer para usar o JAX-RS para expor essa
classe aos clientes da Web. No entanto, talvez esteja se perguntando: se
esse método retornar uma java.util.Collection
de objetos Team, como isso será enviado aos
clientes da Web? A anotação @Produces declara
que você deseja enviar como JSON, mas como o JAX-RS serializará isso no
JSON? Tudo o que é necessário, é incluir mais uma anotação na classe
Team mostrada na listagem 5.
Listagem 5. Classe
Team modificada
@XmlRootElement
@Entity
public class Team {
....
// unchanged from Listing 1
........
}
|
Incluindo a anotação @XmlRootElement, o JAX-RS
pode agora transformar essa classe em um objeto JSON. É possível
reconhecer essa anotação. Ela não pertence ao JAX-RS; é parte da API do
Java Architecture for XML Binding (JAXB) que compõe a plataforma Java 1.6
principal. Essa anotação parece indicar que ela é para XML, mas ela pode
ser, na verdade, usada para diversas saídas do JAXB, inclusive o JSON. Há
muitas outras anotações do JAXB, mas essa é a única que você precisa usar
neste caso. Simplesmente serão usadas convenções para serializar todos os
campos da classe Team para JSON.
Agora, voltemos à listagem 4 e examinemos o segundo
método da classe, o método createTeam. Esse
método usa a anotação @POST para especificar
que ele deve ser chamado quando uma solicitação
POST do HTTP é recebida. Em seguida, ele usa a
anotação @Consumes para declarar que tipo de
solicitação POST ele pode consumir. O
valor especificado aqui corresponde ao cabeçalho de tipo de conteúdo da
solicitação HTTP. Nesse caso, ele é especificado como
x-www-form-urlencoded. Esse é o tipo que você
receberá quando um formulário HTML for submetido. Assim, esse método será
chamado quando um formulário HTML for submetido com o terminal
/SoccerOrg/resources/teams. Finalmente, observe que o método apresenta um
único parâmetro de entrada, uma cadeia de caractere denominada
teamName. Note que esse parâmetro está
decorado com a anotação @FormParam. Essa
informa ao tempo de execução do JAX-RS para procurar um parâmetro de
formulário no corpo da solicitação de nome
teamName (o valor da anotação) e ligar o
parâmetro a uma variável informada na chamada do método. Desse modo, é
possível facilmente manusear um envio de formulário simples e ligá-lo ao
código. Isso pode ficar confuso se você tiver um monte de dados sendo
enviados. Nesse caso, talvez seja apropriado usar uma abordagem mais
estruturada. A listagem 6 mostra um exemplo de como criar um objeto Player .
Listagem 6. Manipulação de dados
POST estruturados usando o JAX-RS
@Path("/players")
public class PlayerDao {
....private EntityManager mgr =
DaoHelper.getInstance().getEntityManager();
....
....@POST
....@Consumes("application/json")
....@Produces("application/json")
....public Player addPlayer(JAXBElement<Player> player){
........Player p = player.getValue();
........EntityTransaction txn = mgr.getTransaction();
........txn.begin();
........Team t = p.getTeam();
........Team mt = mgr.merge(t);
........p.setTeam(mt);
........mgr.persist(p);
........txn.commit();
........return p;
....}
....
....@GET
....@Produces("application/json")
....public List<Player> getAllPlayers(){
........TypedQuery<Player> query =
............mgr.createQuery("SELECT p FROM Player p", Player.class);
........return query.getResultList();
....}
}
|
A classe PlayerDao na listagem
6 é muito similar à classe TeamDao da
listagem 5. A principal diferença que você deseja
examinar é seu método addPlayer. Esse manipula
as solicitações POST do HTTP, similar ao
método createTeam no
TeamDao. No entanto, ele consome
application/json — ou seja, está esperando dados JSON.
Isso implica em duas coisas. Primeiro, a solicitação precisa especificar
um tipo de conteúdo application/json de modo que o método seja chamado.
Em seguida, o corpo da postagem deve ser dados JSON. Observe que o
parâmetro de entrada desse método é do tipo
JAXBElement<Player>, ou seja, é um
wrapper do JAXB ao redor de um objeto Player.
Isso informa ao JAX-RS para analisar automaticamente os dados postados em
um wrapper JAXBElement, assim não é necessário
ter o incômodo de escrever código de análise com esse objetivo. Observe
que no corpo do método, leva apenas uma linha de código para obter
um objeto Player completo que pode ser usado
para salvar o novo Player no banco de dados
usando a JPA.
A última coisa a ser feita para concluir a história do JAX-RS é mostrar a configuração necessária para ligar tudo isso. Para tal, é necessário apenas modificar o web.xml do seu aplicativo. A Listagem 7 mostra o web.xml do aplicativo.
Listagem 7. web.xml do aplicativo
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
....xmlns="http://java.sun.com/xml/ns/javaee"
....xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
....xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
....id="Soccer_Org" version="2.5">
<display-name>SoccerOrg</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>JAXRS-Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.
ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>org.developerworks.soccer.model;org.developerworks.
soccer.web</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>JAXRS-Servlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
</web-app>
|
Como é possível ver na listagem 7, o seu aplicativo tem um único servlet declarado. Esse é o servlet fornecido pelo Jersey, a implementação do JAX-RS que está sendo usada. Você passa um parâmetro de inicialização ao servlet — os pacotes contendo as classes sobre as quais o JAX-RS deve saber. Neste caso, há um pacote onde são mantidos os modelos de dados e outro que mantém os objetos de acessos a dados. Você precisa que os modelos sejam descobertos de modo que o JAX-RS possa convertê-los em JSON. Evidentemente, é necessário que os DAOs sejam descobertos de modo que o JAX-RS possa encaminhar solicitações para eles. Finalmente, observe o mapeamento do servlet. É aí que a parte /resources dos caminhos URL é especificada. Agora você está pronto para usar todo esse código de backend no cliente para criar uma UI usando o Dojo.
Usando o REST no Cliente com Dojo
O Dojo Toolkit fornece praticamente qualquer tipo de biblioteca ou utilitário que pode ser necessário para desenvolver o lado do cliente do seu aplicativo da Web. Você verá como ele é útil quando trabalhar com Ajax, formulários, JSON e criar as widgets da UI. (No entanto, ele pode fazer muito mais do que isso. Acontece, que isso é tudo o que este exemplo simples necessita.) Em um sistema grande, talvez você queira fazer download do kit de ferramentas completo e um desenvolvimento customizado para obter exatamente o que o seu aplicativo precisa. Neste aplicativo de exemplo, será preciso usar as Google Ajax APIs para obter acesso às diversas partes do conjunto de ferramentas necessário. Além de isso ser conveniente, há algumas vantagens interessantes de desempenho visto que as cópias do Dojo do Google são fornecidas pela content delivery network (CDN) altamente eficiente do Google.
O seu aplicativo é centrado a dados, assim para iniciar é necessário
incluir algum dado nele. Usaremos o Dojo para criar uma UI de inclusão de
Teams. A listagem 8 mostra
todo o código necessário para isso.
Listagem 8. Incluindo
Teams usando o Dojo
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Harness</title>
<link rel="stylesheet" type="text/css"
....href="http://ajax.googleapis.com/ajax/libs/dojo/1.4/dijit
/themes/soria/soria.css"/>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojo/dojo.xd.js"
djConfig="parseOnLoad: true"></script>
<script type="text/javascript">
....function init(){
.... var btn = dijit.byId("addTeamBtn");
.... dojo.connect(btn, "onClick", function(event){
.... ....event.preventDefault();
event.stopPropagation();
dojo.xhrPost({
form : dojo.byId("addTeamForm"),
....handleAs: "json",
....load : function(data){
........addTeam(data);
........alert("Team added");
....},
....error : function(error){
.... alert("Error adding team: " + error);
....}
});
.... });
....}
</script>
</head>
<body class="soria">
....Add a Team<br/>
....<form method="POST" action="/SoccerOrg/resources/teams" id="addTeamForm">
........<label for="teamName">Team Name:</label>
........<input name="teamName" type="text" id="teamName"
dojoType="dijit.form.TextBox"/>
........<button type="submit" id="addTeamBtn" dojoType=
"dijit.form.Button">Add Team</button>
....</form>
....<script type="text/javascript">
........dojo.require("dijit.form.Button");
.... dojo.require("dijit.form.TextBox");
.... dojo.addOnLoad(init);
....</script>
</body>
</html>
|
Observe na listagem 8 que você faz referência à
biblioteca base do Dojo a partir da CDN do Google. Uma vez feito isso, é
possível solicitar cada parte adicional desejada do Dojo usando a função
dojo.require (consulte o bloco de scripts na
parte inferior da listagem 8). Observe que você acabou
de criar um formulário HTML normal, mas são usados alguns atributos
extras específicos do Dojo. Isso informa ao Dojo para incluir algum
estilo adicional nos elementos visuais e adicionar alguns recursos extras
aos elementos DOM correspondentes. Você informa ao Dojo uma vez para
executar a função init e tudo o mais é
carregado (todos os componentes do Dojo). Nessa função, é usada a função
dijit.byId para obter uma manipulação no botão
do formulário.
Dijit é a biblioteca de widgets do Dojo. É
possível usar dojo.byId para fazer referência
a qualquer elemento do DOM por seu ID, mas o
dijit.byId similar fornece um widget com
recursos extras (se o elemento estiver marcado como widget, o que é o
caso do botão na listagem 8).
O Dojo é usado para associar um manipulador de eventos para quando o botão
é clicado. O manipulador para o envio do formulário e, em vez disso, usa
o Ajax por meio da função dojo.xhrPost. Essa
função facilita a postagem (POST) de
formulários HTML. Ela descobre o terminal do Ajax inspecionando o
atributo action do formulário HTML. Ela
também lê todos os elementos do formulário e os passa para o
POST do Ajax. Quando obtém uma resposta do
servidor, ela chama a função load que é
transmitida para xhrPost. Observe que você
declarou que JSON será retornado pelo servidor configurando a propriedade
handleAs passada para a função
xhrPost. Você verá a função
addTeam em breve, mas pode transmitir o objeto
de dados diretamente porque o Dojo já analisou com segurança os dados
JSON em um objeto JavaScript utilizável. Esta função
addTeam é usada em conjunto com outro
formulário, para a inclusão de Players. A Listagem 9 mostra o HTML desse formulário.
Listagem 9. Inclusão do formulário
Player
Add a Player<br/>
<form id="addPlayerForm" action="/SoccerOrg/resources/players">
....<label for="firstName">First Name:</label>
....<input name="firstName" id="firstName" type="text"
dojoType="dijit.form.TextBox"/>
....<label for="lastName">Last Name:</label>
....<input type="text" name="lastName" id="lastName"
dojoType="dijit.form.TextBox"/><br/>
....<label for="age">Age:</label>
....<input type="text" name="age" id="age"
dojoType="dijit.form.TextBox"/><br/>
....<label for="team">Team:</label>
....<select id="team" name="team" dojoType="dijit.form.
Select"></select>
....<button type="submit" id="addPlayerBtn" dojoType=
"dijit.form.Button">Add Player</button>
</form>
<script type="text/javascript">
dojo.require("dijit.form.Select");
dojo.addOnLoad(loadTeams);
</script>
|
Esse formulário, a exemplo do presente na listagem 8, é
um formulário HTML válido. No entanto, ele também tem os atributos específicos do Dojo incluídos nos seus elementos. Observe que ele tem um
elemento SELECT que servirá como lista
suspensa das equipes (Teams), de modo que o
usuário pode selecionar qual Team incluir
para o novo Player. Esses são dados dinâmicos
que precisam ser carregados do servidor. Observe que você incluiu outra
função para ser chamada na inicialização — a função loadTeams. E essa função que carrega as
equipes do servidor. A listagem 10 mostra essa função,
além da função addTeam que você viu
referenciada na listagem 9.
Listagem 10. As funções
loadTeams e addTeam
var teams = {};
function loadTeams(){
....var select = dijit.byId("team");
....dojo.xhrGet({
........url: "/SoccerOrg/resources/teams",
........handleAs:"json",
........load : function(data){
............var i = 0;
............for (i in data.team){
................addTeam(data.team[i]);
............}
........},
........error : function(error){
............alert("Error loading team data: " + error);
........}
....});
}
function addTeam(team){
....teams[team.id] = team;
....var select = dijit.byId("team");
....var opt = {"label":team.name, "value":team.id};
....select.addOption(opt);
}
|
Aqui, mais uma vez, os utilitários Ajax do Dojo são usados para acessar os
dados fornecidos pelo terminal do JAX-RS criado anteriormente. Desta vez,
é usado o dojo.xhrGet, que faz uma solicitação
GET do HTTP para um terminal do Ajax. Neste
caso, é necessário especificar a URL, mas por outro lado, ele seria muito
similar ao xhrPost visto na
listagem 9. Finalmente, é possível ver o método
addTeam. Esse, mais uma vez, usa os recursos
extras de widget do Dojo para incluir facilmente novas opções na lista
suspensa que mostra as equipes. Agora que você viu como o formulário do
jogador é criado, examine o código que manipula os envios (veja a
listagem 11).
Listagem 11. Incluindo um novo
Player
var button = dijit.byId("addPlayerBtn");
dojo.connect(button, "onClick", function(event){
.... event.preventDefault();
event.stopPropagation();
var data = dojo.formToObject("addPlayerForm");
var team = teams[data.team];
data.team = team;
data = dojo.toJson(data);
var xhrArgs = {
postData: data,
handleAs: "json",
load: function(data) {
alert("Player added: " + data);
dojo.byId("gridContainer").innerHTML = "";
loadPlayers();
},
error: function(error) {
alert("Error! " + error);
},
url: "/SoccerOrg/resources/players",
headers: { "Content-Type": "application/json"}
};
var deferred = dojo.xhrPost(xhrArgs);
});
|
Este código enviará dados para o método
PlayerDao.addPlayer já mencionado na
listagem 6. Esse código espera que o objeto
Player seja serializado em uma estrutura de
dados do JSON. Primeiro, o Dojo é usado mais uma vez para ligar um
manipulador de eventos a um clique de botão no formulário. Em seguida,
você usa a função de conveniência do Dojo,
dojo.formToObject, para transformar todos os
dados do formulário em um objeto JavaScript. Então, esse objeto
JavaScript é modificado um pouco para corresponder com a estrutura
esperada no servidor. Em seguida, a função
dojo.toJson do Dojo é usada para transformar o
objeto em uma cadeia de caractere do JSON. Em seguida, a sequência é passada para o
dojo.xhrPost, do mesmo modo como o formulário
addTeam foi enviado. Observe que é incluído um
cabeçalho do HTTP, Content-Type, para
assegurar que ela será encaminhada para o método
PlayerDao.addPlayer.
O xhrPost mais uma vez tem uma função
load que será chamada assim que a solicitação
do Ajax retornar com uma resposta bem-sucedida do servidor. Neste caso,
ela é claramente um elemento na página denominado
gridContainer e chamando uma função denominada
loadPlayers. Esse é outro widget do Dojo usado
para mostrar todos os jogadores. A listagem 12 mostra
o HTML e o JavaScript usados para tal.
Listagem 12. HTML e JavaScript da grade de jogadores
<style type="text/css">
@import
"http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojox/grid/resources/Grid.css";
@import
"http://ajax.googleapis.com/ajax/libs/dojo/1.4/dojox/grid/resources/soriaGrid.css";
.dojoxGrid table { margin: 0; }
html, body { width: 100%; height: 100%; margin: 0; }
</style>
<script type="text/javascript">
function loadPlayers(){
....var pStore = new dojox.data.JsonRestStore({
........target: "/SoccerOrg/resources/players"
....});
....pStore._processResults = function(data, deferred){
........return {totalCount:deferred.fullLength || data.player.length,
items: data.player};
....};
var pLayout = [{
field: "firstName",
name: "First Name",
width: "200px"
},
{
field: "lastName",
name: "Last Name",
width: "200px"
},
{
field: "age",
name: "Age",
width: "100px"
},
{
field : "teamName",
name : "Team",
width: "200px"
}];
var grid = new dojox.grid.DataGrid({
store: pStore,
clientSort: true,
rowSelector: "20px",
structure: pLayout
}, document.createElement("div"));
dojo.byId("gridContainer").appendChild(grid.domNode);
grid.startup();
}
</script>
<div id="gridContainer" style="width: 100%; height: 100%;"></div>
<script type="text/javascript">
dojo.require("dojox.grid.DataGrid");
dojo.require("dojox.data.JsonRestStore");
dojo.addOnLoad(loadPlayers);
</script>
|
A Listagem 12 mostra o widget DataGrid do Dojo. Esse é um dos widgets mais
complexos no Dojo e, portanto, requer algum CSS extra também. Para criar uma grade, é necessário fazer duas coisas. Primeiro, é necessário criar
um armazenamento de dados para ela. Neste caso, esses serão os dados do
JSON provenientes do seu servidor, assim crie um novo objeto
JsonRestStore e aponte-o para a URL no seu
servidor que produzirá esses dados.
Em seguida, substitua seu _processResults.
Você só tem que fazer isso porque é esperado um array de dados JSON e
seu terminal JAX-RS produzirá um objeto um pouco mais complicado (ele
terá uma propriedade denominada player cujo
valor estará no array JSON esperado pelo
JsonRestStore). A próxima coisa que a grade
precisa são os metadados do layout que informam o que as colunas mostram e
qual será a propriedade correspondente no objeto JavaScript. Em seguida,
é possível criar a grade e soltá-la na árvore do DOM.
Agora você concluiu o aplicativo de futebol de amostra e tem um modo muito elaborado de mostrar os jogadores de futebol na liga. É possível expandir facilmente este exemplo simples adicionando a edição de jogadores, a classificação da grade ou incluindo mais dados como jogos e resultados.
Este artigo mostrou um modo rápido para criar um aplicativo da Web elaborado, centrado em dados. Você usou várias tecnologias-chave para remover código de clichê, tedioso, do lado do servidor e do lado do cliente: JPA, JAX-RS e Dojo. Em muitos casos, as convenções padrão foram usadas para reduzir adicionalmente a quantidade de código necessária para criar o aplicativo da Web. O resultado é um aplicativo da Web muito moderno, criado com o mínimo de código. Todas as tecnologias usadas são extensíveis e têm qualidade de produção, assim é possível expandir confiantemente o aplicativo de amostra (ou seu próprio aplicativo) para casos de uso mais robustos de uma maneira simples. E o melhor é que não há nenhum impedimento. Foram usados padrões abertos no lado do servidor. É possível trocar facilmente as tecnologias de banco de dados, por exemplo. Foram usados REST e JSON no front-end, o que significa que é possível usar um kit de UIs diferente ou conectar facilmente um cliente móvel.
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Article source code | SoccerOrg.zip | 14KB | HTTP |
Informações sobre métodos de download
Aprender
-
Introduction to Spring 2 and JPA (Sing Li, developerWorks,
agosto de 2006): Saiba mais sobre a JPA.
-
Implementing composite keys with JPA and Hibernate (Stephen
Morris, developerWorks, agosto de 2009): Aprofunde-se na JPA e no Hibernate.
-
Create
RESTful Web services with Java technology (Dustin Amrhein e
Nick Gallardo, developerWorks, fevereiro de 2010): Obtenha uma
introdução completa do JAX-RS.
-
Crie aplicativos Ajax para a Web móvel (Michael Galpin,
developerWorks, março de 2010): Veja como o JAX-RS é grande também para
aplicativos da Web móveis.
-
Escrevendo um aplicativo Dojo customizado (Wendi Nusbickel e Melissa
Betancourt, developerWorks, dezembro de 2008): Saiba muito mais sobre o
Dojo.
-
Develop HTML widgets with Dojo (Igor Kusakov, developerWorks,
outubro de 2006): Explore a extensibilidade do Dojo.
- "Comment lines: Using Ant and ShrinkSafe to improve performance of Web
applications that use Dojo" (Kevin Haverlock, developerWorks, março de 2010):
Veja um exemplo real de como usar chamadas REST para carregar
preguiçosamente dados JSON e preencher um widget em árvore do Dojo Dijit.
- "Comment
lines: Lazily loading your Dojo Dijit tree widget can improve
performance" (Scott Johnson, developerWorks, maio de 2008): Saiba como
usar o utilitário de desenvolvimento Ant com o ShrinkSafe do Dojo para automatizar
o desenvolvimento do perfil, resultando em melhor desempenho para as páginas da Web
baseadas em Dojo.
- A
zona de desenvolvimento
da Web do developerWorks detalha em artigos a cobertura de várias
soluções baseadas na Web.
Obter produtos e tecnologias
- Faça download do Dojo
Toolkit.
- Obtenha o Java SDK.
Este artigo usou o JDK 1.6.0_17.
- Obtenha Apache Tomcat.
Este artigo usou o Apache Tomcat 6.0.14.
- Obtenha Apache
Derby 10.6.1.0.
-
Jersey
é a implementação de referência do JAX-RS: é software livre e tem
qualidade de produção.
-
Hibernate é uma
implementação da Java Persistence API (JPA). Este artigo usou a Versão
3.5.3.
- Faça o download das versões de avaliação de produto IBM
e tenha em suas mãos ferramentas de desenvolvimento de aplicativo e
produtos de middleware do DB2, Lotus, Rational, Tivoli e WebSphere.
Discutir
- Crie seu perfil do My developerWorks hoje e configure uma lista de controle no Dojo.
Conecte-se e fique conectado com o My developerWorks.
- Encontre outros membros do developerWorks interessados no desenvolvimento da Web.
- Desenvolvedores da Web, compartilhe sua experiência e conhecimento no grupo de desenvolvimento da Web.
- Compartilhe seus conhecimentos: ingresse em um dos grupos do developerWorks enfocados nos tópicos da Web.
- Roland Barcia fala sobre Web 2.0 e middleware nesse blog.
- Siga indicadores compartilhados sobre os tópicos da Web dos membros do developerWorks.
- Obtenha respostas rapidamente: Visite o fórum Web 2.0 Apps.
