Produtividade na web com Groovy e Grails
Quem somos? Lucas Aquiles / @lucas_aquiles ADS / IFPI lucasaquiles@gmail.com lucasaquiles.com.br/blog Fco Marcos / @fcomarcosrocha ADS / IFPI Colaborador LAPESI fmarcosrocha@gmail.com
O Grails Inspiração Convenção ao invés de configuração Ruby on Rails, Django, TurboGears Construído sobre gigantes Java/ JEE Spring Framework Hiberante Reduz a complexidade Produtividade
O Grails GORM Baseado no Hiberante Camada de visão GSP (Groovy Server Pages) TagLib dinâmicas e SiteMesh Camada de controle: Baseado no Spring MVC / Spring Web Flow Dependency Injection (DI) Spring Container Internacionalização (i18n)
Grails - Instalação e Configuração http://www.grails.org/downloads Descompacte o arquivo e configure o GRAILS_HOME Hello Grails grails create-app helloword grais create-controller HelloWord grails- app/controllers/helloword/hellowordcontroller.groovy def helloword = { render meu 123487 hello word! }
Comandos - Grails Comandos básicos grails create-app AppDemo grails create-domain-class br.edu.ifpi.minhaclass grails create-controller br.edu.ifpi.minhaclass grails create-service br.edu.ifpi.minhaclass grails generate-all // gera as views os controlleres grails schema-export // expora o esquema de tabelas grails console // abre o console do groovy grails clean // limpa aterações grails run-app // roda a aplicação
Grails - Estrutura Arquivos de configuração: DataSource.groovy Config.groovy Bootstrap.groovy internacionalização Libs adicionais: ex mysql-connector.jar web.xml
DataSource - Grails DataSource - Arquivo de configuração de banco de dados Configurado por padrão com o HSQLDB Um banco de dados leve, usado para testes Possui três ambientes de trabalho Test, Production e Development
DataSource - Grails
MVC - Grails Modelo Tudo que será usado como Entidade ficá aqui. grails-app/domain/ grails create-domain-class Separar a lógica de negócio do modelo Cada classe de domínio corresponde à uma tabela do banco de dados relacional
MVC - Grails Controller: Toda regra de negócio fica no controller. grails-app/controller grails create-controller action: São clousures que irão receber as requisições e fazer alguma coisa def actionquefazalgumacoisa = { render \\o/ }
MVC - Grails Controller params: é um map (hash) de parâmetros de uma requisição def actionquepegaoparamseexibe = { } render parametros: ${params} flash: map temporário que armazena objetos da seção, o hash é limpo a cada nova requisição def actionquemostraoflashmessage = { } flash.message = ${params}
MVC - Grails Controller render: renderiza uma resposta redirect: redireciona uma ação usando HTTP redirect def actionqueredireciontapraoutraaction = { } redirect(controller:meucontroller, action: outraaction )
MVC Grails Controller scaffolding cria a estrura de CRUD para aquele modelo def scaffolding = MinhaClasseDeDominio
MVC - Grails Views crails create-view grails-app/views/<domain>/ <% %> ou <%= %> Utilizam a GSP taglib Evita misturar código de programação com linguagem de marcação Semelhando ao JSP def show = { [book:book.get(params.id)]} <%= book.title %>
MVC - Grails Views Loops <g:each in= ${livros} > <p>título: ${it.titulo}</p> </g:each> <g:each in= ${livros} var= livro > <p>título: ${livro.titulo}</p> </g:each>
MVC - Grails Views Condições <g:if test= ${nome == 'tr00'} > Hello, ${tr00} </g:if> <g:else> --- faz alguma coisa </g:else> <g:elseif test= 2 % 2 == 0 > faz outra coisa </g:elseif>
Service - Grails Services grails create-service grails-app/services/ Centraliza a regra de negócio Compartilha a mesma regra com classes de domínio que possuam essa lógica Injetado automaticamente no controller pelo Spring
Service - Grails Services Transactions transactional = true Essencial para manter a integridade do banco de dados via ACID; Atomicidade A terefa foi completa ou não Consistência - o banco de dados deve permanecer consistente antes e depois de uma operação Isolação uma transação está isolada das outras operações Durabilidade desde que a transação esteja feita, isso garante que a transação não possa ser desfeita
Scaffolding - Grails Scaffolding Permite criar rapidamente interfaces de CRUD para classes de domínio que estejam definidas Ótimo para prototipação
Scaffolding - Grails Scaffolding dinâmico: def scaffolding = MyDomainClass Scaffolding estático grails genreate-views: gera as views para uma classe de domínio específica grails generate-controller: cria o controlador para uma classe de domínio específica grails generate-all: cria os controlers + views ex: grails generate-all br.edu.ifpi.beans.aluno
MVC - Grails GORM Hibernate por baixo dos panos Permite fazer o mapeamento objeto / relacional do modelo orientado a objetos com o banco de dados relacional Cada classe de domínio representa uma tabela do banco de dados Uma instância representa uma linha da tabela Cada atributo da classe representa uma coluna da tabela
MVC - Grails Enquanto isso no hibernate... Criar uma classe, anotar a classe com a implementação do JPA, mapea a classe no arquivo de configuração, cria uma fabrica de sessões, cria um Dao, e por fim instancia um objeto da classe e persiste.
TUDO ISSO?
GORM - Grails Com o GORM do grails grails create-domain-class Usuario grails console def usuario = new User(login: tr00,password: tr00 ) usuario.save() Não precisa extender de ninguém, não precisa de annotations. grande semelhança com o ActiveRecord
GORM - Grails Métodos do GORM save() list() delete() get(object o) Buscadores dinâmicos
GORM - Grails Buscadores dinâmicos FindBy* Usuario.findByUsernameAndPassword( mock, mocklogin ) FindAllBy* Usuario.findAllByGroup(Group.get(1)) FindWhere, findallwhere Usuario.findWhere([ "username": "mock", login: "mocklogin"]) HQL Hibernate Query Language User.find( from User where login = :login and senha = :senha, [ mock, mocklogin ]) Parâmetros: max, sort, order
ORM - Grails Comparadores Between User.findByDateCreatedBetween(today-10, today) Like User.findByBioLike('%tr00%') NotEqual Album.findByTitleNotEqual('titulo de teste') IsNull User.findByGroupIsNull() IsNotNull User.findByGroupIsNotNull()
GORM - Grails Usando Criteria do Hibernate Uma das mais poderosos de de busca get: retorna uma instancia da query list: retorna uma lista de instancias count: retorna um total de resultados como um inteiro da query def c = DomainClass.createCriteria() def result = c.list{ eq('nome','tr00' }
GORM - Grails Relacionamentos Permite 4 tipos de relacionamentos One-to-one, One-to-Many, Many-to-One e Many-to-Many OneToMany Player hasone club HasMany - club hasmany players Métodos dinâmicos Club.addToPlayers(new Player()) Club.removeFromPlayers(Player.get(1L)) BelongsTo Player belongsto clube
i18n - Grails Internacionalização i18n grails-app/i18n/ Permite exibir mensagens no idioma de preferência do usuário Os arquivos.properties
Testes - Grails Testes Sempre que uma um controller, service ou classe domínio é criada, é criada uma classe de teste de integração correspondente Usa o Junit e o Canoo por baixo dos panos Permite fazer: Testes unitários Testes de integração Testes funcionais A aplicação vai trabalhar como esperado A classe de testes extendem de GroovyTestCase Permite o uso de assert*, setup e teardown
Tests - Grails Testes Teste de Integração!= teste Unitário Testes unitários no grails são criados com o comando: grails create-unit-test tests/unit/ nos testes unitários os métodos dinâmicos como save, findby* não estão disponíveis O grails faz isso pra ajudar você a diferenciar testes unitários e de integração testes unitários se preucupam em testar apenas uma parte do código e não o problema como um todo
Testes - Grails mas como testar sem os métodos dinâmicos?
Testes - Grails Testes Aí entram em cena o MockFor* e o StubFor* http://groovy.codehaus.org/groovy+mocks
Aplicação de exemplo - Grails Querist Aplicação de perguntas e respostas onde um usuário envia perguntas e outros usuários enviam as respostas. Uma resposta pode receber votos, a resposta mais votada é tída como a mais confiável Regras: Um usuário tem muitas perguntas e mutias respostas Uma pergunta tem um usuário ( quem perguntou ) e várias respostas Uma resposta pertence a uma pergunta e possui vários usuários ( quem respondu )