Aumente sua produtividade com o framework Play

Propaganda
play_
Aumente sua produtividade
com o framework
Play
Crie um sistema completo em minutos e entenda
por que tantas pessoas estão abandonando o seu
framework web preferido para usar Play.
N
o ano de 2007 o desenvolvedor Guillaume Bort
trabalhava em um projeto na empresa Zenexity
(em Paris) e ele precisava de um framework bem produtivo. Ele não via o JSF como uma boa opção para
aplicações web, e invejava a produtividade do desenvolvimento em Ruby on Rails. Com isso ele criou o
framework baseado em suas próprias necessidades,
e nesse momento ele está focado na versão 2.0 que
promete muitas mudanças. Entretanto, vamos focar
este artigo na versão 1.2.x, que é a mais usada.
simplicidade e rápida curva de aprendizado. Além de
possuir vários recursos embutidos, o playframework
possui uma boa lista de módulos que podem ser
“plugados” à aplicação, disponibilizando recursos
mais avançados, como, por exemplo, Web Services,
integrações com redes sociais Facebook e Twitter,
testes automatizados, entre outros.
A instalação é muito simples e está destacada
mais adiante.
Começamos criando a aplicação com a chamada:
Conheça o framework
play new NetCitacoes
Um erro comum é comparar o Play com outros
frameworks Java do mercado, como Spring MVC,
Struts, Mentawai ou VRaptor, ele foge dos tradicionais padrões Java Enterprise e busca soluções baseadas em script semelhante ao Ruby on Rails, PHP Cake
ou Grails. Além disso, ele possui um servidor HTTP
embutido e não é baseado na API de Servlet (apesar
de exportar um pacote WAR totalmente compatível
com o padrão JEE).
O framework Play é famoso por facilitar, e muito, a vida do desenvolvedor que precisa criar uma
aplicação MVC de forma fácil e rápida. Os recursos
que o framework disponibiliza impressionam pela
/ 14
Com isso será criada uma estrutura básica de sua
aplicação (figura 1). Entre no diretório criado e digite
play run
Depois acesse no browser no endereço http://
localhost:9000 .
Vamos para o Eclipse agora?
play eclipsify
Com isso ele criará os arquivos .classpath e .project para podermos importar esse projeto para dentro do Eclipse.
Eduardo Cerqueira | [email protected]
Formado pela Universidade Ibirapuera, trabalha com java desde 2005 e sócio-diretor da WebStart Solutions, empresa com foco na
prestação de serviços de desenvolvimento de software também dos criadores do site E-AgendaMédica ( www.eagendamedica.com.br )
Fernando Boaglio | [email protected]
Formado pela Unesp em BCC, foi instrutor oficial da Sun Microsystems e da Oracle Education. Atualmente contribui para alguns
projetos open source, como KDE e Mentawai e é da equipe de arquitetura da Discover Technology, prestando serviços para a Tokio
Marine Seguradora.
O desenvolvimento de aplicações web ficou mais fácil, leve e rápido
com esse framework que, apesar de ser relativamente novo, causa
bastante barulho na comunidade e tem sido uma “mão na roda” no
desenvolvimento de aplicações para startups no mundo todo. Mostraremos neste artigo como ele funciona, como é definida sua arquitetura e desenvolveremos uma aplicação completa demonstrando
alguns dos incríveis recursos desse framework e, o melhor de tudo,
sem dor!
o framework Play possui quatro arquivos principais de configuração:
» application.conf − guarda configurações da
JVM, informações de log, persistência, rede e
Proxy;
» dependencies.yml − lista os módulos usados
pelo seu sistema;
» messages − localização de mensagens;
» routes − define os mapeamentos das URIs do
seu sistema, apontado para controladores estáticos ou dinâmicos.
Uma das qualidades do play é sua velocidade no
desenvolvimento. Esqueça deploy, start e stop de
servidor, vamos criar um controlador e uma página
que recebe o seu resultado sem precisar fazer nada
da maneira convencional, basta apenas criar as novas rotinas.
O seu primeiro controller
Figura 1. Estrutura básica de um projeto novo.
Em primeiro lugar, deixe o servidor do play rodando no projeto (play run mencionado anteriormente).
Dentro do pacote app.controllers, crie a classe
Teste que estende da classe play.mvc.Controller, com
um método chamado index conforme a Listagem 1.
15 \
Listagem 1. Primeiro controlador de exemplo.
package controllers;
import play.mvc.Controller;
public class Teste extends Controller {
public static void index() {
renderArgs.put(“variavel”,”teste”);
render();
}
}
@Entity
public class ListaDeCompras extends Model {
@Required
public String nome;
}
Continuamos o exemplo criando o controlador da
Listagem 4, que possui o método index para efetuar a busca da lista do banco de dados e jogar na tela
Depois disso, dentro do diretório views, crie um através do método render, e o método save, que recediretório com o nome do controlador (Teste), e den- be como parâmetro o objeto que vamos persistir no
tro dele um arquivo chamado index.html contendo a banco de dados.
página HTML conforme a Listagem 2.
Listagem 4. Controlador da lista de compras.
Listagem 2. Página HTML do primeiro controlador de
package controllers;
exemplo.
<html>
<h2>meu primeiro ${variavel} !</h2>
</html>>
Em seguida, acesse o browser no endereço http://
localhost:9000/teste/index e perceba a magia do play!
Classes e páginas novas ficam disponíveis dinamicamente agilizando o processo de desenvolvimento! É
como o autor diz: “arrume o bug e pressione reload”.
Essa mágica é possível graças ao poderoso engine
baseado em Groovy, que também é a raiz do projeto
Grails.
import java.util.List;
import models.ListaDeCompras;
import play.mvc.Controller;
public class Lista extends Controller {
public static void index() {
List<ListaDeCompras> compras =
models.ListaDeCompras.all().fetch();
render(compras);
}
public static void save(ListaDeCompras item) {
item.save();
index();
}
O seu primeiro cadastro
É comum começarmos o desenvolvimento de
um cadastro e com o tempo mudarmos o valor dos
campos da tela (ou colunas de uma tabela). A mesma flexibilidade que play oferece com as classes Java
também é oferecida com o banco de dados. Edite o
arquivo application.conf “descomentando” a linha
db=mem para automaticamente mapear o nosso banco de dados na memória.
Vamos criar uma simples lista de compras e, seguindo o modelo MVC, vamos começar com a representação do negócio com a classe ListaDeCompras
(Listagem 3). Para termos o mapeamento desejado,
basta que a classe estenda play.db.jpa.Model e tenha
a anotação Entity.
Listagem 3. Classe que representa uma lista de
compras.
package models;
import javax.persistence.Entity;
import play.data.validation.
Required;
import play.db.jpa.Model;
/ 16
}
Finalmente, na camada view (Listagem 5) temos
o arquivo index.html (dentro da pasta app/views/Lista) com o formulário que aponta para o método Lista.
save e uma rotina que exibe os dados da lista de compras enviados pelo controlador.
Listagem 5. Arquivo index.html que representa a
lista de compras.
<html>
<h2>Lista de compras</h2>
#{form @Lista.save()}
<table>
<th> <input type=”text” name=”item.nome”
value=”${item?.nome}”/> </th>
<td><input type=”submit” name=”submit”
value=”Cadastrar” /> </td>
#{/form}
</table>
<hr/>
<table>
#{list items:compras, as:’item’}
<tr><td>${item.nome}</td></tr>
#{/list}
</table>
</html>
Para ver o resultado, acesse http://localhost:9000/
lista/index e faça alguns cadastros. Confira também o
log das operações executadas que aparece no console
Figura
4. Tela de cadastro de usuários.
onde foi digitado play run.
Depois dessa pequena introdução para entender
o framework, vamos abandonar a lista de compras e
fazer um sistema um pouco mais complexo.
Conheça o NetCitações
Temos um simples sistema de citações famosas,
onde vamos persistir informações das frases, dos co- Figura 5. Tela de listagem de usuários.
mentários de cada frase e das pessoas que cadastraram. Nesse sistema, apenas os administradores podem cadastrar os usuários (figura 2).
Usando o módulo scaffold
o módulo scaffold, como comentado anteriormente, tem o objetivo de gerar automaticamente
Módulos utilizados
Para criar as telas de CRUD automaticamente as classes de controle e os htmls de visualização da
utilizamos o módulo scaffold, que de forma simples nossa aplicação. Poderíamos fazer isso manualmenirá gerar as nossas classes de controle e visualização te, porém utilizaremos esse módulo para poupar
rapidamente e usamos também o módulo secure para trabalho. o scaffold utiliza as classes de modelo que
validar a autenticação do cadastro de usuários (figura geramos para saber quais controllers e views precisa
criar. Além disso, ele analisa os tipos de dados e ano3).
tações para gerar também mecanismos de validação
nas views.
Configurações do módulo scaffold
Como pré-requisito desse módulo, as classes
de domínio Usuario, Citacao e Comentario já foram
criadas para permitir a geração dos demais arquivos-fonte.
Para instalar o módulo, precisamos editar o arquivo dependencies.yml e incluir a chamada para o
módulo conforme Listagem 6.
Figura 3. Tela de cadastro de usuário do NetCitações.
Figura 2. Classes do NetCitações.
17 \
Listagem 6. Configurando módulo scaffold.
#Application dependencies
require: -play
-play -> scaffold head
A linha que adicionamos das informações do módulo que usaremos, no caso, scaffold e sua versão,
que nesse caso será head.
Após salvar o arquivo, o play precisa baixar os arquivos do módulo que nós acabamos de configurá-lo.
Para isso, é preciso executar o comando:
Listagem 7. Configurando módulo secure.
#Application dependencies
require: -play
-play -> scaffold head
-play -> secure
O módulo secure já faz parte dos pacotes padrões do
play, porém precisamos ainda executar todos os comandos para que o framework inclua os arquivos do
módulo. Então digitaremos mais uma vez os comandos que têm essa finalidade.
play deps --sync
play deps --sync
play eclipsify
play scaffold:gen
play scaffolg:gen --overwrite --withlogin --with-layout
Depois de baixar todos os arquivos, é preciso recriar os arquivos do projeto do Eclipse para que sejam
Módulos scaffold e secure trabalhando
incluídos em seu path.
Lembre-se de fechar a aplicação no Eclipse antes juntos
de executar o comando, pois pode haver problemas
Agora que já instalamos os módulos que precisana atualização dos arquivos.
mos, vamos usar o módulo scaffold para gerar a nosAgora, vamos usar o módulo para gerar nossas sa tela de login e controlar nossos usuários de forma
classes de controle e views.
integrada.
Para essa tarefa, executamos o comando:
Essa tarefa é feita através do comando abaixo:
Então, executamos o comando de configuração
do Eclipse novamente, como exibido abaixo:
Verificando o nosso projeto, podemos ver que o
módulo gerou arquivos dentro do pacote controller
e views.
Basta agora executar o servidor novamente para
que os arquivos estejam disponíveis acessando via
browser com o comando:
O comando acima irá sobreescrever os arquivos
e regerar as classes de controle e as views do sistema
e também as classes de controle responsáveis pelo
login com a tela respectiva e ainda incluiremos um
pouco de estilo para as telas ficarem mais amigáveis.
Rodamos mais uma vez o comando para configurar o projeto no Eclipse e incluir os arquivos em seus
paths. Esse passo é necessário apenas na inclusão de
um módulo novo no seu projeto.
play run
play eclipsify
play eclipsify
Pronto, nosso cadastro básico está concluído,
porém precisamos ainda adicionar mais funcionalidades à nossa aplicação, como, por exemplo, autenticação.
Passaremos então a falar do próximo módulo utilizado na aplicação, o módulo Secure.
Usando o módulo secure
E subimos o servidor para acessar a aplicação.
play run NetCitacoes
Algumas convenções do módulo
scaffold
Nas documentações do play, temos a convenção
de utilizarmos o nome do controller no plural para
o seu respectivo modelo, por exemplo, para a classe
de modelo Citacao utiliza-se o nome Citacaos para a
controller, porém, quando escrevemos as classes em
português, fica meio esquisito. O nome da controller
pode ser alterado sem qualquer prejuízo pra aplicação, porém se futuramente precisar regerar as classes
utilizando o módulo scaffold, as classes serão geradas
com os nomes originais.
O módulo secure é responsável pelo mecanismo
de autenticação de usuários no play, existem outros
módulos que têm essa mesma função e ainda realizam integração com Facebook, Twitter e outros
utilizando OpenAuth e outros protocolos de autenticação, porém, utilizaremos o Secure por ser mais
simples e atender ao propósito da aplicação.
O método de instalação do módulo é semelhante
ao já mencionado na instalação do módulo scaffold.
Vamos editar novamente o arquivo dependencies.yml Olhando o código mais a fundo
Vamos olhar alguns dos arquivos e destacar alincluindo uma linha a mais de informação, conforme
guns itens para entendimento.
Listagem 7.
/ 18
A classe model Usuario.java
rificar o preenchimento dessa informação e retornará
Na classe de modelo usuário, na Listagem 8, te- uma mensagem de erro caso isso não tenha sido feito.
mos algumas anotações que devemos olhar com mais Olharemos mais adiante na classe Controller como
isso será feito.
atenção.
Agora, só nos resta falar sobre a anotação @
Listagem 8. Arquivo model Usuario.
Email, ela serve pra que no momento da validação
do objeto a ser persistido o framework verifique se o
package models;
valor informado nesse atributo possui o formato de
um e-mail válido, ou seja, a existência de um ‘@’ no
import java.util.List;
valor.
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import play.data.validation.Email;
import play.data.validation.Required;
import play.db.jpa.Model;
@Entity
public class Usuario extends Model {
@Required
public String nome;
@Required
@Email
public String email;
public boolean isAdmin;
public String senha;
@OneToMany(mappedBy=”usuario”)
public List<Citacao> citacoes;
@Override
public String toString() {
return nome;
}
}
Olhando com mais cuidado, veremos que apesar de utilizarmos JPA, nós não precisamos definir
a chave primária da entidade com o @Id. Porém, a
especificação JPA nos diz que somos obrigados a ter
um atributo de classe com a anotação representando a chave primária da entidade. Repare que estamos
estendendo a classe play.db.jpa.Model e nela temos
o atributo com a anotação associada, ou seja, ao estendermos essa classe não precisamos definir quem
será nossa chave primeira, pois a classe já irá associar
o que precisamos.
Entretanto, em alguns casos queremos definir o
nome da coluna utilizada como chave primária. Para
isso devemos então trocar a classe play.db.jpa.Model
para play.db.jpa.GenericModel. Desse modo, podemos definir o atributo de chave primária normalmente.
Temos mais duas anotações que necessitam da
nossa atenção, @Required que informa ao framework
que esses campos são de preenchimento obrigatório.
Sendo assim, em um formulário, o framework irá ve-
A classe controller Usuarios.java
Nessa classe temos algumas anotações que são
utilizadas pelo módulo secure para definir controle
de acesso. Por exemplo, para cadastrar, editar ou deletar um usuário eu preciso ser um usuário autenticado e ter perfil de administrador.
A Listagem 9 dá uma amostra da classe gerada
pelo módulo.
Listagem 9. Arquivo controller Usuarios.
package controllers;
import java.util.List;
import models.Usuario;
import play.data.validation.Valid;
import play.i18n.Messages;
import play.mvc.Before;
import play.mvc.Controller;
import play.mvc.With;
@With(Secure.class)
public class Usuarios extends Controller {
@Before
static void user() {
renderArgs.put(“user”, Security.connected());
}
public static void index() {
List<Usuario> entities = models.Usuario.all().fetch();
render(entities);
}
public static void create(Usuario entity) {
render(entity);
}
public static void show(java.lang.Long id) {
Usuario entity = Usuario.findById(id);
render(entity);
}
public static void edit(java.lang.Long id) {
Usuario entity = Usuario.findById(id);
render(entity);
}
public static void delete(java.lang.Long id) {
Usuario entity = Usuario.findById(id);
entity.delete();
index();
}
19 \
A classe controller Application.java
public static void save(@Valid Usuario entity) {
if (validation.hasErrors()) {
flash.error(Messages.get(“scaffold.validation”));
render(“@create”, entity);
}
entity.save();
flash.success(Messages.get(“scaffold.created”,
“Usuario”));
index();
}
public static void update(@Valid Usuario entity) {
if (validation.hasErrors()) {
flash.error(Messages.get(“scaffold.validation”));
render(“@edit”, entity);
}
entity = entity.merge();
entity.save();
flash.success(Messages.get(“scaffold.updated”,
“Usuario”));
index();
}
Essa controller é a classe de entrada da aplicação, ou seja, é o nosso index, a primeira página e controller carregada quando a aplicação é executada. No
nosso exemplo, ela não tem muita responsabilidade,
uma vez que possui apenas os métodos index() que
é o método inicial propriamente dito, verificando se
existe algum usuário logado e retorna esse usuário, e
o sair() que é responsável pelo logout do usuário. A
Listagem 10 mostra como a classe está definida.
Listagem 10. Arquivo controller Application.
package controllers;
import play.mvc.Controller;
public class Application extends Controller {
public static void index() {
String user = Security.connected();
render(user);
}
public static void sair() throws Throwable {
Secure.logout();
index();
}
}
Para dizer ao Play que somente usuários logados
podem acessar à tela de usuários, eu utilizo a anotação @With(Secure.class), assim quando um usuário
tentar acessar as informações contidas nesse controller, ele precisará estar logado.
Porém, existe uma action chamada user() que recupera o usuário logado através do método Security.
getConnected() e coloca na sessão com a chave user
associada a ela.
Esse método pode ser utilizado sem que um usuário esteja necessariamente logado, porque ele é um
método que está sendo usado no momento do login
e por isso não deve ser controlado. Para resolver esse
problema, o play possui uma anotação @Before. Ela
informa ao framework que essa action pode ser acionada antes que seja verificado se o usuário possui ou
não acesso a ela.
Olhando a action save() podemos ver outra anotação, o @Valid. Ela indica ao play que deve receber
como argumento um Usuario válido. Então, caso essas diretrizes não sejam respeitadas, o play retorna
uma mensagem de erro dizendo que o objeto não é
válido.
O Play sabe que se um objeto é válido ou não verificando as anotações existentes na classe de modelo. No nosso exemplo, o @Required e o @Email. Portanto, olhando a Listagem 8 podemos constatar que
um usuário válido é aquele que possui os atributos
nome preenchido e que o atributo e-mail tenha um
formato de e-mail válido.
/ 20
}
A classe controller Security.java
Por default, o módulo Secure permite que todos
os usuários consigam se autenticar na aplicação, apenas preenchendo os campos de login e senha quando
solicitados. Porém, para aplicarmos nossas próprias
regras de autenticação, como, por exemplo, um e-mail e senha que estejam cadastrados no banco de
dados, precisamos sobrecarregar os métodos de autenticação e checagem para a nossa realidade.
A Listagem 11 mostra a classe Security que criamos para efetuarmos a autenticação no sistema. No
método authenticate(), incluímos uma verificação do
usuário admin diretamente no código, pois o modelo não contempla a criação de perfis diferenciados
no sistema, poderíamos ter feito isso, mas no nosso
exemplo não é relevante, então optamos por não colocar e assim termos um material mais enxuto possível. Nesse mesmo método, caso não seja o e-mail e
senha que definimos no código, a aplicação irá verificar a existência do usuário com o e-mail informado
no banco de dados e irá comparar sua senha.
Listagem 11. Arquivo controller Security.
package controllers;
import models.Usuario;
public class Security extends Secure.Security{
static boolean authenticate(String email,
String senha) {
if(email.equals(“[email protected]”) &&
senha.equals(“!@QWas”)){
return true;
}
}
Usuario usuario = Usuario.find(“byEmail”, email).
first();
return usuario != null &&
usuario.senha.equals(senha);
static boolean check(String perfil) {
if(connected().equals(
“[email protected]”)){
return true;
}
}
Usuario usuario = Usuario.find(“byEmail”,
connected()).first();
if (usuario != null && “admin”.equals(perfil)) {
return usuario.isAdmin;
} else {
return false;
}
}
Deploy da aplicação
O play framework já possui um container onde
a aplicação pode ser implantada, que na verdade é
o mesmo utilizado para o desenvolvimento, porém
com configurações da aplicação setadas para modo
PROD. Na própria documentação do framework é
fortemente recomendada essa prática, pois evita surpresas quando executar deploy em servidores de aplicação e servlet containers, evitando ter que alterar a
aplicação no momento da subida após concluído o
desenvolvimento, porém a execução da aplicação em
um servlet container ou servidor de aplicação seja
uma premissa, o play framework disponibiliza formas
de gerar um arquivo WAR para deploy normalmente.
Primeiramente, o deploy padrão do play, que é
executando apenas digitando o comando abaixo:
lizamos algum servidor HTTP, como, por exemplo, o
Apache na porta 80 e rodarmos o container do play
na porta 9000. Nessa segunda abordagem, podemos
configurar um balancer que irá facilitar também em
uma atualização de release, uma vez que conseguimos “chavear” a aplicação que irá responder as requisições recebidas, enquanto outra instância está sendo
atualizada.
Porém, caso essa abordagem não seja possível,
e termos que implantar a aplicação fora do container padrão do play, podemos executar o seguinte
comando para a geração de um arquivo WAR. Obs.:
esse comando precisa ser executado fora da pasta da
aplicação.
play war NetCitacoes -o netcitacoes.war
--zip --exclude .svn:target:logs:tmp
Explicando com detalhes o comando que executamos:
»» opção -o que permite escolhermos o nome do
arquivo gerado;
»» opção --zip informa o gerador que queremos
uma cópia compactada;
»» opção --exclude informa que os diretórios,
.svn, target, logs e tmp não sejam incluídos no
pacote.
Considerações finais
Após uma visão geral do framework, foi codificado e demonstrado uma pequena amostra do que o
Play pode fazer e seus diferenciais de produtividade
ficaram claros com o decorrer do uso.
O código-fonte e demais referências estão no final do artigo.
/referências
> http://vimeo.com/7087610 − aplicação play em 10
minutos (vídeo oficial)
> http://www.playframework.org/documentation/1.2.5/
home − documentação da versão 1.2.5
> https://github.com/egcerqueira/NetCitacoes − códigofonte do projeto NetCitações
play start NetCitacoes
Pronto, apenas isso é suficiente para colocar a
aplicação em modo produção, pois o container embutido do play irá verificar as configurações no application.conf procurando pelas variáveis definidas para
o modo produção, setá-las na aplicação e subir o servidor. Por padrão, a porta 9000 permanecerá mesmo
no modo produção. Nesse caso, podemos usar duas
abordagens de arquitetura, a primeira seria utilizar o
container do play na porta 80. A segunda, seria uti-
A instalação do framework play exige no mínimo Java 1.5 ou superior.
Primeiro efetue o download do play e descompacte em algum lugar
(exemplo: Windows: C:\play\ , Linux e MacOS: $HOME/play/), depois
se certifique que o executável play está no path do sistema (Windows:
PATH=%PATH%;C:\play\, Linux e MacOS: PATH=$PATH:/play/).
Para testar a instalação, digite “play version” para ver a versão instalada.
21 \
Download