§Play 2.1 有什麼新功能?
§遷移至 Scala 2.10
Play 的整個執行時間 API 已遷移至 Scala 2.10,讓您的應用程式可以參與此新語言版本提供的絕佳新功能。
同時,我們已中斷 建置系統 (sbt) 使用的 Scala 版本與執行時間使用的 Scala 版本之間的相依性。如此一來,便更容易在 Scala 語言的實驗性或不穩定分支上建置並測試 Play。
§遷移至 scala.concurrent.Future
Scala 2.10 提供的其中一項最棒的功能,就是用於管理 Scala 中非同步程式碼的新標準 scala.concurrent.Future
函式庫。Play 現在以這個 API 為基礎,其非凡的非同步 HTTP 和串流功能現在可直接與任何使用相同 API 的其他函式庫相容。
這讓 Play 與 Akka 搭配使用變得更簡單,或任何即將推出的非同步資料儲存驅動程式,這些驅動程式都將使用這個新 API。
同時,我們致力於簡化執行內容模型,並提供一種簡單的方式,讓您為應用程式的每個部分選擇用於執行程式碼的基礎 ExecutionContext
。
§模組化
Play 專案已分割成許多子專案,讓您可以選擇專案所需的最小依賴項組。
您必須在下列清單中選擇應用程式所需的精確選用依賴項組:
jdbc
:JDBC 連線池和play.api.db
API。anorm
:Anorm 元件。javaCore
:核心 Java API。javaJdbc
:Java 資料庫 API。javaEbean
:Java 的 Ebean 外掛程式。javaJpa
:Java 的 JPA 外掛程式。filters
:Play 的內建篩選器組(例如 CSRF 篩選器)
play
核心專案現在有非常有限的外部依賴項組,且可用作沒有其他元件的最小非同步、高執行效能 HTTP 伺服器。
§允許專案有更多模組化
為了進一步允許在您自己的專案中撰寫和重複使用元件,Play 2.1 支援子路由器撰寫。
例如,子專案可以使用自己的命名空間定義自己的路由器元件,例如
在 conf/my.subproject.routes
中
GET / my.subproject.controllers.Application.index
然後,您可以透過連接路由器將此元件整合至您的主要應用程式,例如
# The home page
GET / controllers.Application.index
# Include a sub-project
-> /my-subproject my.subproject.Routes
# The static assets
GET /public/*file controllers.Assets.at(file)
在組態中,在執行時期呼叫 /my-subproject
URL 最終會呼叫 my.subproject.controllers.Application.index
動作。
注意:為了避免與主要應用程式的名稱衝突問題,請務必確定您在屬於子專案的控制器類別中定義一個子套件 (例如,在此特定範例中為
my.subproject
)。您還需要確定子專案的 Assets 控制器在同一個名稱空間中定義。
可以在 使用子專案 中找到有關此功能的更多資訊。
§在 Java API 中傳播 Http.Context
在 Play 2.0 中,HTTP 背景會在非同步回呼期間遺失,因為這些程式碼片段是在與處理 HTTP 要求的原始片段不同的執行緒上執行。
考量
public static Result index() {
return async(
aServiceSomewhere.getData().map(new Function<String,Result>(data) {
// Ouch! You try to access the request data in an asynchronous callback
String user = session().get("user");
return ok("Here is the result " + user + ": " + data);
})
);
}
此程式碼並未以這種方式運作。如果您考量基礎非同步架構,則有非常好的理由,但這對 Java 開發人員來說真的令人驚訝。
我們最終找到解決此問題的方法,並將 Http.Context
傳播到跨越多個執行緒的堆疊,因此此程式碼現在以這種方式運作。
§Java API 的更佳執行緒模型
在可變資料結構上執行非同步程式碼時,如果您沒有正確同步您的程式碼,很可能會遇到一些競爭條件。由於 Play 推廣高度非同步和非封鎖程式碼,而且由於 Java 資料結構大多是可變的且非執行緒安全的,因此處理同步問題是您的程式碼的責任。
考量
public static Result index() {
final HashMap<String,Integer> result = new HashMap<String,Integer>();
aService.doSomethingAsync().map(new Function<String,String>(key) {
Integer i = result.get(key);
if(i != null) {
result.set(key, i++);
}
return key;
});
aService.doSomethingElse().map(new Function<String,String>(key) {
result.remove(key);
return null;
});
...
}
在此程式碼中,如果 2 個回呼在 2 個不同的執行緒上同時執行,同時每個都存取共用 result
HashMap,則很可能會遇到競爭條件。而後果可能是由於底層 Java HashMap 的實作,在您的應用程式中造成一些偽死鎖。
為了避免這些問題,我們決定在架構層級管理回呼執行同步。Play 2.1 絕不會同時執行 2 個針對相同 Http.Context
的回呼。在此背景下,所有回呼執行都將順序執行(雖然無法保證它們會在同一個執行緒上執行)。
§管理的控制器類別實例化
預設情況下,Play 會靜態地將 URL 繫結到控制器方法,也就是說,架構不會建立任何控制器實例,且會根據指定的 URL 呼叫適當的靜態方法。然而,在某些情況下,您可能想要管理控制器建立,而這時新的路由語法就派上用場了。
以 @ 開頭的路由定義將由 Global::getControllerInstance
方法管理,因此,給定下列路由定義
GET / @controllers.Application.index()
Play 會呼叫 getControllerInstance
方法,作為回報,它會提供 controllers.Application
的執行個體(預設情況下,這是透過預設建構函式發生的)。因此,如果您想要透過依賴注入架構或手動管理控制器類別實例化,您可以透過在應用程式的 Global 類別中覆寫 getControllerInstance 來執行此動作。
正如此範例 所展示的,它允許將任何依賴注入架構(例如 Spring)連接到您的 Play 應用程式。
§新的 Scala JSON API
新的 Scala JSON API 提供了許多優異的功能,例如 JSON 樹的轉換和驗證。請查看 Scala Json 組合器文件 中的新文件。
§新的 Filter API 和 CSRF 保護
Play 2.1 提供了一個新的且功能強大的 filter API,允許以完全非封鎖的方式攔截 HTTP 請求或回應的每個部分。
為此,我們引進了一個新的更簡單的類型,取代舊的 Action[A]
類型,稱為 EssentialAction
,其定義如下
RequestHeader => Iteratee[Array[Byte], Result]
因此,filter 簡單地定義如下
EssentialAction => EssentialAction
注意:舊的
Action[A]
類型仍可使用,以確保相容性。
標準 Play 發行版中包含的 filters
專案包含一組標準 filter,例如 CSRF
,提供針對 CSRF 安全性問題的自動 token 管理。
§RequireJS
在 play 2.0 中,Javascript 的預設行為是使用 google closure 的 commonJS 模組支援。在 2.1 中,這已變更為改用 requireJS。
在實務上,這表示 Play 預設只會在 stage、dist 和 start 模式中壓縮和合併檔案。在 dev 模式中,Play 會在客戶端解析相依性。
如果你想使用這項功能,你必須將你的模組加入 build 檔案的設定區塊
requireJs := "main.js"
有關這項功能的更多資訊,請參閱 RequireJS 文件頁面。
§內容協商
內容協商的支援已獲得改善,例如現在控制器會根據 Accept-Language
要求標頭值中設定的品質值自動選擇最合適的語言。
現在也更容易撰寫支援同一個資源的數種表示形式的 Web 服務,並根據 Accept
要求標頭值自動選擇最佳表示形式
val list = Action { implicit request =>
val items = Item.findAll
render {
case Accepts.Html() => Ok(views.html.list(items))
case Accepts.Json() => Ok(Json.toJson(items))
}
}
有關內容協商的更多資訊,請參閱 Scala 和 Java 的內容協商文件頁面。
下一步:移轉指南
在這個文件中發現錯誤?此頁面的原始程式碼可以在 這裡 找到。在閱讀 文件指南 後,請隨時貢獻一個 pull request。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開討論。