介紹
本文的目標(biāo)是通過一個(gè)用戶登錄示例何吝,簡要的介紹使用Play進(jìn)行Web開發(fā)的基本流程愕够。本文并不會(huì)手把手教你如何創(chuàng)建一個(gè)Play應(yīng)用,而是通過核心的代碼片段傳遞Play的一些設(shè)計(jì)理念挠日,為不熟悉Play框架的同學(xué)提供一個(gè)快速了解的途徑缘眶。
創(chuàng)建登錄Controller
在controllers
目錄下創(chuàng)建ApplicationController
類:
package controllers
import play.api.mvc._
class ApplicationController extends Controller {
def login = Action {
Ok(views.html.login("用戶登錄"))
}
def doLogin(userName: String, password: String) = Action {
val mess = userName + "&" + password
Ok(mess)
}
}
上面定義了login
和doLogin
兩個(gè)Action,一個(gè)用于引導(dǎo)用戶至登錄頁面束莫,另一個(gè)用戶處理登錄請求懒棉。一個(gè)Action其實(shí)就是一個(gè)函數(shù)御吞,接受一個(gè)request作為參數(shù),返回一個(gè)Result漓藕,返回的Result最終會(huì)被以Http響應(yīng)的形式寫回給瀏覽器陶珠。Ok(mess)
返回的結(jié)果就是Result類型。
不熟悉Scala的同學(xué)看上面的代碼會(huì)感覺比較奇怪享钞,
Action{...}
和Ok(...)
是什么鬼揍诽?其實(shí)這是調(diào)用單例對(duì)象上apply
方法的簡寫形式,即Action{...}
等價(jià)于Action.apply(...)
,Ok(...)
等價(jià)于Ok.apply(...)
栗竖。省略掉.apply
是不是看起來感覺舒服一點(diǎn)_暑脆。
另外Scala不建議使用return
語句,默認(rèn)最后一條語句的值作為函數(shù)的返回值狐肢。
創(chuàng)建登錄View
在views
目錄下創(chuàng)建login.scala.html
:
@(title: String)
<!DOCTYPE html>
<html lang="en">
<head><title>@title</title></head>
<body>
<form action="/doLogin">
<input name="userName" type="text" placeholder="User Name" />
<input name="password" type="password" placeholder="Password" />
<button type="submit">立即登錄</button>
</form>
</body>
</html>
我們知道模板頁面中有兩部分內(nèi)容添吗,一部分是不可變的Html內(nèi)容,另一部分是需要?jiǎng)討B(tài)執(zhí)行的代碼份名。而神奇的@
符號(hào)就是要告訴Play碟联,它后面跟著的是需要?jiǎng)討B(tài)執(zhí)行的代碼。在Play中僵腺,一個(gè)模板文件就是一個(gè)函數(shù)鲤孵,接受一組參數(shù),返回動(dòng)態(tài)執(zhí)行后的Html內(nèi)容辰如,函數(shù)名就是不帶后綴的文件名普监,例如上面定義的模板文件編譯后生成的函數(shù)名稱是login
。模板文件的第一行用于指明函數(shù)的參數(shù)列表琉兜,上面的模板文件相當(dāng)于定義了一個(gè)login(title: String)
函數(shù)凯正。
把View抽象成函數(shù)好處還是很多的,例如組合多個(gè)View變成了函數(shù)之間的相互調(diào)用豌蟋,另外我們也可以使用多線程加速大頁面的渲染廊散。
Play的模板層采用Scala
語言編寫,借助Scala語言夺饲,在Play的模板層你會(huì)感覺自己像是一只脫了韁的野馬奸汇。其實(shí)在模板層只需要了解Scala的if
和for
語法即可。Scala雖然入門門檻較高往声,但是帶來的收益是巨大的,隨著你對(duì)Play了解的深入一定可以慢慢的體會(huì)到這點(diǎn)戳吝。
關(guān)聯(lián)Http請求和Action
Play使用routes文件定義Http請求和Action之間的映射關(guān)系浩销,編輯conf/routes
文件,添加一行:
GET /login controllers.ApplicationController.login
GET /doLogin controllers.ApplicationController.doLogin(userName: String, password: String)
啟動(dòng)看看效果
進(jìn)入命令行听哭,執(zhí)行activator run
慢洋,在瀏覽器中打開http://localhost:9000/login
:
加上數(shù)據(jù)驗(yàn)證
通常登錄操作使用Post請求塘雳,所以我們調(diào)整一下routes:
POST /doLogin controllers.ApplicationController.doLogin
ApplicationController
代碼調(diào)整如下:
package controllers
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
class ApplicationController extends Controller {
def login = Action {
Ok(views.html.login("用戶登錄"))
}
def doLogin = Action { implicit request =>
val loginForm = Form(
tuple(
"userName" -> email,
"password" -> text(minLength = 6)
)
)
loginForm.bindFromRequest().fold(
errorForm => Ok(errorForm.errors.toString()),
tupleData => {
val (userName, password) = tupleData
Ok(userName + "&" + password)
}
)
}
}
上面的fold
函數(shù)用于處理表單參數(shù)驗(yàn)證通過和不通過兩種情況。
再來看看效果
小結(jié)
通過上面簡單的登錄示例我們會(huì)發(fā)現(xiàn)普筹,Play中Controller和View是兩個(gè)獨(dú)立的模塊败明,之間沒有任何耦合。Controller完成一些業(yè)務(wù)運(yùn)算太防,然后將數(shù)據(jù)以參數(shù)的形式傳遞給View妻顶,View沒有任何的內(nèi)置對(duì)象,所有的依賴都定義在參數(shù)列表中蜒车,Controller和View之間只是簡單的函數(shù)調(diào)用關(guān)系讳嘱,狀態(tài)通過函數(shù)參數(shù)進(jìn)行傳遞,這樣的好處是程序執(zhí)行流程容易追蹤酿愧,代碼容易閱讀沥潭,并且單元測試會(huì)變得非常簡單,當(dāng)然最大的好處是多線程環(huán)境下代碼無需同步嬉挡,極大地提高了執(zhí)行效率钝鸽。另外Play在改動(dòng)代碼后無需重啟,直接刷新瀏覽器就可以了庞钢,開發(fā)體驗(yàn)還是不錯(cuò)的寞埠。