本文来自: http://fair-jm.iteye.com/ 转截请注明出处
又做了一些笔记 因为长时间没做play的应用现在都已经生疏了
play官网的doc非常详细是非常好的学习教程 我想有了这个其他书都是浮云了
这是最近看的时候摘录的一些内容 翻译了一下 如果错误麻烦指正
第一章的内容还差两节 等有空 翻译之后会放上来
1、HTTP编程(HTTP programming)
1.1 Actions, Controllers and Results
SimpleResult
def index =Action{
SimpleResult(
header =ResponseHeader(200,Map(CONTENT_TYPE ->"text/plain")),
body =Enumerator("Hello world!".getBytes())
)
}
来自 <https://www.playframework.com/documentation/2.2.x/ScalaActions>
Status(状态码)(内容)
Action可以只使用TODO来表明还没被实现
def index(name:String)= TODO
来自 <https://www.playframework.com/documentation/2.2.x/ScalaActions>
1.2 HTTP routing
动态参数
用:name的形式
对于要包含/的形式用
*name
GET /files/*name controllers.Application.download(name)
GET /files/images/logo.png, name 会为images/logo.png
来自 <https://www.playframework.com/documentation/2.2.x/ScalaRouting>
对于正则用:
$id<[0-9]+>
对于后面的值
如果是固定的用 =
不是固定的而是一个默认值的话用 ?=
参数的类型可以不写不写当作String
或者写作Option表示可有可无
# Pagination links, like /clients?page=3
GET /clients controllers.Clients.list(page:Int?=1)
来自 <https://www.playframework.com/documentation/2.2.x/ScalaRouting>
# Extract the page parameter from the path, or fix the value for /
GET / controllers.Application.show(page ="home")
GET /:page controllers.Application.show(page)
来自 <https://www.playframework.com/documentation/2.2.x/ScalaRouting>
GET /clients/:id controllers.Clients.show(id:Long)
来自 <https://www.playframework.com/documentation/2.2.x/ScalaRouting>
# The version parameter is optional. E.g. /api/list-all?version=3.0
GET /api/list-all controllers.Api.list(version:Option[String])
来自 <https://www.playframework.com/documentation/2.2.x/ScalaRouting>
优先级:
写在前面的会被最先匹配
(请把越具体的写在越前面)
路由反转:
在routes包下
和实际的Action有相同的签名返回的是play.api.mvc.Call
返回的结果会自动从指定的返回体的scala值中判断出来:
- val textResult =Ok("Hello World!")
content-type会是 text/plain
- val xmlResult = Ok(<message>Hello World!</message>)
content-type会是 application/xml
(通过 play.api.http.ContentTypeOf完成的)
可以使用 Result的as方法来指定content-type
val htmlResult = Ok(<h1>Hello World!</h1>).as("text/html")
或者:
val htmlResult2 = Ok(<h1>Hello World!</h1>).as(HTML)
操作HTTP头部
val result = Ok("Hello World!").withHeaders(
CACHE_CONTROL -> "max-age=3600",
ETAG -> "xx")
来自 <https://www.playframework.com/documentation/2.2.x/ScalaResults>
会自动把原先设置以及存在的值给去掉
设置和取消Cookie
val result3 = result.withCookies(Cookie("theme", "blue")).discardingCookies(DiscardingCookie("skin"))
改变基于文字的响应的字符集
默认是UTF-8
使用HTML的时候可以通过传入一个隐式的Codec来更改:
objectApplicationextendsController{
implicitval myCustomCharset =Codec.javaSupported("iso-8859-1")
def index =Action{
Ok(<h1>HelloWorld!</h1>).as(HTML)
}
}
HTML的实现:
def HTML(implicit codec: Codec) = {
"text/html; charset=" + codec.charset
}
自己也可以实现
1.4 Session和Flash范围Session and Flash scopes
Session范围的数据对整个会话都是有效的
而Flash的数据只对下一个请求有效
Play中Session和Flash都不是放在服务器端的他们是通过cookie机制加到每一个后续的Http请求中
只能存string的值只有4KB
默认的cookie名是PLAY_SESSION 可以在application.conf中配置 session.cookieName 改变名字
(也可以在上面的设置和取消Cookie里修改)
要存一些数据可以用Cache
session存储(Tuple2):
Ok("Welcome!").withSession(
"connected"->"user@gmail.com")
他会清空其他所有的值只会有connected这一个key
要避免清空用 + 增加用 - 取消
Ok("Hello World!").withSession(
request.session +("saidHello"->"yes"))
Ok("Theme reset!").withSession(
request.session -"theme")
session读取:
用request参数读取:
def index =Action{ request =>
request.session.get("connected").map { user =>
Ok("Hello "+ user)
}.getOrElse {
Unauthorized("Oops, you are not connected")
}
取消整个session:
Ok("Bye").withNewSession
1.5 Body解析
什么是Body解析
HTTP的PUT和POST请求包含请求体。可以是任何的Content-Type类型
在play中,一个body解析器将请求体转换到Scala类型。
一个请求体可能非常大并且一个body解析器不能一直等到全部数据载入内存中再解析
一个Body解析器本质是一个 Iteratee[Array[Byte],A]
接受字节块(chunks of bytes)
例子:
|
body解析器可以在解析请求体之前访问HTTP请求头,并可以运行一些前置检查。
所以 body解析不是真正的Iteratee[Array[Byte],A] 但更准确地是一个Iteratee[Array[Byte],Either[Result,A]]
当解析结束后会返回A,此时对应的Action会被执行。
更多关于Action的内容
traitAction[A]extends(Request[A]=>Result){
def parser:BodyParser[A]
}
Request的定义:
traitRequest[+A]extendsRequestHeader{
def body: A
}
A就是请求体的返回类型
总结一下,Action[A] 使用一个BodyParser[A]从HTTP请求中得到类型为A的内容,并构建一个Request来执行Action的代码
默认的Body解析:AnyContent
如果我们不指定自己的Body解析器默认的是play.api.mvc.AnyContent的一个实例
这个Body解析器检查Content-Type头并且决定使用解析那种body:
来自 <https://www.playframework.com/documentation/2.3.x/ScalaBodyParsers>
|
比如:
def save =Action{ request =>
val body:AnyContent= request.body
val textBody:Option[String]= body.asText
// Expecting text body
textBody.map { text =>
Ok("Got: "+ text)
}.getOrElse {
BadRequest("Expecting text/plain request body")
}
}
指定一个body解析器:
可用的body解析器定义在play.api.mvc.BodyParsers.parse中
例如:
def save =Action(parse.text){ request =>
Ok("Got: "+ request.body)
}
如果内容不是text的那么就会返回400
或者我们可以使用:
def save =Action(parse.tolerantText){ request =>
Ok("Got: "+ request.body)
}
与上面不同他不会检查Content-Type并总是把请求体作为String载入
(所有的body解析器都有其对应的tolerant类型)
另一个将请求体存入文件的例子:
def save =Action(parse.file(to =newFile("/tmp/upload"))){ request =>
Ok("Saved the request content to "+ request.body)
}
组合body解析器
上面的例子中会将所有请求都放在一个相同的文件中不太合理这里有另一个按照用户名存文件的方式:
val storeInUserFile = parse.using { request =>
request.session.get("username").map { user =>
file(to =newFile("/tmp/"+ user +".upload"))
}.getOrElse {
sys.error("You don't have the right to upload here")
}
}
def save =Action(storeInUserFile){ request =>
Ok("Saved the request content to "+ request.body)
}
我们并没写自己的Body解析器只是单纯结合了现有的。从脚手架开始书写一个自定义解析器在高级章节中介绍。
最大内容长度
基于文本的body解析器(text,json,xml或formUrlEncoded)使用了一个最大内容长度因为他们必须将所有的内容载入内存
默认的大小是100KB你也可以指定:
// Accept only 10KB of data.
def save =Action(parse.text(maxLength =1024*10)){ request =>
Ok("Got: "+ text)
}
默认的内容大小定义在application.conf:
parsers.text.maxLength=128K
更多的内容可以在Configuration找到
你也可以将任何的body解析器用maxLength包裹:
// Accept only 10KB of data.
def save =Action(parse.maxLength(1024*10, storeInUserFile)){ request =>
Ok("Saved the request content to "+ request.body)
}
来自 <https://www.playframework.com/documentation/2.3.x/ScalaBodyParsers>
1.6 Action组合
这个章节介绍了几种定义通用action功能的方法.
自定义Action构造器
构建Action的方法实际上都定义在ActionBuilder这个特质里。
我们用来声明的action的Action对象都是这个特质的实例。
通过实现自己的ActionBuilder可以定义可复用的action栈用来构建actions。
首先是实现invokeBlock方法:
import play.api.mvc._
objectLoggingActionextendsActionBuilder[Request]{
def invokeBlock[A](request:Request[A], block:(Request[A])=>Future[Result])={
Logger.info("Calling action")
block(request)
}
}
来自 <https://playframework.com/documentation/2.3.x/ScalaActionsComposition>
然后我们可以用和使用Action同样的方式来使用了:
def index =LoggingAction{
Ok("Hello World")
}
def submit =LoggingAction(parse.text){ request =>
Ok("Got a body "+ request.body.length +" bytes long")
}
组合Actions
在大多数的应用中,我们需要多个action构造器,一些用来做验证,一些用来提供不同类型的通用功能。
可重用的action可以用包裹actions来实现:
import play.api.mvc._
caseclassLogging[A](action:Action[A])extendsAction[A]{
def apply(request:Request[A]):Future[Result]={
Logger.info("Calling action")
action(request)
}
lazyval parser = action.parser
}
或者可以这样避免定义一个类:
import play.api.mvc._
def logging[A](action:Action[A])=Action.async(action.parser){ request =>
Logger.info("Calling action")
action(request)
}
Actions可以通过composeAction方法混入action构造器:
objectLoggingActionextendsActionBuilder[Request]{
def invokeBlock[A](request:Request[A], block:(Request[A])=>Future[Result])={
block(request)
}
overridedef composeAction[A](action:Action[A])=newLogging(action)
}
调用和原来一样:
def index =LoggingAction{
Ok("Hello World")
}
或者不用Action构造器的方式:
def index =Logging{
Action{
Ok("Hello World")
}
}
更复杂的action
上面的action并不影响action,当然我们也可以修改传入的request对象
import play.api.mvc._
def xForwardedFor[A](action:Action[A])=Action.async(action.parser){ request =>
val newRequest = request.headers.get("X-Forwarded-For").map { xff =>
newWrappedRequest[A](request){
overridedef remoteAddress = xff
}
} getOrElse request
action(newRequest)
}
注:play已经有内置的对于X-Forwarded-For头的支持
我们可以截获这个请求:
import play.api.mvc._
def onlyHttps[A](action:Action[A])=Action.async(action.parser){ request =>
request.headers.get("X-Forwarded-Proto").collect {
case"https"=> action(request)
} getOrElse {
Future.successful(Forbidden("Only HTTPS requests allowed"))
}
}
或者修改返回的结果:
import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits._
def addUaHeader[A](action:Action[A])=Action.async(action.parser){ request =>
action(request).map(_.withHeaders("X-UA-Compatible"->"Chrome=1"))
}
不同的请求类型
action组合允许执行一些在HTTP请求和回应等级的额外处理
常常也会需要构建一些对请求本身的例如添加上下文或进行验证的数据转换管道
ActionFunction
每一个function都表示一个模块化的处理
比如验证权限检查等你希望在action间组合和重用的功能
几个预定义的ActionFunction:
- ActionTransformer can change the request, for example by adding additional information.
- ActionFilter can selectively intercept requests, for example to produce errors, without changing the request value.
- ActionRefiner is the general case of both of the above.
- ActionBuilder is the special case of functions that take Request as input, and thus can build actions.
也可以实现ActionFunction定义自己的抽象。
验证
import play.api.mvc._
classUserRequest[A](val username:Option[String], request:Request[A])extendsWrappedRequest[A](request)
objectUserActionextends
ActionBuilder[UserRequest]withActionTransformer[Request,UserRequest]{
def transform[A](request:Request[A])=Future.successful {
newUserRequest(request.session.get("username"), request)
}
}
增加额外信息
比如/item/:itemId每一个在这个路径下的routes
都需要先查询拿到Item
先定义一个新的类似用来存放Item到UserRequest(上面的)
import play.api.mvc._
classItemRequest[A](val item:Item, request:UserRequest[A])extendsWrappedRequest[A](request){
def username = request.username
}
返回一个Either返回错误是Left 一个新的ItemRequest是Right
defItemAction(itemId:String)=newActionRefiner[UserRequest,ItemRequest]{
def refine[A](input:UserRequest[A])=Future.successful {
ItemDao.findById(itemId)
.map(newItemRequest(_, input))
.toRight(NotFound)
}
}
Option的toRight 是如果Option不为空就返回Right 为空就以Left返回NotFound
验证请求
objectPermissionCheckActionextendsActionFilter[ItemRequest]{
def filter[A](input:ItemRequest[A])=Future.successful {
if(!input.item.accessibleByUser(input.username))
Some(Forbidden)
else
None
}
}
结合起来
可以将这些功能(以ActionBuilder开头)使用andThen组合起来创建一个Action:
def tagItem(itemId:String, tag:String)=
(UserAction andThen ItemAction(itemId) andThen PermissionCheckAction){ request =>
request.item.addTag(tag)
Ok("User "+ request.username +" tagged "+ request.item.id)
}
1.7 内容协商Content negotiation
内容协商是对同一个资源(URI)返回不同表示方式的机制。
比如,在web service中,同一个资源可以输出多种格式(XML,JSON等)。
服务端驱动的协商通过Accept*头来执行。(http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html)
语言
可接受的语言使用
play.api.mvc.RequestHeader#acceptLanguages
来从
Accept-Language
头中获取值
排序按照quality factor(q参数)
play在
play.api.mvc.Controller#lang
中使用这个头并提供一个隐式的
play.api.i18n.Lang
到你的Action中
自动地使用最合适的语言(如果你的应用支持,不然使用默认的语言)
内容
play.api.mvc.RequestHeader#acceptedTypes
返回请求的MIME类型列表从请求的Accept头中获取
排序按照quality factor(q参数)
Accept头可能不包含具体的MIME类型而是一个媒体范围(比如 text/* 或 */*)
controller提供了高阶的render方法来帮助处理:
val list =Action{implicit request =>
val items =Item.findAll
render {
caseAccepts.Html()=>Ok(views.html.list(items))
caseAccepts.Json()=>Ok(Json.toJson(items))
}
}
Render方法的参数是一个偏函数
play.api.http.MediaRange =>play.api.mvc.Result
如果没有符合的会返回
NotAcceptable
请求抽取器(Request extractors)
可以查看
play.api.mvc.AcceptExtractors.Accepts
的API文档去查看在render方法中play内置支持的MIME类型
也可以用
play.api.mvc.Accepting样本类来创建自定义MIME类型抽取器
以下的代码就是创建一个自定义的audio/MP3 MIME类型的抽取器:
valAcceptsMp3=Accepting("audio/mp3")
render {
caseAcceptsMp3()=>???
}
}
本文来自: http://fair-jm.iteye.com/ 转截请注明出处
相关推荐
默认情况下与 Play 2.x + TypeScript + Webpack + Scalariform + Scalastyle + 配置的安全选项捆绑在一起的 Scala 项目模板。 内容 客户端: 替代JS :TypeScript 是 JavaScript 的超集,可以编译为干净的 ...
《Android 4.X 应用与开发实战手册:适用Android 4.X-2.X(第2版)》还介绍了如何将应用程序上传到Google Play(原Android Market)供全球Android移动设备用户下载,以及如何将Ad Mob广告板置入应用程序,即使应用...
### 如何部署Play 1.2.x:详细指南 Play框架是基于Java和Scala的轻量级Web开发框架,以其简单、快速的开发方式而受到欢迎。本文将详细介绍如何在Windows和Linux环境下部署Play 1.2.x版本,并提供具体的步骤和注意...
play2-auth, Play2.x 身份验证和授权模块 用于身份验证和授权的 Play2.x MODULE [Gitter](https://badges.gitter.im/Join chat 。svg )!这里 MODULE 为 Play2.x 应用程序提供身份验证和授权功能 Sc
适用于Play框架2.x的Memcached插件 Play 2.x的Cache API的Memcached实现。 在内部使用spymemcached,与Play 1.x的默认Cache实现相同。 用法 将以下依赖项添加到您的Play项目中: 库依赖 对于Play 2.6.x及更高版本:!...
这个过程会生成一个包含签名信息的新APK,证明该应用的代码和内容未经篡改,确保了应用的完整性和安全性。 `.x509.pem` 文件是公钥证书,遵循X.509标准。它包含了证书持有者的公开密钥以及证书颁发机构(CA)对这个...
在IT行业中,Play Framework是一个流行的Java和Scala全栈Web应用框架,它以其简洁的API和对测试驱动开发(TDD)的友好支持而受到开发者们的喜爱。MongoDB则是一款基于分布式文件存储的开源文档数据库系统,广泛应用于...
`signapk.jar`的工作原理是它接受一个公钥证书(`.x509.pem`)和一个私钥文件(`.pk8`),然后使用它们对APK的 `.apk` 文件进行签名,生成一个已签名的APK,这样设备才能识别并信任这个应用。 `platform.pk8`是平台...
play2-war-plugin, 用于 Play Framework 2.x的WAR插件 用于 Play Framework 2.x的 WAR插件Current versions: Play 2.2.x : 1.2.1 Play 2.3.0 -> 2.3.1 : 1.3-beta1 (Scala 2.1
微信v7.0.21.1821谷歌版+obb数据包.rar
《Cocos2d-x 3.X游戏开发实战》是由肖文吉编著的一本专业级游戏开发指南,专为想要掌握Cocos2d-x 3.X框架进行游戏开发的程序员设计。Cocos2d-x是一个开源的游戏开发框架,广泛应用于跨平台的2D游戏制作,支持iOS、...
Cocos2dx 3.x 是一个广泛使用的开源游戏开发框架,它基于C++,并提供了对多种平台的支持,包括Android。在这个示例中,我们关注的是如何将Cocos2dx 3.x游戏与Google Play Game Services集成,以便实现游戏排行榜功能...
A macro can now be repeated by using the Repeat play function. You can specify the number of repeats, or let the macro run to the end of the file A new Code Assistant preference has been added: ...
让play2.x支持ebean6.x 1,修改play项目的plugins.sbt //注释以在初始化期间获取更多信息logLevel:= Level.Warn //位于“ ”的Typesafe资源库解析器+ =“ Typesafe资源库” libraryDependencies ++ = Seq(“ ...
Google Play services_v22.42.12 (040400-481949630)_apkpure.com.xapk
黑群晖最经典的版本 DSM_DS918+_24922.pat
WAR Play框架2.x插件Current versions: Play 2.2.x : 1.2.1 Play 2.3.0 -> 2.3.1 : 1.3-beta1 (Scala 2.10 & 2.11) Play 2.3.2+ : 1.3-beta3 (Scala 2.10 & 2.11) Play 2.4.x : 1.4.0 (Scala 2.10 & 2.11) Play 2.5....
Google Play Store_40.3.31-23 [0] [PR] 619730322_Apkpure.xapk
1.第一位X * X defines Android version: 0 for Android 表示Android5.0以下版本 4 and 7 for Android >=5.0 // 4和7表示Android5.0及以上 8 for Android TV // 8表示Android电视应用 2.第二位Y * Y defines CPU ...