Linguagem dinâmica         •  Groovy

                                               Arquitetura            •  MVC

                                       Mapeamento Objeto Relacional   •  Hibernate

                                                Convenção             •  Sobre configuração

Grails                                             DRY                •  Dont Repeat Yourself

                                                  YAGNI               •  You aint gonna need it

                                                  KISS                •  Keep It Simple, Stupid




         Simplicidade e Poder                                           Plataforma
                                    Não apenas um framework
                                    Um ambiente full-stack

                                    Servidor web
                                    Banco de dados
Criando um projeto
                          Instalando e testando              6 passos na linha de comando
    Exige Java 5.0 ou superior                       grails createApp nomeProjeto
                                                           Comando para criar o projeto
     Download Grails:
                                                        
 
                                                      cd nomeProjeto
         http://grails.org/Download                      Navegar até o diretório da nova aplicação

    Descompacte                                      grails createController nomeControlador
                                                          Criar nosso primeiro controlador
    Cria uma variável de ambiente
         GRAILS_HOME                                 Escrever algum código no melhor estilo hello...
                                                      grails testApp
    Adicione GRAILS_HOMEbin ao seu PATH                 Escrever o código de teste e executar os testes

    Valide a instalação                              grails runApp
                                                          Comando para executar a aplicação
         grails




                                                                 Acessar a pasta do projeto



                                                                      cd projeto
grails createController Loja
                                                   Criação de 2 classes
                                                        Loja Controller.groovy
                                                              No diretório controllers/jctunes
                                                        Classe de teste




                                                                                                  render
                    Exibindo uma mensagem                                    Um dos métodos implícitos
    Para todo controlador, por default        package projeto
         Grails cria uma ação chamada index
                                               class LojaController {
           package projeto
                                                 def index = {
                                                        render "Seja benvindo a Loja"
           class LojaController {
                                                    }
               def index = { }                 }
           }

    Por convenção tenta renderizar
         grails-app/views/loja/index.gsp
Testando o código
                                      com Grails                Escrevendo o código de testes
                                                   package projeto
  Testes de                                        import grails.test.*
                             Testes unitários
 integração                                        class LojaControllerTests extends ControllerUnitTestCase {
                                                       protected void setUp() {
                                                           super.setUp()
 Para todo o ambiente                                  }
desenvolvido incluindo a                               protected void tearDown() {
    base de dados                   Rápidos                super.tearDown()
                                                       }

                                                       void testPaginaPrincipal() {
Geralmente, mais lentos                                   controller.index()
                                                            assertEquals "Seja benvindo a Loja",
                                                                     controller.response.contentAsString
                                   Fazem uso           }
Aplicação deve possuir          de mocks e stubs
                                                   }
 alguma completude




                                                                                          grails test-app
Testando o Código
    target/test-reports




                               grails runApp   grails runApp
Porta em Conflito???



                                                            Iniciando Grails
grails –Dserver.port=8087 runApp
                                            CRUD, Scaffolding e Domínio




                                                                  Scaffolding

                                   Permite gerar
                                   rapidamente interfaces
                                   de CRUD para classes
                                   de domínio

                                   Facilita o
                                   entendimento de como
                                   a Visão e o Controle
                                   interagem no Grails
Classes de Domínio                              Classes de Domínio
                         Lógica do negócio
                         São persistidas
                         Mapeadas automaticamente para tabelas de
                          banco de dados
                              Hibernate
                         Localização
                              grails-appdomainnomeDoProjeto
                         Criação
                              grails createDomainClass




                          grails createDomainClass Musica
grails createDomainClass Musica                           Again...
package projeto

class Musica {

         static constraints = {
         }
}




    grails createDomainClass Musica                       Scaffolding
package projeto

class Musica {
                                         Dinâmicos       Estáticos
        String titulo
                                      • Lógica do    • Criação de
        String artista                  controle e     templates
        Integer duracao                 visões são
        Date lancamento                 geradas em
    static constraints = {              tempo de
    }                                   execução
}
grails createController
                                                                     Musica
                                         package projeto

                                         class MusicaController {

                                             def index = {
                                             }
                                         }




                           Habilitando
            o Scaffolding dinâmico
package jcTunes

class MusicaController {


    def scaffold = Musica
}
Vamos testar...            Relacionamentos com classes
                          1 para 1
                          1 para muitos
                          Muitos para 1
                          Muitos para muitos
                          ...




        Nova classe



*   1
Como definir uma relação
                         1 para muitos?                                    Classe Album
                                             package projeto

                                             class Album {
                                              String titulo
    static hasMany = [musicas: Musica]
                                                 static hasMany = [musica: Musica]

                                                 static constraints = {
                                                 }
                                             }



                                                               Altere a classe Musica
      static hasMany = [musica: Musica]                        para tornar a relação bi-direcional
                                             package jctunes
    Esta relação é unidirecional
                                             class Musica {


    Para torná-la bidirecional inclua uma        ...
     referência de Album na classe Musica          Album album
                                                  ...
                                             }
