(Quick Reference)

6.1.2 控制器和作用域 - Reference Documentation

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

Version: null

6.1.2 控制器和作用域

Available Scopes

Scopes are hash-like objects where you can store variables. The following scopes are available to controllers:

  • servletContext - Also known as application scope, this scope lets you share state across the entire web application. The servletContext is an instance of ServletContext
  • session - The session allows associating state with a given user and typically uses cookies to associate a session with a client. The session object is an instance of HttpSession
  • request - The request object allows the storage of objects for the current request only. The request object is an instance of HttpServletRequest
  • params - Mutable map of incoming request query string or POST parameters
  • flash - See below

有效作用域

作用域就像是hash对象,允许你存储变量。以下是控制器有效作用域:

  • servletContext - 也被叫做应用级别范围,它允许你共享整个web应用的状态。 servletContext对象是ServletContext的一个实例
  • session - 会话(session)允许关联某个用户的状态,通常使用Cookie把会话与客户端关联起来。session对象是HttpSession的一个实例
  • request - 请求对象仅为当前的请求存储对象。request对象是HttpServletRequest的一个实例
  • params - 带查询字串(query string)或者POST参数输入请求的可变map
  • flash - 见下文

Accessing Scopes

Scopes can be accessed using the variable names above in combination with Groovy's array index operator, even on classes provided by the Servlet API such as the HttpServletRequest:

class BookController {
    def find() {
        def findBy = params["findBy"]
        def appContext = request["foo"]
        def loggedUser = session["logged_user"]
    }
}

You can also access values within scopes using the de-reference operator, making the syntax even more clear:

class BookController {
    def find() {
        def findBy = params.findBy
        def appContext = request.foo
        def loggedUser = session.logged_user
    }
}

This is one of the ways that Grails unifies access to the different scopes.

访问作用域

作用域可以通过上述提到的变量名和Groovy的数组索引操作符的方式来访问,即使这些类是Servlet API的类,例如HttpServletRequest也可以用,比如:

class BookController {
    def find() {
        def findBy = params["findBy"]
        def appContext = request["foo"]
        def loggedUser = session["logged_user"]
    }
}

你甚至可以使用"."操作符来访问作用域的值,这样使语法更加简洁清晰:

class BookController {
    def find() {
        def findBy = params.findBy
        def appContext = request.foo
        def loggedUser = session.logged_user
    }
}

这是统一访问不同作用域的方式之一。

Using Flash Scope

Grails supports the concept of flash scope as a temporary store to make attributes available for this request and the next request only. Afterwards the attributes are cleared. This is useful for setting a message directly before redirecting, for example:

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

When the list action is requested, the message value will be in scope and can be used to display an information message. It will be removed from the flash scope after this second request.

Note that the attribute name can be anything you want, and the values are often strings used to display messages, but can be any object type.

使用Flash作用域

Grails支持flash作用域的概念,它只存贮本次请求和下次请求之间临时用到的属性,随后属性值将被清除。这在重定向之前,设置提示消息是非常有用的,比如:

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

list操作被请求时,message的值在此范围内有效,可以用以显示一个提示信息。在第二次请求的时候,此值将从flash作用域移除。

注意,属性的名称可以是你期望的任何东西,其值多是用以显示信息的字符串,不过也可以是任何对象。

Scoped Controllers

By default, a new controller instance is created for each request. In fact, because the controller is prototype scoped, it is thread-safe since each request happens on its own thread.

You can change this behaviour by placing a controller in a particular scope. The supported scopes are:

  • prototype (default) - A new controller will be created for each request (recommended for actions as Closure properties)
  • session - One controller is created for the scope of a user session
  • singleton - Only one instance of the controller ever exists (recommended for actions as methods)

To enable one of the scopes, add a static scope property to your class with one of the valid scope values listed above, for example

static scope = "singleton"

You can define the default strategy under in Config.groovy with the grails.controllers.defaultScope key, for example:

grails.controllers.defaultScope = "singleton"

Use scoped controllers wisely. For instance, we don't recommend having any properties in a singleton-scoped controller since they will be shared for all requests. Setting a default scope other than prototype may also lead to unexpected behaviors if you have controllers provided by installed plugins that expect that the scope is prototype.

控制器的作用域

通常,每一个请求会创建一个控制器实例。事实上,是因为控制器的作用域是prototype,并且每个请求都有自己的线程,所以控制器是线程安全的。

不过,你还是可以在控制器内放置一个特定的作用域来改变这种行为。其支持的作用域如下:

  • prototype (缺省) - 每一次请求创建一个新的控制器实例(当操作为必包属性时推荐使用)
  • session - 在一个用户会话的作用域内只创建一个控制器实例
  • singleton - 自始自终只有一个控制器实例(当操作时一个方法时推荐使用)

要想使用上述的作用域,请在类内增加一个静态的scope属性,并且使用上述作用域之一为其赋值,比如:

static scope = "singleton"

你也可以在Config.groovy中改变grails.controllers.defaultScope的值来改变缺省策略,比如

grails.controllers.defaultScope = "singleton"

请明智的使用控制器的作用域。比如我们不推荐singleton作用域的控制器有任何属性,因为他们将在 所有 的请求共享。此外,如果你安装的插件的控制器是prototype的,那么修改缺省的prototype作用域也可能导致不可预知的行为。