- 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