play框架概述


今天是來百度實習的第四天,在項目過程中mentor說會用到play框架,當時就一個暈啊。Java還有一個叫play框架,作為一個從大三開始用java的重度javaer,居然不知道這個框架的存在,內心一陣草泥馬飛過,於是乎就花了一下午研究一下。

What's play framework?

先來個開胃菜吧,什么是play框架呢?

先來點官方的解釋:Play是一款開源、輕量、無狀態、Web友好的架構,使用Java語言編寫並遵循MVC模式,集成了當今Web開發所需的組件和API。此外Play可以給應用程序提供可預測的和最小的資源消耗(CPU,內存,線程),可構建高擴展的應用程序。play項目的地址如下:http://www.playframework.com/。該地址已經被qiang,自備梯子。還有個一個中文社區的網站,地址如下:http://play-framework.herokuapp.com/。帖子大部分都是針對1.2這個版本的,所以跟最新版的有一定區別。

目前play框架最新的版本是2.3.1,下載的鏈接是:http://www.playframework.com/download

下面是從某些網站抄來的關於play框架的優劣分析:

優勢:
1. 開發效率高。 用Java但開發效率直追RoR; (可以通過play提供的命令行工具,快速創建java應用)
2. 無狀態,可拓展性好。比如它的session是以加密方式保存在cookie中的。
3. 使用 Groovy 作為視圖層模板使用的表達式語言。模板之間的繼承機制避免了重復的代碼。
4. 支持異步開發
5. 源碼動態編譯,無需重啟服務器。修改任何java或模板代碼,都不需要重啟server。
6. 文檔和例子很完善

劣勢:
1. 在國內還是非主流
2. 反傳統的Java框架,完全拋棄Servlet
3. play!社區比較沉穩,沒有太多的市場宣傳和功能承諾,目前還不太會吸引不太懂技術的人或者說要有hacker精神才會進行嘗試。

play框架的版本

Play當前的版本有點亂,不同版本之間差別還相當大,這常常讓初學者一頭霧水。具體的說明見:http://www.cnblogs.com/babybluevino/p/3851866.html

play框架的使用

在win下要想使用play是很簡單的,從上述的鏈接中download下play框架的二進制包,再在環境變量PATH中配置相應的二進制包的路徑。就可以在cmd下使用play框架了。但是需要特殊指出的一點是,play框架需要jdk的支持,所以你在本機需要預先裝好不同版本play框架對應的jdk版本。

經過以上操作之后,你就可以在cmd下使用activator命令了。(Tips:在2.3.1版本中使用activator命令代替了原來的play命令)如下圖示:

接下來就可以使用activator new my-first-app play-java 命令使用java模板創建一個play工程。

第一個play工程my-first-app創建完成之后,你可以進入該工程目錄。 cd my-first-app

然后鍵入activator,這時候你就會進入一個console,如下圖所示:

然后你可以在這個console里進行一系列的操作,比如獲取幫助:help,比如獲取某個固定命令run的幫助:help run

在console里輸入run是運行這個應用(play框架會啟動自帶的netty服務器),如下圖所示:

這時候你可以用瀏覽器訪問 http://localhost:9000 並看到應用的默認頁面。

與eclipse的集成開發

play既然作為一個java的web框架,自然離不開神一樣的java開發環境eclipse。

Play 提供一個生成 Eclipse 配置的命令。要將 Play 應用轉化為 Ecipse 工程。進入這個工程目錄,運行eclipse命令。

然后,你需要使用 File/Import/General/Existing project… 菜單將應用導入到你的工作區中。(javaer不會不知道吧)


以上講解的都是2.x的版本,鑒於mentor告訴我我們的開發要基於1.7這個版本,所以就繼續要看1.7這個版本的。

1.7版本和2.x版本的命令使用不一樣,在2.x版本中使用activator,而1.x版本使用play命令。把普通的項目變成eclipse的項目在1.7的命令是:play eclipsify <項目名稱>

