<!DOCTYPE html>
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]-->
<!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!-->
<html lang="en" class="no-js"><!--<![endif]-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title><g:layoutTitle default="Grails"/></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="${assetPath(src: 'favicon.ico')}" type="image/x-icon">
<link rel="apple-touch-icon" href="${assetPath(src: 'apple-touch-icon.png')}">
<link rel="apple-touch-icon" sizes="114x114" href="${assetPath(src: 'apple-touch-icon-retina.png')}">
<asset:stylesheet src="application.css"/>
<asset:javascript src="application.js"/>
<g:layoutHead/>
</head>
<body>
<div id="grailsLogo" role="banner"><a href="http://grails.org"><asset:image src="grails_logo.png" alt="Grails"/></a></div>
<g:layoutBody/>
<div class="footer" role="contentinfo"></div>
<div id="spinner" class="spinner" style="display:none;"><g:message code="spinner.alt" default="Loading…"/></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>
<g:if env="development">Grails Runtime Exception</g:if><g:else>Error</g:else>
</title>
<meta name="layout" content="main">
<g:if env="development"><asset:stylesheet src="errors.css"/></g:if>
</head>
<body>
<g:if env="development">
<g:renderException exception="${exception}" />
</g:if>
<g:else>
<ul class="errors">
<li>An error has occurred</li>
</ul>
</g:else>
</body>
</html>
_footer.gsp
<div class="footer" role="contentinfo">
© 2015 Experto en Desarrollo de Aplicaciones Web con JavaEE y Javascript<br/>
Aplicación Todo creada por Francisco José García Rico (21.542.334F)
</div>
main.gsp
<g:layoutBody/>
<g:render template="/common/footer"/>
<div id="spinner"...
main.css
.footer {
background: #abbf78;
color: #000;
clear: both;
font-size: 0.8em;
margin-top: 1.5em;
padding: 1em;
min-height: 1em;
text-align:center;
}
main.gsp
<body>
<g:render template="/common/header"/>
<div id="grailsLogo" role="banner">
<a href="http://grails.org">
<img src="${resource(dir: 'images', file: 'grails_logo.png')}" alt="Grails"/>
</a>
</div>
<g:layoutBody/>
<g:render template="/common/footer"/>
...
_header.gsp
<div id="menu">
<nobr>
<g:if test="${isUserLoggedIn}">
<b>${userInstance?.name} ${userInstance?.surnames}</b> |
<g:link controller="user" action="logout">Logout</g:link>
</g:if>
<g:else>
<g:link controller="user" action="login">Login</g:link>
</g:else>
</nobr>
</div>
main.css
#header {
text-align:left;
margin: 0px;
padding: 0;
}
#header #menu{
float: right;
width: 240px;
text-align:right;
font-size:12px;
padding:4px;
}
<% now = new Date() %>
<%= now %>
<html>
<body>
<% [1,2,3,4].each { num -> %>
<p><%="Hello ${num}!" %></p>
<%}%>
</body>
</html>
<html>
<body>
<% if (params.hello == 'true')%>
<%="Hello!"%>
<% else %>
<%="Goodbye!"%>
</body>
</html>
<%@ page import="java.awt.*" %>
<%@ page contentType="text/json" %>
<html>
<body>
Hello ${params.name}
</body>
</html>
<g:if test="${userInstance?.type == 'admin'}">
<%-- mostrar funciones de administrador --%>
</g:if>
<g:else>
<%-- mostrar funciones básicas --%>
</g:else>
<g:set var="num" value="${1}" />
<g:while test="${num < 5 }">
<p>Number ${num++}
</g:while>
/*************************************/
<g:each in="${[1,2,3]}" var="num">
<p>Number ${num}</p>
</g:each>
/*************************************/
Stephen King's Books:
<g:findAll in="${books}" expr="it.author == 'Stephen King'">
<p>Title: ${it.title}
</g:findAll>
<g:set var="now" value="${new Date()}" />
/*************************************/
<g:set var="myHTML">
Some re-usable code on: ${new Date()}
</g:set>
/*************************************/
<g:set var="now" value="${new Date()}" scope="request" />
<g:link action="show" id="1">Book 1</g:link>
<g:link action="show" id="${currentBook.id}">${currentBook.name}</g:link>
<g:link controller="book">Book Home</g:link>
<g:link controller="book" action="list">Book List</g:link>
<g:link url="[action: 'list', controller: 'book']">Book List</g:link>
<g:link params="[sort: 'title', order: 'asc', author: currentBook.author]" action="list">
Book List
</g:link>
<g:form name="myForm" url="[controller:'book',action:'list']">...</g:form>
/*************************************/
<g:textField name="myField" value="${myValue}" />
/*************************************/
<g:actionSubmit value="Some update label" action="update" />
<g:render template="bookTemplate" model="[book: myBook]" />
/*************************************/
<g:render template="bookTemplate" var="book" collection="${bookList}" />
/*************************************/
<img src="<g:createLinkTo dir="images" file="logo.jpg" />" />
<g:eachError bean="${book}">
<li>${it}</li>
</g:eachError>
/*************************************/
<g:message code="my.message.code" />
grails create-tag-lib es.ua.expertojava.todo.Todo
TodoTagLib
package es.ua.expertojava.todo
class TodoTagLib {
static defaultEncodeAs = [taglib:'html']
//static encodeAsForTags = [tagName: [taglib:'html'], otherTagName: [taglib:'none']]
}
def includeJs = {attrs ->
out << ""
}
<g:includeJs script="miscript"/>
package es.ua.expertojava.todo
class TodoTagLib {
static defaultEncodeAs = [taglib:'html']
//static encodeAsForTags = [tagName: [taglib:'html'], otherTagName: [taglib:'none']]
static namespace = 'me'
def includeJs = {attrs ->
out << "<script src='scripts/${attrs['script']}.js'/>"
}
}
<me:includeJs script="miscript"/>
def renderImage = { attrs ->
println "Rendering the image ${attrs.image}"
asset.image(src:attrs.image)
}
def esAdmin = { attrs, body ->
def usuario = attrs['usuario']
if(usuario != null && usuario.tipo=="administrador") {
out << body()
}
}
<me:esAdmin usuario="${session.usuario}">
Dar de baja a usuario
</me:esAdmin>
def printLink = { attrs, body ->
def mkp = new groovy.xml.MarkupBuilder(out)
mkp.a(href:body(),body())
}
<me:printLink>http://www.google.com[]</me:printLink>
import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional
@Transactional(readOnly = true)
class TodoController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Todo.list(params), model:[todoInstanceCount: Todo.count()]
}
....
}
Salida en formato json
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X GET http://localhost:8080/todo/todo/index
Salida en formato xml
curl -v -H "Accept: text/xml" -H "Content-type: text/xml" -X GET http://localhost:8080/todo/todo/index
Salida en formato html si desde un navegador accedemos a:
http://localhost:8080/todo/todo/index
static defaultAction = "list"
def show(Todo todoInstance) {
respond todoInstance
}
Grails renderiza la vista grails-app/views/todo/show.gsp
...
if (todoInstance.hasErrors()) {
respond todoInstance.errors, view:'create'
return
}
...
Grails renderiza la vista grails-app/views/todo/create.gsp
<g:form url="[resource:todoInstance, action:'save']" >
<fieldset class="form">
<g:render template="form"/>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
Formulario procesado por el método save()
def create() {
respond new Todo(params)
}
<g:form url="[resource:todoInstance, action:'save']" >
<fieldset class="form">
<g:render template="form"/>
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
@Transactional
def save(Todo todoInstance) {
if (todoInstance == null) {
notFound()
return
}
if (todoInstance.hasErrors()) {
respond todoInstance.errors, view:'create'
return
}
todoInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'todo.label', default: 'Todo'), todoInstance.id])
redirect todoInstance
}
'*' { respond todoInstance, [status: CREATED] }
}
}
todoInstance.save flush:true
flash.message = message(code: 'default.created.message', args: [message(code: 'todo.label', default: 'Todo'), todoInstance.id])
redirect todoInstance
<g:if test="${flash.message}">
<div class="message" role="status">${flash.message}</div>
</g:if>
'*' { respond todoInstance, [status: CREATED] }
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d "{'title':'Hacer los ejercicios de Groovy','date_day':25,'date_month':3,'date_year':2015,'date':'date.struct'}" http://localhost:8080/todo/todo/save
curl -v -H "Accept: text/xml" -H "Content-type: application/json" -X POST -d "{'title':'Hacer los ejercicios de Grails','date_day':26,'date_month':3,'date_year':2015,'date':'date.struct'}" http://localhost:8080/todo/todo/save
render "Hello World!"
render {
10.times {
div(id: it, "Div ${it}")
}
}
render(view: 'show')
render(template: 'book_template', collection: Book.list())
render(text: "some xml ", contentType: "text/xml", encoding: "UTF-8")
//Redirección que se hace dentro del mismo controlador
redirect(action: login)
//Redirección que se hace a otro controlador
redirect(controller: 'home', action: 'index')
//Redirección a una uri explícitamente
redirect(uri: "/login.html")
//Redirección a una url absoluta
redirect(url: "http://grails.org")
//Redirección pasando parámetros
redirect(action: 'myaction', params: [myparam: "myvalue"])
class ExampleChainController {
def first() {
chain(action: second, model: [one: 1])
}
def second () {
chain(action: third, model: [two: 2])
}
def third() {
[three: 3])
}
}
Se termina el encadenamiento con el método third()
[one: 1, two: 2, three: 3]
Podemos acceder a los modelos dentro de una cadena con chainModel
class ChainController {
def nextInChain() {
def model = chainModel.myModel
…
}
}
package todo
class LogFilters {
def filters = {
all(controller:'*', action:'*') {
before = {
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
}
}
package todo
class LogFilters {
def filters = {
all(controller:'todo|category|tag', action:'create|edit|index|show') {
before = {
}
after = { Map model ->
println "Controlador ${controllerName} - Accion ${actionName} - Modelo ${model}"
}
afterView = { Exception e ->
}
}
}
}