在比较漫长的期待之后(期间经历了Grails被SpringSource收购和Groovy1.6助速的利好消息),Grails 1.1终于跟我们广大的Grailers见面了,正如Grails的Roadmap所描述,此次的发布新增不少的人性化的特性,闲话少说,让我们一起来对Grails 1.1的新特性,先睹为快,以下只是主要内容的摘录和简译,详细请参考原文:
http://www.grails.org/1.1+Release+Notes。
GORM--期待已久了:)
独立的GORM
GORM现在不再依赖Grails 1.1了,只需要带有命名空间的Spring配置来设置必要的Hibernate SessionFactory就好了:
<gorm:sessionFactory base-package="org.grails.samples"
data-source-ref="dataSource"
message-source-ref="messageSource">
<property name="hibernateProperties">
<util:map>
<entry key="hibernate.hbm2ddl.auto" value="update"/>
</util:map>
</property>
</gorm:sessionFactory>
上述示例将扫描"org.grails.samples"包,只要每个GORM实体被grails.persistence.Entity注释(annotation)就可以了:
@Entity
class Book {
String title
}
更多信息参考在GRAILS_HOME/samples/petclinic-mvcSpring MVC petclinic示例。
更好的GORM事件支持
在以前的版本中,GORM已经支持beforeInsert, beforeUpdate和beforeDelete事件了,现在相对应的afterInsert, afterUpdate and afterDelete也完全支持了。
持久化原生类型集合(Persistence of Collections of Basic Types)
现在,GORM通过关联表(join table)的方式支持原生类型集合的持久化,象String, Integer等集合:
class Person {
static hasMany = [nicknames:String]
}
持久化枚举类型集合
GORM提供对枚举类型集合的持久化:
enum VehicleStatus { OFF, IDLING, ACCELERATING, DECELARATING }
class Truck {
static hasMany = [statuses:VehicleStatus]
}
只读的对象实例
通过read方法,领域对象实例可以以只读的方式加载:
def book = Book.read(1)
缺省的排序
关联关系(Associations)可以在类级别中声明一个缺省的排序:
class Book {
String title
static mapping = {
sort "title"
}
}
或者在关联级别(association level):
class Author {
static hasMany = [books:Book]
static mapping = {
books sort:"title"
}
}
批量读取(Batch Fetching)
GORM支持在类级别中使用ORM DSL来配置批量读取(优化的延迟加载):
class Book {
String title
static mapping = {
batchSize 15
}
}
或者在关联级别(association level):
class Author {
static hasMany = [books:Book]
static mapping = {
books batchSize:15
}
}
更好的动态查找器(Dynamic Finders)
现有的动态查找器中新增了InList后缀:
def groovyBooks = Book.findByAuthorInList(['Dierk Koenig', 'Graeme Rocher'])
动态查找器还可以使用查询缓存:
def books = Book.findByTitle("Groovy in Action", [cache:true] )
并且还支持悲观锁(pessimistic lock):
def books = Book.findByTitle("Groovy in Action", [lock:true] )
支持遗留系统的单向一对多映射
单向的One-to-many关联可以通过joinTable参数来更改映射到基础数据库的方式:
class Book {
String title
static belongsTo = Author
static hasMany = [authors:Author]
static mapping = {
authors joinTable:[name:"mm_author_books", key:'mm_book_id' ] }
}
class Author {
String name static hasMany = [books:Book]
static mapping = { books joinTable:[name:"mm_author_books", key:'mm_author_id'] }
}
更好的枚举类型支持
枚举类型现在可以通过特定的getId()方法来确定要持久化的状态信息。这是除了枚举名称或者顺序值(Enum name or the ordinal value)之外的另外一种持久化的机制。
enum Country {
AUSTRIA('at'),
UNITED_STATES('us'),
GERMANY('de');
final String id
Country(String id) { this.id = id } }
插件(Plugins)--确实比以前便利了很多
全局插件
可以插件插件为所有应用所全局共享:
grails install-plugin webtest -global
多个插件仓库
现在,Grails支持配置多个插件存储仓库的能力,你只需要在USER_HOME/.grails/settings.groovy或者grails-app/conf/BuildConfig.groovy文件中包含要配置的仓库信息就可以了:
grails.plugin.repos.discovery.myRepository="http://svn.codehaus.org/grails/trunk/grails-test-plugin-repo"
grails.plugin.repos.distribution.myRepository="https://svn.codehaus.org/grails/trunk/grails-test-plugin-repo"
Grails发现插件的命令(plugin discovery commands)比如list-plugin和install-plugin将会自动的根据所配置的仓库去工作,要发布一个插件到特定的仓库,你可以用repository参数来指定特定的仓库:
grails release-plugin -repository=myRepository
自动的解决插件依赖传递(Automatic Transitive Plugin Resolution)
插件将不再需要检测SVN,在应用第一次加载的时候,会根据插件的元数据自动的被安装。
此外插件的依赖也将会通过类似传递来解决
插件的范围和环境(Plugin Scopes and Environments)
Plugins可以通过指定环境(environment)或者预定义的构建来标识范围:
def environments = ['dev', 'test']
def scopes = [excludes:'war']
插件就会只加载那些environments中定义的,并将不会被打包到WAR文件中,这样开发类插件("development-only" plugins)就不会被打包到产品中.使用而不再产品中.
插件资源的排除(Plugin Excludes)
你可以在插件中描述那些要排除的某些资源:
def pluginExcludes = [
'grails-app/controller/DemoController.groovy',
'grails-app/domain/DemoDomain.groovy'
]
这将在最后打包插件的时候,排除那些test/demo的资源很有用.
使用插件进行模块化应用开发(Modular Application Development with Plugins)
一个应用可以从任何地方进行加载,甚至都没有安装都可以,要达到如此,你只需要在你的BuildConfig.groovy 文件中指定位置即可:
// Useful to test plugins you are developing.
grails.plugin.location.jsecurity = "/home/dilbert/dev/plugins/grails-jsecurity"
// Useful for modular applications where all plugins and // applications are in the same directory. grails.plugin.location.'grails-ui' = "../grails-grails-ui"
这样做在以下两处地方有好处:
1. 你正在开发一个插件,但是想在真正的应用中测试,却又不想先打包再安装.
2. 你将一个应用拆分成一系列插件和一个应用,而且这些都在同样的"super-project" 目录中
测试
测试框架
新的
测试框架已经被集成到Grails 1.1了
测试框架增加了模仿所有通用类型比如controllers, domain class, tag libraries and url mappings,这样就可以更少更快的运行单元测试.
class SongTests extends grails.test.GrailsUnitTestCase {
void testMinimumDuration() {
mockDomain(Song)
def song = new Song(duration: 0)
assertFalse 'validation should have failed', song.validate()
assertEquals "min", song.errors.duration }
}
数据绑定(Data Binding)--更灵活了
绑定属性的一个子集
更简单的绑定属性子集,以前的语法是:
person.properties = params
这将请求参数中所有数据绑定到person中。如果你不期望这样的行为,你可以使用bindData,而现在你要帮定属性的子集,只需要使用下标操作符(subscript operator)就可以了:
person.properties["firstName","lastName"] = params
要访问领域类属性的子集也是同样的语法:
person.properties["firstName","lastName"].each { println it }
集合类型的帮定
Grails支持象lists, sets和maps集合类型的绑定.
<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />
Grails会根据指定的索引自动的初始化领域对象实例并且赋予相应的关联对象的值
脚手架(Scaffolding)
模板和动态脚手架
通过install-templates命令,可以安装模板,动态脚手架现在使用此模板来运行
支持更多的关联类型
脚手架支持多对多和单向的一对多关联关系
控制器(Controllers)--新特性还不错
更好的RESTful映射
你可以使用如下的REST URLs:
"/books"(resource:"book")
上述示例中URI "/books"将会自动的映射到BookController. 而HTTP的GET, PUT, POST 和DELETE 将会相应地被"show", "save", "update" and "delete"所处理.
处理重复的提交
通过同步令牌模式("Synchronizer Token Pattern"),Grails内建了对重复提交的处理。不过首先你要在form中声明一个令牌:
<g:form useToken="true">
然后通过withForm方法你可以检测出是重复的还是无效的请求:
withForm {
// good request
}.invalidToken {
// bad request
}
转发请求(Forwarding Requests)
作为重定向的一个替代,你可以通过forward方法来转发你的一个请求:
forward controller:"home", action:"index"
声明式的错误处理
你可以在你的UrlMappings文件中声明一个特定类型的异常处理:
"500"(controller:"errors", exception:IllegalArgumentException)
视图(Groovy Server Pages)--兼容性更好
在GSP中支持JSP的标签
GSP支持重用JSP的能力:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatNumber value="${10}" pattern=".00"/>
在GSP中也支持方法式的JSP标签调用 :
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
${fmt.formatNumber(value:10, pattern:".00")}
模板的命名空间(Template Namespace)
对于模板的使用来说,增加了一个特定的命名空间,因此一个如下所示的_tableRow.gsp模板:
<tr>
<td class="prop">${label}</td>
<td class="value">${value}</td>
</tr>
可以通过使用tmpl命名来调用:
<tmpl:tableRow label="one" value="two" />
服务器端的包含
新增了一个<g:include>标签在当前的视图中来引入另外一个controller, action 或者 view的响应:
<g:include controller="book" action="list"></g:include>
此标签也可以在 controller 或者 另外的tag library中使用:
def content = include(controller:"book", action:"list")
工程基础架构(Project Infrastructure)--更多更好的构建集成
maven集成
Grails 1.1 comes with an associated Maven plugin and archetype that allows you to build your Grails project easily using Maven. Follow the instructions here and either use the archetype to create a new Grails project, or run:
mvn grails:create-pom
to create a Maven POM for an existing project.
Ant + Ivy 集成
Grails now creates an Ant build.xml and corresponding ivy.xml file for each project allowing you to build a Grails project on any build server that supports Ant (like CruiseControl and Hudson) without needing Grails installed on the target server.
在BeanBuilder中支持Spring的命名空间
Grails' Spring DSL has been extended to include access to the Spring namespace APIs allowing you to easily use Spring advanced AOP support (among other things):
beans = {
xmlns aop:"http://www.springframework.org/schema/aop"
fred(Person) { name = "Fred" age = 45 } birthdayCardSenderAspect(BirthdayCardSender)
aop {
config("proxy-target-class":true) {
aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) {
after method:"onBirthday", pointcut: "execution(void ..Person.birthday()) and this(person)" } } } }
Environment and Metadata API
There is a new API to access the current Environment:
import grails.util.Environment
...
switch(Environment.current) { case Environment.DEVELOPMENT: configureForDevelopment() break case Environment.PRODUCTION: configureForProduction() break }
There is also a new class for easily accessing application meta-data:
def metadata = grails.util.Metadata.current
println metadata.applicationName
println metadata.applicationVersion
Log4j DSL
A new Log4j DSL is available that replaces the old way of configuring Log4j:
log4j = {
appenders {
rollingFile name: 'fileLog',
fileName: 'logs/full.log',
maxFileSize: 26214400,
maxBackupIndex: 10,
layout: pattern(conversionPattern: '%d{yyyy-MM-dd HH:mm:ss,SSS} %p %c{2} %m%n')
}
root {
error()
additivity = true
}
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages' // GSP
debug fileLog:'grails.app'
warn 'org.mortbay.log' }
Full documentation for the Log4j DSL is available in the user guide.
Flexible Build Configuration
A new grails-app/conf/BuildConfig.groovy file is available that allows you to configure different aspects of the Grails build including output paths and servers used for resolution of plugins:
grails.work.dir="/tmp/work"
grails.plugins.dir="/usr/local/grails/plugins"
grails.project.test.reports.dir="/usr/local/grails/test-reports"
Non-interactive mode
Grails now supports a --non-interactive flag at the command line that can be passed in order to disable any user prompts:
grails run-app --non-interactive
This is useful for continuous integration servers.
Encrypted Data Sources
DataSource passwords can now be encrypted using a supplied codec class:
dataSource {
username = "foo"
password = "438uodf9s872398783r"
passwordEncryptionCodec="my.company.encryption.BlowfishCodec"
}
The supplied codec uses Grails' existing codec mechanism
升级注意事项--有必要专门写个blog总结一下
Grails 1.1 has a number of changes, but should be mostly backwards compatible with 1.0.x series applications. If you have issues please report them. The following is a list of known issues that need to be considered when upgrading
* Plugins are now stored in your USER_HOME directory. You will need to re-install your plugins or run:
grails -Dgrails.project.plugins.dir =./plugins run-app
* Enums are now mapped onto the database with String values instead of ordinals by default
* jsession id is now disabled by default. See GRAILS-3364
* GSP whitespace handling has been changed for the better, you may have more whitespace than before. See GRAILS-3277
* The The grails.testing.reports.destDir config option has been replaced by grails.project.test.reports.dir
* PreInit.groovy is now BuildConfig.groovy
* The allowedMethods property in a controller should now be marked static. Non static version is deprecated but still works and will result in messages on the console.
8 楼 herowzz 2009-03-11 11:25
7 楼 sword721 2009-03-11 10:56
6 楼 tongyi121 2009-03-11 10:34
ruby on rails可以进入博物馆了
这个有点过了,比较ror现在还是比较流行的。gog想赶上,还有断不短的路要走。
5 楼 JohnnyJian 2009-03-11 10:30
ruby on rails可以进入博物馆了
说得好
4 楼 sword721 2009-03-11 10:22
3 楼 Arden 2009-03-11 10:14
2 楼 fcoffee 2009-03-11 09:31
1 楼 tongyi121 2009-03-11 09:09