使用play框架的Web應用的目錄結構如下圖所示:

app: 包含應用核心,分為models,controllers和views目錄。其中 models 和 controllers 目錄下面是 Java 源文件,而 views 目錄下面則是視圖層使用的模板文件。一個Controller就是一個Java 類,它的靜態公共方法則是動作(Action)。動作是接收HTTP請求后的Java處理入口點。Controller類實際是面向過程的,非OO。 Action從HTTP請求中提取數據,讀或更新Model對象,然后返回一個包裝成HTTP響應(HTTP Response)的結果。

conf:包含應用的所有配置。application.conf應用主配置.routes定義url路由規則,messages國際化用。應用的主入口點配置在conf/routes文件中。它定義了應用所有可訪問的URL。比如,默認的helloworld里,它告訴Play,當/路徑收到GET請求后調用Application.indexJava方法。它是controllers.Application.
index的縮寫,因為controllers包是隱式的附加的。
在play框架中,一個url對應一個action的方法,定義action方法的類稱為controller。

一個URL一個。這些方法稱為action方法。定義action方法的類稱為controller。

lib:包含應用依賴的標准.jar文件。

public:包含所有外部可訪問的資源,如:js,css和image。

test:包含所有應用的測試程序。測試程序基於JUnit或Selenium。

另外,由於是eclipse項目,還會多出一個eclipse目錄,包含三個啟動配置:

  • JPDA:連接到已經啟動的Play Server,實現alive調試
  • helloworld:本地運行
  • Test:測試

  選中它們,右鍵執行Run As,即可完成相應的任務。

把Javaweb項目打成war包

play生成war包:activator war exp-platform-mgt/ -o exp.war
tips:war包里面是有源碼的。
如果不要源碼包的話:
activator war exp-platform-mgt/ --exclude app/controller:app/models -o exp1.war
這樣打成war包,會將源文件編譯到precompiled目錄里。

請求生命周期

Play是完全無狀態的(stateless),且僅面向請求-應答(Request-Response)。所有請求遵循相同路徑:

框架收到一個HTTP請求
Router匹配請求和Controller、Action,執行動作方法。
應用代碼執行
繪制模型,呈現視圖
動作方法的結構作為HTTP響應返回。

model層

模型層包含的是 Web 應用中的領域對象。Play 框架推薦的實踐是模型層的對象不應該是僅包含 getter/setter 方法的簡單 Java Beans,而應該有自己的業務邏輯。Play 框架中應用的模型層類可以是任何的 Java 類。與一般的 Java Beans 不同的是,模型層類使用聲明為 public 的域作為對象的屬性。Play 框架會自動生成相應的 getter/setter 方法。這樣可以使得代碼更加簡潔。開發人員也可以提供自己的 getter/setter 方法實現。例如,當我們聲明一個類:

public class Product {
    public String name; 
    public Integer price; 
}

實際上類被加載會變成這樣:

public class Product {
 
    public String name;
    public Integer price;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Integer getPrice() {
        return price;
    }
 
    public void setPrice(Integer price) {
        this.price = price;
    }
}

當你想訪問 一個屬性時,你可以直接寫成:product.name = "a dog"; product.price = 58;

model層的持久化

領域對象的實例一般需要持久化下來。最常見的持久化方式就是使用關系數據庫。Play 框架使用 JPA 規范來進行領域對象的持久化。具體的后台實現使用的是 Hibernate。開發人員只需要使用 JPA 規范定義的標注,就可以聲明領域的持久化行為。比較好的做法是將領域對象類繼承自 Play 框架提供的 play.db.jpa.Model 類,該類提供了一個域id作為對象的標識符。play.db.jpa.JPASupport 類是 play.db.jpa.Model的父類,提供了一些實用方法用來完成從領域對象到數據庫之間的映射。下表中列出了一些重要的方法,包括常用的增刪改查操作。

