- 浏览: 2583679 次
- 性别:
- 来自: 成都
-
文章分类
最新评论
-
nation:
你好,在部署Mesos+Spark的运行环境时,出现一个现象, ...
Spark(4)Deal with Mesos -
sillycat:
AMAZON Relatedhttps://www.godad ...
AMAZON API Gateway(2)Client Side SSL with NGINX -
sillycat:
sudo usermod -aG docker ec2-use ...
Docker and VirtualBox(1)Set up Shared Disk for Virtual Box -
sillycat:
Every Half an Hour30 * * * * /u ...
Build Home NAS(3)Data Redundancy -
sillycat:
3 List the Cron Job I Have>c ...
Build Home NAS(3)Data Redundancy
Playframework(8)Scala Project and Asynchronous HTTP Programming
1.5 Body Parsers
An HTTP PUT or POST request contains a body. This body can use any format, specified in the Cotnent-Type request header.
In Play, a body parser transforms this request body into a Scala value.
More about Actions
Previously we said that an Action was a Request => Result function. This is not entirely true. Let's have a more precise look at the Action trait.
trait Action[A] extends (Request[A] => Result) {
def parser: BodyParser[A]
}
trait Request[+A] extends RequestHeader{
def body: A
}
To summarize, an Action[A] uses a BodyParser[A] to retrieve a value of type A from the HTTP request, and to build a Request[A] object that is passed to the action code.
Default body parser: AnyContent
If we did not specify our own body parser, Play will use the default, play.api.mvc.AnyContent. The body parser checks the Content-Type header and decides what kind of body to process:
text/plain: String
application/json: JsValue
text/xml: NodeSeq
application/form-url-encoded: Map[String, Seq[String]]
multipart/form-data: MultipartFormData[TemporaryFile]
any other content type: RawBuffer
Specifying a body parser
def save = Action(parse.text) { request =>
Ok("Got: " + request.body)
}
parse.text body parser will send a 400 BAD_REQUEST response if something goes wrong. We don't have to check again in our action code, and we can safely assume that request.body contains the valid String body.
Alternatively
def save = Action(parse.tolerantText) { request =>
Ok("Got: " + request.body)
}
This one doesn't check the Content-Type header and always loads the request body as a String.
def save = Action(parse.file(to = new File("/tmp/upload"))){ request =>
Ok("Save the request content to " + request.body)
}
Combining body parsers
In the previous example, all request bodies are stored in the same file, that is a bit problematic.
val storeInUserFile = parse.using { request =>
request.session.get("username").map{ user =>
file( to = new File("/tmp/" + user + ".upload"))
}.getOrElse{
error(Unauthorized("You don't have the right to upload here"))
}
}
def save = Action(storeInUserFile) { request =>
Ok("Saved the request content to " + request.body)
}
Max content length
There is a default content length (the default is 100KB), but you can also specify it inline:
def save = Action(parse.text(maxLength = 1024 * 10)) { request =>
Ok("Got: " + text)
}
The default content size can be defined in application.conf
parsers.text.maxLength=128K
1.6 Action Composition
Basic action composition
Provide a helper method building a standard action:
def LoggingAction( f: Request[AnyContent] => Result) : Action[AnyContent] = {
Action { request =>
Logger.info("Calling action")
f(request)
}
}
Then we can use this function like this:
def index = LoggingAction{ request =>
Ok("Hello World!")
}
This will work with the default parse.anyContent body parser.
def LoggingAction[A](bp: BodyParser[A]) (f:Request[A] => Result) : Action[A] = {
Action(bp) { request =>
Logge.info("Calling action")
f(request)
}
}
And then we can pass the body parser to that function
def index = LoggingAction(parse.text) { request =>
Ok("Hello World");
}
Wrapping existing actions
Another way to define our own LoggingAction that would be a wrapper over another Action:
case class Logging[A] (action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Result = {
Logger.info("Calling action")
action(request)
}
lazy val parser = action.parser
}
Wrap any other action:
def index = Logging {
Action{
Ok("Hello World")
}
}
def index = Logging{
Action(parse.text){
Ok("Hello World")
}
}
A more complicated example
I will choose directly use play.api.mvc.Security.authenticated
Another way to create the Authenticated action
…snip…
2. Asynchronous HTTP Programming
2.1 Handing asynchronous results
The same as Java, we need to response the client a promise of result.
…snip…
2.2 Streaming HTTP responses
…snip…
2.3 Comet Sockets
…snip...
3. The template engine
3.1 Template syntax
A type safe template engine based on Scala
Overview
A Play Scala template is a simple text file, that contains small block of Scala code. They can generate any text-based format, such as HTML, XML or CSV.
Naming convention
views/Application/index.scala.html
views.html.Application.index
@(customer: Customer, orders: Seq[Order])
<h1>Welcome @customer.name!</h1>
<ul>
@orders.map { order =>
<li>@order.title</li>
}
</ul>
We can then call this from any Scala code as we would call a function:
val html = views.html.Application.index(customer, orders)
The same as in Java Play project.
@**************************
* Comments
****************************@
3.2 Common Usecase
…snip…
4. HTTP form submission and validation
4.1 Form definitions
Defining a form in Project
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
}
)
This form can generate a (String, String) result value from Map[String, String] data:
val anyData = Map("email" -> "luohuazju@gmail.com", "password" -> "111111")
val (user, password) = loginForm.bind(anyData).get
Put the value into a tuple. We can do that to request.
val (use, password) = loginForm.bindFromRequest.get
Constructing complex objects
case class User(name: String, age: Int)
val userForm = Form(
mapping(
"name" -> text,
"age" -> number
)(User.apply)(User.unapply)
)
val anyData = Map("name" ->"sillycat", "age" ->"30")
val user: User = user form.bind(anyData).get
If we use class, we need to define apply and unapply, if we use tuple, we do not need that.
Checkbox for terms of service, we don't need to add this data to our User value. It is just a dummy field that is used for form validation but which doesn't carry any useful information once validated.
val userForm = Form(
mapping(
"name" -> text,
"age" -> number,
"accept" -> checked("Please accept the terms and conditions")
)((name, age, _) => User(name, age))
((user: User) => Some((user.name, user,age,false))
)
Defining constraints
For each mapping, you can also define additional validation constraints that will be checked during the binding phase.
case class User(name: String, age: Int)
val userForm = Form(
mapping(
"name" -> text.verifying(required),
"age" -> number.verifying(min(0), max(100))
)(User.apply)(User.unapply)
)
alternatively, we can write like this
mapping(
"name" -> nonEmptyText,
"age" -> number(min=0, max=100)
)
ad-hoc constraints
val loginForm = Form(
tuple(
"email" -> nonEmptyText,
"password" -> text
) verifying("Invalid user name or password", fields => fields match{
case(e,p) => User.authenticate(e,p).isDefined
})
)
Handling binding failure
use fold operation for binding errors.
loginForm.bindFromRequest.fold(
formWithErrors => // binding failure, you retrieve the form containing errors
value => //binding success, you get the actual value
)
Fill a form with initial default values
val filledForm = userForm.fill(User("Carl", 18))
Nested values
case class User(name: String, address: Address)
case class Address(street: String, city: String)
val userForm = Form(
mapping(
"name" -> text,
"address" -> mapping(
"street" -> text,
"city" -> text
)(Address.apply)(Address.unapply)
)(User.apply, User.unapply)
)
The form values sent by the browser must be named like this:
address,street, address.city
Repeated values
case class User(name: String, emails: List[String])
val userForm = Form(
mapping(
"name" -> text,
"emails" -> list(text)
)(User.apply, User.unapply)
)
The form values sent by the browser must be named
emails[0], emails[1], emails[2], etc.
Optional values
case class User(name: String, email: Option[String])
val userForm = Form(
mapping(
"name" -> text,
"email" -> optiional(text)
)(User.apply, User.unapply)
)
Ignored values
case class User(id: Long, name: String, email: Option[String])
val userForm = Form(
mapping(
"id" -> ignored(1234),
"name" -> text,
"email" -> optional(text)
)(User.apply, User.unapply)
)
4.2 Using the form template helpers
@helper.form(action = routes.Application.submit, 'id->"myForm") {
}
Mostly the same as Play Java Project.
References:
http://www.playframework.org/documentation/2.0.4/ScalaHome
http://www.playframework.org/documentation/2.0.4/ScalaBodyParsers
1.5 Body Parsers
An HTTP PUT or POST request contains a body. This body can use any format, specified in the Cotnent-Type request header.
In Play, a body parser transforms this request body into a Scala value.
More about Actions
Previously we said that an Action was a Request => Result function. This is not entirely true. Let's have a more precise look at the Action trait.
trait Action[A] extends (Request[A] => Result) {
def parser: BodyParser[A]
}
trait Request[+A] extends RequestHeader{
def body: A
}
To summarize, an Action[A] uses a BodyParser[A] to retrieve a value of type A from the HTTP request, and to build a Request[A] object that is passed to the action code.
Default body parser: AnyContent
If we did not specify our own body parser, Play will use the default, play.api.mvc.AnyContent. The body parser checks the Content-Type header and decides what kind of body to process:
text/plain: String
application/json: JsValue
text/xml: NodeSeq
application/form-url-encoded: Map[String, Seq[String]]
multipart/form-data: MultipartFormData[TemporaryFile]
any other content type: RawBuffer
Specifying a body parser
def save = Action(parse.text) { request =>
Ok("Got: " + request.body)
}
parse.text body parser will send a 400 BAD_REQUEST response if something goes wrong. We don't have to check again in our action code, and we can safely assume that request.body contains the valid String body.
Alternatively
def save = Action(parse.tolerantText) { request =>
Ok("Got: " + request.body)
}
This one doesn't check the Content-Type header and always loads the request body as a String.
def save = Action(parse.file(to = new File("/tmp/upload"))){ request =>
Ok("Save the request content to " + request.body)
}
Combining body parsers
In the previous example, all request bodies are stored in the same file, that is a bit problematic.
val storeInUserFile = parse.using { request =>
request.session.get("username").map{ user =>
file( to = new File("/tmp/" + user + ".upload"))
}.getOrElse{
error(Unauthorized("You don't have the right to upload here"))
}
}
def save = Action(storeInUserFile) { request =>
Ok("Saved the request content to " + request.body)
}
Max content length
There is a default content length (the default is 100KB), but you can also specify it inline:
def save = Action(parse.text(maxLength = 1024 * 10)) { request =>
Ok("Got: " + text)
}
The default content size can be defined in application.conf
parsers.text.maxLength=128K
1.6 Action Composition
Basic action composition
Provide a helper method building a standard action:
def LoggingAction( f: Request[AnyContent] => Result) : Action[AnyContent] = {
Action { request =>
Logger.info("Calling action")
f(request)
}
}
Then we can use this function like this:
def index = LoggingAction{ request =>
Ok("Hello World!")
}
This will work with the default parse.anyContent body parser.
def LoggingAction[A](bp: BodyParser[A]) (f:Request[A] => Result) : Action[A] = {
Action(bp) { request =>
Logge.info("Calling action")
f(request)
}
}
And then we can pass the body parser to that function
def index = LoggingAction(parse.text) { request =>
Ok("Hello World");
}
Wrapping existing actions
Another way to define our own LoggingAction that would be a wrapper over another Action:
case class Logging[A] (action: Action[A]) extends Action[A] {
def apply(request: Request[A]): Result = {
Logger.info("Calling action")
action(request)
}
lazy val parser = action.parser
}
Wrap any other action:
def index = Logging {
Action{
Ok("Hello World")
}
}
def index = Logging{
Action(parse.text){
Ok("Hello World")
}
}
A more complicated example
I will choose directly use play.api.mvc.Security.authenticated
Another way to create the Authenticated action
…snip…
2. Asynchronous HTTP Programming
2.1 Handing asynchronous results
The same as Java, we need to response the client a promise of result.
…snip…
2.2 Streaming HTTP responses
…snip…
2.3 Comet Sockets
…snip...
3. The template engine
3.1 Template syntax
A type safe template engine based on Scala
Overview
A Play Scala template is a simple text file, that contains small block of Scala code. They can generate any text-based format, such as HTML, XML or CSV.
Naming convention
views/Application/index.scala.html
views.html.Application.index
@(customer: Customer, orders: Seq[Order])
<h1>Welcome @customer.name!</h1>
<ul>
@orders.map { order =>
<li>@order.title</li>
}
</ul>
We can then call this from any Scala code as we would call a function:
val html = views.html.Application.index(customer, orders)
The same as in Java Play project.
@**************************
* Comments
****************************@
3.2 Common Usecase
…snip…
4. HTTP form submission and validation
4.1 Form definitions
Defining a form in Project
val loginForm = Form(
tuple(
"email" -> text,
"password" -> text
}
)
This form can generate a (String, String) result value from Map[String, String] data:
val anyData = Map("email" -> "luohuazju@gmail.com", "password" -> "111111")
val (user, password) = loginForm.bind(anyData).get
Put the value into a tuple. We can do that to request.
val (use, password) = loginForm.bindFromRequest.get
Constructing complex objects
case class User(name: String, age: Int)
val userForm = Form(
mapping(
"name" -> text,
"age" -> number
)(User.apply)(User.unapply)
)
val anyData = Map("name" ->"sillycat", "age" ->"30")
val user: User = user form.bind(anyData).get
If we use class, we need to define apply and unapply, if we use tuple, we do not need that.
Checkbox for terms of service, we don't need to add this data to our User value. It is just a dummy field that is used for form validation but which doesn't carry any useful information once validated.
val userForm = Form(
mapping(
"name" -> text,
"age" -> number,
"accept" -> checked("Please accept the terms and conditions")
)((name, age, _) => User(name, age))
((user: User) => Some((user.name, user,age,false))
)
Defining constraints
For each mapping, you can also define additional validation constraints that will be checked during the binding phase.
case class User(name: String, age: Int)
val userForm = Form(
mapping(
"name" -> text.verifying(required),
"age" -> number.verifying(min(0), max(100))
)(User.apply)(User.unapply)
)
alternatively, we can write like this
mapping(
"name" -> nonEmptyText,
"age" -> number(min=0, max=100)
)
ad-hoc constraints
val loginForm = Form(
tuple(
"email" -> nonEmptyText,
"password" -> text
) verifying("Invalid user name or password", fields => fields match{
case(e,p) => User.authenticate(e,p).isDefined
})
)
Handling binding failure
use fold operation for binding errors.
loginForm.bindFromRequest.fold(
formWithErrors => // binding failure, you retrieve the form containing errors
value => //binding success, you get the actual value
)
Fill a form with initial default values
val filledForm = userForm.fill(User("Carl", 18))
Nested values
case class User(name: String, address: Address)
case class Address(street: String, city: String)
val userForm = Form(
mapping(
"name" -> text,
"address" -> mapping(
"street" -> text,
"city" -> text
)(Address.apply)(Address.unapply)
)(User.apply, User.unapply)
)
The form values sent by the browser must be named like this:
address,street, address.city
Repeated values
case class User(name: String, emails: List[String])
val userForm = Form(
mapping(
"name" -> text,
"emails" -> list(text)
)(User.apply, User.unapply)
)
The form values sent by the browser must be named
emails[0], emails[1], emails[2], etc.
Optional values
case class User(name: String, email: Option[String])
val userForm = Form(
mapping(
"name" -> text,
"email" -> optiional(text)
)(User.apply, User.unapply)
)
Ignored values
case class User(id: Long, name: String, email: Option[String])
val userForm = Form(
mapping(
"id" -> ignored(1234),
"name" -> text,
"email" -> optional(text)
)(User.apply, User.unapply)
)
4.2 Using the form template helpers
@helper.form(action = routes.Application.submit, 'id->"myForm") {
}
Mostly the same as Play Java Project.
References:
http://www.playframework.org/documentation/2.0.4/ScalaHome
http://www.playframework.org/documentation/2.0.4/ScalaBodyParsers
发表评论
-
NodeJS12 and Zlib
2020-04-01 07:44 509NodeJS12 and Zlib It works as ... -
Traefik 2020(1)Introduction and Installation
2020-03-29 13:52 370Traefik 2020(1)Introduction and ... -
Private Registry 2020(1)No auth in registry Nginx AUTH for UI
2020-03-18 00:56 470Private Registry 2020(1)No auth ... -
Buffer in NodeJS 12 and NodeJS 8
2020-02-25 06:43 420Buffer in NodeJS 12 and NodeJS ... -
NodeJS ENV Similar to JENV and PyENV
2020-02-25 05:14 516NodeJS ENV Similar to JENV and ... -
Prometheus HA 2020(3)AlertManager Cluster
2020-02-24 01:47 452Prometheus HA 2020(3)AlertManag ... -
Serverless with NodeJS and TencentCloud 2020(5)CRON and Settings
2020-02-24 01:46 354Serverless with NodeJS and Tenc ... -
GraphQL 2019(3)Connect to MySQL
2020-02-24 01:48 273GraphQL 2019(3)Connect to MySQL ... -
GraphQL 2019(2)GraphQL and Deploy to Tencent Cloud
2020-02-24 01:48 473GraphQL 2019(2)GraphQL and Depl ... -
GraphQL 2019(1)Apollo Basic
2020-02-19 01:36 349GraphQL 2019(1)Apollo Basic Cl ... -
Serverless with NodeJS and TencentCloud 2020(4)Multiple Handlers and Running wit
2020-02-19 01:19 334Serverless with NodeJS and Tenc ... -
Serverless with NodeJS and TencentCloud 2020(3)Build Tree and Traverse Tree
2020-02-19 01:19 345Serverless with NodeJS and Tenc ... -
Serverless with NodeJS and TencentCloud 2020(2)Trigger SCF in SCF
2020-02-19 01:18 317Serverless with NodeJS and Tenc ... -
Serverless with NodeJS and TencentCloud 2020(1)Running with Component
2020-02-19 01:17 332Serverless with NodeJS and Tenc ... -
NodeJS MySQL Library and npmjs
2020-02-07 06:21 321NodeJS MySQL Library and npmjs ... -
Python Library 2019(1)requests and aiohttp
2019-12-18 01:12 283Python Library 2019(1)requests ... -
NodeJS Installation 2019
2019-10-20 02:57 597NodeJS Installation 2019 Insta ... -
Monitor Tool 2019(2)Monit on Multiple Instances and Email Alerts
2019-10-18 10:57 294Monitor Tool 2019(2)Monit on Mu ... -
Sqlite Database 2019(1)Sqlite3 Installation and Docker phpsqliteadmin
2019-09-05 11:24 406Sqlite Database 2019(1)Sqlite3 ... -
Supervisor 2019(2)Ubuntu and Multiple Services
2019-08-19 10:53 393Supervisor 2019(2)Ubuntu and Mu ...
相关推荐
Mastering Play Framework for Scala
Leverage the awesome features of Play Framework to build scalable, resilient, and responsive applications First published: May 2015 274page
Mastering Play Framework for Scala 英文无水印pdf pdf使用FoxitReader和PDF-XChangeViewer测试可以打开
Mastering Play Framework for Scala 英文mobi 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
Mastering Play Framework for Scala 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
Harness reactive programming to build scalable and fault-tolerant distributed systems using Scala and Akka About This Book Use the concepts of reactive programming to build distributed systems ...
《精通Scala的Play框架》是一本专为Scala开发者设计的深度学习指南,旨在帮助读者全面理解和熟练运用Play框架。Play框架是构建Web应用程序的一个强大工具,尤其在Scala语言的支持下,它提供了高度的灵活性和效率。这...
注意是Programming Scala的第二版,而不是Programming in Scala的第二版,更注重于与Spark相关的知识!强烈推荐!Programming Scala- Scalability = Functional Programming + Objects, 2 edition
总之,《Programming in Scala》是一本非常有价值的书籍,无论你是初学者还是有经验的程序员,都能从中获得宝贵的知识和技能。通过本书的学习,你可以更好地理解和运用Scala这一强大而优雅的编程语言。
This book is intended for those developers who are keen to master the internal workings of Play Framework to effectively build and deploy web-related apps.
《Programming In Scala》是一本权威的Scala编程语言教程,它由Martin Odersky(Scala的创造者)、Lex Spoon 和 Bill Venners 共同编写。中文版包含了1到13章的内容,这些章节涵盖了Scala的基础知识和基本应用,适合...
Play Framework 是一个基于Java和Scala的高性能Web应用框架,它提供了快速开发、可测试和敏捷迭代的能力。在Play Framework中,安全模块是一个重要的组件,它帮助开发者实现基本的认证(Authentication)和授权...
Play Framework是一種用Scala編寫的Web應用框架,其遵循模型-視圖-控制器建築模式。Play Framework使用Scala編寫,並可以被編譯成Java虛擬機器位元組碼中的其他編程語言使用;例如Java語言。
英文原版 scala函数式编程 function programming in scala
Programming in Scala is the definitive book on Scala, the new language for the Java Platform that blends object-oriented and functional programming concepts into a unique and powerful tool for ...