首页 > 代码库 > Scala下Play框架学习笔记(Actions,Controllers and Results)

Scala下Play框架学习笔记(Actions,Controllers and Results)

Scala下Play框架的学习是一件辛苦的事情,因为该框架比较新,scala语言也较新,所以中文资料很少,经过同事推荐,去了如下英文网站看资料:

https://www.playframework.com/documentation/2.5.x/ScalaHome

虽然我的同事以在云中飞的速度学完了,但对我来说还是任重而道远。

Action是什么?

由于Scala和Play有关的API都在play.api下面,所以其实Action的过程是这样的:

play.api.mvc.Action(play.api.mvc.Request=> play.api.mvc.Result)

例如:

def echo = Action { request =>
 
Ok("Got request [" + request + "]")
}

最简单的构建Action的模式如下:

Action {
 
Ok("Hello world")
}

有一个参数的Action可以构建如下:

Action { request =>
  Ok("Got request [" + request + "]")

}

设置成隐式的request可以让其他的API在需要的时候调用:

Action { implicit request =>
  Ok("Got request [" + request + "]")

}

引入特定的BodyParser参数方式如下:

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

控制器(Controllers)是Action的生成器

控制器用来产生Action类型的值,可以被定义为一个利用依赖注入特性的类或对象。依赖注入是一种用来从依赖中分离组件行为的设计模式,Play框架在scala中同时支持运行时依赖注入和编译时依赖注入。运行时依赖注入在运行时才会创建依赖关系图,并根据关系验证特定组件是否存在依赖。

依赖注入的目标:(1)同一个组件可以绑定多个接口,当用接口来实例化组件或者注入接口用于测试时很有用;(2)避免了全局静态。

Play中依赖注入的实现:通过在routes文件中的配置来创建路由,同时控制器注入构造器,创建Application的实例。另外,Play框架还提供内置的trait来允许创建在编译时与app关联的Scala接口。

当一个组件需要依赖另一个组件时,使用@Inject注解,譬如放在构造器的声明中:

import javax.inject._
import play.api.libs.ws._

class MyComponent @Inject() (ws: WSClient) {
  // ...

}

注解的声明位置必须在构造器名和参数名之间。

Play框架使用依赖注入控制器的方式有两种:

(1)注入routes generator,产生控制器把他们自己作为依赖注入的路由,在build.sbt中添加如下配置:

routesGenerator := InjectedRoutesGenerator

(2)静态routes generator,如下加入到build.sbt:

routesGenerator := StaticRoutesGenerator

如果使用静态路由,每一个Action都有一个由@作为前缀修饰的已经注入的控制器:

GET        /some/path           @controllers.Application.index

最简单的定义action generator的方式是定义一个返回Action实例的无参方法:

package controllers

import play.api.mvc._

class Application extends Controller {

  def index = Action {
    Ok("It works!")
  }

}

action generator 的有参数方法如下,其中参数会被Action闭包所捕获:

def hello(name: String) = Action {
  Ok("Hello " + name)

}

简单HTTP请求的结果包含如下内容:

一个状态码、一个HTTP header集合、以及将被发送到web客户端的body,结果被play.api.mvc.Result所定义:

import play.api.http.HttpEntity

def index = Action {
  Result(
    header = ResponseHeader(200, Map.empty),
    body = HttpEntity.Strict(ByteString("Hello world!"), Some("text/plain"))
  )

}

用OK定义的简单结果:

def index = Action {
  Ok("Hello world!")

}

这和前面获得的结果几乎相同,因为源码中OK就表示状态码为200的Status对象。

play.api.mvc.Results接口及其伴生类可以看到许多种Result的创建方式:

val ok = Ok("Hello world!")
val notFound = NotFound
val pageNotFound = NotFound(<h1>Page not found</h1>)
val badRequest = BadRequest(views.html.form(formWithErrors))
val oops = InternalServerError("Oops")

val anyStatus = Status(488)("Strange response type")

把浏览器重定向到新的URL也是一种简单Result的类型,不带web响应主体:

def index = Action {
  Redirect("/user/home")

}

def index = Action {
  Redirect("/user/home", MOVED_PERMANENTLY)

}

还没实现的Action接口:

def index(name:String) = TODO


Scala下Play框架学习笔记(Actions,Controllers and Results)