AlbumController
                       package jctunes

                       class AlbumController {


                           def scaffold = Album
                       }




                                              Scaffolding estático
                       Geração do código das visões e dos
                       controles


                           Pode ajudar na familiarização com o
                           Grails e como o todo trabalha junto

Scaffolding Estático           Ponto de partida para adicionar
                               para casos de uso que precisam de
                               uma lógica além CRUD
Scaffolding estático
                                     3 targets básicos

              grails           •  Gera as visões para uma
          generateViews           classe de domínio específico


           grails              •  Gera o controle para uma
     generateController           classe de domínio específico


             grails            •  Gera ambos controle e
           generateAll            visões associados




                                                                                             Vamos examinar
                           Grails fará 2 perguntas                                           o código gerado
    Como o controle já existe
         ele pergunta se você deseja sobrescrever a classe           Milhares de linhas?
          AlbumController e sua classe de teste -> responda Y (yes)
                                                                      10 camadas???
                                                                      •  DAO
                                                                      •  Controle
                                                                      •  Classe de Negócio
                                                                      •  TO
                                                                      •  POJO
Em tempo de execução




                  Repita o processo
               para a classe MUsica
Gere o controlador de Musica novamente

grails generateController projeto.Musica


       Gere as visões novamente

 grails generateViews projeto.Musica
Relacionamentos
                                       class Carro {
                                           Motor motor
                                       }

                                       class Motor {
  Relacionamentos                          Carro carro
                                       }
                                       Não há relação de pertença




                  Relacionamentos                                   Outra forma
class Carro {                          class Carro {
    Motor motor                            Motor motor
}                                      }

class Motor {                          class Motor {
    static belongsTo = [carro:Carro]       static belongsTo = Carro
}                                      }
Qual a diferença?                                                    belongsTo
    static belongsTo = [carro:Carro]                           A propriedade que pertence sofrerá
         A classe Motor tem sua própria referência para         exclusões em cascata
          carro
                                                                Grails saberá que o Motor pertence a um
    static belongsTo = Carro                                    Carro
         A classe Motor não possui referência para carro            então sempre que um Carro for excluído do
                                                                      banco, o Motor será excluído em conjunto




                                       Outra classe                                             Classe Artista
    Artista                                                class Artista {
         Propriedades                                          String nome
               nome
               albuns
                                                                       static hasMany = [albuns:Album]
    Album pertencerá a um Artista
         Com referência                                    }
    Música pertencerá a um Album
         Sem referencia
Classe Album                                  Musica
class Album {                                    class Musica{
    String titulo
                                                     String titulo
                                                     Integer duracao
    static hasMany = [musicas:Musica]
                                                     Date lancamento
    static belongsTo = [artista:Artista]
}                                                    static belongsTo = Album
                                                 }




                            Classe Artista
class Artista {
    String nome

    static hasMany =                                         Classes de Domínio
      [albuns:Album, instrumentos:Instrumento]
}
Classes de Domínio                      Validando classes de domínio
    Por default, todos os campos de uma classe de         Toda aplicação tem regras de negócios que
     domínio são persistidas no banco de dados              restringem os valores válidos de uma
    Para tipos simples como Strings e Integers,            propriedade de classe
     cada propriedade da classe será mapeada para             Idade não pode ser < 0
     uma coluna de uma tabela                                 Email deve possuir @ e .

    Para tipos complexos serão necessários tabelas           O número de um cartão de crédito deve seguir

    Toda classe mapeada para uma tabela receberá              um padrão
     um campo adicional, o id, que será a chave            Regras como estas deve estar em um local
     primária                                               específico




                               Validando
               as propriedades da Musica                                                             Constraints
class Musica {                                             blank                            notEqual
   String titulo
                                                           creditCard                       nullable
   String artista
   Integer duracao
                                                           email                            range
   Date lancamento                                         inList                           scale
                                                           matches                          size
     static constraints = {                                max                              unique
        titulo(blank: false,minSize:2)
                                                           maxSize                          url
        artista(blank: false)
                                                           min                              validator
        duracao(min:1)
     }
                                                           minSize
}
                                                      OBS: A validação ocorre quando o método save de um objeto é chamadov
Propriedades Transientes                                         Exemplos
    Por default, toda propriedade de uma classe   package projeto
     de domínio é persistida no banco de dados
                                                   class Album {
                                                    String titulo
    E quando existirem propriedades que não
     necessitam ser persistidas?                    String nomeFalso

                                                       static transients = [‘nomeFalso’]
    static transients
                                                       ...
                                                   }




                              Outro exemplo
class Pessoa {
  BigDecimal saldo
  BigDecimal limiteEspecial

    BigDecimal getSaldoDisponivel () {
        saldo+limiteEspecial                           mockDomain()
     }                                                 Testando a classe de domínio
    static transients = [‘saldoDisponivel’]
    ...
}
Testando uma classe de domínio
                                           mockDomain

void testDuracaoMinima() {
       mockDomain(Musica)                                                                         Entendendo
          def musica = new Musica(duracao: 0)                                                    os Controles
          assertFalse 'Validacao deve falhar', musica.validate()

          assertEquals "min", musica.errors.duracao
}




                                                Introdução                                            Introdução
    Os controles são classes responsáveis por                         Existe um controle para cada requisição
     manipular requisições que chegam à
     aplicação
       O controle recebe a requisição                                 Não precisam herdar ou implementar uma
       Geralmente, realiza alguma tarefa com a
                                                                        interface específica
        requisição
       E finalmente decide o que deve acontecer em
        seguida
              Executar uma outra ação dele ou de outro controle
              Renderizar uma visão
              Renderizar informações diretamente para uma visão
Definindo um controle                                            Ações de um controle
    Localização                                             class                                       Ações são definidas
                                                               SampleController {                         como um campo
          grails-app/controllers
                                                               def first = {...}                         Cada campo é atribuído
    Convenção                                                 def second = {...}                         a bloco de código
          O nome da classe deve terminar com “Controller”     def third = {...}                          utilizando uma closure
                                                               def fourth = {...}                         Groovy
                                                             }                                           Controller pode definir
                                                                                                          um número qualquer de
                                                                                                          ações




                Mapeamentos, urls no Grails                                      Configurando a ação default
class SampleController {                                         Se o controle
  def first = {...}                                                   Tem apenas 1 ação
  ...                                                                       Tal ação torna-se a default
}
     A primeira parte de uma url representa qual controle            Possui uma ação chamada index
      está sendo acessado                                                   A ação index será a default
     A segunda parte representa a ação a ser executada
                                                                      Define uma propriedade defaultAction
                    nomeAplicacao/sample/first                              Seu valor será a ação default
Controle                                                           Controle
                 Tem apenas 1 ação          Possui uma ação chamada index


                                        class SampleController {
class SampleController {                  def list = {}
  def list = {}                           def index = {}
}                                       }




                             Controle
    com propriedade defaultAction              Objetos implícitos no controle
                                           actionName      •  Nome da ação que está sendo executada

                                            actionUri      •  Uri relativa a ação em execução

                                          controllerName   •  Nome do atual controle em execução
class   SampleController {                 controllerUri   •  Uri do controle em execução

  def   defaultAction = 'list'                flash        •  Objeto para acessar o escopo flash

                                               log         •  Instância de org.apache.commons.logging.Log
  def   list = {}
                                             params        •  Mapa de parâmetros de requisição
  def   index = {}                           request       •  O objeto HttpServletRequest
}                                           response       •  O objeto HttpServletResponse

                                             session       •  O objeto HttpSession object

                                          servletContext   •  O objeto ServletContext
Escopos dos controles                                     Escopos dos controle
                                    request
                                         Objetos colocados dentro de request estarão disponíveis
                                          durante a execução da requisição corrente
                                    flash
                                         Objetos colocados dentro de flash estarão disponíveis
                                          para a requisição atual e para a próxima
                                    session
                                         Objetos colocados no session serão mantidos até que a
                                          sessão do usuário seja invalidada, ou manualmente ou
                                          por expiração
                                    servletContext
                                         Objetos colocados no servletContext são compartilhados
                                          por toda a aplicação e mantidos durante todo o tempo de
                                          vida da aplicação




Acessando parâmetros da                             Acessando parâmetros da
              requisição                                          requisição
                                    Via propriedade params do Grails


                                     def userName = params.userName
                                     log.info("User Name: ${userName}")




     Valores da página
     => parâmetros do request
Redirect
                        Redirecionando a requisição                  Redirecionando a requisição
                                                          class SampleController {
                                                            def first = {
                                                              // redireciona para a acao “second”
                                   Todo controle tem          redirect(action: "second")
Às vezes é necessário
                                 acesso a um método         }
    redirecionar o
                                  chamado redirect,
 controle para outra                                        def second = {
                                 que recebe um mapa
  ação de controle                                            // ...
                                    como argumento
                                                            }
                                                          }




            Redirecionando para outro
                             controle                                        Argumentos do redirect
