(Quick Reference)

1 简介 - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

1 简介

如今的Java Web开发对于需求来说已经变得过于复杂。当今众多Java领域的Web开发框架不仅使用复杂,而且并没有很好的遵循Don't Repeat Yourself(DRY)原则。

像Rails,Django和TurboGears这样的动态框架在Web开发领域开辟了一条新的道路,Grails基于这些概念之上,采用动态方法减小了Java平台上进行Web开发的复杂度,不过与那些框架不同的是,Grails是构建在Spring和Hibernate等Java已有的技术之上的。

Grails是一个full-stack框架,它借助于核心技术与相关的插件(plug-in)来解决Web开发中方方面面的问题,其中包括:

  • 易于使用的基于Hibernate的对象-关系映射(ORM)层
  • 称为Groovy Server Pages (GSP)的表现层技术
  • 基于Spring MVC的控制器层
  • 构建于Gant 上的命令行脚本运行环境
  • 内置Tomcat
  • 利用内置的Spring 容器实现依赖注入
  • 基于Spring的MessageSource核心概念,提供了对国际化(i18n)的支持
  • 基于Spring事务抽象概念,实现事务服务层

借助于功能强大的Groovy动态语言和领域特定语言(Domain Specific Language,DSL),以上那些特性变得非常易用。

这篇文档会向你介绍如何使用Grails框架来搭建Web应用程序。

Java web development as it stands today is dramatically more complicated than it needs to be. Most modern web frameworks in the Java space are over complicated and don't embrace the Don't Repeat Yourself (DRY) principles.

Dynamic frameworks like Rails, Django and TurboGears helped pave the way to a more modern way of thinking about web applications. Grails builds on these concepts and dramatically reduces the complexity of building web applications on the Java platform. What makes it different, however, is that it does so by building on already established Java technologies like Spring and Hibernate.

Grails is a full stack framework and attempts to solve as many pieces of the web development puzzle through the core technology and its associated plugins. Included out the box are things like:

  • An easy to use Object Relational Mapping (ORM) layer built on Hibernate
  • An expressive view technology called Groovy Server Pages (GSP)
  • A controller layer built on Spring MVC
  • A command line scripting environment built on the Groovy-powered Gant
  • An embedded Tomcat container which is configured for on the fly reloading
  • Dependency injection with the inbuilt Spring container
  • Support for internationalization (i18n) built on Spring's core MessageSource concept
  • A transactional service layer built on Spring's transaction abstraction

All of these are made easy to use through the power of the Groovy language and the extensive use of Domain Specific Languages​​ (DSLs)

This documentation will take you through getting started with Grails and building web applications with the Grails framework.

1.1 Grails 2.0有那些新特性?

This section covers the new features that are present in 2.0 and is broken down into sections covering the build system, core APIs, the web tier, persistence enhancements and improvements in testing. Note there are many more small enhancements and improvements, these sections just cover some of the highlights.

在本章节中,主要涉及当前2.0中的新特性,这些又被细分为系统构建、核心API、WEB层、持久层的增强以及在测试方面的改进。值得一提的是,虽然还有其他更多少范围的增强和改进,但在本章后续的章节中只会将其中的一些亮点进行介绍。

1.1.1 面向开发的特性

Interactive Mode and Console Enhancements

Grails 2.0 features brand new console output that is more concise and user friendly to consume. An example of the new output when running tests can be seen below:

In general Grails makes its best effort to display update information on a single line and only present the information that is crucial. This means that while in previous versions of Grails the war command produced many lines of output, in Grails 2.0 only 1 line of output is produced:

In addition simply typing 'grails' at the command line activates the new interactive mode which features TAB completion, command history and keeps the JVM running to ensure commands execute much quicker than otherwise

For more information on the new features of the console refer to the section of the user guide that covers the console and interactive mode.

交互模式和命令行的增强

Grails 2.0中新的命令行输出将更加简洁和友好,以执行测试为例,新的输出如下图所示:

