Chinese Controllers

Grails 控制器(Controllers)

什么是控制器?

一个控制器处理请求并创建或准备返回内容,他可以自己生成返回内容或者委派到一个视图。 创建一个控制器很简单,只需要创建一个以"Controller"结尾的类,并且放到"grails-app/controllers"目录下就可以了。

控制器名字的第一部分被映射到一个URI,同时控制器里定义的每个操作(action)都被映射到一个包含控制器名字的URI。

控制器是一个request-scoped的对象,每次请求都会创建新的实例。. 

创建Grails 控制器

I如果你很懒的话,你可以执行"create-controller"这个 target来创建,该命令回提示你输入控制器的名字:

grails create-controller

例如,我们输入 "book" 便会创建以下控制器:

class BookController { ... }

BookController 将映射到 <...>/book 这个URI,注意:grails 并没有在后台做什么特别的事情,他只是通过一个模板来创建一个控制器给你。

创建操作(Actions)

一个控制器可以有多个closure(闭包)属性,每一个都映射到一个URI:

class BookController {
    @Property list = {

        // do controller logic
        // create model

        return model
    };
}

这个例子将映射到<...>/book/list 这个URI,如果只有一个closure属性,控制器的默认URI将会映射到这个属性上,当然,你可以定义一个名叫"index" 的操作,他会用来处理没有声明操作的URI,如 <...>/book

设置默认的操作

有两种方法来设置默认操作(URI中只有控制器名字的时候执行的操作), 最简单的就是创建一个名叫"index"的操作:

@Property index = {
   redirect(action:list)
}

另外,你可以明确的设置 "defaultAction" 属性:

@Property defaultAction = "list"

访问请求参数(request parameter),session等

每个控制器都会有若干属性会在运行时被注入, 这似的你可以访问到请求参数和session等。完整的参考请参见 [动态方法参考]

class BookController {
    @Property find = {
        def findBy = params["findBy"]
        def appContext = servletContext["appContext"]
        def loggedUser = session["logged_user"]

        // do stuff
        // return model
        return model
    };
}

使用Flash Scope

Flash scope 是在 Rails 中提到的一个概念,其本质是临时储存一些属性给(并且仅给)下一个请求使用,使用过后便被清除掉。这在重定向前需要设置一些信息时非常有用,例如:

@Property delete = {
    def b = Book.get( params['id'] )
    if(!b) {
        flash['message'] = "User not found for id ${params['id']}"
        redirect(action:list)
    }
    ... // remaining code
}

将请求数据绑定到Model

请求的参数都是以字符串传递给web应用的, 因此通常我们需要把这些参数转换为他实际上代表的对象。通过Grails 域对象的"properties"属性,这变的很容易 :

@Property save = {
  def b = new Book()
  b.properties = params
  b.save()
}

在上面的例子里,一行代码就可以把请求参数自动的、神奇的转换并设置到Book的实例里。如果你使用一个别的自定义对象,你可以使用控制器提供的"bindData" 方法:

def sc = new SaveCommand()
bindData(sc, params)

返回Model

一个model实际上是一个在渲染视图时需要的一个map,有很多种方法来返回一个model,第一种就是显式的返回一个map实例:

@Property show = {
    def b = Book.get( params['id'] )
    return [ book : b ]
}

如果没有显式的返回一个model实例,控制器上的属性将被作为model使用,因此你可以这么写:

class BookController {
    @Property List books
    @Property List authors
    @Property list = {
           books = Book.list()
           authors = Author.list()
    }
}

在这里"books" 和"authors" 这两个属性将可以在视图渲染时使用,更复杂的一种做法是直接返回一个 Spring ModelAndView 类的实例.

渲染返回内容

有时候这很简单 (特别是在Ajax 应用里) ,只需要在控制器里直接返回文本或者代码就可以了。使用相当灵活的 "render" 方法:

render "Hello World!"

这个例子直接使用 "Hello World!" 作为返回内容,再给一个例子:

// write some markup
render {
   for(b in books) {
      div(id:b.id, b.title)
   }
}
// render a specific view
render(view:'show')
// render a template for each item in a collection
render(template:'book_template', collection:B
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.