llushuang 2012-12-28
Playframework(10)ScalaProjectandDatabase
UsingtheParserAPI
ThemosteasiestparseristoparseavaluetoScalaLong
valrowParser=scalar[Long]
valrsParser=scalar[Long].single
ThiskindofsimpleparserAPIisusefultoproducetheresultbyasimpleselectcountquery:
valcount:Long=SQL("selectcount(*)fromCountry").as(scalar[Long].single)
Acomplexonewithstr("name")~int("population")
valpopulations:List[String~Int]={
SQL("select*fromCountry").as(str("name")~int("population")*)
}
Alternatively,wecanwritelikethis:
valresult:List[String~Int]={
SQL("select*fromCountry").as(get[String]("name")~get[Int]("population")*)
}
…snip…
8.3Integratingwithotherdatabaseaccesslibraries
IntegratingwithScalaQuery
…snip..
ExposingthedatasourcethroughJNDI
…snip...
9.UsingtheCache
ItisbasedonEhcache.
AccessingtheCacheAPI
UsingthissimpleAPItostoredataincache:
Cache.set("item.key",connectedUser)
retrieveitlater:
valmaybeUser:Option[User]=Cache.getAs[User]("item.key")
CachingHTTPresponses
Playprovidesadefaultbuilt-inhelperforstandardcases:
defindex=Cached("homePage"){
Action{
Ok("Helloworld")
}
}
10.CallingWebServices
10.1ThePlayWSAPI
Anycallsmadebyplay.api.libs.ws.WSshouldreturnaPromise[play.api.libs.ws.Response]whichwecanlaterhandlewithPaly'sasynchronousmechanisms.
MakinganHTTPcall
Thesimplewayistousews.url().
valhomePage:Promise[ws.Response]=WS.url("http://mysite.com").get();
Or:
valresult:Promise[ws.Response]={
WS.url("http://localhost:9001/post").post("content")
}
Posturl-form-encodeddata
…snip…
10.2ConnectingtoOpenIDservices
TheOpenIDflowinanutshell
1.TheusergivesyouhisOpenID(aURL).
2.YourserverinspectsthecontentbehindtheURLtoproduceaURLwhereyouneedtoredirecttheuser.
3.TheuserconfirmstheauthorizationonhisOpenIDprovider,andgetredirectedbacktoyourserver.
4.Yourserverreceivesinformationfromthatredirect,andcheckswiththeproviderthattheinformationiscorrect.
OpenIDinPlay
TheopenIDAPIhas2importfunctions:
OpenID.redirectURL.ItreturnsaPromise[String]ratherthanaString.IftheOpenIDisinvalid,thereturnedPromisewillbeaThrown.
OpenID.verifiedId.ItwilldoacalltotheOpenIDservertochecktheauthenticityoftheinformation,thisiswhyitreturnsaPromise[UserInfo]ratherthanjustUserInfo.Iftheinformationisnotcorrectoriftheservercheckisfalse,thereturnedPromisewillbeaThrown.
Hereisanexampleofusage:
deflogin=Action{
Ok(views.html.login())
}
defloginPost=Action{implicitrequest=>
Form(single(
"openid"->nonEmptyText
)).bindFromRequest.fold(
error=>{
Logger.info("badrequest"+error.toString)
BadRequest(error.toString)
},
{
case(openid)=>AsyncResult(OpenID.redirectURL(openid,routes.Application.openIDCallback.absoluteURL()).extend(_.valuematch{
caseRedeemed(url)=>Redirect(url)
caseThrow(t)=>Redirect(routes.Application.login)
}))
}
)
}
defopenIDCallback=Action{implicitrequest=>
AsyncResult(
OpenID.verifiedId.extend(_.valuematch{
caseRedeemed(info)=>Ok(info.id+"\n"+info.attributes)
caseThrown(t)=>{
Redirect(routes.Application.login)
}
}
)
}
ExtendedAttributes
TheOpenIDofausergivesyouhisidentity.Theprotocolalsosupportsgettingextendedattributessuchasthee-mailaddress,thefirstname,orthelastname.
OpenID.redirectURL(
openid,
routes.Application.openIDCallback.absoluteURL(),
Seq("email"->"http://schema.openid.net/contact/email")
)
10.3AccessingresourcesprotectedbyOAuth
Thereare2verydifferentversionsofOAuth:OAuth1.0andOAuth2.0.Version2issimpleenoughtobeimplementedeasilywithoutlibraryorhelpers.PlayonlyprovidessupportforOAuth1.0.
…snip...
11.IntegratingwithAkka
…snip…
12.Internationlization
…snip...
13TheapplicationGlobalobject
13.1Applicationglobalsettings
TheGlobalobject
objectGlobalextendsGlobalSettings{
}
Hookingintoapplicationstartandstopevents
OverridetheonStartandonStopmethodstobenotifiedoftheeventsintheapplicationlife-cycle:
objectGlobalextendsGlobalSettings{
overridedefonStart(app:Application){
Logger.info("Applicationhasstarted")
}
overridedefonStop(app:Application){
Logger.info("Applicationshutdown...")
}
}
Providinganapplicationerrorpage
Whenanexceptionoccursinyourapplication,theonErroroperationwillbecalled.
objectGlobalextendsGlobalSettings{
overridedefonError(request:RequestHeader,ex:Throwable)={
InternalServerError(
views.html.errorPage(ex)
)
}
}
Handlingmissingactionsandbindingerrors
Iftheframeworkdoesn'tfindanActionforarequest,theonHandlerNotFoundoperationwillbecalled:
objectGlobalextendsGlobalSettings{
overridedefonHandlerNotFound(request:RequestHeader):Result={
NotFound(
views.html.notFoundPage(request.path)
)
}
}
onBadRequestisforthatifaroutewasfound,butitwasnotpossibletobindtherequestparameters.
13.2Interceptingrequests
OverridingonRouteRequest
objectGlobalextendsGlobalSettings{
defonRouteRequest(request:RequestHeader):Option[Handler]={
println("executedbeforeeveryrequest:"+request.toString)
super.onRouteRequest(request)
}
}
14Testingyourapplication
14.1Writingtests
Usingspecs2
Unitspecificationsextendtheorg.specs2.mutable.Specificationtraitandareusingtheshould/informat:
classHelloWorldSpecextendsSpecification{
"The'Helloworld'string"should{
"contain11characters"in{
"Helloworld"musthavesize(11)
}
"startwith'Hello'"in{
"Helloworld"muststartWith("Hello")
}
"endwith'world'"in{
"Helloworld"mustendWith("world")
}
}
}
Runninginafakeapplication
…snip...
References:
http://www.playframework.org/documentation/2.0.4/ScalaHome
http://www.playframework.org/documentation/2.0.4/ScalaAnorm