总的来说,Grails尽量在一行中显示所有相关的更新信息,并且仅仅显示当前最重要的信息,换句话说,以前版本的war命令将产生很多行的输出,但是在2.0中,只有如下图所示的一行输出。

此外如果只是简单的输入'grails'命令,系统将进入新的带TAB补全和纪录命令历史的交互模式。在此模式下,JVM一直保持运行,这样就可以保证命令的执行可以比其他情况快速。新的交互模式如下图所示:

更多命令行新特性请参考本用户手册的命令行和交互模式章节。

Reloading Agent

Grails 2.0 reloading mechanism no longer uses class loaders, but instead uses a JVM agent to reload changes to class files. This results in greatly improved reliability when reloading changes and also ensures that the class files stored in disk remain consistent with the class files loaded in memory, which reduces the need to run the clean command.

重新加载代理

Grails 2.0的重新加载机制不再使用用户的类加载器(Class Loaders),而是使用JVM代理来重新加载那些改变过的类.这样一来,既能提高系统的稳定性,也可以保证磁盘和内存中的类的一致性,从而可以减少执行clean的次数。

New Test Report and Documentation Templates

There are new templates for displaying test results that are clearer and more user friendly than the previous reports:

In addition, the Grails documentation engine has received a facelift with a new template for presenting Grails application and plugin documentation:

See the section on the documentation engine for more usage info.

全新的测试报告和文档模板

相比以前的测试报告,现在的测试结果显示更加简洁清晰和友好,新的报告截图如下:

除此之外,Grails的文档引擎也采用了全新的模板来展现其插件和应用的文档,如下图所示:

更多信息请参考文档引擎章节。

Use a TOC for Project Docs

The old documentation engine relied on you putting section numbers into the gdoc filenames. Although convenient, this effectively made it difficult to restructure your user guide by inserting new chapters and sections. In addition, any such restructuring or renaming of section titles resulted in breaking changes to the URLs.

You can now use logical names for your gdoc files and define the structure and section titles in a YAML table-of-contents file, as described in the section on the documentation engine. The logical names appear in the URLs, so as long as you don't change those, your URLs will always remain the same no matter how much restructuring or changing of titles you do.

Grails 2.0 even provides a migrate-docs command to aid you in migrating existing gdoc user guides.

在项目文档中使用目录索引(TOC-Table Of Contents)

旧有的文档引擎将章节号写死在gdoc文件中,此举虽然便利,但是会导致在新增章节的时候很难重新构造你的用户手册,而且任何章节标题的改动,将会导致此章节的URL失效.(在处理多国语言的时候尤其不便-译者注)

现在,你可以将结构和章节的标题的逻辑名称定义在YAML目录索引(TOC,在文档引擎有更多描述)文件中,这样在你的gdoc文件中只需使用相应的逻辑名称即可。如此一来,不管你改了结构或者标题,只要你在URL中的逻辑名称没有改变,那么你URL将不会受任何影响。

对已有的gdoc用户手册,Grails 2.0还提供了migrate-docs命令来帮助你进行迁移。

Enhanced Error Reporting and Diagnosis

Error reporting and problem diagnosis has been greatly improved with a new errors view that analyses stack traces and recursively displays problem areas in your code:

In addition stack trace filtering has been further enhanced to display only relevant trace information:

Line | Method
->>   9 | getValue     in Book.groovy
- - - - - - - - - - - - - - - - - - - - - - - - -
|     7 | getBookValue in BookService.groovy
|   886 | runTask . .  in ThreadPoolExecutor.java
|   908 | run          in     ''
^   662 | run . . . .  in Thread.java

错误报告和诊断的增强

错误报告和问题诊断现在得到了极大的提高,在新的错误视图中,系统分析堆栈的异常,并且在你的代码中递归的显示问题区域。如下图所示:

此外,加强的异常堆栈跟踪过滤,只显示相关的异常跟踪信息,如下边代码所示:

Line | Method
->>   9 | getValue     in Book.groovy
- - - - - - - - - - - - - - - - - - - - - - - - -
|     7 | getBookValue in BookService.groovy
|   886 | runTask . .  in ThreadPoolExecutor.java
|   908 | run          in     ''
^   662 | run . . . .  in Thread.java

H2 Database and Console

Grails 2.0 now uses the H2 database instead of HSQLDB, and enables the H2 database console in development mode (at the URI /dbconsole) so that the in-memory database can be easily queried from the browser:

H2数据库及其管理界面

在Grails 2.0中,已经舍弃了HSQLDB,取而代之的是H2数据库,并且在开发模式下,还增加了数据库管理界面(通过URI /dbconsole访问),这样即使数据库在内存模式下,也可以通过浏览器来查询,管理界面如下:

Plugin Usage Tracking

To enhance community awareness of the most popular plugins an opt-in plugin usage tracking system has been included where users can participate in providing feedback to the plugin community on which plugins are most popular.

This will help drive the roadmap and increase support of key plugins while reducing the need to support older or less popular plugins thus helping plugin development teams focus their efforts.

跟踪插件的使用情况

为了增强社区对最受欢迎插件的意识,一种称之为“单向确认(opt-in)”的跟踪插件使用情况系统被引入,这样用户可以将那些是最受欢迎的插件反馈给插件社区。

这有助于推动系统的线路图和增加对重要插件的支持,同时对那些陈旧或者不受欢迎的减插件少不必要的支持,从而帮助插件开发团队做更多有意义的事情。

Dependency Resolution Improvements

There are numerous improvements to dependency resolution handling via Ivy including:

  • Grails now makes a best effort to cache the previous resolve and avoid resolving again unless you change BuildConfig.groovy.
  • Plugins dependencies now appear in the dependency report generated by grails dependency-report
  • Plugins published with the release plugin now publish their transitive plugin dependencies in the generated POM which are later resolved.
  • It is now possible to customize the ivy cache directory via BuildConfig.groovy

grails.project.dependency.resolution = {
    cacheDir "target/ivy-cache"
}
  • You can change the ivy cache directory for all projects via settings.groovy

grails.dependency.cache.dir = "${userHome}/.ivy2/cache"
  • It is now possible to completely disable resolution from inherited repositories (repositories defined by other plugins):