play.db.jpa.JPASupport API 說明
方法 說明
create(type, name, params) 用來創建領域對象類的一個實例。參數 type 表示的是領域對象類,類型是 java.lang.Classname 表示的是領域對象類的名稱;params表示的是一個包含了實例中屬性值的類型為java.util.Map<java.lang.String,java.lang.String[]> 的哈希表。
edit(obj, name, params) 用來編輯領域對象類的一個實例。參數 obj 表示的是領域對象實例;參數 name 和 params 的含義與 create() 方法的相同。
delete() 用來刪除單個領域對象類的實例。
delete(query, params) 用來刪除多個領域對象類的實例。參數 query 表示的是檢索待刪除實例的查詢,而 params 表示的是查詢所使用的參數。
deleteAll() 用來刪除領域對象類的所有實例。
find(query, params) 用來查找領域對象類的實例。參數 query 表示的是查找時所用的查詢,而 params 表示的是查詢所使用的參數。
findAll() 用來查找領域對象的所有實例。
findById(id) 用來根據標識符查找領域對象的實例。
count(query, params) 用來計算某個查詢結果中包含的領域對象的實例數。參數 query 和 params 的含義與 find() 方法相同。
save() 用來保存該領域對象實例到數據庫中。
all() 用來查找系統中的全部領域對象的實例。

表中列出的方法中,find() 和 all() 方法的返回值是 play.db.jpa.JPASupport.JPAQuery 類的實例,表示一個領域對象實例的查詢結果。對於此查詢結果,可以進行進一步的操作。

play.db.jpa.JPASupport.JPAQuery API 說明
方法 說明
bind(name, param) 用來綁定一個參數的實際值到查詢上。在查詢語句中可以使用形式參數作為占位符,參數的實際值可以通過此方法來指定。
fetch() 用來獲取此查詢的所有記錄。
fetch(max) 用來獲取此查詢的前面 max 條記錄。
fetch(page, length) 用來對查詢結果進行分頁。參數 page 表示當前的頁數,從 1 開始;length 表示每頁的記錄數。
first() 用來返回查詢結果中的第一條記錄
from(position) 用來設置查詢結果中處理的起始位置。參數 position 表示起始位置的序號。該方法的返回結果是一個新的play.db.jpa.JPASupport.JPAQuery 對象。

使用上表中給出的方法,就可以在領域對象類中添加一些非常實用的方法,而不需要把這些方法添加到額外的服務層中。

控制層

Play 框架中的每個控制器都是一個普通的 Java 類,繼承自 play.mvc.Controller 類,在包 controllers 中。控制器類中的每個公開的靜態方法都表示一個動作。每個動作負責完整的請求 / 響應的流程,也就是說,所有前面提到的所有請求/響應的過程都需要在每個動作中來完成。

解析參數

在控制層實現中很繁瑣但是必不可少的操作就是解析 HTTP 請求中的參數。不同的 Web 開發框架會提供自己的參數解析方式。Play 框架也提供了相應的支持。Play 框架可以解析 HTTP 請求中查詢字符串和 URI 路徑中包含的以及請求體中以格式編碼的參數。所有這些參數都放在 params 對象中,其中包含 get()、getAll() 和 put() 等方法用來獲取和設置參數的值。除了這種傳統的使用方式之外,Play 框架還支持直接把參數的值綁定到動作方法的參數上面。比如一個動作方法的聲明是 show(String username),那么請求中的參數 username 的值會在 show() 方法被調用時作為實際參數傳遞進去。Play 框架會負責完成相應的類型轉換。值得一提的是對於日期類型(java.util.Date)的參數,Play 框架支持多種類型的日期格式的轉換。比如動作方法的聲明是 display(Date postedAt),而請求的格式可能是 /display?postedAt=2010-09-22,Play 框架會自動完成相應的類型轉換。
除了常見的基本數據類型之外,Play 框架還支持直接綁定領域對象的實例。比如動作方法的聲明是 create(Note note),可以在參數中直接指定對象實例的屬性的值。請求的格式可能是 /create?title=Note123&content=Good。Play 框架會負責創建一個 Note 類的實例,並根據參數的值設置該實例的屬性 title 和 content 的值。這種綁定方式不僅支持簡單對象,還支持嵌套對象和列表。比如 /create?tags[0]=ajax&tags[1]=web 可以設置列表類型屬性 tags 的值。
Play 框架的這種綁定方式還支持文件對象,使得上傳文件變得非常簡單。只需要在表單中添加文件上傳的控件(<input type="file">)並使用 multipart/form-data編碼來提交請求,在動作方法的參數中就可以獲取到上傳文件對應的 java.io.File 對象。比如動作方法的聲明可能是 upload(File picture)。上傳的文件被保存在臨時目錄中,在請求完成之后會被自動刪除。可以在動作方法中完成對上傳文件的操作。

