博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从零开始创建Grails应用
阅读量:5883 次
发布时间:2019-06-19

本文共 11027 字,大约阅读时间需要 36 分钟。

本篇文章主要介绍如何从零开始一步一步创建一个 Grails 应用程序。整个过程中,你将学到如何改变 Grails 运行的端口,了解 Grails 应用的基础组成部分(领域类、控制器和视图)、指定字段的缺省值,以及其他许多内容。

1. 安装

下载压缩包然后解压或者通过rpm、deb发行包安装。

这里,我在 mac 上安装 grails :

$ brew install grails

2. 创建应用

以 blog 为例,创建一个应用程序,在命令行输入 grails create-app blog 

$ grails create-app blog2014-9-9 10:43:29 org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule newModule警告: Module [groovy-all] - Unable to load extension class [org.codehaus.groovy.runtime.NioGroovyMethods]2014-9-9 10:43:29 org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule newModule| Created Grails Application at /Users/june/workspace/groovy/blog

这样,就创建了一个空的应用程序,进入到 blog 目录,输入 grails run-app :

$ cd blog$ grails run-app...2014-9-9 10:45:31 org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule newModule警告: Module [groovy-all] - Unable to load extension class [org.codehaus.groovy.runtime.NioGroovyMethods]| Server running. Browse to http://localhost:8080/blog

一切顺刟癿话,你应该可以在浏觅器中访问 http://localhost:8080/blog/ 并查看欢迎页面。

如果发现端口冲突,你可以:

  • 在启动时添加参数:grails -Dserver.port=9090 run-app
  • 在 grails-app/conf 目录修改 BuildConfig.groovy,添加 grails.server.port.http=9090  server.port=9090
  • 修改用户的默认设置。修改 ~/.grails/settings.groovy,添加 grails.server.port.http = 9000
  • 修改Grails程序的默认设置。在 $GRAILS_HOME/scripts/_GrailsSettings.groovy 中添加:serverPort = getPropertyValue("server.port", 9000).toInteger()

测试应用:

grails test-app

如果想部署应用:

grails war

上面命令默认使用的是 production 环境,也可以添加参数使用 dev 环境:

grails dev war

当部署应用时候,最后是设置 jvm 内存:

-server -Xmx512M -XX:MaxPermSize=256m

在 blog 目录查看应用目录结构:

$ blog  tree -L 2.├── application.properties├── grails-app│   ├── assets│   ├── conf			# 配置文件(如数据源、URL 映射、遗留的 Spring 和 Hibernate 配置文件)│   ├── controllers		# 控制器(MVC 中的“C”)│   ├── domain			# 领域类(MVC 中的模型或“M”。该目弽中 癿每个文件在数据库中都有对应癿表。)│   ├── i18n			# 国际化│   ├── migrations		# 迁移│   ├── services		# 服务类│   ├── taglib			# 自定义标签库│   ├── utils			# 工具│   └── views			# 视图├── grailsw├── grailsw.bat├── lib					# 存放第三方 jar├── scripts				# Gant 脚本├── src 				# 源代码文件│   ├── groovy│   └── java├── target│   ├── classes│   ├── stacktrace.log│   └── work├── test				# 单元测试│   ├── integration│   └── unit├── web-app				# web 资源文件│   ├── META-INF│   ├── WEB-INF│   ├── css│   ├── images│   └── js└── wrapper    ├── grails-wrapper-runtime-2.4.3.jar    ├── grails-wrapper.properties    └── springloaded-1.2.0.RELEASE.jar29 directories, 7 files

Grails 非常强调惯例优于配置(convention over configuration)。这意味着 Grails 并不是靠配置(configuration)文件来把应用各部分组织在一起,相反,它靠的是惯例 (convention)。所有领域类都存放在 domain 目录,控制器保存在 controllers 目录,视图则=放在 views 目录,等等。

3. 创建领域类

Grails 接受这些简单的类,并用它们完成许多工作。相应的数据库表会自劢为每个领域 类创建,控制器和视图会从关联的领域类中派生出相应的类。领域类还是存放验证规则、定义 “一对多”关系,以及包含其他许多信息的地方。

创建 User 领域类:

$ grails create-domain-class User...| Created file grails-app/domain/blog/User.groovy| Compiling 1 source files| Created file test/unit/blog/UserSpec.groovy

你会发现 Grails 同时创建了一个领域类和一个测试类,领域类中包名为 blog,其实,你也可以在创建领域类的时候自定义包名。

编辑 grails-app/domain/blog/User.groovy,添加一些属性:

class User {
String name Integer age String sex Date dateCreated Date lastUpdated static mapping = {
autoTimestamp false } static constraints = {
}}

以上只是添加了一些简单的属性,你还可以添加两个特殊的属性。如果你定义了一个名为 dateCreated 的日期字段,Grails 将自动在第一次向数据库保存实例的时候填上这个值。要是你创建了 另一个名为 lastUpdated 的日期字段,Grails 将在每次把更新后的记录存回数据库的时候填充这个日期。这个可以在 static mapping 代码块中来配置:

