- Web Layer
- Controller
class BookController {
static defaultAction = "list"
def index(){}
def list() {
// do controller logic create model
return model
}
}
- Controllers and Scope
- servletContext(instance of ServletContext) Also known as application scope, share state across the entire web application.
- session(HttpSession) - The session allows associating state with a given user and typically uses cookies to associate a session with a client.
- request(HttpServletRequest) - The request object allows the storage of objects for the current request only.
- params - Mutable map of incoming request query string or POST parameters
flash - make attributes available for this request and the next request only
def findBy = params["findBy"] def appContext = request["foo"] def loggedUser = session["logged_user"]
def findBy = params.findBy def appContext = request.foo def loggedUser = session.logged_user
flash.message = "User not found for id ${params.id}"
- Scoped Controllers - static scope = "singleton"
- prototype (default) - A new controller will be created for each request (recommended for actions as Closure properties)
- session - One controller is created for the scope of a user session
- singleton - Only one instance of the controller ever exists (recommended for actions as methods)
- In Config.groovy defines the default: grails.controllers.defaultScope = "singleton"
- Models and Views
- Returning a map:
def show() { [book: Book.get(params.id)] }
- Returning a ModelAndView
def index() {
// get some books just for the index page, perhaps your favorites
def favoriteBooks = ...
// forward to the list view to show them
return new ModelAndView("/book/list", [ bookList : favoriteBooks ])
}
- Selecting a view (uses a render method)
class BookController {
def show() {
def map = [book: Book.get(params.id)]
render(view: "display", model: map) //Render the view grails-app/views/book/display.gsp
or render(view: "/shared/display", model: map) // grails-app/views/shared/display.gsp.
}
}
// render a template to the response for the specified model
def theShining = new Book(title: 'The Shining', author: 'Stephen King')
render(template: "book", model: [book: theShining])
render Book.list(params) as JSON
- Redirects and Chaining
- redirect(controller: 'home', action: "next", params: params) // Also redirects to the index action in the home controller
- redirect(uri: "/login.html") // Redirect to an explicit URI
- redirect(url: "http://grails.org") // Redirect to a URL
- class ExampleChainController {
def first() { chain(action: second, model: [one: 1]) }
def second () { chain(action: third, model: [two: 2] , params: [myparam: "param1"]) }
def third() { [three: 3]) }
}
result: [one: 1, two: 2, three: 3]
- Controller Interceptors
def beforeInterceptor = { println "Tracing action ${actionUri}" }
or def beforeInterceptor = [action: this.&auth, except: 'login']
// defined with private scope, so it's not considered an action
private auth() {}
def login() { }
- Data Binding
def b = new Book(params) // params passed by form.
or p.properties['firstName','lastName'] = params
or bindData(p, params, [exclude: 'dateOfBirth'])
or def displayInvoice(String accountNumber, int accountType) //with params.accountNumber, and params.accountType
- XML and JSON
def results = Book.list()
render(contentType: "text/xml") { OR render(contentType: "text/json") {
books {
for (b in results) {
book(title: b.title)
}
}
OR def result = builder.build {
categories = ['a', 'b', 'c']
title = "Hello JSON"
}
- Upload
- def f = request.getFile('myFile')
- GSP (Groovy Server Page)
- Scopes
application - The javax.servlet.ServletContext instance
applicationContext The Spring ApplicationContext instance
flash - The flash object
grailsApplication - The GrailsApplication instance
out - The response writer for writing to the output stream
params - The params object for retrieving request parameters
request - The HttpServletRequest instance
response - The HttpServletResponse instance
session - The HttpSession instance
webRequest - The GrailsWebRequest instance
- GSP Tags
<g:example attr="${new Date()}" attr2="[one:1, two:2, three:3]">
Hello world
</g:example>
- Variables and Scope
<g:set var="now" value="${new Date()}" scope="request" />
- Logic and iteration
<g:if test="${session.role == 'admin'}">
<%-- show administrative functions --%>
</g:if>
<g:else>
<%-- show basic functions --%>
</g:else>
<g:each in="${[1,2,3]}" var="num">
<p>Number ${num}</p>
</g:each>
- Link and Resources
<g:link controller="book" action="list" id="${currentBook.id} >Book List</g:link>
<g:link url="[action: 'list', controller: 'book'] params="[sort: 'title', order: 'asc', author: currentBook.author]">Book List</g:link>
- Form
<g:form name="myForm" url="[controller:'book',action:'list']">...</g:form>
- Fields
textField - For input fields of type 'text'
passwordField - For input fields of type 'password'
checkBox - For input fields of type 'checkbox'
radio - For input fields of type 'radio'
hiddenField - For input fields of type 'hidden'
select - For dealing with HTML select boxes
<g:textField name="myField" value="${myValue}" />
- Submit
<g:actionSubmit value="Some update label" action="update" />
- Tags
<img src="<g:createLinkTo dir="images" file="logo.jpg" />" />
- Views and Template
<g:render template="bookTemplate" model="[book: myBook]" />
<g:render template="bookTemplate" var="book" collection="${bookList}" />
can be expressed as <tmpl:bookTemplate book="${myBook}" />
- Layout in siteMesh (a decorator enginer to support view layouts grails-app/views/layouts)
layoutTitle - outputs the target page's title
layoutHead - outputs the target page's head tag contents
layoutBody - outputs the target page's body tag contents
<html> <head>
<title><g:layoutTitle default="An example decorator" /></title>
<g:layoutHead />
</head> <body onload="${pageProperty(name:'body.onload')}">
<div class="menu"><!--my common menu goes here--></menu>
<div class="body">
<g:layoutBody />
</div>
</div>
</body>
</html>
- Server side include
<g:include controller="book" action="list" />
- Tag Lib
Just create a class in grails-app/taglib
ex: class SimpleTagLib {
def emoticon = { attrs, body ->
out << body() << (attrs.happy == 'true' ? " :-)" : " :-(")
}
}
in GSP: <g:emoticon happy="true">Hi John</g:emoticon>
ex 2: def dateFormat = { attrs, body ->
out << new java.text.SimpleDateFormat(attrs.format).format(attrs.date)
}
<g:dateFormat format="dd-MM-yyyy" date="${new Date()}" />
ex 3: def isAdmin = { attrs, body ->
def user = attrs.user
if (user && checkUserPrivs(user)) {
out << body()
}
}
<g:isAdmin user="${myUser}">
// some restricted content
</g:isAdmin>
- Tags Namespace : static namespace = "my" use: <my:example name="..." />
- JSP Tag Libs
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <fmt:formatNumber value="${10}" pattern=".00"/>
- URL Mapping in grails-app/conf/UrlMappings.groovy
- ex:
class UrlMappings {
static mappings = { }
}
- To Controller and Actions
"/product"(controller: "product", action: "list"). -> localhost:8080/project/product
- Variables
- "/product/$id?"(controller: "product") -> localhost:8080/project/product/MacBook // ? shows optional
- "/$blog/$year/$month/$day/$id"(controller: "blog", action: "show") -> localhost:8080/project/blogName/2013/10/30/IdValue
- "/$controller/$action?/$id?"() Dinamic Controller and action
- Mapping to views
- "/"(view: "/index") // map the root URL
- "403"(controller: "errors", action: "forbidden") or "403"(view: "/errors/forbidden") -> when there is a specific error.
- To HTTP Methods
- "/product/$id"(controller:"product") { action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"] }
- It is possible to impose constraints
- "/$blog/$year?/$month?/$day?/$id?" {
controller = "blog"
action = "show"
constraints {
year(matches:/\d{4}/) //obly to be 4 digits
month(matches:/\d{2}/)
day(matches:/\d{2}/)
}
}
- WebFlow (TO DO)
- Just adds "Flow" at the end of an action.
- Filters
- Just create a Class that ends with Filters in grails-app/conf directory.
all(controller: '*', action: '*') { //Every controller and every action
justBook(controller: 'book', action: '*') // all actions in controller book.
notBook(controller: 'book', invert: true) //every controlelr except BookController
- Types
- before
- after
- afterView
- AJAX
Must add previously int <head> <g:javascript library="jquery" />
- Remote link
- <div id="message"></div>
<div id="error"></div>
<g:remoteLink update="[success: 'message', failure: 'error']" action="delete" id="1">
Delete Book
</g:remoteLink>
- def delete() {
def b = Book.get(params.id)
b.delete()
render "Book ${b.id} was deleted"
}
- Remote Form Submission
<g:formRemote url="[controller: 'book', action: 'delete']" update="[success: 'message', failure: 'error']">
<input type="hidden" name="id" value="1" />
<input type="submit" value="Delete Book!" />
</g:formRemote >
OR
<form action="delete">
<input type="hidden" name="id" value="1" />
<g:submitToRemote action="delete" update="[success: 'message', failure: 'error']" />
</form>
- AJAX Events
- onSuccess - The JavaScript function to call if successful
- onFailure - The JavaScript function to call if the call failed
- on_ERROR_CODE - The JavaScript function to call to handle specified error codes (eg on404="alert('not found!')")
- onUninitialized - The JavaScript function to call the a Ajax engine failed to initialise
- onLoading - The JavaScript function to call when the remote function is loading the response
- onLoaded - The JavaScript function to call when the remote function is completed loading the response
- onComplete - The JavaScript function to call when the remote function is complete, including any updates
- Ajax on the Server
- Content Centric Ajax - Where you just use the HTML result of a remote call to update the page
gsp:
<g:remoteLink action="showBook" id="${book.id}"
update="book${book.id}">Update Book</g:remoteLink>
<div id="book${book.id}">
<!--existing book mark-up -->
</div>
groovy:
render(template: "bookTemplate", model: [book: b])
- Data Centric Ajax - Where you actually send an XML or JSON response from the server and programmatically update the page
gsp:
<g:javascript>
function updateBook(e) {
var book = eval("("+e.responseText+")") // evaluate the JSON
$("book" + book.id + "_title").innerHTML = book.title
}
<g:javascript>
<g:remoteLink action="test" update="foo" onSuccess="updateBook(e)">
Update Book
</g:remoteLink>
<g:set var="bookId">book${book.id}</g:set>
<div id="${bookId}">
<div id="${bookId}_title">The Stand</div>
</div>
groovy:
def b = Book.get(params.id)
render b as JSON
- Script Centric Ajax - Where the server sends down a stream of JavaScript to be evaluated on the fly
def b = Book.get(params.id)
response.contentType = "text/javascript"
String title = b.title.encodeAsJavascript()
render "$('book${b.id}_title')='${title}'"
- Validation
- Constraints
static constraints = { }
- Validating constraints
def user = new User(params)
if (user.validate()) -> else user.errors.allErrors.each { println it }
- Validating on the Client
- <g:renderErrors bean="${user}" />
or
- <g:hasErrors bean="${user}">
<ul>
<g:eachError var="err" bean="${user}">
<li>${err}</li>
</g:eachError>
</ul>
</g:hasErrors>
- Hilight Errors
<div class='value ${hasErrors(bean:user,field:'login','errors')}'>
<input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/>
</div>
Nenhum comentário:
Postar um comentário