#Actions,contorllers,和Results的概念。
1.Action
Action的概念很熟悉吧,Play應用中的大部分請求都有Action來處理。Action可以看作是一個處理請求數據併產生一個結果放回給客戶端的簡單Java方法。
Action返回play.mvc.Result,代表Http響應發送到客戶端,在例子中,ok()構建了一個200狀態的相應,它包含一個text/plain的響應體。
2.Controller
Controller是繼承自play.mvc.Contorller的類,它將若干Action方法組合在一起。
下面是兩個簡單的Action例子。
public static Result index() {
return ok("It works!");
}
public static Result index(String name) {
return ok("Hello" + name);
}
3.Results
Results即結果。最簡單的莫過於包含一個狀態碼、一組HTTP頭和一個Http體的被髮送到web客戶端的Http Resul。
這些Results被play.mvc.Result定義,play.mvc.Results 類提供了一些幫助產生標準Http Results的方法,例如我們用到的ok()方法。
下面的代碼示例創建了各種Results:
Result ok = ok("Hello world!");
Result notFound = notFound();
Result pageNotFound = notFound("<h1>Page not found</h1>").as("text/html");
Result badRequest = badRequest(views.html.form.render(formWithErrors));
Result oops = internalServerError("Oops");
Result anyStatus = status(488, "Strange response type");
這些方法都可以在play.mvc.Results中找到。
重定向同樣是簡單的Results,把瀏覽器重定向到一個新的URL也不過是一種簡單的result,不同的是這些result 類型沒有響應體。
如:
public static Result index() {
return redirect("/user/home");
}
#Http 路由
1.內置的Http路由
路由是將每一個進來的Http請求轉換成一個Action調用(action是contoller類裏的靜態的、公共的方法)的組件。
一個Http請求在MVC框架中被視爲一個事件,這一事件包含了兩個主要的信息塊:
請求路徑和Http方法(get,post...)
路由在conf/routes文件中被定義,並且會被編譯,也就是說你能直接在瀏覽器中看到路由錯誤。
2.路由的配置語法
conf/routes是路由的配置文件,這個文件列出了所有應用需要的用到的路由,每一個
路由包含了一個Http方法和一個指定了action方法調用的通用資源定位符。
示例如下:
# Display a client.
GET /clients/:id controllers.Clients.show(id: Long)
3.Http方法
Http方法指任何被Http所支持的方法,如GET/POST/PUT/DELETE/HEAD等
4.URI
URI定義了路由請求的路徑,請求路徑的某些部分可以是動態的。
靜態路徑,例如準確匹配GET /clients/all的請求,就可以這樣定義路由:
GET /clients controllers.Clients.list()
動態路徑,如果你想定義一個路由,例如通過ID來檢索Client,那麼你需要增加一個動態部分:
GET /clients/:id controllers.Clients.show(id: Long)
很多時候,動態部分不止一個。動態配置也可以使用通配符和正則表達式。如:
GET /files/*name controllers.Application.download(name)
GET /clients/$id<[0-9]+> controllers.Clients.show(id: Long)
5.調用action生成的方法
路由的最後一部分定義了調用的方法,和需要的參數,參數可以定義各種類型,int,long,String,List等等。
6.路由優先級
多個路由匹配同一個請求的時候就會產生衝突,這時候第一個路由會被使用。
#處理響應
1.改變默認的content-Type
結果的content-Type會根據你設置的Http體的Java值來自動進行指定,如Result textResult = ok("Hello World!");將自動設置content-type頭爲"text/plian",
而Result jsonResult = ok(jerksonObject);則會被設置爲"application/json"。
這一點非常有用,當然也可以通過as方法自行設定。如Result htmlResult = ok("<h1>Hello World!</h1>").as("text/html");
或者直接設置Http response也能達到效果response().setContentType("text/html");return ok("<h1>Hello World!</h1>");
2.設置Http響應頭
可以增加或者更改Http響應頭,例如:
public static Result index() {
response().setContentType("text/html");
response().setHeader(CACHE_CONTROL, "max-age=3600");
response().setHeader(ETAG, "xxx");
return ok("<h1>Hello World!</h1>");
}
這些設置會廢棄之前的設置。
3.設置和丟棄cookies
cookies僅僅是Http頭的特殊形式,Play提供了一些方法使得對設置cookies變得更簡單。
例如:
response().setCookie("theme", "blue");
response().discardCookies("theme");
4.爲文本結果指定字符編碼
正確處理基於文本的Http響應的字符編碼十分重要,Play使用UTF-8作爲默認的編碼格式。
#Session和Flash 作用域
1.Session的概念在Play中很不同
如果你要保持跨多個Http請求的數據,你可以把他們保存在Session或者Flash作用域中。保存在Session中的數據在整個用戶會話中可用,
保存在Flash作用域中的數據僅在下個請求中可用。
Session和Flash數據沒有在服務器上儲存,而是使用cookies在後續的Http請求之間傳遞(而是使用cookies被添加到後續的每個Http請求中),理解這一點很重要。
也就是說數據大小受限制了(最大到4KB),並且只能存儲字符。
Cookies被一個密鑰簽名,這樣客戶端就無法修改cookie數據。Play的Session無意作爲一個緩存。如果你需要存儲與某個特定用戶相關的數據,
那麼你可以使用Play內置的緩存機制來存儲。通過存儲一個用戶會話的唯一ID來與緩存中的數據進行關聯。
注意:Play沒有Session超時失效的技術,如果你的應用程序需要這樣的功能,你可以在用漢語Session中存儲一個時間戳,並需要你自己來實現Session失效的功能。
讀取Session
String user = session("connected");
往Session中存儲數據
session("connected", "[email protected]");
刪除某個Session
session.remove("connected");
廢除所有Session
session().clear();
2.Flash作用域(scope)
Flas作用域的工作方式和Session很相似,但是有兩點是不同的:
a 數據僅保持在一個請求中
b 數據未被簽名,因此用戶可以修改Flash cookie的數據。
注意:Flash作用域僅應該被用於在簡單的非Ajax應用中傳遞成功/失敗消息。
因爲其數據僅僅傳遞給下一個請求,但是在複雜的web應用中它無法確保請求的順序。
總之,Flash作用域受到競爭條件限制。
Flash的使用方法與Session相似。
#(Body parses)Http體分析器
1.何爲體解析
一個Http請求會包含一個Http體,這個Http體能過按照content-Type頭中的設定被格式化。
注意:你不能直接使用Java實現BodyParser(體解析器)。因爲Play的體解析器必須直接處理一個迭代矩陣,
而這必須由Scala來實現。
不過Play提供了默認的BodyParser,它可以滿足大部分的情況(解析Json、Xml、Text、上傳文件等)。並且你可以直接使用Java來重用這些解析器
來實現自己的解析器。例如你可以基於Text的解析器來實現一個RDF的解析器。
2.BodyParser的Java API
所有的解析器必須返回play.mvc.Http.RequestBody類型的值。這個由BodyParser產生的值最終可以通過request().body()方法獲取到。
可以通過@BodyParser.Of的註解來指定一個特定的BodyParser,例如:
@BodyParser.Of(BodyParser.Json.class)
pulic static Result index() {
RequestBody body = request().body();
ok("Got json: " + body.asJson());
}
3.Http.RequestBody API
通常BodyParser會返回正確的play.mvc.Http.RequestBody類型的值。但一些解析器能提供比Http.RequestBody更特殊的類型。使用as()方法你可以自動的將請求體轉換爲另一種類型。例如:
@BodyParser.Of(BodyLengthParser.class)
pulic static Result index() {
BodyLength body = request().body().as(BodyLength.class);
ok("Request body length: " + body.getLength());
}
4.默認的體解析器:任意內容
如果你不指定你自覺的體解析器,Play會使用默認的最接近content-Type的解析器。
a text/plain:String,使用asText().
b application:json:JsonNode,使用asJson().
c text/xml: org.w3c.Document,使用asXml();
d application/form-url-encoded:Map<String, String[]>,使用asFormUrlEncoded().
e multipart/form-data:Http.MultipartFormData, 使用asMultipartFormData().
f 其他content type: Http.RawBuffer, 使用asRaw().
例如:
pulic static Result save() {
RequestBody body = request().body();
String textBody = body.asText();
if(textBody != null) {
ok("Got: " + text);
} else {
badRequest("Expecting text/plain request body");
}
}
5.內容的最大長度
基於文本的體解析器有一個最大長度因爲它們要被全部裝載到內存中。
Play默認的內容長度爲100KB,默認的大小可以在application.conf中定義:parsers.text.maxLength=128K
#Action的構成
1.關於actions的提醒
之前,我們說一個Action就是一個返回play.mvc.Result類型值的Java方法。實際上,Play把內部actions當作函數。
因爲Java不支持first class functions,由Java API提供的Action是一個play.mvc.Action的實例:
public abstract class Action {
public abstract Result call(Http.Context ctx);
}
Play爲你建立一個根action來調用正確的action方法,這樣就允許更復雜的action組合。