grails.project.dependency.resolution = {

repositories { inherits false // Whether to inherit repository definitions from plugins … } … }

  • It is now possible to easily disable checksum validation errors:

grails.project.dependency.resolution = {
    checksums false // whether to verify checksums or not
}

依赖解决方案的增强

在解决依赖问题方面,因为Ivy的协助,有了大量的改进:

  • 在不改变BuildConfig.groovy的前提下,Grails将尽量使用以前的缓存,从而避免了再解析检查。
  • 通过grails dependency-report,现在可以生成插件的依赖关系报告。
  • 通过release plugin发布的插件现在可以将其依赖关系的传递性生成在POM中,以备后用。
  • 通过BuildConfig.groovy,现在可以自定义ivy的缓存目录了,代码如下:

grails.project.dependency.resolution = {
    cacheDir "target/ivy-cache"
}
  • 通过修改 settings.groovy 配置来改变所有工程的ivy缓存目录,比如:

grails.dependency.cache.dir = "${userHome}/.ivy2/cache"
  • 在继承过来的存储仓库(定义在别的插件中)中,现在可以完全使继承过来的失效,代码如下:

grails.project.dependency.resolution = {

repositories { inherits false // Whether to inherit repository definitions from plugins … } … }

  • 可以方便的解决因为校验和导致的验证错误,代码如下:

grails.project.dependency.resolution = {
    checksums false // whether to verify checksums or not
}

1.1.2 核心特性

Binary Plugins

Grails plugins can now be packaged as JAR files and published to standard maven repositories. This even works for GSP and static resources (with resources plugin 1.0.1). See the section on Binary plugins for more information.

二进制插件

在Grails 2.0中插件可以被打包为JAR文件,并且可以发布到标准的maven存储空间, 此外还可以通过resources插件(1.0.1版本)将GSP和静态资源进行处理。更多细节请参考二进制插件章节。

Groovy 1.8

Grails 2.0 comes with Groovy 1.8 which includes many new features and enhancements

Groovy 1.8

Grails 2.0使用了Groovy 1.8中很多的新特性和增强

Spring 3.1 Profile Support

Grails' existing environment support has been bridged into the Spring 3.1 profile support. For example when running with a custom Grails environment called "production", a Spring profile of "production" is activated so that you can use Spring's bean configuration APIs to configure beans for a specific profile.

支持Spring 3.1的个性配置(Profile)

Grails原来所支持的环境配置现在已经通过Spring 3.1的Profile来实现了,比如要执行一个自定义的"production"环境,那么Spring的"production"Profile将被激活,这样你就可以通过Spring的bean配置API来操作了。

1.1.3 Web层特性

Controller Actions as Methods

It is now possible to define controller actions as methods instead of using closures as in previous versions of Grails. In fact this is now the preferred way of expressing an action. For example:

// action as a method
def index() {

} // action as a closure def index = {

}

使用函数方法来定义控制器的动作

以前Grails的动作只能通过闭包来定义,现在通过一般的函数方法也可以定义了,实际上这也是优先推荐的方式,比如:

// action as a method
def index() {

} // action as a closure def index = {

}

Binding Primitive Method Action Arguments

It is now possible to bind form parameters to action arguments where the name of the form element matches the argument name. For example given the following form:

<g:form name="myForm" action="save">
    <input name="name" />
    <input name="age" />
</g:form>

You can define an action that declares arguments for each input and automatically converts the parameters to the appropriate type:

def save(String name, int age) {
    // remaining
}

自动绑定带参数的动作方法

现在可以将表单(form)参数跟动作参数进行自动匹配了,只要表单下边子元素的名称名字跟参数名称一致即可,以如下的表单为例:

<g:form name="myForm" action="save">
    <input name="name" />
    <input name="age" />
</g:form>

你可以定义其动作参数为每一个输入元素的名字,系统会自动将参数值转换为其响应的类型,如以下代码所示:

def save(String name, int age) {
    // remaining
}

Static Resource Abstraction

A new static resource abstraction is included that allows declarative handling of JavaScript, CSS and image resources including automatic ordering, compression, caching and gzip handling.

静态资源

新引入的静态资源抽象,可以声明式地处理JavaScript、CSS以及图像资源的自动排序、压缩、缓存.

Servlet 3.0 Async Features

Grails now supports Servlet 3.0 including the Asynchronous programming model defined by the specification:

def index() {
    def ctx = startAsync()
    ctx.start {
        new Book(title:"The Stand").save()
        render template:"books", model:[books:Book.list()]
        ctx.complete()
    }
}

Servlet 3.0 的异步特性

Grails现在已经支持Servlet 3.0了,且包含了其规范中定义的异步编程模型,比如:

def index() {
    def ctx = startAsync()
    ctx.start {
        new Book(title:"The Stand").save()
        render template:"books", model:[books:Book.list()]
        ctx.complete()
    }
}

Link Generation API

A general purpose LinkGenerator class is now available that is usable anywhere within a Grails application and not just within the context of a controller. For example if you need to generate links in a service or an asynchronous background job outside the scope of a request:

LinkGenerator grailsLinkGenerator

def generateLink() { grailsLinkGenerator.link(controller:"book", action:"list") }

生成超链接的API

在Grails应用,新增的通用LinkGenerator类,可以在任何地方生成超链接了,不像以前,只能局限于控制器的上下文中。比如,你要在一个服务或者异步的后台任务等超出web请求范围内使用,可以参考如下代码:

LinkGenerator grailsLinkGenerator

def generateLink() { grailsLinkGenerator.link(controller:"book", action:"list") }

Page Rendering API

Like the LinkGenerator the new PageRenderer can be used to render GSP pages outside the scope of a web request, such as in a scheduled job or web service. The PageRenderer class features a very similar API to the render method found within controllers:

grails.gsp.PageRenderer groovyPageRenderer

void welcomeUser(User user) { def contents = groovyPageRenderer.render(view:"/emails/welcomeLetter", model:[user: user]) sendEmail { to user.email body contents } }

The PageRenderer service also allows you to pre-process GSPs into HTML templates:

new File("/path/to/welcome.html").withWriter { w ->
    groovyPageRenderer.renderTo(view:"/page/content", w)
}

页面渲染API

LinkGenerator类似,新增的PageRenderer能够在超出web请求范围之外的任何地方渲染GSP页面,比如被调度的任务或者WEB服务接口中。PageRenderer 类的API跟在控制器中使用的render方法很类似,比如:

grails.gsp.PageRenderer groovyPageRenderer

void welcomeUser(User user) { def contents = groovyPageRenderer.render(view:"/emails/welcomeLetter", model:[user: user]) sendEmail { to user.email body contents } }

PageRenderer服务还允许你将GSP页面预处理成为HTML模板:

new File("/path/to/welcome.html").withWriter { w ->
    groovyPageRenderer.renderTo(view:"/page/content", w)
}

Filter Exclusions

Filters may now express controller, action and uri exclusions to offer more options for expressing to which requests a particular filter should be applied.

filter1(actionExclude: 'log*') {
    before = {
        // …
    }
}
filter2(controllerExclude: 'auth') {
    before = {
        // …
    }
}

filter3(uriExclude: '/secure*') { before = { // … } }

过滤器的排除

过滤器现在可以明确的指定是排除控制器、动作、还是URI,这为特定请求的过滤器提供了更多选项。

filter1(actionExclude: 'log*') {
    before = {
        // …
    }
}
filter2(controllerExclude: 'auth') {
    before = {
        // …
    }
}

filter3(uriExclude: '/secure*') { before = { // … } }

Performance Improvements

Performance of GSP page rendering has once again been improved by optimizing the GSP compiler to inline method calls where possible.

性能的提升

通过将GSP编译器优化成内联方法,使得GSP的页面渲染性能又一次得到提升。

HTML5 Scaffolding

There is a new HTML5-based scaffolding UI:

HTML5脚手架

新增的基于HTML5的脚手架界面如下:

jQuery by Default

The jQuery plugin is now the default JavaScript library installed into a Grails application. For backwards compatibility a Prototype plugin is available. Refer to the documentation on the Prototype plugin for installation instructions.

jQuery作为缺省JavaScript库

jQuery插件已经作为一个缺省的JavaScript库被安装到Grails应用当中。因为向后兼容的原因,Prototype插件依然是有效的,其安装指令请参考Prototype插件官方文档

Easy Date Parsing

A new date method has been added to the params object to allow easy, null-safe parsing of dates:

def val = params.date('myDate', 'dd-MM-yyyy')

// or a list for formats def val = params.date('myDate', ['yyyy-MM-dd', 'yyyyMMdd', 'yyMMdd'])

// or the format read from messages.properties via the key 'date.myDate.format' def val = params.date('myDate')

易用的日期解析

params对象新增了一个date方法,用以轻松地、空指针安全地解析日期,比如:

def val = params.date('myDate', 'dd-MM-yyyy')

// or a list for formats def val = params.date('myDate', ['yyyy-MM-dd', 'yyyyMMdd', 'yyMMdd'])

// or the format read from messages.properties via the key 'date.myDate.format' def val = params.date('myDate')

1.1.4 持久层特性

The GORM API

The GORM API has been formalized into a set of classes (GormStaticApi, GormInstanceApi and GormValidationApi) that get statically wired into every domain class at the byte code level. The result is better code completion for IDEs, better integration with Java and the potential for more GORM implementations for other types of data stores.

GORM API

GORM API现在已正式规范为类的集合(GormStaticApi, GormInstanceApi, GormValidationApi),并且在每个领域类的字节码级别上进行注入的。如此一来,对IDE的代码补齐,Java的集成,以及潜在的其他类型的GORM实现来说,提供了更好的支持。

New findOrCreate and findOrSave Methods

Domain classes have support for the findOrCreateWhere, findOrSaveWhere, findOrCreateBy and findOrSaveBy query methods which behave just like findWhere and findBy methods except that they should never return null. If a matching instance cannot be found in the database then a new instance is created, populated with values represented in the query parameters and returned. In the case of findOrSaveWhere and findOrSaveBy, the instance is saved before being returned.

def book = Book.findOrCreateWhere(author: 'Douglas Adams', title: "The Hitchiker's Guide To The Galaxy")
def book = Book.findOrSaveWhere(author: 'Daniel Suarez', title: 'Daemon')
def book = Book.findOrCreateByAuthorAndTitle('Daniel Suarez', 'Daemon')
def book = Book.findOrSaveByAuthorAndTitle('Daniel Suarez', 'Daemon')

全新的findOrCreate和findOrSave方法

领域类现在已经支持findOrCreateWhere, findOrSaveWhere, findOrCreateBy和findOrSaveBy查询方法,这些方法除了不返回null值以外,跟findWhere和findBy方法基本类似。如果在数据库中没有找到符合条件的实例,系统将会根据查询参数创建一个全新的实例返回,不过在findOrSaveWhere 和findOrSaveBy中,实例是先保存入库再返回的。示例代码如下:

def book = Book.findOrCreateWhere(author: 'Douglas Adams', title: "The Hitchiker's Guide To The Galaxy")
def book = Book.findOrSaveWhere(author: 'Daniel Suarez', title: 'Daemon')
def book = Book.findOrCreateByAuthorAndTitle('Daniel Suarez', 'Daemon')
def book = Book.findOrSaveByAuthorAndTitle('Daniel Suarez', 'Daemon')

Detached Criteria and Where Queries

Grails 2.0 features support for DetachedCriteria which are criteria queries that are not associated with any session or connection and thus can be more easily reused and composed:

def criteria = new DetachedCriteria(Person).build {
    eq 'lastName', 'Simpson'
}
def results = criteria.list(max:4, sort:"firstName")

To support the addition of DetachedCriteria queries and encourage their use a new where method and DSL has been introduced to greatly reduce the complexity of criteria queries:

def query = Person.where {
    (lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9)
}
def results = query.list(sort:"firstName")

See the documentation on DetachedCriteria and Where Queries for more information.

分离的Criteria和Where查询

Grails 2.0中分离的Criteria是指条件(Criteria)查询不再跟任何数据库会话或者连接关联,因此可以很方便的复用和构造,比如:

def criteria = new DetachedCriteria(Person).build {
    eq 'lastName', 'Simpson'
}
def results = criteria.list(max:4, sort:"firstName")

为了支持分离的Criteria查询和减少条件查询的复杂性,一个新的where方法及其DSL被引入,比如:

def query = Person.where {
    (lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9)
}
def results = query.list(sort:"firstName")

更多信息请参考本手册的分离的Criteria and Where Queries章节。

Abstract Inheritance

GORM now supports abstract inheritance trees which means you can define queries and associations linking to abstract classes:

abstract class Media {
    String title
    …
}
class Book extends Media {
}
class Album extends Media {

} class Account { static hasMany = [purchasedMedia:Media] }

..

def allMedia = Media.list()

抽象继承

GORM现在支持抽象的继承树或者说现在你可以定义抽象类的查询和关联了,比如:

abstract class Media {
    String title
    …
}
class Book extends Media {
}
class Album extends Media {

} class Account { static hasMany = [purchasedMedia:Media] }

..

def allMedia = Media.list()

Multiple Data Sources Support

It is now possible to define multiple datasources in DataSource.groovy and declare one or more datasources a particular domain uses by default:

class ZipCode {

String code

static mapping = { datasource 'ZIP_CODES' } }

If multiple datasources are specified for a domain then you can use the name of a particular datasource as a namespace in front of any regular GORM method:

def zipCode = ZipCode.auditing.get(42)

For more information see the section on Multiple Data Sources in the user guide.

支持多个数据源

现在,可以在DataSource.groovy定义多个数据源了,对于特定的领域类来说,声明一个或者多个数据源的示例如下:

class ZipCode {

String code

static mapping = { datasource 'ZIP_CODES' } }

在使用有多个数据源的领域类时候,只需要在常规的GORM方法前加上特定数据源名称即可。比如:

def zipCode = ZipCode.auditing.get(42)

更多信息请参考本手册的多数据源章节

Database Migrations

A new database migration plugin has been designed and built for Grails 2.0 allowing you to apply migrations to your database, rollback changes and diff your domain model with the current state of the database.

数据库迁移(Database Migration)

新设计的数据库迁移插件完全是基于Grails 2.0的,有了它,你可以迁移你的数据库了,比如根据当前的数据库状态回滚所做的变化,比较领域模型。

Database Reverse Engineering

A new database reverse engineering plugin has been designed and built for Grails 2.0 that allows you to generate a domain model from an existing database schema.

数据库逆向工程

基于Grails 2.0的数据库逆向工程插件可以根据已有的数据库模式(database schema),自动生成领域模型。

Hibernate 3.6

Grails 2.0 is now built on Hibernate 3.6

Hibernate 3.6

Grails 2.0现在基于Hibernate 3.6了

Bag Collections

You can now use Hibernate Bags for mapped collections to avoid the memory and performance issues of loading large collections to enforce Set uniqueness or List order.

For more information see the section on Sets, Lists and Maps in the user guide.

Bag集合

现在Hibernate的Bag集合(Bag集合,即在集合中允许重复,可以简单的看作为Set和List的结合体--译者注)在Grails 2.0中也得到了支持,由此也比较好的解决了加载大数据量集合转换(Set必须唯一或者List必须有序)导致的内存和性能问题。

更多信息请参考本手册的集合、列表、映射章节。

1.1.5 测试特性

New Unit Testing Console Output

Test output from the test-app command has been improved:

新的单元测试输出结果

运行test-app命令的输出结果已经提升为如下图所示:

New Unit Testing API

There is a new unit testing API based on mixins that supports JUnit 3, 4 and Spock style tests (with Spock 0.6 and above). Example:

import grails.test.mixin.TestFor

@TestFor(SimpleController) class SimpleControllerTests { void testIndex() { controller.home()

assert view == "/simple/homePage" assert model.title == "Hello World" } }

The documentation on testing has also been re-written around this new framework.

新的单元测试API

新的单元测试API现在支持JUnit 3, 4和Spock风格(Spock 0.6以上)的测试了,比如:

import grails.test.mixin.TestFor

@TestFor(SimpleController) class SimpleControllerTests { void testIndex() { controller.home()

assert view == "/simple/homePage" assert model.title == "Hello World" } }

本文档中的测试部分也基于此框架进行了重写。

Unit Testing GORM

A new in-memory GORM implementation is present that supports many more features of the GORM API making unit testing of criteria queries, named queries and other previously unsupported methods possible.

GORM的单元测试

在单元测试方面,新的基于内存的GORM实现,使得GORM在条件查询、命名查询以及以前并未支持的方法也得到了很好的支持。

Faster Unit Testing with Interactive Mode

The new interactive mode (activated by typing 'grails') greatly improves the execution time of running unit and integration tests.

交互模式下更快的单元测试

新的交互模式(通过输入'grails'命令激活)极大的缩短了单元和集成测试的运行时间。

Unit Test Scaffolding

A unit test is now generated for scaffolded controllers

脚手架(Scaffolding)的单元测试

使用脚手架的控制器现在也自动生成一个单元测试。