§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
現在是 ScalaFuture
- Play
Redeemable
現在是 ScalaPromise
§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 或小於 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
檔案的設定區塊中
requireJs := "main.js"
可以在 RequireJS 文件頁面 上找到更多關於此功能的資訊。
下一頁:Scala 3 遷移指南
在這個文件中發現錯誤了嗎?此頁面的原始碼可以在 這裡 找到。在閱讀 文件指南 後,請隨時提出 pull request。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開對話。