class SampleController {
  def first = {
                                                       action                controller              id
    //redirecionar para a acao list de Loja            •  O nome da ação     •  O nome do controle   •  Valor do parâmetro
    redirect(action: "list", controller: "Loja")          para                  para                    id para ser enviado
                                                          redirecionamento      redirecionamento        no redirecionamento
  }
}
                                                       params                uri                     url
                                                       •  Um mapa de         •  Um endereço          •  Um endereço
                                                          parâmetros            relativo para           absoluto
                                                                                redirecionar
Criando um modelo
                                                       Uma das atividades fundamentais do controle
                                                            Reunir dados para serem renderizados na visão


                                                       O controle pode realizar esta tarefa
                                                            Ou delegar para uma classe de serviço ou
      Informações que chegam às visões
                                                             outros componentes
      O Model




                       Criando um modelo                                        Retornando dados
    Quando o controle faz esta tarefa, os dados        class MusicaController {
     são disponibilizados diretamente para as             def show = {
     visões através de um mapa, o MODEL                     [ musica: Musica.get(params.id) ]
                                                          }
    O mapa é retornado pelas ações de um               }
     controle                                        return é opcional
                                                     Como a última expressão avaliada pela ação foi um mapa,
                                                      então o mapa é o valor retornado desta ação
                                                     O mapa pode ter qualquer quantidade de valores
Renderizando                                             E se eu quiser
                                                        a Visão                               alterar a View de destino?
    O controle MusicaController                                           Utilize o método render
             1 método chamado show
                   Retorna um modelo contendo uma chave e um objeto   class MusicaController {
                                                                         def show = {
                                                                                     render(view:"exibir",
    Onde está a referência para qual visão ele irá                                         model:[musica: Musica.get(params.id)])
     despachar o fluxo?                                                     }
                                                                       }

                                                                           Por convenção
    Por convenção                                                                  grails-app/views/musica/exibir.gsp
             grails-app/views/musica/show.gsp




                                                                                                 Ligando dados da visão
                            E para mudar o diretório?                                                    para o controle
    Utilize um caminho absoluto

class MusicaController {
  def show = {
              render(view:"/outrapasta/exibir",
                     model:[musica: Musica.get(params.id)])
     }
}

             grails-app/views/outrapasta/exibir.gsp
Ligando dados
                                Ligando dados                                 primeira forma
    Controles também precisam                       class AlbumController {
       Criar novos objetos de domínio                 def save = {
       Popular as propriedades destes objetos com       def album = new Album()
        valores recebidos como parâmetros na
        requisição                                           album.genero = params.genero
                                                             album.titulo = params.titulo

                                                             album.save()
                                                         }
                                                     }




                                                     class AlbumController {
                                                       def save = {

                                                             def album = new Album(params)

                                                             album.save()
                                                         }
                                                     }
Alterando as propriedades com                                        DataBinding
                           dataBinding                               de objetos múltiplos
class AlbumController {
  def update= {
    def album = Album.get(params.id)

        album.properties = params        def album = new Album( params["album"] )
                                         def artist = new Artista( params["artista"] )

        album.save()    }
}




            DataBinding e Associações                                  2 cenários na visão
    Na classe de domínio                    <input type="text" name="artista.name" />
                                                  Uma nova instância de artista é criada e atribuída
class Album {                                      à instância do Álbum

         Artista artista
                                             <input type="text"
         ...
                                                 name="artista.id" value="1" />,
}                                                 Recupera uma instância de um artista existente e
  Na classe de controle                           atribui à classe do Álbum

def album       = new Album(params)
Uma variação dos cenários
<input type="text”
 name="songs[0].title"
 value="The Bucket" />
<input type="text
 name="songs[1].title" value="Milk" />

<input type="text" name="songs[0].id"                           GORM
 value="23" />                                                  Grails Object Relational Mapping
<input type="text" name="songs[1].id"
 value="47" />




                                                   get()                                       getAll()


def album = Album.get(params.id)                           def album = Album.getAll(1,2,3)

    Get recebe um id e retorna                                Recebe
         Ou a instância do objeto correspondente ao id             Vários identificadores
         Ou null caso não exista                              Retorna
                                                                    Uma lista de instâncias
read()                                                             list()
                                                             4 atributos
                                                                   max
def album = Album.read(params.id)                              

                                                                        Número máximo de instâncias a serem retornadas
                                                                  offset
    Recebe                                                             Qual o 0 relativo da consulta
         Um identificador                                        sort
    Retorna                                                            Nome da propriedade para utilizar no ORDER BY

         Um objeto em estado somente leitura                     order
                                                                        Se a ordenação é ASC ou DESC




                                    Classe Album                                                                   list()
class Album {                                                def allAlbums = Album.list()
    String titulo                                                 Recupera todos os albuns


