Grails 採 MVC 架構,視圖存放於 grails-app/views,採用 Groovy Server Pages (GSP) 作為預設表示技術。本文深入 GSP 特性、標籤庫、片段模板與腳手架客製化,並概覽替代視圖技術。
Grails 為標準 Java EE 應用,視圖層可自由替換:
web-app/js 即可使用但 GSP 以「HTML 上薄薄一層 Groovy」特性,提供最原生、可脫離框架的開發體驗。
<g:each in="${tripList}" status="i" var="trip">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
<td><g:link action="show" id="${trip.id}">${trip.id?.encodeAsHTML()}</g:link></td>
<td>${trip.airline?.encodeAsHTML()}</td>
<td>${trip.name?.encodeAsHTML()}</td>
<td>${trip.city?.encodeAsHTML()}</td>
<td>${trip.startDate?.encodeAsHTML()}</td>
<td>${trip.endDate?.encodeAsHTML()}</td>
</tr>
</g:each>
status 為計數器,var 命名當前項,?. 安全導航避免 NPE。
<div class="nav">
<span class="menuButton"><a class="home" href="${createLinkTo(dir: '')}">Home</a></span>
<span class="menuButton"><g:link class="create" action="create">New Trip</g:link></span>
</div>
支援屬性式(標籤體)與方法式(大括號)兩種呼叫風格。
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:paginate>:自動分頁導航<g:sortableColumn>:可排序欄位標題<g:form>/<g:submitButton>:表單與送出按鈕class DateTagLib {
def thisYear = { out << Calendar.getInstance().get(Calendar.YEAR) }
def copyright = { attrs, body ->
out << "<div id='copyright'>"
out << "© ${attrs['startYear']} - ${thisYear()}, ${body()}"
out << " All Rights Reserved.</div>"
}
}
使用:<g:copyright startYear="2002">FakeCo Inc.</g:copyright>
class DateTagLibTests extends GroovyTestCase {
def dateTagLib
void setUp() { dateTagLib = new DateTagLib() }
void testThisYear() {
def expected = Calendar.getInstance().get(Calendar.YEAR)
assertEquals("the years don't match", expected, dateTagLib.thisYear())
}
}
執行 grails test-app,HTML 報告產出於 test/reports/html/index.html。

class DateTagLib {
static namespace = 'trip'
// ...
}
使用:<trip:copyright startYear="2002">...</trip:copyright>
檔名以下劃線開頭(_footer.gsp),置於 grails-app/views 供全域共用:
<div id="footer">
<g:copyright startYear='2002'>FakeCo, Inc.</g:copyright>
<div id="powered-by">
<img src="${createLinkTo(dir:'images', file:'grails-powered.jpg')}"/>
</div>
</div>
引入:<g:render template="/footer" />(去掉底線,斜槓表相對 views 根目錄)。
grails install-templates 產生 src/templatesartifacts/(類別模板)、scaffolding/(視圖模板)、war/(web.xml)scaffolding/list.gsp 加入 <g:render template="/footer" />所有動態腳手架與 generate-views 產出的視圖將自動包含頁腳。
GSP 與 TagLib、片段模板構建了強大且可測試的視圖層。下一篇將聚焦 Ajax:以「微型」HTTP 請求打造 Google Maps 風格的動態體驗,並實作多對多關聯的 AJAX 化介面。