
Quem já experimentou frameworks como Django e Rails sabe bem que o desenvolvimento de aplicações web pode perfeitamente ser produtivo e até divertido. Isso estava fora da realidade do mundo Java antes do surgimento do Play Framework!.
O Play é um framework full stack, stateless, focado em produtividade, bastante parecido com Django e Rails. É construído sobre uma arquitetura assíncrona baseada em eventos, sendo muito simples de escalar. Possui suporte a módulos, gerenciamento de dependências e configuração baseada em arquivos properties. Não é necessário compilar e realizar deploy em um servidor de aplicações, o Play vem com um servidor embutido, e durante o desenvolvimento basta alterar o código, salvar e recarregar o browser. O próprio framework compila e recarrega a aplicação, como em linguagens interpretadas. E se houverem erros, eles serão exibidos no próprio browser, de forma intuitiva.
O Play vem com um conjunto de ferramentas em modo console para várias tarefas, como criar novos projetos, iniciar a aplicação com o servidor embutido, executar testes, configurar dependências, gerar um pacote WAR, etc, o que o torna bastante produtivo tanto para novos projetos quanto para dar manutenção em um projeto já existente. É possível desenvolver em Java ou Scala (sim, Scala!).
Vamos enumerar alguma das caracteristicas do framework:
- Limpo, Rápido e Dinâmico
- Produtivo, Poderoso e Divertido!
- Puro Java (Permite a importação e uso de qualquer biblioteca Java)
- Utiliza o sistema de template Groovy(Groovy trabalha de forma transparente com todos os objetos e bibliotecas Java existentes e compila diretamente para Java bytecode tanto no desenvolvimento de aplicações como no modo script.)
- Utiliza sistemas de tradução de Rotas
- Facilidade na resolução de erro
- Padrão MVC
- Assíncrono (I/O não bloqueante)
- Stateless
- Arquitetura RESTful ( REST (ou Representational State Transfer) é um estilo de desenvolvimento para sistemas distribuídos que privilegia a trasferência de estado sem envolver camadas de mapeamento (como o SOAP faz). Assim, os verbos GET, POST, PUT e DELETE mapeam quase que diretamente para ações READ, UPDATE, CREATE e DELETE (CRUD).
- Persistência com JPA (JPA é uma especificação de Persistência da plataforma Java, para persistir as classes java em bancos de dados relacionais. )
- Extensível (Através de Módulos / Bibliotecas Java)
- TDD – Test Development Drive (Test Driven Development (TDD) ou em português Desenvolvimento dirigido por testes )
Como iniciar uma aplicação no Play?
É facil, basta usar o comando no consolhe (Terminal no Linux e Prompt de comando no Windows, lembrando que você terá que estar dentro da pasta do framework no windows e no linux ter adicionado o caminho da pasta ao PATH para executar o comando play):
play new nomedaaplicacao
Toda a estrutura do projeto será criada, incluindo arquivos de configuração e o roteamento inicial da aplicação. Se você deseja abrir o projeto no Eclipse ou no Netbeans, o Play! cria o projeto para você. Basta fazer assim:
play eclipsify nomedaaplicacao
Ou se preferir o Netbeans:
play netbeansify nomedaaplicacao
Dessa forma, você poderá importar o projeto de sua IDE e todas as configurações estarão realizadas. Outro comando importante é a gerador de war (deploy).
play war nomeDoProjeto -o nomeDoProjeto.war
Pronto, feito isto basta começar a programar no projeto usando Java ou Scala 🙂 !
Slide da apresentação feita na SWX: play-framework-apresentaçao
Código de uma pequena aplicação de uma agenda feita na SWX:
No diretório /conf no arquivo application.conf , caso use mysql, basta localizar e modificar o padrão para seu usuário e senha do mysql e o nome do banco (No exemplo a seguir está sem senha).
# To connect to a local MySQL5 database, use:
db=mysql:acson@minha_agenda
// acson -> usuário do banco, minha_agenda -> banco
No diretório /app/controllers , modifique o Application.java (ou crie se não existir) para:
package controllers;
import play.*;
import play.mvc.*;
import play.data.validation.*;
import java.util.*;
import models.*;
public class Application extends Controller {
public static void index() {
List<Contato> contatos = Contato.find("order by nome asc").fetch();
render(contatos);
}
public static void inserir() {
render();
}
public static void visualizar(String email) {
Contato contato = Contato.find("email", email).first();
render(contato);
}
public static void editar(String email) {
Contato contato = Contato.find("email", email).first();
render(contato);
}
public static void excluir(String email) {
Contato contato = Contato.find("email", email).first();
contato.delete();
index();
}
public static void cadastrar_contato(@Required String nome, @Required String email, String telefone, String twitter, String skype) {
Contato contato = new Contato(nome, email, telefone, twitter, skype);
if (validation.hasErrors()) {
render("Application/inserir.html", contato);
}
contato.save();
index();
}
public static void editar_contato(long id) {
validation.required(request.params.get("nome"));
validation.required(request.params.get("email"));
Contato contato = Contato.find("id", id).first();
if (validation.hasErrors()) {
render("Application/editar.html", contato);
}
contato.nome = request.params.get("nome");
contato.telefone = request.params.get("telefone");
contato.email = request.params.get("email");
contato.twitter = request.params.get("twitter");
contato.skype = request.params.get("skype");
contato.save();
index();
}
}
No diretório /app/models , crie a classe Contato (Contato.java) com o seguinte código:
package models;
import play.*;
import play.db.jpa.*;
import javax.persistence.*;
import java.util.*;
@Entity
public class Contato extends Model {
public String nome;
public String email;
public String telefone;
public String twitter;
public String skype;
public Contato(String nome, String email, String telefone, String twitter, String skype) {
this.nome = nome;
this.email = email;
this.telefone = telefone;
this.twitter = twitter;
this.skype = skype;
}
}
No diretório /app/views , crie o arquivo application.html com o seguinte código:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>.: Agenda de Contatos - #{get 'title' /}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/principal.css'}">
#{get 'moreStyles' /}
<script src="@{'/public/javascripts/jquery-1.4.2.min.js'}" type="text/javascript" charset="utf-8"></script>
#{get 'moreScripts' /}
</head>
<body id="page1">
<div id="geral">
<div id="conteudo">
<div id="logo"></div>
<div class="linha">
<div class="titulo">.: Agenda de Contatos</div>
#{if request.actionMethod != "inserir" && request.actionMethod != "editar"}
<div class="text"><a href="@{Application.inserir()}" class="button">+ Incluir Contato</a></div>
#{/if}
</div>
<div class="linha"></div>
#{doLayout /}
</div>
</div>
</div>
</body>
</html>
No diretório /app/views/Application , crie o arquivo inserir.html com o seguinte código:
#{extends 'application.html' /}
#{set title:'Inclusão' /}
#{form @Application.cadastrar_contato()}
#{ifErrors}
<div class="linha"><p style="color:red;"><strong>ATENÇÃO: </strong>Preencha todos os campos obrigatórios.</p></div>
<div class="linha"></div>
#{/ifErrors}
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="nome">Nome:</label></p>
</div>
<div class="dir">
<p><input type="text" name="nome" id="nome" value="${params.nome}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="telefone">Telefone:</label></p>
</div>
<div class="dir">
<p><input type="text" name="telefone" id="telefone" value="${params.telefone}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="email">Email:</label></p>
</div>
<div class="dir">
<p><input type="text" name="email" id="email" value="${params.email}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="twitter">Twitter:</label></p>
</div>
<div class="dir">
<p><input type="text" name="twitter" id="twitter" value="${params.twitter}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="skype">Skype:</label></p>
</div>
<div class="dir">
<p><input type="text" name="skype" id="skype" value="${params.skype}" /></p>
</div>
</div>
</div>
<div class="btn-submit">
<p><input type="submit" value="Cadastrar o Contato" /></p>
</div>
#{/form}
No diretório /app/views/Application , crie o arquivo visualizar.html com o seguinte código:
#{extends 'application.html' /}
#{set title:'Visualizao' /}
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="nome">Nome:</label></p>
</div>
<div class="dir">
<p>${contato.nome}</p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="telefone">Telefone:</label></p>
</div>
<div class="dir">
<p>${contato.telefone}</p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="email">Email:</label></p>
</div>
<div class="dir">
<p>${contato.email}</p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="twitter">Twitter:</label></p>
</div>
<div class="dir">
<p>${contato.twitter}</p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="skype">Skype:</label></p>
</div>
<div class="dir">
<p>${contato.skype}</p>
</div>
</div>
</div>
<div class="btn-submit">
<p>
<a href="@{Application.index()}">Cancelar</a>
<a href="@{Application.editar(contato.email)}">Editar</a>
<a href="@{Application.excluir(contato.email)}" onClick="if(!confirm('Deseja excluir este contato?')){return false;}">Excluir</a>
</p>
</div>
No diretório /app/views/Application , crie o arquivo editar.html com o seguinte código:
#{extends 'application.html' /}
#{set title:'Edição' /}
#{form @Application.editar_contato(contato.id)}
#{ifErrors}
<div class="linha"><p style="color:red;"><strong>ATENÇÃO: </strong>Preencha todos os campos obrigatórios.</p></div>
<div class="linha"></div>
#{/ifErrors}
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="nome">Nome:</label></p>
</div>
<div class="dir">
<p><input type="text" name="nome" id="nome" value="${contato.nome}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="telefone">Telefone:</label></p>
</div>
<div class="dir">
<p><input type="text" name="telefone" id="telefone" value="${contato.telefone}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="email">Email:</label></p>
</div>
<div class="dir">
<p><input type="text" name="email" id="email" value="${contato.email}" /></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="twitter">Twitter:</label></p>
</div>
<div class="dir">
<p><input type="text" name="twitter" id="twitter" value="${contato.twitter}"/></p>
</div>
</div>
</div>
<div class="linha">
<div class="duas-colunas">
<div class="esq">
<p><label for="skype">Skype:</label></p>
</div>
<div class="dir">
<p><input type="text" name="skype" id="skype" value="${contato.skype}" /></p>
</div>
</div>
</div>
<div class="btn-submit">
<p><input type="submit" value="Editar o Contato" /></p>
</div>
#{/form}
No diretório /app/views/Application , crie o arquivo index.html com o seguinte código:
#{extends 'application.html' /}
#{set title:'Listagem' /}
#{if contatos.size() == 0}
<div class="linha">
<p>Nenhum contato cadastrado.</p>
</div>
#{/if}
#{else}
#{list items:contatos, as:'contato'}
<div class="linha">
<p><a href="@{Application.visualizar(contato.email)}">» ${contato.nome} - ${contato.email}</a></p>
</div>
#{/list}
#{/else}
E para ficar mais agradável e padronizado, vamos mudar o arquivo de rotas que fica em /conf , o arquivo é o routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / Application.index
GET /cadastrar Application.inserir
GET /visualizar/{email} Application.visualizar
GET /editar/{email} Application.editar
GET /excluir/{email} Application.excluir
# Map static resources from the /app/public folder to the /public path
GET /public/ staticDir:public
# Catch all
* /{controller}/{action} {controller}.{action}
Quando o usuário chamar o método de inserir que está no Application.java, no browser aparecerá dominio/cadastrar, e assim por diante.
Terminando isso o aplicativo está pronto para uso.
Abaixo algumas telas de uma pequena aplicação que fizemos, uma agenda de contados:
Site oficial do Play Framework: http://www.playframework.org/
Github do Play Framework: https://github.com/playframework/play
Algumas fontes consultadas: Imasters, Bragil.net