Jako, że grails jest frameworkiem mvc i opisałem model(klasy domenowe ), controller(kontrolery ), to najwyższa pora na view. Wpis oparty na książce Definitive guide to grails.
Dlaczego warto używać gsp:
- Aby wykorzystać zalety groovy, technologia widoku musi mieć wiedzę o groovy
- Lepszy język wyrażeń (GPath, przeciążone operatory)
- GString, wyrażenia regularne, operacje na listach i mapach
Atrybuty zasięgu takie jak w kontrolerach.
out – Writer w responsie
Gsp jest podobne do jsp i wiele obiektów z jsp jest dostępnych w gsp. GSP jest bardziej zwinny (agile) niż jsp.
Dyrektywy <%@ %>
<%@ page contentType="text/xml; charset=UTF-8" %>
Także importy w dyrektywach są rzadziej używane z racji tego groovy domyślnie importuje wiele pakietów.
Skryptlety <% %>, dla zgodności z jsp, należy używać tagów gsp.
Wyrażenia <%= %>
<%= "print me!" %> równoznaczne z <% out << "print me!" %>
Strony gsp można traktować jako jeden wielki GString.
<c:out value="${album.title}" />
i to samo w gsp
${album.title}
Strony gsp posiadają swoje własne wbudowane tagi, których nie trzeba importować. Przestrzenią nazw dla nich jest g. Można importować tagi jsp.
Wbudowane tagi gsp.
Tagi gsp są domknięciami.
Ustawienie wartości tagiem g:set
<g:set var="albumTitle" value="${album.title}" />
var to zmienna a value przypisana wartość. Można dodać scope dla zakresu, np
<g:set scope="session" var="user" value="${user}" />
Tagi z logiką<g:if>, <g:elseif> i <g:else> odpowiadają za sprawdzenie warunków. Tagi <g:if> i <g:elseif> posiadają atrybut test, który może być w języku wyrażeń (expression language) i w nim jest warunek.
<g:if test="${album?.year < 1980 && album?.genre == 'Rock'}">
Classic rock
</g:if>
<g:elseif test="${album?.year >= 1980 && album?.genre == 'Rock'}">
Modern Rock
</g:elseif>
<g:else>
Other
</g:else>
Konstrukcja album?.year zostanie wywołana wtedy gdy album jest różny od null. Null w stronach gsp jest wyświetlany jako pusty string.
Tagi iterujące
<g:each in="${album.songs?}">
<span class="tag">${it.title}</span>
</g:each>
Jeśli zostanie użyty ? w wyrażeniu to jeśli będzie null nie będzie iterowane. Można nadać nazwę zmiennej aby nie używać domyślnej nazwy – it. Dokonuje się tego poprzez var.
<g:while> jak pętla while
<g:set var="i" expr="${album.songs?.size()}" />
<g:while test="${i > 0}">
<g:set var="i" expr="${i-1}" />
</g:while>
odpowiednik tego w groovy to
while(i > 0) i=i-1
Dodatkowo tagi iterujące wspierają operacje na listach takie jak collect, findAll zapewniają obsługę GPath.
<ol>
<g:collect in="${albums}" expr="${it.title}">
<li>${it}</li>
</g:collect></ol>
jest równoznaczne z
<ol>
<g:each in="${albums.title}" >
<li>${it}</li>
</g:each></ol>
przykład z findAll
<g:findAll in="${albums}" expr="${it.songs?.title.contains('Love')}">
<li>
${it.title}</li>
</g:findAll>
Dynamiczne tagi
Można ich używać tak samo jak tagów wbudowanych dodatkowo mogą być wywołane jako metody w skryptletach lub wyrażeniach GString.
<!-- With a regular tag -->
<a href="<g:createLink action="list" />">A dynamic link</a>
<!-- As a method call -->
<a href="${createLink(action:'list')}">A dynamic link</a>
Ciało taga może być przekazane jako ostatni argument w metodzie
Tagi linkujące:
<g:link> linkuje do jakiś akcji, wspiera atrybuty
-controller – nazwa kontrolera
-action – nazwa akcji
-id – id doklejane do końca URI
-params – parametry przekazywane jako mapa.
Co najmniej jeden z atrybutów controller/action jest wymagany. Jeśli podany jest tylko controller bez action zostanie wywołana domyślna akcja danego kontrolera. Jeśli jest action bez kontrolera to zostanie wywołana akcja w obecnie wykonywanym kontrolerze. wspiera również wszystkie atrybuty htmlowego tagu anchor.
<g:link controller="album" action="list">List Albums</g:link>
<g:link action="show" id="1">Show album with id 1</g:link>
przykład z przekazaniem parametrów
<g:link controller="album"
action="list"
params="[max:10,order:'title']">pokazuje pierwsze 10 sortowane po tytule</g:link>
inne tagi linkujące to <g:createLink> podobne działanie jak tylko, że tworzony jest link a nie kotwica.
<g:createLinkTo> można linkować do zasobów w kontekście aplikacji. Najczęściej linkowanie do obrazków, arkuszy styli.
<link rel="stylesheet" href="${createLinkTo(dir:'css',file:'main.css')}"></link>
Formularze
<g:form action="register" name="registerForm">
</g:form>
<g:textField> równoznaczny z <input type=”text”>.
checkbox
<g:checkBox name="aBooleanValue" value="${true}" />
Radio są grupowane i muszą posiadać taką samą nazwę aby były połączone.
<g:radio name="myGroup" value="1" checked="${someValue == 1}" /> Radio 1
<g:radio name="myGroup" value="2" checked="${someValue == 2}" /> Radio 2
select
<g:select name="genre" from="${['Rock', 'Blues', 'Jazz']}"
value="${album.genre}" />
posiada 2 ciekawe atrybuty optionKey i optionValue co pokazuje przykład
<g:select name="album.id" from="${Album.list()}"
optionKey="id" optionValue="title"/>
jest równoznaczne z
<select name="album.id">
<option value="1">Undertow</option>
...
</select>
Podobne tagi to <g:currencySelect>, <g:localeSelect> i <g:timeZoneSelect>
daty
<g:datePicker name="myDate" value="${new Date()}" precision="day" />
gdzie precision określa precyzję daty. Bez tego atrybutu pokazywane jest ze szczegółowością co do sekundy. dataPicker jest instancją java.util.Date.
<g:hasErrors> czy są błędy atrybuty, które mogą się pojawić to bean, field, model.
<g:eachError> iterowanie po błędach.
Domyślne komunikaty dla błędów znajdują się w grails-app/i18n/message.properties
Można wyświetlać błędy jako listę.
<g:renderErrors bean="${album}" as="list" />
Stronicowanie odbywa się za pomocą tagu , domyślna ilość to 10 rekordów na stronę, obowiązkowym polem jest total, opis atrybutów tego tagu.
Szablony gsp (gsp templates) są specjalnym plikiem gsp zawierającym tylko kawałek strony, który może być wykorzystany na wielu stronach. W szablonach mogą pojawić się wszystkie rzeczy jak w zwykłych stronach gsp. Specyficzną cechą szablonów jest ich nazwa, która zaczyna się podkreśleniem(_). Przykładowa ścieżka to grails-app/views/album/_albumList.gsp
Aby dołączyć szablon do strony należy użyć tagu render z atrybutem template, podczas jego użycia znika z niego podkreślenie w nazwie
<g:render template="/album/albumList"/>
Aby przekazać dane do szablonu należy użyć atrybuty model, który jest mapą
<g:render template="/album/albumList"
model="[albums: top5Albums]"/>
Mapa jest zdefiniowana w akcji danego kontrolera
[top5Albums: Album.list(max:5, sort:"dateCreated", order:"desc")]
Tworzenia własnych tagów gsp.
Można podzielić na 3 kategorie:
- proste tagi (simple tags) – tagi posiadają atrybuty bez ciała
- tagi logiczne (logical tags) – ciało jest wykonywane pod pewnym warunkiem
- tagi iteracyjne (iterative tags) – ciało jest wykonywane conajmniej jeden raz
Tagi definiuje się w klasie, która kończy się TagLib i znajduje się w grails-app/taglib. Aby utworzyć taką klasę należy użyć polecenia grails create-taglib. Własne tagi (custom tags) pełnią role helperów dla widoku.
Tag jest domknięciem, które posiada 2 parametry: atrybuty tagu jako mapa i ciało jako domknięcie.
def repeat = { attrs, body ->
attrs.times?.toInteger().times { n ->
body(n)
}
}
a użycie tego to
<g:repeat times="3">
Hello number ${it}
</g:repeat>
Domyślną przestrzenią nazw dla własnych tagów jest g, można ustawić własną poprzez
static namespace = 'someNamespace'
Własne tagi można testować. Podstawowa klasa to grails.test.TagLibUnitTestCase