这篇文章的重点是显著地更改 Grails 应用程序的外观。去年的 Trip Planner 的外观很怪异,恐怕只有开发人员才会喜欢(说句公道话,与外观相比,我对核心功能更感兴趣)。在本文中,通过使用一些 CSS 和局部模板进行调整,将得到一个外观新颖的 Grails 应用程序。在这个过程中,您还可以简单温习一下 Grails 特性,比如 scaffold、自动时间戳、修改默认模板、创建自定义 TagLib,以及调整关键配置文件(比如 Bootstrap.groovy 和 URLMapper.groovy)。
|
关于本系列
Grails 是一个现代的 Web 开发框架,它将熟悉的 Java 技术(比如 Spring 和 Hibernate)和最新的实践(比如约定优于配置)结合起来。Grails 是用 Groovy 编写的,它使您能够与遗留的 Java 代码无缝集成,同时又增加了脚本语言的灵活性和动态性。学习了 Grails 之后,您将对 Web 开发有新的看法。
|
|
在开始之前,必须安装 Grails 1.1。撰写本文时,它还是 beta 版。
安装 Grails 1.1
Grails 在 Java 1.5 或 1.6 上运行表现最佳。通过命令提示符输入 java -version
,确保 Java 版本是比较新的。
Java 1.5 或 1.6 就绪之后,安装 Grails 的步骤就很简单了:
- 从 Grails 站点 下载 grails.zip 文件。
- 解压缩 grails.zip。
- 创建一个
GRAILS_HOME
环境变量。
- 将 GRAILS_HOME/bin 添加到
PATH
。
如果您使用的应用程序是使用上一版本的 Grails 编写的,则可以输入 grails upgrade
将其迁移到最新的版本。但如果需要处理多个版本的 Grails,应该怎么办呢?
如果运行的是 UNIX®-esque OS(UNIX、Linux®,或 OS X)系统,通过将 $GRAILS_HOME
环境变量指向 symlink 就可以轻松处理 Grails 的多个版本。在我的系统上,将 GRAILS_HOME
指向 /opt/grails。这个步骤完成之后,通过快捷的 ln -s
就可以在各个版本之间切换,如清单 1 所示:
清单 1. 为 UNIX、Linux 或 Mac OS X 系统上的 $GRAILS_HOME
创建一个 symlink
在 Windows® 系统上,最好是直接更改 %GRAILS_HOME%
变量。在变更之后,不要忘记重新启动现有的命令提示符。
输入 grails -version
以确保使用了最新的版本,并且正确设置了 GRAILS_HOME
变量。现在,输入应该如清单 2 所示:
清单 2. grails -version
的输出结果
$ grails -version
Welcome to Grails 1.1-beta2 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /opt/grails
|
现在 Grails 1.1 已经安装完成,可以创建新的应用程序了。
创建应用程序
输入 grails create-app blogito
以生成初始的目录结构。转到新的 blogito 目录并输入 grails create-domain-class Entry
,以创建表示 blog 条目的类。在 grails-app/domain 找到 Entry.groovy,并添加清单 3 中的代码:
清单 3. 创建 Entry
类
每个 Entry
有一个 title
和 summary
字段。将 maxSize
限制范围设置为 1,000 个字符,这会导致动态地构造 HTML 表单,从而为 summary
字段提供文本区域(而不是简单的文本字段)。
|
下一篇文章:为 blog 条目添加内容
在下一篇文章中,将添加一个能够保存 blog 条目的实际内容的 body 字段。在本文中,我忽略了 body 字段,因为要完整地实现它,必须先理解 Grails 如何处理用户身份验证和文件上传。Blogito 允许终端用户上传各种类型的数据 — HTML、图像,甚至 MP3。
|
|
记住,dateCreated
和 lastUpdated
是 Grails 中比较神奇的字段名。这些时间戳字段非常适合 blog 应用程序 — 它们允许在列表的顶部保留最新的 Entry
。
在域类准备就绪之后,下一步就是创建一个控制器。输入 grails create-controller Entry
。将清单 4 中的代码添加到 grails-app/controllers/EntryController.groovy:
清单 4. 创建 EntryController
class EntryController {
def scaffold = Entry
}
|
表面上看起来很简单的 def scaffold = Entry
行指示 Grails 为 Entry
类构造其余的支持。您随后将获得一个条目表,其中 Entry
类中的每个字段都有一个列(以及一个主键 ID 字段和一个乐观锁定的版本字段)。您还获得完整的 Groovy 服务器页面(Groovy Server Pages,GSP),它们提供很普通但至关重要的 Create/Retrieve/Update/Delete (CRUD) 功能。
输入 grails run-app
并通过 Web 浏览器访问 http://localhost:8080/blogito。单击 EntryController,然后单击 New Entry。这样做的好处是所有 Entry
字段都出现在创建表单中(如图 1 所示)。但这也有不好的地方 — 用户不应该处理这些时间戳字段。您需要调整默认的模板来解决这个问题。
图 1. Create Entry 表单中可编辑的时间戳字段
调整默认模板
您可以输入 grails generate-views Entry
手动地从 GSP 文件中删除 dateCreated
和 lastUpdated
字段,但这不能从根本上解决问题。您可能希望这些字段永远不出现在创建和编辑表单中。最好是在 def scaffold
中更改模板。
输入 grails install-templates
。在 src/templates/scaffolding 中查找 create.gsp 和 edit.gsp。在每个文件中,将 dateCreated
和 lastUpdated
添加到 excludedProps
,如清单 5 所示:
清单 5. 从 list.gsp 和 show.gsp 模板中删除时间戳字段
excludedProps = ['version',
'id',
'dateCreated',
'lastUpdated',
Events.ONLOAD_EVENT,
Events.BEFORE_DELETE_EVENT,
Events.BEFORE_INSERT_EVENT,
Events.BEFORE_UPDATE_EVENT]
|
重启 Grails,确保时间戳字段不再出现(参见图 2):
图 2. 不包含时间戳字段的表单
更改排序的顺序
添加新条目时,默认情况下是根据 ID 对表进行排序的。blog 通常以逆时针顺序对条目进行排序 — 最新的排在前面。在以前版本的 Grails 中,要更改默认的排序顺序,则必须在 EntryController.groovy 中手动编辑列表闭包。在现有的代码行下面添加两个排序代码行并不困难(见清单 6)。问题是不能再从幕后动态构建这个代码(可以查找 src/templates/scaffolding/Controller.groovy 或输入 grails generate-controller Entry
查看默认的底层实现)。
清单 6. Grails 1.0.x 中的排序
def list = {
if(!params.max) params.max = 10
if(!params.sort) params.sort = "lastUpdated"
if(!params.order) params.order = "desc"
[ entryList: Entry.list( params ) ]
}
|
Grails 1.1 将一个很简单但极为有用的特性添加到静态映射块,即 sort
。将清单 7 中的映射块添加到 Entry.groovy。通过在域类中处理排序,您可以继续对控制器执行 def scaffold
操作。
清单 7. 将 sort
添加到 static mapping
块
class Entry {
static constraints = {
title()
summary(maxSize:1000)
dateCreated()
lastUpdated()
}
static mapping = {
sort "lastUpdated":"desc"
}
String title
String summary
Date dateCreated
Date lastUpdated
}
|
重启 Grails,确保编辑后的条目移动到列表的顶端,如图 3 所示:
图 3. 验证新的排序顺序
在开发模式下创建伪记录
每次重启 Grails 时将丢失现有的条目,您注意到了吗?记住,这是一个特性,而不是 bug。在每次启动 Grails 时将创建条目表,并且在关闭 Grails 时删除它们。打开 grails-app/conf/DataSource.groovy 验证这个特性。很明显,开发模式中的 db-create
值设置为 create-drop
。
可以将该值更改为 update
,但这也不是很理想。在开发过程的前期,模式是很不稳定的 — 您可以随时添加或删除字段,或修改限制条件等等。在所有东西稳定下来之前,我觉得最好将 db-create
设置为 create-drop
。
在开发模式中经常要重新输入样例数据,为了使这个操作没那么繁琐,可以为 grails-app/conf/BootStrap.groovy 添加一些逻辑。清单 8 中的代码在 Grails 每次启动时插入新的记录:
清单 8. 在开发模式中添加伪记录
再次重启 Grails。这一次,条目表中将出现现有的记录,如图 4 所示:
图 4. 在引导时出现的伪记录
改善列表的外观
列表视图中的默认 HTML 表对入门人员已经足够好,但对 Blogito 而言,这明显不是长期解决办法。blog 页面通常垂直地显示 date、title 和 summary 字段,而不是横向地显示(每次显示一个字段)。
为进行这种更改,输入 grails generate-views Entry
。前面动态构造的 GSP 文件现在应该出现在 grails-app/views/entry 中。在文本编辑器中打开 list.gsp。在头部将标题从 Entry List
更改为 Blogito
。删除 <h1>
和 <g:if>
块,然后用清单 9 中的代码代替现有的 <div class="list">
。
清单 9. 更改 list.gsp 视图
<div class="list">
<g:each in="${entryInstanceList}" status="i" var="entryInstance">
<div class="entry">
<span class="entry-date">${entryInstance.lastUpdated}</span>
<h2><g:link action="show" id="${entryInstance.id}">${entryInstance.title}</g:link></h2>
<p>${entryInstance.summary}</p>
</div>
</g:each>
</div>
|
注意,这些代码是经过大大简化的。可以删除 <fieldValue>
标记 — 它们帮助将域类绑定到 HTML 表单字段,但在这里没有实用价值。每个 Entry
都包含在一个指定的 <div>
中,而 lastUpdated
字段则包含在指定的 <span>
中。这些类属性连接到随后将构建的 CSS 格式中。title
和 summary
字段包含在普通的 HTML 头部和段落标记中。
|
CSS 101:<div> 和 <span>
当谈论 CSS 和其他与图像设计(而不是软件工程)关系更紧密的技术时,一些程序员就显得厌烦。但是我承认,当 CSS 变得复杂时,它可以是非常 复杂的。但反之亦然:当 CSS 比较简单时,它可以是非常简单的。
HTML 标记可以分为两大类:块和内联。块标记(比如 <h1> 、<p> 和 <div> )通常用于包含大的、杂乱的内容块。浏览器通常在每个块元素的末尾抛出一个隐式的新行。<h1> 和 <p> 有预定义的外观。我们通常将信息块包含在 <div> 标记中,以便为其命名和自定义样式。
内联元素(比如 <a> 、<strong> 和 <span> )通常用来包含一个或两个单词,而不是整个段落。内联元素的末尾没有添加隐式的新行。像块元素一样,像 <strong> 和 <em> 这样的内联元素有与之关联的默认格式,而 <span> 则必须通过 CSS 来应用格式。
对不熟悉的人而言,命名 <span> 和 <div> 元素的方式可能会造成混乱。需要在页面的多个元素上重用 class 属性。需要创建 CSS 类,比如 entry 和 entry-date ,以让具有相同类的所有元素同时出现。它们在样式表中显示时带有前导点:例如,.entry 和 .entry-date 。
您还可能碰到带有 id 属性的元素。id 在 HTML 文档中必须是惟一的。在本文的后面,将创建一个 <div id="header"> 。这意味着每页只能有一个 header 元素。id 在样式表中显示时带有一个前导 hash,比如在 #header 中。
要快速回顾 CSS 基础知识,请查看 参考资料。
|
|
在浏览器中刷新列表视图(见图 5)。这还不算是进步。但是添加一些新的 CSS 指令之后,它的外观将有很大的改善。
图 5. 没有使用 CSS 的新列表
将清单 10 中的 CSS 添加到 web-app/css/main.css 的底部:
清单 10. list.gsp 视图的 CSS 自定义
/* Blogito customizations */
.entry {
padding-bottom: 2em;
}
.entry-date {
color: #999;
}
|
再次刷新浏览器将看到更加好看的外观(见图 6)。现在还没有充分利用 CSS,但是已经拥有一个好的起点。
图 6. 带有 CSS 的新列表
创建 Date
TagLib
|
CSS 102:em 和 px
在浏览 main.css 时,就会看到许多字体的大小是用像素来表示的。从技术上讲,使用固定的大小(这很常见)是没有错误的,但这会影响使用。对于有视觉缺陷的用户和具有超大监视器(或超低分辨率)的机器而言,固定大小的字体都是不理想的。在 web 管理员的显示器上看起来很好的东西在其他地方显示时往往收不到这么好的效果 — 包括从电影屏幕到 iPhone 手机等众多显示屏上。
CSS 中的像素度量并不都是不好的 — 它们非常适合具有固定大小的元素,比如图像。但是总体而言,相对度量单元(比如 em)更适用于字体大小。1em 等效于由浏览器或周围父元素设置的默认字体大小的 100%。2em 是字体大小的 2 倍,依此类推。
参见 参考资料 获得更多信息。
|
|
现在,需要使 lastUpdated
日期外观更加友好。最好将可重用代码片段放在自定义 TagLib 中。输入 grails create-tag-lib Date
。将清单 11 中的代码添加到 grails-app/taglib/DateTagLib.groovy:
清单 11. 针对 DateTagLib
的代码
现在,将 lastUpdated
字段包含在 grails-app/views/entry/list.gsp 中刚才创建的 <g:longDate>
标记中,如清单 12 所示:
清单 12. 在 list.gsp 中使用 <g:longDate>
<div class="entry">
<span class="entry-date"><g:longDate>${entryInstance.lastUpdated}</g:longDate></span>
<h2>${entryInstance.title}</h2>
<p>${entryInstance.summary}</p>
</div>
|
重启 Grails 并刷新 Web 浏览器。您将看到日期的新格式,如图 7 所示:
图 7. 使用自定义 <g:longDate>
标记创建的新日期格式
创建局部模板
这个布局非常漂亮。我打算在 show.gsp 中重用它。在 grails-app/views/entry 中创建 _entry.gsp,并添加清单 13 中所示的代码(当然,可以从 list.gsp 剪切粘贴过来)。
清单 13. 针对 _entry.gsp 的代码
<div class="entry">
<span class="entry-date"><g:longDate>${entryInstance.lastUpdated}</g:longDate></span>
<h2><g:link action="show" id="${entryInstance.id}">${entryInstance.title}</g:link></h2>
<p>${entryInstance.summary}</p>
</div>
|
为了使用刚才创建的局部模板,需要像清单 14 那样调整 list.gsp:
清单 14. 在 list.gsp 中使用 _entry.gsp 局部模板
<div class="list">
<g:each in="${entryInstanceList}" status="i" var="entryInstance">
<g:render template="entry" bean="${entryInstance}" var="entryInstance" />
</g:each>
</div>
|
现在还可以在 list.gsp 中重用局部模板,如清单 15 所示:
清单 15. 在 show.gsp 中使用 _entry.gsp 局部模板
<div class="body">
<g:render template="entry" bean="${entryInstance}" var="entryInstance" />
<div class="buttons">
<!-- snip -->
</div>
</div>
|
在浏览器中刷新列表视图。它将和前面完全一样。现在单击条目的标题,确保它也适用于这个视图。
自定义头部
各个部分将协调地显示。现在需要用自己的标志来代替 Grails 标志。
我没有看到在 list.gsp 或 show.gsp 的其他地方引用了 Grails 徽标。记住,Grails 使用 SiteMesh 将最终页面的不同部分结合起来。查看 grails-app/views/layouts/main.gsp 就会看到包含 grails_logo.jpg 文件的位置。
在 grails-app/views/layouts 中创建另一个名为 _header.gsp 的局部模板。添加清单 16 中的代码。注意,Blogito 是一个链接到主页的超链接。
清单 16. 针对 _header.gsp 局部模板的代码
<div id="header">
<p><g:link class="header-main" controller="entry">Blogito</g:link></p>
<p class="header-sub">A tiny little blog</p>
</div>
|
现在像清单 17 那样编辑 main.gsp,以包含 _header.gsp 文件:
清单 17. 使用新 _header.gsp 局部模板的 Main.gsp
<body>
<div id="spinner" class="spinner" style="display:none;">
<img src="${createLinkTo(dir:'images',file:'spinner.gif')}" alt="Spinner" />
</div>
<g:render template="/layouts/header"/>
<g:layoutBody />
</body>
|
|
CSS 103:padding 和 margin
用于给块元素留出一些空间的 CSS 方框模型(box model)乍看起来有些迷惑。简单而言,padding 增加了块内的空间,而 margin 增加了块外的空间。
清单 18 的头部使用 padding 来增加文本和蓝色方框边缘之间的空间。它使用 margin 来增加蓝色方框外部的 header <div> 和 nav <div> 之间的空间。
可以将一个方框的四面设置为一致的 padding: 2em; 或 margin: 2em; 。要设置方框的某个边的空间,可以使用 margin-top 、margin-right 、margin-bottom 或 margin-left 直接引用它。如果想要通过一行代码为某条边(如清单 18 所示)设置不同的 padding ,TRBL(Top、Right、Bottom 和 Left 的缩写)将帮助您记住正确的顺序。这样,记忆四条边的顺序就很容易了。
参见 参考资料 获得更多关于 CSS 方框模型的信息。
|
|
最后,再为 web-app/css/main.css 添加一些代码,如清单 18 所示:
清单 18. _header.gsp 局部模板的 CSS 格式
#header {
background: #67c;
padding: 2em 1em 2em 1em;
margin-bottom: 1em;
}
a.header-main:link, a.header-main:visited {
color: #fff;
font-size: 3em;
font-weight: bold;
}
.header-sub {
color: #fff;
font-size: 1.25em;
font-style: italic;
}
|
刷新浏览器查看发生了什么变化(见图 8)。单击条目的标题,然后在头部单击 Blogito 导航到主页。
图 8. 展示新的头部
在登录之前隐藏导航栏
您还需要处理一个容易弄错的标志,它表示这是一个 Grails 应用程序:导航栏。尽管我们在下一篇文章中才进行身份验证,但是现在可以为未验证的用户关闭导航栏。这可以通过将 <div>
包含在简单的 <g:if>
测试来实现。这个测试查找存储在会话范围中的 user
变量。
像清单 19 那样修改 list.gsp 和 show.gsp:
清单 19. 在登录之前隐藏导航栏
在 show.gsp 中,在按钮 <div>
的周围添加相同的测试(您最不愿意看到的事情就是用户编辑未经验证或删除 blog 条目,不是吗?)。
最后,对 list.gsp 的外观进行调整。将 paginateButtons <div>
从 body <div>
移出,如清单 20 所示。这使导航栏能够横跨整个屏幕,从而在屏幕的底部添加一个漂亮的可视锚。
清单 20. 将 paginateButtons <div>
从 body <div>
移出,改善外观
再添加一些 CSS,如清单 21 所示,确保 paginateButtons <div>
出现在 body <div>
的底部,而不是旁边:
清单 21. 确保 paginateButtons <div>
出现在屏幕底部的 CSS
.paginateButtons{
clear: left;
}
|
最后一次刷新浏览器。您的屏幕应该如图 9 所示:
图 9. 隐藏导航栏
设置主页
现在,一切准备就绪了,此时应该将 EntryController
设置为默认主页。为此,需要添加一个将 /
(URL http://localhost:9090/blogito/ 中的尾部反斜杠)重新定向到 EntryController
的映射。根据清单 22 编辑 grails-app/conf/UrlMappings.groovy:
清单 22. 将 EntryController
设置为默认主页
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
"/"(controller:"entry")
"500"(view:'/error')
}
}
|
分享到:
相关推荐
本文内容包括:ShortenUrl插件简介创建TinyUrl类测试TinyUrl类创建IsGd类创建ShortenUrl服务打包并部署插件结束语下载参考资料在这个“精通Grails”系列中,ScottDavis将向您展示如何创建您自己的Grails插件。...
In Grails: A Quick-Start Guide, you’ll see how to use Grails by iteratively building an unique, working application. By the time we’re done, you’ll have built and deployed a real, functioning ...
Java web development is notoriously tedious, but help is on the way: Grails. Using the principle of convention-over-configuration and the dynamic Groovy programming language, Grails takes the pain out...
grails-petclinic, Grails的介绍性示例应用程序 Petclinic示例应用程序这是Grails标准的介绍性示例应用程序。 要开始使用它,只需克隆存储库,然后从本地副本运行中进行操作: ./gradlew run 在unix系统上,或者 ...
精通grails.rar
使用 Groovy on Rails (Grails) 构建的 Web 应用程序。 它使用Bootstrap为网页赋予样式,从而管理学生和课程的数据库,并以HTML呈现内容。 用户可以看到数据库中所有课程/用户的列表; 还有课程和用户的详细视图。...
精通Grails 之用 JSON 和Ajax 实现异步Grails。书中包含了全部代码。免费下载
是用于使用编程语言构建Web应用程序的框架。 核心框架是非常可扩展的,并且有许多可用的,可以轻松集成附加功能。 Grails由位于密苏里州圣路易斯的赞助。 请联系以获取支持查询。 入门 您需要安装Java开发工具包...
html格式 IBM 精通Grails系列讲解 Grails 是一种新型 Web 开发框架,它将常见的 Spring 和 Hibernate 等 Java 技术与当前流行的约定优于配置等实践相结合。...学习完 Grails 之后,您将彻底改变看待 Web 开发的方式。
您可以像这样启动应用程序: gradlew run 您可以像这样运行所有测试(Groovy和Javascript): gradlew test 如果您只想运行Jasmine(JavaScript)测试,请使用此命令 gradlew jasmineRun 以下将在监视模式下运行...
Grails入门好资料
MongoDB Grails插件主要作为称为“ mongo”的Spring bean公开给Grails应用程序。 然后,只需添加“ mongo”,Grails类就可以轻松地在整个代码中使用它。 支持依赖注入(域/控制器/服务)的类的属性,例如: class ...
详细讲解grails开发环境配置。 详细讲解grails连接mysql数据库,crud开发
使用GORM构建Spring Boot应用程序 Grails指南_ Grails框架.pdf
Elasticsearch Grails 插件 - 示例应用Elasticsearch Grails 插件的示例应用程序。 插件主页由 Noam Y. Tenne 维护并托管在 。为什么? 如果您习惯了 grails 但从未使用过 ,那么安装插件后您可能会有点迷茫。 ...
NULL 博文链接:https://358184482-qq-com.iteye.com/blog/379961
Grails Web 应用框架:grails-core
本教程介绍 Grails,这是一个搭建在动态语言 Groovy 之上的开源 MVC 快速 Web 开发框架。使用 Grails 可以提高 Web 开发的效率,降低 Web 开发的复杂度。本文 从 Grails 自动生成代码入手,以示例为中心逐步增加深度...