返回響應結果:

在控制層的動作方法完成了與業務邏輯相關的處理之后,需要把響應返回給客戶端。響應的結果可能是正確完成,也可能是出現錯誤。Play 框架提供了方便的實現用來返回不同類型的響應。使用 play.mvc.Controller 類提供的不同方法就可以生成這些響應內容。
請求正確完成,HTTP 狀態代碼為 200。使用 ok() 方法生成不帶內容的響應。使用 render() 方法來生成使用模板的響應。使用 renderText() 方法生成 text/plain 類型的純文本響應。使用 renderXml() 方法生成 text/xml 類型的 XML 格式的響應。使用 renderJSON() 方法生成 application/json 類型的 JSON 格式的響應。使用 renderBinary() 方法生成二進制內容的響應。
跳轉到新的頁面,HTTP 狀態代碼為 3XX。使用 redirect() 方法來跳轉到新的 URL。使用 notModified() 方法來返回狀態代碼 304。
HTTP 狀態代碼 4XX。使用 unauthorized() 方法返回狀態代碼 401。使用 forbidden() 方法返回狀態代碼 403。使用 notFound() 方法返回狀態代碼 404。
服務器內部錯誤,HTTP 狀態代碼 5XX。使用 error() 方法返回狀態代碼 500。
從上面列出的方法可以看出,Play 框架使用一些有意義的方法名稱替換掉了難以記憶的 HTTP 狀態代碼,使用起來更加方便。同時,對於常見的響應格式,包括 HTML、XML、JSON 和二進制內容,都提供了相應的方法,使得開發人員不會遺漏掉響應中 Content-Type 的聲明。

方法攔截
控制層的方法通常需要執行一些橫切的邏輯,比如用戶認證、加載通用信息和記錄日志等。在 Spring 框架中,這些橫切的邏輯是通過面向方面編程(AOP)的支持來實現的。Play 框架提供了更加簡單易用的方法攔截支持,通過簡單的標注就可以定義一些執行攔截操作的方法。這些方法必須非公開的靜態方法。Play 框架支持的方法攔截標注有 @Before、@After、@Finally 和 @With 等四種。
用 @Before 標注的方法在動作方法執行之前被調用。@After 標注的方法在動作方法執行之后被調用。@Finally 標注的方法在動作方法的響應結果已經成功生成之后被調用。這三個標注都支持額外的兩個屬性:priority 表示標注的方法的優先級,0 為最高;unless 是一個字符串數組,表示不適用此攔截方法的動作方法的名稱。如 @Before(unless="index") 表示此攔截方法不會應用在動作方法 index() 上。
如果控制器類中存在繼承體系結構的話,父類中聲明的攔截方法對於所有子類的動作方法都是適用的。在有些情況下,開發人員可能希望把攔截方法定義在不同的類體系結構中。由於 Java 不支持多繼承,無法通過繼承的方式來應用來自不同類體系結構上的攔截方法。針對這種情況,Play 框架提供了 @With 標注。在控制器類 ControllerA 中定義的攔截方法可以通過 @With 標注來應用到另外一個控制器類 ControllerB 上,而且不通過繼承方式來實現。只需要在 ControllerB 中聲明 @With(ControllerA.class) 即可。


 

