§Play 2.1 迁移指南
本指南介绍如何从 Play 2.0 迁移到 Play 2.1。
要将 **Play 2.0.x** 应用程序迁移到 **Play 2.1.0**,首先在 project/plugins.sbt
文件中更新 Play 的 sbt-plugin
addSbtPlugin("play" % "sbt-plugin" % "2.1.0")
现在更新 project/Build.scala
文件,使用新的 play.Project
类代替 PlayProject
类
首先导入
import play.Project._
然后创建 main
项目
val main = play.Project(appName, appVersion, appDependencies).settings(
最后,更新您的 project/build.properties
文件
sbt.version=0.12.2
然后使用 **Play 2.1.0** 发行版中的 play
命令清理并重新编译您的项目
play clean
play ~run
如果出现任何编译错误,本文档将帮助您找出可能导致错误的弃用或不兼容更改。
§构建文件更改
由于 Play 2.1 引入了进一步的模块化,您现在必须明确指定应用程序所需的依赖项。默认情况下,任何 play.Project
仅包含对核心 Play 库的依赖项。您必须选择应用程序所需的精确可选依赖项集。以下是 **Play 2.1** 中新的模块化依赖项
jdbc
: **JDBC** 连接池和play.api.db
API。anorm
: **Anorm** 组件。javaCore
: 核心 **Java** API。javaJdbc
: Java 数据库 API。javaEbean
: Java 的 Ebean 插件。javaJpa
: Java 的 JPA 插件。filters
: 一组 Play 的内置过滤器(例如 CSRF 过滤器)。
以下是 **Play 2.1** 的典型 Build.scala
文件
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
val appName = "app-name"
val appVersion = "1.0"
val appDependencies = Seq(
javaCore, javaJdbc, javaEbean
)
val main = play.Project(appName, appVersion, appDependencies).settings(
// Add your own project settings here
)
}
项目的 mainLang
参数不再需要。主要语言是根据添加到项目中的依赖项确定的。如果依赖项包含 javaCore
,则语言设置为 JAVA
,否则设置为 SCALA
。请注意 appDependencies
部分中的模块化依赖项。
§play.mvc.Controller.form() 重命名为 play.data.Form.form()
同样与模块化相关,play.data
包及其依赖项已从 Play 核心移至 javaCore
工件。因此,play.mvc.Controller#form
已移至 play.data.Form#form
§play.db.ebean.Model.Finder.join() 重命名为 fetch()
作为清理工作的一部分,Finder API 的 join 方法被 fetch 方法取代。它们的行为完全相同。
§Play 的 Promise 成为 Scala 的 Future
随着 Scala 2.10 中引入 scala.concurrent.Future
,Scala 生态系统在统一各种 Future 和 Promise 库方面取得了巨大进步。
Play 现在直接使用 scala.concurrent.Future
,这意味着用户可以轻松地组合来自内部 API 或外部库的 future/promise。
Java 用户目前将继续使用 Play 对 scala.concurrent.Future 的包装器。
考虑以下代码片段
import play.api.libs.iteratee._
import play.api.libs.concurrent._
import akka.util.duration._
def stream = Action {
AsyncResult {
implicit val timeout = Timeout(5.seconds)
val akkaFuture = (ChatRoomActor.ref ? (Join()) ).mapTo[Enumerator[String]]
//convert to play promise before sending the response
akkaFuture.asPromise.map { chunks =>
Ok.stream(chunks &> Comet( callback = "parent.message"))
}
}
}
使用新的 scala.concurrent.Future
,这将变为
import play.api.libs.iteratee._
import play.api.libs.concurrent._
import play.api.libs.concurrent.Execution.Implicits._
import scala.concurrent.duration._
def stream = Action {
AsyncResult {
implicit val timeout = Timeout(5.seconds)
val scalaFuture = (ChatRoomActor.ref ? (Join()) ).mapTo[Enumerator[String]]
scalaFuture.map { chunks =>
Ok.stream(chunks &> Comet( callback = "parent.message"))
}
}
}
注意为以下内容添加的额外导入:
- 用于执行上下文的新的导入
play.api.libs.concurrent.Execution.Implicits
- 用于持续时间的更改
scala.concurrent.duration
(而不是使用 Akka API) asPromise
方法已被删除
一般来说,如果您看到错误消息“error: could not find implicit value for parameter executor”,您可能需要添加
import play.api.libs.concurrent.Execution.Implicits._
(有关更多信息,请参阅 Scala 关于执行上下文的文档)
请记住
- Play 的
Promise
现在是 Scala 的Future
- Play 的
Redeemable
现在是 Scala 的Promise
§Scala JSON API 的更改
Play 2.1 带来了一个全新的 Scala JSON 验证器和路径导航器。但是,这个新的 API 与现有的 JSON 解析器不兼容。
play.api.libs.json.Reads
类型签名已更改。考虑
trait play.api.libs.json.Reads[A] {
self =>
def reads(jsValue: JsValue): A
}
在 2.1 中,这将变为
trait play.api.libs.json.Reads[A] {
self =>
def reads(jsValue: JsValue): JsResult[A]
}
因此,在 Play 2.0 中,User
类型的 JSON 序列化器的实现为
implicit object UserFormat extends Format[User] {
def writes(o: User): JsValue = JsObject(
List("id" -> JsNumber(o.id),
"name" -> JsString(o.name),
"favThings" -> JsArray(o.favThings.map(JsString(_)))
)
)
def reads(json: JsValue): User = User(
(json \ "id").as[Long],
(json \ "name").as[String],
(json \ "favThings").as[List[String]]
)
}
在 **Play 2.1** 中,你需要将其重构为
implicit object UserFormat extends Format[User] {
def writes(o: User): JsValue = JsObject(
List("id" -> JsNumber(o.id),
"name" -> JsString(o.name),
"favThings" -> JsArray(o.favThings.map(JsString(_)))
)
)
def reads(json: JsValue): JsResult[User] = JsSuccess(User(
(json \ "id").as[Long],
(json \ "name").as[String],
(json \ "favThings").as[List[String]]
))
}
生成 JSON 的 API 也发生了变化。请考虑
val jsonObject = Json.toJson(
Map(
"users" -> Seq(
toJson(
Map(
"name" -> toJson("Bob"),
"age" -> toJson(31),
"email" -> toJson("[email protected]")
)
),
toJson(
Map(
"name" -> toJson("Kiki"),
"age" -> toJson(25),
"email" -> JsNull
)
)
)
)
)
在 **Play 2.1** 中,这变成了
val jsonObject = Json.obj(
"users" -> Json.arr(
Json.obj(
"name" -> "Bob",
"age" -> 31,
"email" -> "[email protected]"
),
Json.obj(
"name" -> "Kiki",
"age" -> 25,
"email" -> JsNull
)
)
)
有关这些功能的更多信息,请参见 JSON 文档。
§Cookie 处理的更改
由于 JBoss Netty 的更改,Cookie 通过将它们的 maxAge
设置为 null
或 None
(取决于 API)来使其成为瞬态的,而不是将 maxAge
设置为 -1。任何等于或小于 0 的 maxAge
值都将导致 Cookie 立即过期。
SimpleResult
上的 discardingCookies(String\*)
(Scala)和 discardCookies(String...)
(Java)方法已弃用,因为这些方法无法处理在特定路径、域或设置为安全的 Cookie。请改用 discardingCookies(DiscardingCookie*)
(Scala)和 discardCookie
(Java)方法。
§RequireJS
在 **Play 2.0** 中,Javascript 的默认行为是使用 Google 的 Closure CommonJS 模块支持。在 **Play 2.1** 中,这已更改为使用 RequireJS。
实际上这意味着,默认情况下,Play 仅在 stage、dist、start 模式下才会最小化和合并文件。在 dev 模式下,Play 将在客户端解析依赖项。
如果你想使用此功能,你需要将你的模块添加到 project/Build.scala
文件的 settings 块中
requireJs := "main.js"
有关此功能的更多信息,请参见 RequireJS 文档页面。
下一步:Scala 3 迁移指南
在此文档中发现错误?此页面的源代码可以在 这里 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区开始对话。