Play Framework
1. Introdução
Play Framework redefine o desenvolvimento web em Java, assim como outros frameworks web modernos, tais como o Spring Boot (Spring Boot, 2018). O seu foco é o divertido desenvolvimento no qual a interface HTTP é algo simples, flexível e poderosa, sendo uma alternativa limpa para as opções Enterprise Java existentes e infladas. Ele foca na produtividade do desenvolvedor para as arquiteturas RESTful, e sua vantagem em relação às linguagens e frameworks não Java, como Rails e PHP, é que ele usufrui de todo o poder da Java Virtual Machine (JVM) (Boaglio, 2014).
Play é um framework para desenvolvimento de aplicação de web de código aberto. Ele é escrito em Scala e em Java, mas desde a versão 2.0, o núcleo deste framework foi reescrito totalmente em Scala. A parte de Build e Deployment migrou para o SBT e passou a usar o sistema de apresentação (template) na linguagem Scala. Play foi altamente inspirado por Ruby on Rails e Django, e é similar a essa família de frameworks. Play é totalmente independente do ambiente de Java EE e muito mais leve comparado a este. Isso torna o Play mais simples de desenvolver em relação a outras plataformas baseadas em Java. Comparando a outros frameworks, este é:
a) Sem-estado (Stateless) e totalmente RESTful. Isso significa que considera cada requisição como uma transação independente e não há vínculo com qualquer requisição anterior, de forma que a comunicação consista em pares de requisição e resposta independentes. Além do mais, não existe a sessão de Java EE por conexão como acontece em frameworks baseados em Java (HILTON, BAKKER e CANEDO, 2013).
b) Tal framework funciona com métodos estáticos: todos pontos de entrada de todos controladores são declarados como estáticos.
c) Entrada e saída assíncrona: pelo fato de utilizar JBoss Netty como servidor web, Play pode fornecer requisições longas de forma assíncrona em vez de amarrar thread de HTTP fazendo regra de negócio (business logic) como framework de Java EE (HILTON, BAKKER e CANEDO, 2013).
d) Arquitetura modular: assim como Rails e Django, Play utiliza o conceito de módulos.
e) Suporte à linguagem Scala: Play utiliza Scala internamente, pode se utilizar tanto o API de Scala como o de Java.
O Play permite que os desenvolvedores utilizem a Application Programming Interface (API) em Java ou Scala para constituírem suas aplicações, sendo o mais aconselhável para iniciantes no framework o uso da linguagem Java devido a simplicidade em comparação a linguagem Scala, porém se o desenvolvedor quiser tornar o desenvolvimento ainda mais rápido e produtivo é recomendado utilizar a linguagem Scala devido ao seu código conciso, escalabilidade e o suporte à programação funcional (LEROUX et al., 2012). O Play apresenta como arquitetura o padrão Model, View, Controller (MVC). Essa arquitetura é organizada em três camadas: modelo (Model), visualização (View) e o controlador (Controller). A camada de modelo representa os dados e a lógica de negócios da aplicação, ou seja, uma representação especifica do domínio da informação em que a aplicação opera. A camada de visualização é a apresentação na tela, em outras palavras, uma interface com o usuário.
Em aplicações web a visão geralmente é feito utilizando Hypertext Markup Language (HTML) ou Xtensible Markup Language (XML). E a camada de controle define a maneira como a interface do usuário reage às entradas do mesmo, ou seja, é o controlador que processa os eventos solicitado pelo usuário. Antes do MVC, os projetos com interface para o usuário tendiam em agrupar todos esses objetos. Nesse sentido, o MVC foi idealizado para aumentar a flexibilidade e a reutilização (GAMMA et al., 2000, p. 20).
Figura 1 – Padrão MVC do Play Framework Play Framework
Fonte: Play Framework (2017)
De acordo com a Figura 1, as requisições do usuário são enviadas para o Controller através das rotas, que é responsável por mapear qual Controller é responsável pela requisição. Depois o Controller manipula e valida dados através da camada Model e envia para camada View, logo em seguida repassa a resposta para o usuário. O Play também apresenta integração com as Integrated Development Environment (IDE) e editores de textos, tais como: Eclipse, NetBeans, IntelliJ, TextMate e Sublime Text.
2. Configurando o Play Framework
A versão do Play Framework que iremos utilizar será a 2.2.6, que está disponível para download no link: https://downloads.typesafe.com/play/2.2.6/play-2.2.6.zip Após o download, descompacte o arquivo zip em alguma pasta (de preferência uma que não tenha restrições de acesso). Após isso, inclua o Play no PATH do seu sistema operacional. No Windows, pode ser adicionando ao PATH na opção de configurações de variáveis de ambiente (exemplo de inclusão no PATH: C:\play-2-2-6). No Linux, inclua o caminho para a pasta onde foi descompactado o Play no final do arquivo .bashrc (comando no console: gedit ~/.bashrc), conforme o exemplo:
export PATH=$PATH:/caminho/para/pasta/do/play
Outro exemplo prático:
export PATH=$PATH:/home/tads/Documentos/play-2.2.6
Salve o arquivo e reinicie o Linux.
2.1. Criando um projeto e importando para o Eclipse
Para criar um projeto, abra o console ou terminal e execute o comando:
play new nome_do projeto
Para deixar o projeto configurado para a IDE Eclipse, execute em seguida o comando:
play eclipse
Em seguida, importe como um projeto Java no Eclipse
3. Exemplo prático (criando projeto)
Como exemplo prático do desenvolvimento de uma aplicação web com Play Framework, iremos fazer um CRUD para cadastro de pessoas. Inicialmente iremos criar o projeto, por meio do comando:
play new aula_play
3.1. Configurando o banco de dados
Após importarmos o projeto para o Eclipse, iremos agora criar o script do nosso banco de dados, que iremos chamar de ‘aula_play’, e uma tabela chamada pessoa. Antes de criar o script, crie uma pasta chamada ‘database’ dentro da pasta ‘conf’. A pasta ou diretório ‘conf’ é utilizado como padrão pelo Play para alocarmos dentro dela nossos arquivos de configuração do projeto. Após criada a nova pasta, adicione a ela um arquivo chamado ‘create_database.sql’ com o conteúdo abaixo:
DROP DATABASE IF EXISTS aula_play;
CREATE DATABASE IF NOT EXISTS aula_play CHARSET=UTF8;
USE aula_play;
create table pessoa ( id bigint auto_increment not null, nome varchar(255), sobrenome varchar(255), idade integer, constraint pk_pessoa primary key (id) ) DEFAULT CHARSET=UTF8;
Em seguida, importe o script para o MySql via linha de comando, estando na pasta database do projeto (levando-se em conta que o MySql está instalado e configurado em seu sistema operacional):
mysql -u root –pSUASENHA < create_database.sql
Ok, criamos nosso projeto, o script para criação de nosso banco de dados e tabela, e importamos o mesmo para o MySql. Agora, vamos configurar o projeto para ter suporte ao Mysql (adicionando o conector do MySql). No arquivo ‘build.sbt’, que fica na raiz do projeto, adicione a dependência do MySql que será gerenciada pelo sbt, que é um gerenciador de dependências embutido no Play. Veja o exemplo abaixo:
name := "aula_play"
version := "1.0-SNAPSHOT"
libraryDependencies ++= Seq(
javaJdbc, javaEbean, cache, "mysql" % "mysql-connector-java" % "5.1.16"
)
play.Project.playJavaSettings
Agora, na pasta ‘conf’, vamos abrir o arquivo ‘application.conf’ (este é o arquivo onde estão as propriedades de configuração do projeto) e adicionar a seguinte linha ao final do arquivo:
- include “local.conf”
Com isto estamos dizendo ao Play que teremos um outro arquivo de configuração adicionado ao nosso projeto, onde iremos customizar algumas propriedades ou adicionar novas. As propriedades de configuração que adicionarmos ao ‘local.conf’ irão sobrescrever as existentes no ‘application.conf’. Estamos adicionando o ‘local.conf’ para mostrar a possibilidade de termos configurações locais em nosso projeto, mas não é um arquivo obrigatório de ser adicionado, sendo que poderíamos colocar as propriedades de configuração a seguir no próprio ‘application.conf’.
Bom, feito isto vamos adicionar as seguintes configurações ao ‘local.conf’.
- Linguagem dos labels e mensagens da aplicação
application.langs="pt-BR"
- Ebean configuration
- 10h16min de 13 de julho de 2018 (BRT)
- O Ebean eh o ORM embutido no Play.
- A propriedade abaixo indica em que pacote estao nossas entidades
ebean.default="models.*"
- Configurações de banco de dados
db.default.driver=com.mysql.jdbc.Driver db.default.url="jdbc:mysql://localhost:3306/aula_play" db.default.user="root" db.default.password="suasenha"
- Desabilitar evolution, que eh um plugin que gera automaticamente
- as tabelas do banco de dados. Neste projeto iremos criamos nossa
- tabela pelo script create_database.sql
evolutionplugin=disabled
3.2. Criando a Entidade para nosso Modelo
Vamos criar a classe que será a entidade para nosso modelo de dados, ou seja, ela será uma classe espelho da tabela pessoa, com os atributos e métodos para o acesso e persistência dos dados. Esta classe será mapeada pelo Ebean (ORM embutido no Play que iremos utilizar). Crie uma classe chamada ‘Pessoa’, dentro de um pacote chamado ‘models’.
Veja o exemplo abaixo:
package models;
import java.util.List;
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id;
import play.data.validation.Constraints.Required; import play.db.ebean.Model;
@Entity public class Pessoa extends Model {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Long id;
@Required public String nome;
public String sobrenome; public Integer idade;
// variavel com instancia da classe Finder, // que eh um utilitario para consultas ao banco de dados public static Finder<Long, Pessoa> find = new Finder<Long, Pessoa>(Long.class, Pessoa.class);
// metodos para consulta ao banco de dados proporcionados pelo Ebean
public static List<Pessoa> listPessoa() { return find.all(); }
public static Pessoa getPessoaById(Long id) { return find.byId(id); }
}
4. Controlador (Controller)
Iremos agora criar uma classe chamada PessoaController, dentro do pacote controller. Esta classe irá herdar de Controller, que é uma classe utilitária do Play para indicarmos um controlador. Segue exemplo:
package controllers;
import java.util.List;
import models.Pessoa; import play.data.DynamicForm; import play.data.Form; import play.i18n.Messages; import play.libs.Json; import play.mvc.Controller; import play.mvc.Result;
public class PessoaController extends Controller {
// constante de um formulario do tipo Pessoa private static final Form<Pessoa> pessoaForm = Form.form(Pessoa.class);
// listar pessoas e retornar json public Result listPessoa() { List<Pessoa> pessoas = Pessoa.listPessoa(); return ok(Json.toJson(pessoas)); }
public Result list() { List<Pessoa> pessoas = Pessoa.listPessoa();
return ok(views.html.list.render( Messages.get("title_list_person"), pessoas)); }
// criar uma pessoa via GET public Result createPessoa(String nome) {
Pessoa p = new Pessoa(); p.nome = nome; p.save();
return ok(Messages .get("msg.success_created_person", p.nome)); }
// criar pessoa utilizando dynamicform (via POST) public Result create() {
// pega os parametros da requisição DynamicForm request = Form.form().bindFromRequest(); String nome = request.get("nome"); String sobrenome = request.get("sobrenome"); int idade = Integer.valueOf(request.get("idade"));
// instanciar pessoa e salvar no banco de dados
Pessoa p = new Pessoa();
p.nome = nome; p.sobrenome = sobrenome; p.idade = idade;
// metodo save() fornecido pelo Ebean p.save();
return ok(Messages .get("msg.success_created_person", p.nome)); }
// criar pessoa utilizando form do tipo pessoa public Result save() {
// Form<Pessoa> pessoaForm = Form.form(Pessoa.class);
// pega a requisicao e converte em um formulario do tipo pessoa Form<Pessoa> form = pessoaForm.bindFromRequest();
// se houver erros na requisição if(form.hasErrors()) { // criar uma mensagem de erro para ser exibida na view flash("error-add-person", "Erro na criação de pessoa! Confira os campos.");
// redirecionar para a view de criar pessoa return redirect("/create"); }
// pega a pessoa do formulario Pessoa p = form.get();
// metodo save() fornecido pelo Ebean p.save();
flash("success-add-person", Messages.get("msg.success_created_person", p.nome)); return redirect("/list"); }
public Result createView() { return ok(views.html.create.render("Criar Pessoa")); }
public Result delete(Long id) {
Pessoa p = Pessoa.getPessoaById(id);
// metodo delete() fornecido pelo Ebean p.delete();
flash("person-deleted", Messages.get("msg.person.deleted", p.nome));
return redirect("/list"); } }
Observe que estamos utilizando como retorno dos métodos o tipo Result. Result é um tipo de objeto do Play para retornarmos ao cliente uma resposta (response) adequada a requisição, seja um HTML ou um JSON, por exemplo. A classe Controller, da qual PessoaController está herdando, nos fornece métodos para renderização apropriada de nossas respostas, tais como ok() e redirect(), que são métodos propícios para renderização de páginas HTML ou mesmo de um JSON, utilizando a biblioteca JSON embutida no Play.
4.1. Mensagens (Messages)
Em alguns métodos da classe PessoaController estamos também definindo mensagens para serem exibidas aos usuários, por meio dos métodos ‘flash()’ e ‘Messages.get()’ fornecidos pelo Play, em que ambos recebem 2 parâmetros, em que o primeiro será a chave da mensagem e o segundo o valor. As chaves a serem utilizadas no ‘Messages.get()’ foram definidas no arquivo ‘messages.pt-BR’ que deve ser criado na pasta ‘conf’. Segue exemplo:
- LABELS
name=Nome last_name=Sobrenome age=Idade title_list_person=Listagem de Pessoas actions=Ações delete=Deletar
- MESSAGES
msg.no_persons_found=Não há pessoas cadastradas msg.success_created_person={0} foi criado com sucesso! msg.person.deleted={0} foi deletado com sucesso!
O valor, ou o texto, das mensagens podem receber parâmetros. Para isso basta incluir a expressão ‘{n}’ no corpo do valor/texto da mensagem no arquivo ‘messages.pt-BR’, onde ‘n’ é referente a ordem dos parâmetros que estão sendo passados (Exemplo: 0 equivale ao primeiro parâmetro, 1 ao segundo, etc). Podemos ter vários arquivos de mensagens para internacionalização do projeto. Onde ‘messages.pt-BR’ é referente as mensagens com o texto em português e ‘messages.en’ em inglês, por exemplo.
5. Views
Para as views de nossa aplicação (que serão as páginas HTML) o Play utiliza uma junção da linguagem Scala com HTML para criarmos nossos templates/páginas. O Play utiliza Scala nos templates para adicionar lógica de programação na exibição dos dados. Como exemplo, vamos criar um arquivo chamado ‘create.scala.html’ dentro do pacote views.
@(title: String)
@main(title) {
@if(flash.get("error-add-person")) {
@flash.get("error-add-person")
}
<form method="POST" action="/pessoa/save">
<label>Nome</label> <input type="text" id="nome" name="nome" required />
<label>Sobrenome</label> <input type="text" id="sobrenome" name="sobrenome" />
<label>Idade</label> <input type="text" id="idade" name="idade" />
<button type="submit">Salvar</button>
</form>
}
As linhas iniciadas com ‘@’ indicam que ali está sendo utilizado um código escrito em Scala. As chaves ‘{‘ e ‘}’ indicam respectivamente o início e final de um código Scala. As tags HTML contidas entre estas chaves serão renderizadas caso a condição imposta pelo código Scala seja atendida. É possível receber argumentos enviados do controlador para as views, como na linha ‘@(title: String)’. A linha ‘@main(title)’ se refere ao template ‘main.scala.html’ (este template e o ‘index.scala.html’ já estão presentes quando um novo projeto é criado). Agora, vamos criar o ‘list.scala.html’:
@(title: String, pessoas: List[Pessoa]) @main(title) {
@if(flash.get("success-add-person")) {
@flash.get("success-add-person")
} @if(flash.get("person-deleted")) {
@flash.get("person-deleted")
}
@if(pessoas.size() > 0) {
<thead> </thead> <tbody> @for(pessoa <- pessoas) { } </tbody>ID | @Messages("name") | @Messages("last_name") | @Messages("age") | @Messages("actions") |
---|---|---|---|---|
@pessoa.id | @pessoa.nome | @pessoa.sobrenome | @pessoa.idade |
<a id="deletar" href="/delete/@pessoa.id"> <button> @Messages("delete") </button> </a> |
} else {
@Messages("msg.no_persons_found")
} }
6. Rotas (Routes)
Com a nossa entidade modelo (Pessoa), controlador (PessoaController) e views criadas, vamos agora fazer o mapeamento de nossas requisições, ou seja, indicar as rotas, entre URLs e controladores (PessoaController). Para a criação das rotas, iremos utilizar o arquivo ‘routes’, localizado na pasta ‘conf’. Segue exemplo:
- Routes
- This file defines all application routes (Higher priority routes first)
- Jean.costa (discussão) 10h16min de 13 de julho de 2018 (BRT)
- Pessoa
GET /pessoa @controllers.PessoaController.listPessoa() GET /pessoa/:nome @controllers.PessoaController.createPessoa(nome:String) POST /pessoa/create @controllers.PessoaController.create() POST /pessoa/save @controllers.PessoaController.save()
- Views de Pessoa
GET /list @controllers.PessoaController.list() GET /create @controllers.PessoaController.createView() GET /delete/:id @controllers.PessoaController.delete(id: Long)
- Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path="/public", file)
Uma rota é indicada pelo método HTTP que seja utilizado (GET, POST, PUT, DELETE), uma URL e o controlador e método que irá receber a requisição. Uma URL pode receber parâmetros , assim como o método no controlador indicado para atender a requisição, como no exemplo de ‘pessoa/:nome’ em que ‘:nome’ se refere ao parâmetro sendo fornecido e o método ‘createPessoa(nome: String)’ recebe como parâmetro a String nome fornecida também como parâmetro na URL da requisição GET. Parâmetros enviados em URLs que usem o método POST são obtidos no controlador usando os tipos utilitários Form e DynamicForm (exemplificados em alguns métodos na classe PessoaController).
6.1. Rodando o projeto
Para rodarmos e testarmos o projeto, vamos abrir um console na pasta do projeto e digitar o comando:
play run
Feito isso, a aplicação será rodada e testada no endereço http://localhost:9000 (sendo que 9000 é a porta utilizada pelo servidor web embutido no Play).
7. Bibliografia
Boaglio, F. Play Framework: Java para web sem servlets e com diversão, 2014, Primeira Edição, Casa do Código, Brasil. HILTON, P.; BAKKER, E.; CANEDO, F. Play for Scala. [S.l.]: Mannings Publications Co, 2013. LEROUX, Nicolas; KAPER, Sietse de. Play for Java: Covers Play 2. New York: Manning, 2012. GAMMA, Erich et al. Padrões de Projeto: Soluções reutilizáveis de software Orientado a Objetos. Porto Alegre: Bookman, 2000. PLAY FRAMEWORK; Play 1.0 Documentation. Disponível em:< https://www.playframework.com/documentation/1.0/main>. Acesso em: 17 agosto. 2017. SPRING BOOT; Overview. Disponível em:< https://spring.io/projects/spring-boot >. Acesso em: 10 de julho. 2018.