quinta-feira, 22 de agosto de 2013

About Grails

- Grails

    Framework Web dinâmico que proporciona alta produtividade e roda em qualquer servlet container Java
    Utiliza o princípio KISS ao máximo, tendo a simplicidade como meta principal, de forma a descartar complexidade desnecessária
    Grails é um framework web completo, desenvolvido com base em tecnologias maduras e bem estabelecidas
        Hibernate: mapeamento objeto relacional
        Spring: injeção de dependência
        Quartz: agendamento de tarefas
        SiteMesh: templates de tela
        JSP: construção de telas
    Plugins
        Arquitetura baseada em plugins permite estender qualquer parte do framework
        Repositório centralizado de plugins reúne atualmente mais de 700 plugins
        http://grails.org/plugins/
    MVC
        Uma aplicação Grails é segmentada em camadas de acordo com o paradigma MVC
        Modelo: GORM
        Visão: GSP
        Controle: Groovy
        Grails conta ainda com uma camada de serviços que pode ser usada para acomodar regras de negócio complexas
    Framework
        Grails se sobressai aos demais frameworks Java devido aos seguintes princípios utilizados para o seu desenvolvimento:
        Convention over Configuration (CoC)
        Tarefas simples devem ser simples de realizar,  tarefas avançadas devem ser possíveis
        Não reinventar a roda, mas aprimorar o que existe
    Camada Web
        A camada Web é composta por controladores e por páginas GSP
        Os controladores controlam o fluxo de navegação entre as páginas e promovem a integração da interface com as classes de domínio
        Controller
            class MainController {
                def index ={
                    def forums = ["Groovy", "Grails"]
                    [forums:forums]
                }
            }
        GSP
            <html>
                <head><title>Main</title></head>
                <body>Welcome to Groovy and Grails forum
                <div>
                  <ul>
                    <g:each in="${forums}" var="forum">
                      <li><g:link controller="viewForum"
                          params='[forumName:"${forum}"]'>
                         ${forum}</g:link></li>
                    </g:each>
                  </ul>
                </div>
                </body>
            </html>
        Camada de Domínio
            A camada de domínio representa as entidades de negócio do sistema
            As classes de domínio são desenvolvidas através de uma DSL (Domain Specific Language) disponível no GORM
            Seguindo as convenções do framework não é necessária nenhuma configuração adicional
            class Post {
                String message, subject
                Date date
            }

            class Topic extends Post {
                String subject
                static belongsTo = [forum: Forum]
                static hasMany = [posts: Post]
            }

            class Forum {
                String name, description
                Date lastPost
                Boolean flag
                static hasMany = [topics: Topic]
                static mapping = { table 'forums' }
                static constraints = { name(unique: true) }
                static transients = ['flag']
            }
           
            class User {
                String firstName
                String lastName
                String email
                static hasMany = [topics: Topic, posts: Post]
                Avatar avatar
                static constraints = {avatar(unique: true)}
                Address address
                static embedded = ['address'] //the address information will be inside the User Table.
            }

            class Address {
                String address1
                String address2
                int zip
                int phone
            }
        Scaffold
            Visão Geral
                Através de Scaffold é possível gerar código de forma estática ou dinâmica
                O código gerado de forma estática pode ser alterado, mas não é atualizado automaticamente com mudanças no domínio
                O código gerado dinâmicamente não pode ser alterado diretamente, mas é atualizado toda vez que ocorre modificações no domínio
       
            Dinâmico (runtime)
                O código da camada Web é gerado em memória em tempo de execução
                Utiliza templates para gerar código
                Código gerado em tempo de execução reflete as alterações nas classes de domínio usando reflexão e metaprogramação do groovy
                class SongController {
                    def scaffold = Song
                }
            Estático (template driven)
                Infraestrutura básica
                Templates (CoC) - Permite que faça customização da interface.
                Permite gerar código da camada Web (views e controllers) com base nas classes de domínio
                Para a geração de código são utilizados templates que podem ser customizados
                O código gerado não reflete alterações nas classes de domínio
                • grails generate-views: Generates views for the specified domain class
                • grails generate-controller: Generates a controller for the specified domain class
                • grails generate-all: Generates both a controller and associated views
        Templates
            É possível alterar os templates utilizados para geração de código
            Comando install-templates
                grails install-templates
            Os templates podem ser encontrados na pasta
                grails-app/src/templates/scaffolding

        Camada Web
            http://localhost:8080/Aplicacao/controle/acao
                -> //ControleController.groovy
                    class ControleController {
                        def acao = {
                            [par1: "Hello", par2: "World!"]
                        }
                    }
                    ->
                        <!-- acao.gsp -->
                        <!-- grails-app/views/controle -->
                        <html>
                        <body>
                            <p>${par1} ${par2}</p>
                        </body>
                        </html>
        Criação dos Controllers
            grails create-controller main
        Criando vários controllers
            grails create-controller main forum post
        Renderizando Conteúdo
            Método render
            Renderizando HTML
                def action = {
                    render "<h1>Welcome to Grails!</h1>"
                }

            Renderizando outro GSP
                 def action = {
                    render (view: "outroGsp", model: [par1: 'val'])
                }
            Parâmetros principais:
                text
                view
                template
                model

        Renderizando JSON                  
            Método render - contentType: "text/json"
            def action = {
                render (contentType: "text/json") {
                    forum {
                        post(subject: "Assunto", message: "Msg")
                    }
                }
            }
            //Saída: {forum: [{subject: "Assunto", message: "Msg"}]}
        Redirecionamento
            Método redirect - Redireciona através de nova request
            Parâmetros principais:
            uri/url
            controller
            action
            id
            fragment (#ancora)

            - Multiplas actions
                def defaultAction = "action"
                def index = {}
                def action = {
                    [date: new Date()]
                }
            - Encadeamento de Actions - Método chain
               
                def action1 = {
                    [par1: params.par1]
                }
                def action2 = {
                    chain(action: action1, model: [par1: 'val'])
                }
                def action3 = {
                    chain(action: action2, model: [par1: 'val'])
                }
        TagLib
            Tablibs padrões
                g:set
                g:if, g:else, g:elseif
                g:each, g:while, g:collect
                g:findAll, g:grep
                g:createLink, g:createLinkTo, g:link, g:javascript
                g:form, g:textField, g:checkBox, g:radio,     g:hiddenField, g:select, g:submitButton,     g:actionSubmit
            Usando TagLib no Controller
                Objeto ímplicito g no Controller
                def action = {
                    def date = g.formatDate(
                        format: "yyyy-MM-dd",
                        date: new Date())
                    [date: date]
                }
            Custom Tags
                Classe com nome terminado em TagLib
                Pasta grails-app/tagLib
                Comando
                    grails create-tag-lib editor
                Por convenção, utiliza namespace g
                Para utilizar outro namespace
                        static namespace = "custom"
                // TagLib
                class EditorTagLib {
                    def editor = { attrs, body ->
                        out << render (template: "/editor",
                                 model: [campoNome: attrs.campoNome,
                                         campoMsg: attrs.campoMsg])
                    }
                }

                <!-- Template -->
                Assunto: <g:textField name="${campoNome}"
                             value="${campoNome}"/>
                Topico: <g:textArea name="${campoMsg}"
                            value="${campoMsg}" />

                <!-- GSP -->
                <g:editor campoNome="form.assunto"
                              campoMsg="form.msg" />
        Objetos Ímplicitos
        Controllers e GSPs
            servletContext - global
            session
            request
            params
            flash
        Fazer o Binding automático
       
            //Controller
            class MeuController {
                def submit = {
        ----->        def form = new Form(params['form'])  <-------------
                }
            }
            class Form {
                String nome, descr
            }
            <!– GSP -->
            <html>
                <body>
                    <g:form action="submit">
                        Nome: <g:textField name="form.nome" />
                        Descricao: <g:textArea name="form.descr" />
                        <g:submitButton value="Enviar" />
                    </g:form>
                </body>
            </html>
        Templates
            Blocos de código reutilizáveis em páginas GSP
            Por convenção, o nome deve iniciar por _
            Exemplo: _mostrarTopicos.gsp
            Devem ficar na raiz das views ou na pasta do controller correspondente
            grails-app/views
            grails-app/views/controle
            Se ficar na raiz, deve ser referenciado com /  
            <!– _mostrarTopicos.gsp -->
            <g:link action="mostrarTopicos"
                    params="[forum: 'groovy',
                                subject: topico.assunto]">
                ${topico.assunto}
            </g:link>
            <br/>

            <!– index.gsp -->
            <g:render template="mostrarTopicos" var="topico"
                collection="${session.forum}" />
        Layouts
            GSP com estrutura para as páginas
            Pasta grails-app/views/layout
            Importa arquivos CSS e JavaScript
            Para aplicar um layout a um GSP inteiro:
            <meta name="layout" content="main" />
            Para aplicar a um trecho do GSP:
            <g:applyLayout name="portal">
                Conteúdo
            </g:applyLayout>
        Filtros
            Classe com nome terminado em Filters
            Pasta grails-app/conf
            // grails-app/conf/ForumFilters.groovy
            class ForumFilters {
                def filters = {
                    login(controller:'*', action:'*') {
                        before = {
                            if (!session.user) {
                                redirect(action:'login')
                                return false
                            }
                        }
                    }
                }
            }
        AJAX
            Dojo, Prototype, Scriptaculous, ...
            Funcionalidades padrões
            g:formRemote, g:remoteLink
            g:submitRemote, g:remoteFunction
            Eventos
            onSuccess, onFailure, onERROR, onComplete
            <!– Biblioteca JavaScript -->
            <head><g:javascript library="prototype"/><head>

            <!-- Form -->
            <div id='message' />
            <div id='error' />
            <g:formRemote name="myForm" url="[action:'submit']"
                update="[success: 'message', failure: 'error']">
                <!-- campos -->
            </g:formRemote>

            // Controller
            def submit = {
                // processar o form
                render "Operacao realizada com sucesso!"
            }
            RemoteFunction
                Cria uma função JavaScript que pode ser utilizada para acessar um método remoto
                Parâmetros:
                    controller
                    action
                    id
                    update
                Eventos:
                    onSuccess
                    onFailure
                    onERROR
                    onComplete
                // Controller
                class BookController {
                    def list = {
                        [books: Book.list(params)]
                    }
                    def show = {
                        [book: Book.get(params['id'])]
                    }
                    def bookByName = {
                        [book: Book.findByName(params.bookName)]
                    }
                }

                <!-- GSP -->
                $('mydiv').onclick =
                        <g:remoteFunction action="show" id="1" />
    Camada de Dominio
        Visão Geral
            GORM – Grails Object Relational Mapping
            Camada de abstração sobre o Hibernate
            Entidades de domínio ricas
            Banco em memória com HSQLDB
        Criando Classes de Domínio
            Comando create-domain-class
            Criando uma classe -> grails create-domain-class Forum
            Criando várias classes -> grails create-domain-class Forum Topic Post
        Constraint
            Blank, creditCard, Email, inList, matches, max, maxSize, Min, minSize, notEqual, nullable, range, scale, size, unique, url
        Transient
            static transientes = ['nameAndDescription']
        Relacionamentos
            One-to-one
                Unidirecional
                    Apenas referência no pai
                    class User {
                        Avatar avatar
                    }
                Bidirecional
                    Referências no pai e no filho
                    class Avatar {
                        User user
                    }
                Bidirecional com propagação
                    Referências em ambos e belongsTo no filho
                    class Avatar {
                        static belongsTo = [user: User]
                    }
                Composição - os elementos da tabela filha estão dentro da tabela pai.
                    class User{
                        Address address
                        static embebed = ['address']
                    }
                    class Address {
                    }
                   
            One-to-many
            Many-to-one
            Many-to-many
                Unidirecional ou Bidirecional
                class Forum {
                    static hasMany = [ topics: Topic]
                }
                class Topic {
                    static hasMany = [forums:Forum, posts:Post]
                    static belongsTo = Forum
                }
        Relacionamentos Bidirecionais
            Em relacionamentos unidirecionais apenas criações e alterações são propagadas
            Nos relacionamento bidirecionais, exclusão também é propagada
            ExempCamalo:
             class {
                static belongTo = [forum: Forum]
        Propagando Operações
            É possível alterar o comportamento padrão com as seguintes opções:
                create
                merge
                save-update
                delete
                delete-orphan
                lock
                all
            static mapping = {
                topics cascade: "all, delete-orphan"
            }
        Modo de Recuperação
            Todas as associações são lazy por padrão
            Attributo fetchMode
                static fetchMode = [topics:'eager']
            Mapping
                static mapping = {
                    topics lazy: false
                }
    Camada de Serviço
        Criação - Comando create-service
                grails create-service Authentication
            Pasta de serviços
                grails-app/services
        Escopos do Serviço
            singleton (padrão)
            prototype
            request
            session
        Transação - Atributo transactional
            Utilizando transação declarativa do Spring
                boolean transactional = true
    Configurações
        Visão Geral
            Quando não é possível seguir as convenções do framework, é necessário realizar configurações
            Todas as configurações são realizadas em arquivos groovy, na pasta grails-app/conf
            Configurações básicas:
                DataSources, log, dependências, plugins
        Log
            Grails utiliza o Log4j
            Toda configuração é realizada no arquivo grails-app/conf/Config.groovy
            É possível criar configurações específicas para cada ambiente:
            Teste, desenvolvimento, produção
        Empacotamento
            Comando war
                Desenvolvimento: grails dev war
                Produção: grails prod war
                grails war
                Descobrindo o ambiente programaticamente    println grails.util.GrailsUtil.environment
        Dependências
            É possível gerenciar as dependências externas do projeto através do próprio Grails
            As configurações necessárias ficam no arquivo grails-app/conf/BuildConfig.groovy
            Utilizando Apache Ivy, o Grails é capaz de obter dependências de repositórios Maven, Ivy ou do próprio Grails
            O cache local fica em ~/.ivy-cache
            Escopos possíveis para as dependências
                Build
                Compile
                Runtime
                Test
                Provided  
        Comando install-plugin
            Especificando a versão do plugin
                grails install-plugin dojo --version 1.6.1.4
            Arquivo que especifica os plugins utilizados
                application.properties
            Arquivos dos plugins
                ~/.grails/1.3.7/project/NomeProjeto/plugins
        Referenciando plugins sem instalar
            Plugins e projeto no mesmo diretório
            Arquivo grails-app/conf/BuildConfig.groovy
                grails.plugin.location.MenuBar = "../MenuBar"
        Comando create-plugin
            grails create-plugin MenuBar
            Estrutura identica a de um projeto normal
            Ao usar templates, utilizar o contexto de plugin
                render(template: "/menu", model: [separators:     attrs.separators], contextPath: pluginContextPath)

Nenhum comentário:

Postar um comentário