          Date lancamento                                    def top10 = Album.list(
                                                                 max:10, sort:‘lancamentos', order:'desc')
          static hasMany = [musicas:Musica]                       Retorna os 10 albuns mais recentes


          static belongsTo = [artista:Artista]               def totalAlbums = Album.count()
}                                                                 Recupera o total de albuns
Classe Album
                                         class Album {
                                             String titulo

                                             Date lancamento

                                             static hasMany = [musicas:Musica]

                                             static belongsTo = [artista:Artista]
                                         }



                                                                       save()
                        listOrderBy*()             Inserir uma nova instância
def tudoPorLancamento =
Album.listOrderByLancamento()            def album = new Album(params)
                                         album.save()
def tudoPorTitulo =
Album.listOrderByTitulo()
save()                           save()
                 Alterar uma instância                         Variação

def album = Album.get(1)

album.titulo = “Titulo Alterado“           album.save(insert:true)

album.save()




                                delete()
                       Excluir do banco




             album.delete()
findBy                                            findBy
    Retorna uma única instância                           Retorna uma única instância



      Album.findByTituloAndGenero(                            Album.findByTituloOrGenero(
            “RATM”, “Rock”)                                        “RATM”, “Rock”)




                                    Mais findBy                                           Mais findBy
Album.findByLancamentoBetween(hoje-10,hoje)            Album.findByGeneroIsNull()


Album.findByTituloEquals(‘RATM')                       Album.findByGeneroIsNotNull()

                                                       Album.findByLancamentoLessThan(ontem)
Album.findByLancamentoGreaterThan(ontem)
                                                       Album.findByLancamentoLessThanOrEqual(ontem)
Album.findByLancamentoGreaterThanOrEqual(o
  ntem)                                                Album.findByTituloLike(‘O tempo não%')

Album.findByTituloInList([‘123', ‘Brasil'])            Album.findByTituloNotEqual('Odelay")
Métodos “primos”                                                Criteria
    findAllBy*                                             def c = Album.createCriteria()
         Retorna uma lista baseado nos parâmetros
                                                            def results = c.list {
                                                              eq('genero', 'Alternativo')
    countBy*                                                 between(‘lancamento', new Date()-30, new
         Retorna um inteiro com o total de instância que      Date())
          satisfazem a consulta
                                                            }

Grails

  • 1.
    Linguagem dinâmica •  Groovy Arquitetura •  MVC Mapeamento Objeto Relacional •  Hibernate Convenção •  Sobre configuração Grails DRY •  Dont Repeat Yourself YAGNI •  You aint gonna need it KISS •  Keep It Simple, Stupid Simplicidade e Poder Plataforma   Não apenas um framework   Um ambiente full-stack   Servidor web   Banco de dados
  • 2.
    Criando um projeto Instalando e testando 6 passos na linha de comando   Exige Java 5.0 ou superior   grails createApp nomeProjeto Comando para criar o projeto Download Grails:       cd nomeProjeto   http://grails.org/Download   Navegar até o diretório da nova aplicação   Descompacte   grails createController nomeControlador   Criar nosso primeiro controlador   Cria uma variável de ambiente   GRAILS_HOME   Escrever algum código no melhor estilo hello...   grails testApp   Adicione GRAILS_HOMEbin ao seu PATH   Escrever o código de teste e executar os testes   Valide a instalação   grails runApp   Comando para executar a aplicação   grails Acessar a pasta do projeto cd projeto
  • 3.
    grails createController Loja   Criação de 2 classes   Loja Controller.groovy   No diretório controllers/jctunes   Classe de teste render Exibindo uma mensagem Um dos métodos implícitos   Para todo controlador, por default package projeto   Grails cria uma ação chamada index class LojaController { package projeto def index = { render "Seja benvindo a Loja" class LojaController { } def index = { } } }   Por convenção tenta renderizar   grails-app/views/loja/index.gsp
  • 4.
    Testando o código com Grails Escrevendo o código de testes package projeto Testes de import grails.test.* Testes unitários integração class LojaControllerTests extends ControllerUnitTestCase { protected void setUp() { super.setUp() Para todo o ambiente } desenvolvido incluindo a protected void tearDown() { base de dados Rápidos super.tearDown() } void testPaginaPrincipal() { Geralmente, mais lentos controller.index() assertEquals "Seja benvindo a Loja", controller.response.contentAsString Fazem uso } Aplicação deve possuir de mocks e stubs } alguma completude grails test-app
  • 5.
    Testando o Código   target/test-reports grails runApp grails runApp
  • 6.
    Porta em Conflito??? Iniciando Grails grails –Dserver.port=8087 runApp CRUD, Scaffolding e Domínio Scaffolding Permite gerar rapidamente interfaces de CRUD para classes de domínio Facilita o entendimento de como a Visão e o Controle interagem no Grails
  • 7.
    Classes de Domínio Classes de Domínio   Lógica do negócio   São persistidas   Mapeadas automaticamente para tabelas de banco de dados   Hibernate   Localização   grails-appdomainnomeDoProjeto   Criação   grails createDomainClass grails createDomainClass Musica
  • 8.
    grails createDomainClass Musica Again... package projeto class Musica { static constraints = { } } grails createDomainClass Musica Scaffolding package projeto class Musica { Dinâmicos Estáticos String titulo • Lógica do • Criação de String artista controle e templates Integer duracao visões são Date lancamento geradas em static constraints = { tempo de } execução }
  • 9.
    grails createController Musica package projeto class MusicaController { def index = { } } Habilitando o Scaffolding dinâmico package jcTunes class MusicaController { def scaffold = Musica }
  • 10.
    Vamos testar... Relacionamentos com classes   1 para 1   1 para muitos   Muitos para 1   Muitos para muitos   ... Nova classe * 1
  • 11.
    Como definir umarelação 1 para muitos? Classe Album package projeto class Album { String titulo   static hasMany = [musicas: Musica] static hasMany = [musica: Musica] static constraints = { } } Altere a classe Musica static hasMany = [musica: Musica] para tornar a relação bi-direcional package jctunes   Esta relação é unidirecional class Musica {   Para torná-la bidirecional inclua uma ... referência de Album na classe Musica Album album ... }
  • 12.
    AlbumController package jctunes class AlbumController { def scaffold = Album } Scaffolding estático Geração do código das visões e dos controles Pode ajudar na familiarização com o Grails e como o todo trabalha junto Scaffolding Estático Ponto de partida para adicionar para casos de uso que precisam de uma lógica além CRUD
  • 13.
    Scaffolding estático 3 targets básicos grails •  Gera as visões para uma generateViews classe de domínio específico grails •  Gera o controle para uma generateController classe de domínio específico grails •  Gera ambos controle e generateAll visões associados Vamos examinar Grails fará 2 perguntas o código gerado   Como o controle já existe   ele pergunta se você deseja sobrescrever a classe Milhares de linhas? AlbumController e sua classe de teste -> responda Y (yes) 10 camadas??? •  DAO •  Controle •  Classe de Negócio •  TO •  POJO
  • 14.
    Em tempo deexecução Repita o processo para a classe MUsica Gere o controlador de Musica novamente grails generateController projeto.Musica Gere as visões novamente grails generateViews projeto.Musica
  • 15.
    Relacionamentos class Carro { Motor motor } class Motor { Relacionamentos Carro carro } Não há relação de pertença Relacionamentos Outra forma class Carro { class Carro { Motor motor Motor motor } } class Motor { class Motor { static belongsTo = [carro:Carro] static belongsTo = Carro } }
  • 16.
    Qual a diferença? belongsTo   static belongsTo = [carro:Carro]   A propriedade que pertence sofrerá   A classe Motor tem sua própria referência para exclusões em cascata carro   Grails saberá que o Motor pertence a um   static belongsTo = Carro Carro   A classe Motor não possui referência para carro   então sempre que um Carro for excluído do banco, o Motor será excluído em conjunto Outra classe Classe Artista   Artista class Artista {   Propriedades String nome   nome   albuns static hasMany = [albuns:Album]   Album pertencerá a um Artista   Com referência }   Música pertencerá a um Album   Sem referencia
  • 17.
    Classe Album Musica class Album { class Musica{ String titulo String titulo Integer duracao static hasMany = [musicas:Musica] Date lancamento static belongsTo = [artista:Artista] } static belongsTo = Album } Classe Artista class Artista { String nome static hasMany = Classes de Domínio [albuns:Album, instrumentos:Instrumento] }
  • 18.
    Classes de Domínio Validando classes de domínio   Por default, todos os campos de uma classe de   Toda aplicação tem regras de negócios que domínio são persistidas no banco de dados restringem os valores válidos de uma   Para tipos simples como Strings e Integers, propriedade de classe cada propriedade da classe será mapeada para   Idade não pode ser < 0 uma coluna de uma tabela   Email deve possuir @ e .   Para tipos complexos serão necessários tabelas   O número de um cartão de crédito deve seguir   Toda classe mapeada para uma tabela receberá um padrão um campo adicional, o id, que será a chave   Regras como estas deve estar em um local primária específico Validando as propriedades da Musica Constraints class Musica {   blank   notEqual String titulo   creditCard   nullable String artista Integer duracao   email   range Date lancamento   inList   scale   matches   size static constraints = {   max   unique titulo(blank: false,minSize:2)   maxSize   url artista(blank: false)   min   validator duracao(min:1) }   minSize } OBS: A validação ocorre quando o método save de um objeto é chamadov
  • 19.
    Propriedades Transientes Exemplos   Por default, toda propriedade de uma classe package projeto de domínio é persistida no banco de dados class Album { String titulo   E quando existirem propriedades que não necessitam ser persistidas? String nomeFalso static transients = [‘nomeFalso’]   static transients ... } Outro exemplo class Pessoa { BigDecimal saldo BigDecimal limiteEspecial BigDecimal getSaldoDisponivel () { saldo+limiteEspecial mockDomain() } Testando a classe de domínio static transients = [‘saldoDisponivel’] ... }
  • 20.
    Testando uma classede domínio mockDomain void testDuracaoMinima() { mockDomain(Musica) Entendendo def musica = new Musica(duracao: 0) os Controles assertFalse 'Validacao deve falhar', musica.validate() assertEquals "min", musica.errors.duracao } Introdução Introdução   Os controles são classes responsáveis por   Existe um controle para cada requisição manipular requisições que chegam à aplicação   O controle recebe a requisição   Não precisam herdar ou implementar uma   Geralmente, realiza alguma tarefa com a interface específica requisição   E finalmente decide o que deve acontecer em seguida   Executar uma outra ação dele ou de outro controle   Renderizar uma visão   Renderizar informações diretamente para uma visão
  • 21.
    Definindo um controle Ações de um controle   Localização class   Ações são definidas SampleController { como um campo   grails-app/controllers def first = {...}   Cada campo é atribuído   Convenção def second = {...} a bloco de código   O nome da classe deve terminar com “Controller” def third = {...} utilizando uma closure def fourth = {...} Groovy }   Controller pode definir um número qualquer de ações Mapeamentos, urls no Grails Configurando a ação default class SampleController {   Se o controle def first = {...}   Tem apenas 1 ação ...   Tal ação torna-se a default }   A primeira parte de uma url representa qual controle   Possui uma ação chamada index está sendo acessado   A ação index será a default   A segunda parte representa a ação a ser executada   Define uma propriedade defaultAction nomeAplicacao/sample/first   Seu valor será a ação default
  • 22.
    Controle Controle Tem apenas 1 ação Possui uma ação chamada index class SampleController { class SampleController { def list = {} def list = {} def index = {} } } Controle com propriedade defaultAction Objetos implícitos no controle actionName •  Nome da ação que está sendo executada actionUri •  Uri relativa a ação em execução controllerName •  Nome do atual controle em execução class SampleController { controllerUri •  Uri do controle em execução def defaultAction = 'list' flash •  Objeto para acessar o escopo flash log •  Instância de org.apache.commons.logging.Log def list = {} params •  Mapa de parâmetros de requisição def index = {} request •  O objeto HttpServletRequest } response •  O objeto HttpServletResponse session •  O objeto HttpSession object servletContext •  O objeto ServletContext
  • 23.
    Escopos dos controles Escopos dos controle   request   Objetos colocados dentro de request estarão disponíveis durante a execução da requisição corrente   flash   Objetos colocados dentro de flash estarão disponíveis para a requisição atual e para a próxima   session   Objetos colocados no session serão mantidos até que a sessão do usuário seja invalidada, ou manualmente ou por expiração   servletContext   Objetos colocados no servletContext são compartilhados por toda a aplicação e mantidos durante todo o tempo de vida da aplicação Acessando parâmetros da Acessando parâmetros da requisição requisição   Via propriedade params do Grails def userName = params.userName log.info("User Name: ${userName}") Valores da página => parâmetros do request
  • 24.
    Redirect Redirecionando a requisição Redirecionando a requisição class SampleController { def first = { // redireciona para a acao “second” Todo controle tem redirect(action: "second") Às vezes é necessário acesso a um método } redirecionar o chamado redirect, controle para outra def second = { que recebe um mapa ação de controle // ... como argumento } } Redirecionando para outro controle Argumentos do redirect class SampleController { def first = { action controller id //redirecionar para a acao list de Loja •  O nome da ação •  O nome do controle •  Valor do parâmetro redirect(action: "list", controller: "Loja") para para id para ser enviado redirecionamento redirecionamento no redirecionamento } } params uri url •  Um mapa de •  Um endereço •  Um endereço parâmetros relativo para absoluto redirecionar
  • 25.
    Criando um modelo   Uma das atividades fundamentais do controle   Reunir dados para serem renderizados na visão   O controle pode realizar esta tarefa   Ou delegar para uma classe de serviço ou Informações que chegam às visões outros componentes O Model Criando um modelo Retornando dados   Quando o controle faz esta tarefa, os dados class MusicaController { são disponibilizados diretamente para as def show = { visões através de um mapa, o MODEL [ musica: Musica.get(params.id) ] }   O mapa é retornado pelas ações de um } controle   return é opcional   Como a última expressão avaliada pela ação foi um mapa, então o mapa é o valor retornado desta ação   O mapa pode ter qualquer quantidade de valores
  • 26.
    Renderizando E se eu quiser a Visão alterar a View de destino?   O controle MusicaController   Utilize o método render   1 método chamado show   Retorna um modelo contendo uma chave e um objeto class MusicaController { def show = { render(view:"exibir",   Onde está a referência para qual visão ele irá model:[musica: Musica.get(params.id)]) despachar o fluxo? } }   Por convenção   Por convenção   grails-app/views/musica/exibir.gsp   grails-app/views/musica/show.gsp Ligando dados da visão E para mudar o diretório? para o controle   Utilize um caminho absoluto class MusicaController { def show = { render(view:"/outrapasta/exibir", model:[musica: Musica.get(params.id)]) } }   grails-app/views/outrapasta/exibir.gsp
  • 27.
    Ligando dados Ligando dados primeira forma   Controles também precisam class AlbumController {   Criar novos objetos de domínio def save = {   Popular as propriedades destes objetos com def album = new Album() valores recebidos como parâmetros na requisição album.genero = params.genero album.titulo = params.titulo album.save() } } class AlbumController { def save = { def album = new Album(params) album.save() } }
  • 28.
    Alterando as propriedadescom DataBinding dataBinding de objetos múltiplos class AlbumController { def update= { def album = Album.get(params.id) album.properties = params def album = new Album( params["album"] ) def artist = new Artista( params["artista"] ) album.save() } } DataBinding e Associações 2 cenários na visão   Na classe de domínio   <input type="text" name="artista.name" />   Uma nova instância de artista é criada e atribuída class Album { à instância do Álbum Artista artista   <input type="text" ... name="artista.id" value="1" />, }   Recupera uma instância de um artista existente e   Na classe de controle atribui à classe do Álbum def album = new Album(params)
  • 29.
    Uma variação doscenários <input type="text” name="songs[0].title" value="The Bucket" /> <input type="text name="songs[1].title" value="Milk" /> <input type="text" name="songs[0].id" GORM value="23" /> Grails Object Relational Mapping <input type="text" name="songs[1].id" value="47" /> get() getAll() def album = Album.get(params.id) def album = Album.getAll(1,2,3)   Get recebe um id e retorna   Recebe   Ou a instância do objeto correspondente ao id   Vários identificadores   Ou null caso não exista   Retorna   Uma lista de instâncias
  • 30.
    read() list()   4 atributos max def album = Album.read(params.id)     Número máximo de instâncias a serem retornadas   offset   Recebe   Qual o 0 relativo da consulta   Um identificador   sort   Retorna   Nome da propriedade para utilizar no ORDER BY   Um objeto em estado somente leitura   order   Se a ordenação é ASC ou DESC Classe Album list() class Album {   def allAlbums = Album.list() String titulo   Recupera todos os albuns Date lancamento   def top10 = Album.list( max:10, sort:‘lancamentos', order:'desc') static hasMany = [musicas:Musica]   Retorna os 10 albuns mais recentes static belongsTo = [artista:Artista]   def totalAlbums = Album.count() }   Recupera o total de albuns
  • 31.
    Classe Album class Album { String titulo Date lancamento static hasMany = [musicas:Musica] static belongsTo = [artista:Artista] } save() listOrderBy*() Inserir uma nova instância def tudoPorLancamento = Album.listOrderByLancamento() def album = new Album(params) album.save() def tudoPorTitulo = Album.listOrderByTitulo()
  • 32.
    save() save() Alterar uma instância Variação def album = Album.get(1) album.titulo = “Titulo Alterado“ album.save(insert:true) album.save() delete() Excluir do banco album.delete()
  • 33.
    findBy findBy   Retorna uma única instância   Retorna uma única instância Album.findByTituloAndGenero( Album.findByTituloOrGenero( “RATM”, “Rock”) “RATM”, “Rock”) Mais findBy Mais findBy Album.findByLancamentoBetween(hoje-10,hoje) Album.findByGeneroIsNull() Album.findByTituloEquals(‘RATM') Album.findByGeneroIsNotNull() Album.findByLancamentoLessThan(ontem) Album.findByLancamentoGreaterThan(ontem) Album.findByLancamentoLessThanOrEqual(ontem) Album.findByLancamentoGreaterThanOrEqual(o ntem) Album.findByTituloLike(‘O tempo não%') Album.findByTituloInList([‘123', ‘Brasil']) Album.findByTituloNotEqual('Odelay")
  • 34.
    Métodos “primos” Criteria   findAllBy* def c = Album.createCriteria()   Retorna uma lista baseado nos parâmetros def results = c.list { eq('genero', 'Alternativo')   countBy* between(‘lancamento', new Date()-30, new   Retorna um inteiro com o total de instância que Date()) satisfazem a consulta }