class User {
Date dateCreated Date lastUpdated static mapping = {
autoTimestamp false }}

另外,你也可以定义一些领域类的生命周期事件来做一些复杂的事情:

class User {
// ... def beforeInsert = {
// your code goes here } def beforeUpdate = {
// your code goes here } def beforeDelete = {
// your code goes here } def onLoad = {
// your code goes here }}

static mapping 还可以做一些其他事情,如制定列表排列顺序:

class User {	static mapping = {		sort "name" 	}	// ... }

关亍 static mapping 代码块更多的信息,请参见:。

4. 创建控制器和视图

在命令行下,输入 grails create-controller User

$ grails create-controller User| Compiling 1 source files| Created file grails-app/controllers/blog/UserController.groovy| Created file grails-app/views/user| Compiling 1 source files| Created file test/unit/blog/UserControllerSpec.groovy

查看 User 的控制器 grails-app/controllers/blog/UserController.groovy,你会发现没有多少内容 :

package blogclass UserController {
def index() {
}}

修改一下内容:

package blogclass UserController {
def index={
render "Hello World" }}

这时候启动应用,访问  你会看到 “Hello World”。

在控制器中定义的任何一个闭包都会暴露成一个 url。

重新修改控制器类代码如下:

package blogclass UserController {
def scaffold = User}

当 Grails 看到控制器中的 scaffold 属性,它会动态地产生针对指定领域类的控制器逻辑和必要的CRUD视图。所有这些只需要这一行代码。

进入  页面,你会发现表单字段排列顺序没有按照预想的情况排列,这时候可在 static constraints 代码块中指定表单顺序:

class User {
String name Integer age String sex Date dateCreated Date lastUpdated static mapping = {
autoTimestamp false sort "name" } static constraints = {
name() age() sex() dateCreated() lastUpdated() }}

当然,也可以增加一些约束条件:

class User {
String name Integer age String sex Date activeDate Date dateCreated Date lastUpdated static mapping = {
autoTimestamp false sort "name" } static constraints = {
name(blank:false, maxSize:50) age(min:0) sex(inList:["F", "M"]) activeDate() dateCreated() lastUpdated() }}

Grails 所有可用的验证选项:

  • blank、nullable
  • creditCard
  • display
  • email
  • password
  • inList
  • matches
  • min, max
  • minSize,maxSize,size
  • notEqual
  • range
  • scale
  • unique
  • url
  • validator

而校验失败的国际化消息保存在 grails-app/i18n 目录下的 messages.properties 文件里。

你可以通过 validator 来指定自定义的校验器,例如,startDate要大于当前时间:

static constraints = {
// ... activeDate(validator: {
return (it > new Date())}) // ...}

然后在 messages.properties 文件里添加一行:

user.activeDate.validator.invalid=Sorry, but the date is the past.

5. 对象关联映射

不管愿不愿意,我们都已经创建了领域类,从来没有操心过这些数据的保存和位置。之所以我们能够如此享福,这都得感谢 GORM。Grails 对象-关系映射(Grails Object-Relational Mapping)API 得以让我们放心地以对象方式去思考问题——而不至于陷入到关系数据库相关的 SQL 当中。

5.1 DataSource

GORM 缺醒设置在 grails-app/conf/DataSource.groovy:

dataSource {
pooled = true jmxExport = true driverClassName = "org.h2.Driver" username = "sa" password = ""}hibernate {
cache.use_second_level_cache = true cache.use_query_cache = false// cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory' // Hibernate 3 cache.region.factory_class = 'org.hibernate.cache.ehcache.EhCacheRegionFactory' // Hibernate 4 singleSession = true // configure OSIV singleSession mode flush.mode = 'manual' // OSIV session flush mode outside of transactional context}// environment specific settingsenvironments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', '' url = "jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE" } } test {
dataSource {
dbCreate = "update" url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE" } } production {
dataSource {
dbCreate = "update" url = "jdbc:h2:prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE" properties {
// See http://grails.org/doc/latest/guide/conf.html#dataSource for documentation jmxEnabled = true initialSize = 5 maxActive = 50 minIdle = 5 maxIdle = 25 maxWait = 10000 maxAge = 10 * 60000 timeBetweenEvictionRunsMillis = 5000 minEvictableIdleTimeMillis = 60000 validationQuery = "SELECT 1" validationQueryTimeout = 3 validationInterval = 15000 testOnBorrow = true testWhileIdle = true testOnReturn = false jdbcInterceptors = "ConnectionState" defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED } } }}

从上面可以看到,Grails 的环境分为三种模式:

  • development:开发模式
  • test:测试模式
  • production:生产模式

并且每种模式下的数据源配置有些许差异,如:dbCreate 值不一样, Grails 默认使用的是 H2内存数据库来保存数据,并三种模式下使用的 JDBC url(内存或者文件)不一样,等等。

如果在 DataSource 上设置dbCreate属性为”update”, “create” or “create-drop”, Grails 会为你自动生成/修改数据表格。

你也可以修改该文件,使用其他的数据库,从而清楚的看到 Grails 创建的表以及其中每一个字段。

dataSource {
pooled = true jmxExport = true driverClassName = "com.mysql.jdbc.Driver" username = "grails" password = "grails"}hibernate {
cache.use_second_level_cache = true cache.use_query_cache = false// cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory' // Hibernate 3 cache.region.factory_class = 'org.hibernate.cache.ehcache.EhCacheRegionFactory' // Hibernate 4 singleSession = true // configure OSIV singleSession mode flush.mode = 'manual' // OSIV session flush mode outside of transactional context}// environment specific settingsenvironments {
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', '' url = "jdbc:mysql://localhost:3306/grails?autoreconnect=true" } } test {
dataSource {
dbCreate = "update" url = "jdbc:mysql://localhost:3306/grails?autoreconnect=true" } } production {
dataSource {
dbCreate = "update" url = "jdbc:mysql://localhost:3306/grails?autoreconnect=true" } }}

当然,你还需要在 mysql 中创建 grails 用户和 grails 数据库,并将 mysql 的 jdbc 驱动拷贝到 lib 目录下。

然后,启动应用观察日志中是否有报错。

5.2 One-to-many

创建 Blog 领域类,并设置 User 和 Blog 的 一对多 的关系。

先创建 Blog 领域类:

$ grails create-domain-class Blog

然后修改 User 领域类:

class User {
// ... static hasMany = [blogs:Blog] }

上述代码创建了一个名为 blogs 的新字段,类型是 java.util.Set。如果有多个关系,可以用逗号分隔。

Grails中默认使用的fetch策略是 “lazy”, 意思就是集合将被延迟初始化。 如果你不小心,这会导致  问题 。 如果需要”eager” 抓取 ,需要使用  或者指定立即抓取作为query的一部分

默认的级联行为是级联保存和更新,但不删除,除非 belongsTo 被指定:

class Blog {
// ... static belongsTo = [user:User] }

这不仅形成了闭环,它还强制了级联更新和删除。

如果在one-to-many的多方拥有2个同类型的属性,必须使用mappedBy 指定哪个集合被映射:

class User {
static hasMany = [blogs:Blog] static mappedBy = [blogs:"users1"]}class Blog {
User users1 User users2}

如果多方拥有多个集合被映射到不同的属性,也是一样的:

class User {
static hasMany = [blogs1:Blog, blogs2:Blog] static mappedBy = [blogs1:"users1", blogs2:"users2"]}class Blog {
User users1 User users2}

另外,为了代码的可读性,我们可以修改领域类的 toString() 方法:

class User {
// ... String toString(){
return "${name}, ${activeDate.format('MM/dd/yyyy')}" }}

5.3 Many-to-many

Grails 支持 many-to-many 关联,通过在关联双方定义 hasMany ,并在关联拥有方定义 belongsTo :

class Book {
static belongsTo = Author static hasMany = [authors:Author] String title}class Author {
static hasMany = [books:Book] String name}

Grails 在数据库层使用一个连接表来映射 many-to-many,在这种情况下,Author 负责持久化关联,并且是唯一可以级联保存另一端的一方 。

5.4 数据初始化

在 grails-app/conf 目录下有一个文件叫做 BootStrap.groovy,可以用来做一些初始化的工作:

class BootStrap {
def init = {
servletContext -> } def destroy = {} }

init 闭包会每次在 Grails 启动时被调用; destroy 闭包会每次在 Grails 停止时被调用。

转载地址:http://hwtix.baihongyu.com/

你可能感兴趣的文章
[转载] Live Writer 配置写 CSDN、BlogBus、cnBlogs、163、sina 博客
查看>>
2013年SEO集群最新优化工具
查看>>
SQL:连表查询
查看>>
MySQL日期函数、时间函数总结(MySQL 5.X)
查看>>
c语言用尾插法新建链表和输出建好的链表
查看>>
Java基础学习总结(1)——equals方法
查看>>
高性能 Oracle JDBC 编程
查看>>
java 中ResultSet可以获取的数据类型及返回值类型列表
查看>>
ubuntu 13 安装SH程序
查看>>
支付宝升级延时到账功能
查看>>
ghost后只剩下一个盘的数据寻回方法
查看>>
输入输出练习
查看>>
Git commit message和工作流规范
查看>>
java面试。答案源于网上
查看>>
yii中取得CActiveDataProvider的分页信息
查看>>
我的大学
查看>>
Google翻译接口收费啦
查看>>
Debian+Apache2服务器
查看>>
MySQL库和表的操作
查看>>
shell编程:编译器、解释器 变量
查看>>