視圖層

Web 開發框架的使用者都習慣於使用某種模板技術來生成 HTML 頁面,這些技術包括常見的 JSP、ASP 和 PHP 等。Play 框架也提供了自己的模板技術,可以用來動態的創建 HTML、XML、JSON 以及其它文本類型的內容。Play 框架使用Groovy作為其模板技術。

模板中可用的動態元素
動態元素 說明
${...} 用來對一個表達式進行求值。如 ${note.title} 的值是領域對象 note 的屬性 title 的值。
@{...} 和@@{...} 用來生成調用控制器中動作方法的 URL,可以用在頁面的鏈接中。@{...} 和 @@{...} 生成的分別是相對 URL 和絕對 URL。如 <a href="@{Application.index()}"> 首頁 </> 生成一個指向首頁的鏈接。
&{...} 用來顯示經過國際化之后的消息內容。
*{...}* 用來添加注釋。如 *{ 這是注釋 }*
%{...}% 用來添加復雜的 Groovy 腳本,可以聲明變量和添加語句。
#{...} 用來調用 Play 框架的或是開發人員自定義的標簽。

Play 框架中的標簽的作用相當於 JSP 中的標簽。Play 框架本身提供一些常用的標簽,開發人員也可以根據需要開發自己的標簽。

play框架的路由機制

在前面介紹過,Play 框架中的控制器用來接受 HTTP 請求並返回相應的響應。這個過程的重要一環就是 HTTP 請求的 URI 與控制器之間的映射關系。Play 框架提供了靈活的 HTTP 路由功能來完成這個映射。路由信息被保存在 config/routes 文件中,采用簡單的方式進行聲明。每條路由記錄包含 3 個元素,分別是 HTTP 方法的名稱、匹配的 URI 模式以及對應的控制器動作方法。路由記錄表示的含義是當使用給定的 HTTP 方法來請求對應模式的 URI 的時候,控制器動作方法就會被調用。
Play 框架支持的 HTTP 方法有 GET、POST、PUT、DELETE 和 HEAD。使用通配符 *可以匹配任何方法。在 URI 模式的聲明中可以使用正則表達式來表示復雜的映射規則。URI 模式中還可以使用 {...} 來聲明動態的部分。每個動態部分都是有名稱的,可以在控制器動作方法中通過 params 對象來獲取。比如,/notes/home 這樣的 URI 模式會匹配 /notes/home,但是 /notes/{id} 可以匹配 /notes/123 和 /notes/abc,而且 URI 模式中 /notes/ 后面的部分可以作為參數 id 的值被獲取到。URI 模式 /notes/{<[0-9]+>id} 使用了正則表達式,只會匹配 /notes/后面緊跟的全是數字的情況。在聲明控制器的動作方法的時候,需要使用帶名稱空間的全名,如 myapp.Notes.show。有些動作方法是帶參數的,可以在聲明的時候預先綁定一些參數值,這樣可以方便的添加一些 URI 別名。比如動作方法 Notes.show() 有一個參數 id 用來指明要顯示的內容的 ID。如果參數 id 的值為 0,則會顯示所有內容的一個列表。這樣的話,就可以定義一個類似 GET /notes/all Notes.show(id:0) 的路由聲明。這樣暴露出來的 URI 更加簡潔和易於記憶。
在路由文件中的路由聲明是按照從上到下的優先級來進行匹配的。比較具體的 URI 模式應該放在比較通用的模式之前。對於靜態文件,可以通過一個特殊的動作方法 staticDir 進行聲明。比如 GET /files staticDir:files 就聲明了 files 目錄中包含的是靜態文件。

參考:

http://www.ibm.com/developerworks/cn/java/j-lo-play/

play2.0 介紹:http://www.cnblogs.com/vamei/p/3691398.html

續寫參考:

兩個中英文網站。

http://segmentfault.com/a/1190000000374033

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM