Play 2.0 中文资料 - Action, Controller 和 Result

Play 2.0 中文资料 - Action, Controller 和 Result

什么是 Action?

多数的请求被 Play 应用接收到,并由  Action 进行处理.

一个 play.api.mvc.Action 简单说来就是一个 (play.api.mvc.Request => play.api.mvc.Result) 函数,它处理请求并产生一个 result 发送给客户端.

1
2
3
val echo = Action { request = >
   Ok( "Got request [" + request + "]" )
}

Action 返回一个 play.api.mvc.Result 值, 代表着发送给 Web 客户端的 HTTP 响应. 上面的例子中 Ok 构造了一个 200 OK 的响应,它包含了 text/plain 类型的响应体.

建造一个 Action

play.api.mvc.Action 伴生对象提供有多个帮助方法用于构建 Action 值.

最简单的一个方法是以返回值为 Result 的表达式块作为参数:

1
2
3
Action {
   Ok( "Hello world" )
}

这是创建 Action 的最简单的方式, 但是我们无法得到传入的请求的引用. 通常调用 Action 的时候会要求访问 HTTP 请求.

因此,还有另外一个 Action 建造器,它接收一个函数 Request => Result 作为参数:

1
2
3
Action { request = >
   Ok( "Got request [" + request + "]" )
}

经常会用 implicit   来标记 request 参数,这样可在其他的 API 需要的时候隐式的使用它:

1
2
3
Action { implicit request = >
   Ok( "Got request [" + request + "]" )
}

最后一种创建 Action 值的方式是指定一个附加的 BodyParser 作为参数:

1
2
3
Action(parse.json) { implicit request = >
   Ok( "Got request [" + request + "]" )
}

Body 解析器将会在本手册的后面讲到. 当前你仅需了解其他创建 Action 值的方法是使用了一个默认的任意内容请求数据体解析器 (Any content body parser).

Controller 是 action 的产生器

Controller 总是一个用来产生 Action 值的单例对象.

最简单的用于定义一个 Action 产生器的案例就是一个无参并返回 Action 值的方法:

01
02
03
04
05
06
07
08
09
10
11
package controllers
 
import play.api.mvc. _
 
object Application extends Controller {
 
   def index = Action {
     Ok( "It works!" )
   }
 
}

当然了, Action 产生器方法也可以带参数, 这些参数能够被 Action 闭包捕获的到:

1
2
3
def hello(name : String) = Action {
   Ok( "Hello " + name)
}

Unmi 注: 从 Action 开始要理解下 Scala 比较灵活的语法了。首先感性的知道下 Scala 方法定义的最主要四种形式是,不妨先记下它们来:

1
2
3
4
def index = Action { ...... }   //不访问 request
def index = Action { request = > ...... }  //代码块中要访问 request
def index = Action(parse.json) { ...... } //这是调用了柯里化(currying) 后的函数
def index(name : String) = Action { ...... } //获得请求参数 name

拿第二行来说明它的由来,它的完整的方法定义如下:

1
2
3
4
5
def index = {
   Action( request = >
     ......
   )
}

Unmi 注: Scala 把上面的写法转换成 def index Action { request => .......} 是基于以下几个规则的:

1. 如果定义的方法返回值不是 Unit 类型的话就必须要在方法实现之前加上等号

2. 如果方法实现只有一条语句,或者 Scala 能够推断出方法何时结束,则可以省略掉方法体外围的大括号,此处的 index 就是直接返回 Action 方法的值

3. 如果方法只有一个参数,则调用它时可以用花括号代替小括号包围参数,所以通常把 Action( request => ......) 写成了 Action{ request => ......}。这样写的好处就是它看起来像是一种内建控制结构。这里 request => ...... 是一个闭包,或称字面函数参数

4. 在 Action.scala 源文件中,Action 是一个单例对象:

1
2
3
4
/**
  * Helper object to create `Action` values.
  */
object Action extends ActionBuilder

直接在对象后加上括号的写法会转去调用它相应的 apply 方法,上面的 Action 继承了特质 ActionBuilder,而在特质 ActionBuilder 中定义了如下几个 apply 方法:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
  * Provides helpers for creating `Action` values.
  */
trait ActionBuilder {
 
   /**
    * Constructs an `Action`.
    *
    * For example:
    * {{{
    * val echo = Action(parse.anyContent) { request =>
    *   Ok("Got request [" + request + "]")
    * }
    * }}}
    *
    * @tparam A the type of the request body
    * @param bodyParser the `BodyParser` to use to parse the request body
    * @param block the action code
    * @return an action
    */
   def apply[A](bodyParser : BodyParser[A])(block : Request[A] = > Result) : Action[A] = new Action[A] {
     def parser = bodyParser
     def apply(ctx : Request[A]) = block(ctx)
   }
 
   /**
    * Constructs an `Action` with default content.
    *
    * For example:
    * {{{
    * val echo = Action { request =>
    *   Ok("Got request [" + request + "]")
    * }
    * }}}
    *
    * @param block the action code
    * @return an action
    */
   def apply(block : Request[AnyContent] = > Result) : Action[AnyContent] = apply(BodyParsers.parse.anyContent)(block)
 
   /**
    * Constructs an `Action` with default content, and no request parameter.
    *
    * For example:
    * {{{
    * val hello = Action {
    *   Ok("Hello!")
    * }
    * }}}
    *
    * @param block the action code
    * @return an action
    */
   def apply(block : = > Result) : Action[AnyContent] = apply( _ = > block)
 
}

从这些源文件知道 Action 里是个闭包就行,返回是个 Result 类型。至于执行时 request 值是怎么产生的还需研究下。

简单的 Result

目前我们只讲述简单的 Result: 一个具有状态代码的 HTTP Result, 一系列 HTTP 头和要发送到 Web 客户端的响应体.

这些 Result 由 play.api.mvc.SimpleResult 定义:

1
2
3
4
5
6
def index = Action {
   SimpleResult(
     header = ResponseHeader( 200 , Map(CONTENT _ TYPE -> "text/plain" )),
     body = Enumerator( "Hello world!" )
   )
}

当然,也有数个帮助方法让你创建通用的 Result,像下面例子中的 Ok Result:

1
2
3
def index = Action {
   Ok( "Hello world!" )
}

这会产生与之上例中完全相同的 Result.

下面是几个创建种种 Result 的例子:

1
2
3
4
5
6
val ok = Ok( "Hello world!" )
val notFound = NotFound
val pageNotFound = NotFound(<h 1 >Page not found</h 1 >)
val badRequest = BadRequest(views.html.form(formWithErrors))
val oops = InternalServerError( "Oops" )
val anyStatus = Status( 488 )( "Strange response type" )

所有的这些帮助方法可在 play.api.mvc.Results 特质和伴生对象中找到.

重定向也是简单的 Result

重定向浏览器到一个新的 URL 是另一类简单的 Result. 然而, 这类 Result 类型不会带上响应体.

下面是些创建重定向 Result 的几个帮助方法:

1
2
3
def index = Action {
   Redirect( "/user/home" )
}

默认是利用 303 SEE_OTHER 响应类型, 但是 你可以根据需要设置特别的状态码:

1
2
3
def index = Action {
   Redirect( "/user/home" , status = MOVED _ PERMANENTLY)
}

Unmi 注: 返回 Result 类型的各方法定义在 Controller 所继承的 Results(.scala) 文件中,如 Ok,Redirect 等方法。

“TODO” 虚页面

你可以用一个定义为 TODO 的空的 Action 实现: 这个 Result 是一个标准的 ‘Not implemented yet’ 结果页:

1
def index(name : String) = TODO

Unmi 注: TODO  定义在 trait Controller(.scala) 中:

1
2
3
   val TODO = Action {
     NotImplemented[play.api.templates.Html](views.html.defaultpages.todo())
   }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值