- 浏览: 2551618 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
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(9)Scala Project and Working with JSON
5. Working with JSON
5.1 The Play JSON library
We recommend to deal with JSON based the type class library play.api.libs.json.
This library is built on top of https://github.com/codahale/jerkson/, which is a Scala wrapper around the super-fast java based JSON library, Jackson.
There are some JSON data types:
JsObject
JsNull
JsUndefined
JsBoolean
JsNumber
JsArray
JsString
All of them inherit from the generic JSON value, JsValue.
Parsing a Json String
val json: JsValue = Json.parse(jsonString)
Navigating into a Json tree
As soon as we have a JsValue we can navigate into the tree.
val json = Json.parse(jsonString)
val maybeName = (json \ "user" \ name).asOpt[String]
val emails = (json \ "user" \\ "emails").map(_.as[String])
asOpt[T] that will return None if the value is missing.
Otherwise we can use as[T] that we fail with an exception if the value was missing.
Converting a Scala value to Json
val jsonNumber = Json.toJson(4)
val jsonArray = Json.toJson(Seq(1, 2, 3, 4))
It is complicated if the Seq contains some other values than Int, for example:
Seq(1, "Carl", 3, 4)
val jsonArray = Json.toJson(Seq(
toJson(1), toJson("Carl"), toJson(3), toJson(4)
))
Serializing Json
val jsonString: String = Json.stringify(jsValue)
Other Options
…snip...
5.2 Handling and serving JSON requests
def sayHi = Action { reqeust =>
request.body.asJson.map { json =>
(json \ "name").asOpt[String].map { name =>
Ok("Hello " + name)
}.getOrElse{
BadRequest("Missing parameter [name] ")
}
}.getOrElse{
BadRequest("Expecting Json data")
}
}
Better and Simpler to specify our own BodyParser
def sayHi = Action(parse.json) { request =>
(request.body \ "name").asOpt[String].map { name =>
Ok("Hello " + name)
}.getOrElse{
…snip...
}
}
We can use command line cURL
>curl
--header "Content-type: application/json"
--request POST
--data '{"name": "Carl"}'
http://localhost:9000/sayHi
Serving a JSON response
def sayHi = Action(parse.json) { request =>
(request.body \ "name").asOpt[String].map { name =>
Ok(toJson(
Map("status" -> "OK", "message" -> ("Hello " + name))
))
}.getOrElse{
BadRequest(toJson(
Map("status" -> "KO", "message" -> "Missing parameter [name]")
))
}
}
6. Working with XML
Handling an XML request
def sayHi = Action { request =>
request.body.asXml.map { xml =>
(xml \\ "name" headOption).map(_.text).map { name=>
Ok("Hello " + name)
}.getOrElse{
BadRequest("Missing parameter [name]")
}
}.getOrElse{
BadRequest("Expecting XML data")
}
}
def sayHi = Action(parse.xml) { request =>
(request.body \\ "name" headOption).map(_.text).map { name=>
Ok("Hello " + name)
}.getOrElse{
BadRequet("Missing parameter [name])
}
}
Serving an XML response
def sayHi = Action(parse.xml) { request =>
(request.body \\ "name" headOption).map(_.text).map { name =>
Ok(<message status="OK"> Hello {name}</message>)
}.getOrElse{
BadRequest(<message status="KO">Missing parameter [name]</message>)
}
}
7 Handling file upload
Uploading files in a form using multipart/form-data
@form(action = routes.Application.upload, 'enctype -> "multipart/form-data")
<input type="file" name="picture">
<p><input type="submit"></p>
}
def upload = Action(parse.multipartFormData) { request =>
request.body.file("picture").map { picture =>
import java.io.File
val filename = picture.filename
val contentType = picture.contentType
picture.ref.moveTo(new File("/tmp/picture"))
Ok("File uploaded")
}.getOrElse{
Redirect(routes.Application.index).flashing(
"error" -> "Missing file"
)
}
}
The ref attribute gives me a reference to a TemporaryFile.
Direct file upload
AJAX upload the file asynchronously in a form.
Writing Our Own Body Parser
8. Accessing an SQL database
8.1 Configuring and Using JDBC
SQLite database engine connection properties
db.default.driver=org.sqlite.JDBC
db.default.url="jdbc:sqlite:/path/to/db-file"
Accessing the JDBC datasource
The play.api.db package provides access to the configured data sources:
val ds = DB.getDataSource()
Obtaining a JDBC connection
val connection = DB.getConnection()
We need to call close after we use the connection. We can do that in another way:
//access "default" database
DB.withConnection{ conn =>
//do whatever you need with the connection
}
//access "orders" database instead of "default"
DB.withConnection("orders") { conn =>
//
}
8.2 Anorm, simple SQL data access
Play includes a simple data access layer called Anorm that uses plain SQL to interact with the database and provides an API to parse and transform the resulting datasets.
mysql configuration
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/world"
db.default.user=root
db.default.password=111111
Overview
It can feel strange to return to plain old SQL to access an SQL database these days. Java Developers accustomed to using a high-level Object Relational Mapper like Hibernate.
But we think these tools are not needed at all when you have the power of a high-level programming language like Scala. On the contrary, they will quickly become counter-productive.
Using JDBC is a pain, but we provide a better API
You don't need another DSL to access relational databases
SQL is already the best DSL for accessing relational databases. We don't need to invent something new.
A type safe DSL to generate SQL is a mistake
Take Control of your SQL code
Executing SQL queries
import anorm._
DB.withConnection { implicit c =>
val result: Boolean = SQL("Select 1").execute()
}
The execute() method returns a Boolean value indicating whether the execution was successful.
To execute an update, you can use executeUpdate(), which returns the number of rows updated.
val result: Int = SQL("delete from City where id = 99").executeUpdate()
If we plan to insert data that has an auto-generated Long primary key, you can call executeInsert().
val id: Int = SQL("insert into City(name, country) values ({name}, {country}")
.on("Cambridge", "New Zealand").executeInsert();
Since Scala supports multi-line strings, feel free to use them for complex SQL statement:
val sqlQuery = SQL(
"""
select * from Country c
join CountryLanguage l on l.CountryCode = c.Code
where c.code = 'FRA';
"""
)
If our SQL query needs dynamic parameters, we can declare placeholders like {name} in the query string, and later assign a value to them:
SQL(
"""
select * from Country c
join CountryLanguage l on l.CountryCode = c.Code
where c.code = {countryCode};
"""
).on("countryCode" -> "FRA")
Retrieving data using the Stream API
The first way to access the results of a select query is to use the Stream API.
When you call apply() on any SQL statement, you will receive a lazy Stream of Row instances, where each row can be seen as a dictionary:
//Create an SQL query
val selectCountries = SQL("Select * from Country")
//Transform the resulting Stream[Row] to a List[(String, String)]
val countries = selectCountries().map(row =>
row[String]("code") -> row[String]("name")
).toList
Count the number of Country entries in the database, so the result set will be a single row with a single column:
val firstRow = SQL("Select count(*) as c from Country").apply().head
//Next get the content of the 'c' column as Long
val countryCount = firstRow[Long]("c")
Using Pattern Matching
…snip…
Special data types
Clobs
SQL("Select name, summary from Country")().map{
case Row(name: String, summary: java.sql.Clob) => name -> summary
}
Binary
SQL("Select name, image from Country")().map{
case Row(name: String, image: Array[Byte]) => name ->image
}
Dealing with Nullable columns
If a column can contain Null values in the database schema, you need to manipulate it as an Option type.
SQL("Select name, indepYear from Country")().collect {
case Row(name:String, Some(year:int)) => name -> year
}
If we try to retrieve the column content as Int directly from the dictionary
SQL("Select name, indepYear from Country")().map{ row =>
row[String]("name") -> row[Int]("indepYear")
}
This will produce an UnexpectedNullableFound(COUNTRY.INDEPYEAR) exception if it encounters a null value.
We need to write like this to an Option[Int]
SQL("Select name, indepYear from Country")().map { row =>
row[String]("name") -> row[Option[Int]]("indepYear")
}
References:
http://www.playframework.org/documentation/2.0.4/ScalaHome
http://www.playframework.org/documentation/2.0.4/ScalaXmlRequests
5. Working with JSON
5.1 The Play JSON library
We recommend to deal with JSON based the type class library play.api.libs.json.
This library is built on top of https://github.com/codahale/jerkson/, which is a Scala wrapper around the super-fast java based JSON library, Jackson.
There are some JSON data types:
JsObject
JsNull
JsUndefined
JsBoolean
JsNumber
JsArray
JsString
All of them inherit from the generic JSON value, JsValue.
Parsing a Json String
val json: JsValue = Json.parse(jsonString)
Navigating into a Json tree
As soon as we have a JsValue we can navigate into the tree.
val json = Json.parse(jsonString)
val maybeName = (json \ "user" \ name).asOpt[String]
val emails = (json \ "user" \\ "emails").map(_.as[String])
asOpt[T] that will return None if the value is missing.
Otherwise we can use as[T] that we fail with an exception if the value was missing.
Converting a Scala value to Json
val jsonNumber = Json.toJson(4)
val jsonArray = Json.toJson(Seq(1, 2, 3, 4))
It is complicated if the Seq contains some other values than Int, for example:
Seq(1, "Carl", 3, 4)
val jsonArray = Json.toJson(Seq(
toJson(1), toJson("Carl"), toJson(3), toJson(4)
))
Serializing Json
val jsonString: String = Json.stringify(jsValue)
Other Options
…snip...
5.2 Handling and serving JSON requests
def sayHi = Action { reqeust =>
request.body.asJson.map { json =>
(json \ "name").asOpt[String].map { name =>
Ok("Hello " + name)
}.getOrElse{
BadRequest("Missing parameter [name] ")
}
}.getOrElse{
BadRequest("Expecting Json data")
}
}
Better and Simpler to specify our own BodyParser
def sayHi = Action(parse.json) { request =>
(request.body \ "name").asOpt[String].map { name =>
Ok("Hello " + name)
}.getOrElse{
…snip...
}
}
We can use command line cURL
>curl
--header "Content-type: application/json"
--request POST
--data '{"name": "Carl"}'
http://localhost:9000/sayHi
Serving a JSON response
def sayHi = Action(parse.json) { request =>
(request.body \ "name").asOpt[String].map { name =>
Ok(toJson(
Map("status" -> "OK", "message" -> ("Hello " + name))
))
}.getOrElse{
BadRequest(toJson(
Map("status" -> "KO", "message" -> "Missing parameter [name]")
))
}
}
6. Working with XML
Handling an XML request
def sayHi = Action { request =>
request.body.asXml.map { xml =>
(xml \\ "name" headOption).map(_.text).map { name=>
Ok("Hello " + name)
}.getOrElse{
BadRequest("Missing parameter [name]")
}
}.getOrElse{
BadRequest("Expecting XML data")
}
}
def sayHi = Action(parse.xml) { request =>
(request.body \\ "name" headOption).map(_.text).map { name=>
Ok("Hello " + name)
}.getOrElse{
BadRequet("Missing parameter [name])
}
}
Serving an XML response
def sayHi = Action(parse.xml) { request =>
(request.body \\ "name" headOption).map(_.text).map { name =>
Ok(<message status="OK"> Hello {name}</message>)
}.getOrElse{
BadRequest(<message status="KO">Missing parameter [name]</message>)
}
}
7 Handling file upload
Uploading files in a form using multipart/form-data
@form(action = routes.Application.upload, 'enctype -> "multipart/form-data")
<input type="file" name="picture">
<p><input type="submit"></p>
}
def upload = Action(parse.multipartFormData) { request =>
request.body.file("picture").map { picture =>
import java.io.File
val filename = picture.filename
val contentType = picture.contentType
picture.ref.moveTo(new File("/tmp/picture"))
Ok("File uploaded")
}.getOrElse{
Redirect(routes.Application.index).flashing(
"error" -> "Missing file"
)
}
}
The ref attribute gives me a reference to a TemporaryFile.
Direct file upload
AJAX upload the file asynchronously in a form.
Writing Our Own Body Parser
8. Accessing an SQL database
8.1 Configuring and Using JDBC
SQLite database engine connection properties
db.default.driver=org.sqlite.JDBC
db.default.url="jdbc:sqlite:/path/to/db-file"
Accessing the JDBC datasource
The play.api.db package provides access to the configured data sources:
val ds = DB.getDataSource()
Obtaining a JDBC connection
val connection = DB.getConnection()
We need to call close after we use the connection. We can do that in another way:
//access "default" database
DB.withConnection{ conn =>
//do whatever you need with the connection
}
//access "orders" database instead of "default"
DB.withConnection("orders") { conn =>
//
}
8.2 Anorm, simple SQL data access
Play includes a simple data access layer called Anorm that uses plain SQL to interact with the database and provides an API to parse and transform the resulting datasets.
mysql configuration
db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/world"
db.default.user=root
db.default.password=111111
Overview
It can feel strange to return to plain old SQL to access an SQL database these days. Java Developers accustomed to using a high-level Object Relational Mapper like Hibernate.
But we think these tools are not needed at all when you have the power of a high-level programming language like Scala. On the contrary, they will quickly become counter-productive.
Using JDBC is a pain, but we provide a better API
You don't need another DSL to access relational databases
SQL is already the best DSL for accessing relational databases. We don't need to invent something new.
A type safe DSL to generate SQL is a mistake
Take Control of your SQL code
Executing SQL queries
import anorm._
DB.withConnection { implicit c =>
val result: Boolean = SQL("Select 1").execute()
}
The execute() method returns a Boolean value indicating whether the execution was successful.
To execute an update, you can use executeUpdate(), which returns the number of rows updated.
val result: Int = SQL("delete from City where id = 99").executeUpdate()
If we plan to insert data that has an auto-generated Long primary key, you can call executeInsert().
val id: Int = SQL("insert into City(name, country) values ({name}, {country}")
.on("Cambridge", "New Zealand").executeInsert();
Since Scala supports multi-line strings, feel free to use them for complex SQL statement:
val sqlQuery = SQL(
"""
select * from Country c
join CountryLanguage l on l.CountryCode = c.Code
where c.code = 'FRA';
"""
)
If our SQL query needs dynamic parameters, we can declare placeholders like {name} in the query string, and later assign a value to them:
SQL(
"""
select * from Country c
join CountryLanguage l on l.CountryCode = c.Code
where c.code = {countryCode};
"""
).on("countryCode" -> "FRA")
Retrieving data using the Stream API
The first way to access the results of a select query is to use the Stream API.
When you call apply() on any SQL statement, you will receive a lazy Stream of Row instances, where each row can be seen as a dictionary:
//Create an SQL query
val selectCountries = SQL("Select * from Country")
//Transform the resulting Stream[Row] to a List[(String, String)]
val countries = selectCountries().map(row =>
row[String]("code") -> row[String]("name")
).toList
Count the number of Country entries in the database, so the result set will be a single row with a single column:
val firstRow = SQL("Select count(*) as c from Country").apply().head
//Next get the content of the 'c' column as Long
val countryCount = firstRow[Long]("c")
Using Pattern Matching
…snip…
Special data types
Clobs
SQL("Select name, summary from Country")().map{
case Row(name: String, summary: java.sql.Clob) => name -> summary
}
Binary
SQL("Select name, image from Country")().map{
case Row(name: String, image: Array[Byte]) => name ->image
}
Dealing with Nullable columns
If a column can contain Null values in the database schema, you need to manipulate it as an Option type.
SQL("Select name, indepYear from Country")().collect {
case Row(name:String, Some(year:int)) => name -> year
}
If we try to retrieve the column content as Int directly from the dictionary
SQL("Select name, indepYear from Country")().map{ row =>
row[String]("name") -> row[Int]("indepYear")
}
This will produce an UnexpectedNullableFound(COUNTRY.INDEPYEAR) exception if it encounters a null value.
We need to write like this to an Option[Int]
SQL("Select name, indepYear from Country")().map { row =>
row[String]("name") -> row[Option[Int]]("indepYear")
}
References:
http://www.playframework.org/documentation/2.0.4/ScalaHome
http://www.playframework.org/documentation/2.0.4/ScalaXmlRequests
发表评论
-
NodeJS12 and Zlib
2020-04-01 07:44 475NodeJS12 and Zlib It works as ... -
Traefik 2020(1)Introduction and Installation
2020-03-29 13:52 336Traefik 2020(1)Introduction and ... -
Private Registry 2020(1)No auth in registry Nginx AUTH for UI
2020-03-18 00:56 435Private Registry 2020(1)No auth ... -
Buffer in NodeJS 12 and NodeJS 8
2020-02-25 06:43 384Buffer in NodeJS 12 and NodeJS ... -
NodeJS ENV Similar to JENV and PyENV
2020-02-25 05:14 478NodeJS ENV Similar to JENV and ... -
Prometheus HA 2020(3)AlertManager Cluster
2020-02-24 01:47 423Prometheus HA 2020(3)AlertManag ... -
Serverless with NodeJS and TencentCloud 2020(5)CRON and Settings
2020-02-24 01:46 337Serverless with NodeJS and Tenc ... -
GraphQL 2019(3)Connect to MySQL
2020-02-24 01:48 247GraphQL 2019(3)Connect to MySQL ... -
GraphQL 2019(2)GraphQL and Deploy to Tencent Cloud
2020-02-24 01:48 450GraphQL 2019(2)GraphQL and Depl ... -
GraphQL 2019(1)Apollo Basic
2020-02-19 01:36 328GraphQL 2019(1)Apollo Basic Cl ... -
Serverless with NodeJS and TencentCloud 2020(4)Multiple Handlers and Running wit
2020-02-19 01:19 314Serverless with NodeJS and Tenc ... -
Serverless with NodeJS and TencentCloud 2020(3)Build Tree and Traverse Tree
2020-02-19 01:19 317Serverless with NodeJS and Tenc ... -
Serverless with NodeJS and TencentCloud 2020(2)Trigger SCF in SCF
2020-02-19 01:18 293Serverless with NodeJS and Tenc ... -
Serverless with NodeJS and TencentCloud 2020(1)Running with Component
2020-02-19 01:17 312Serverless with NodeJS and Tenc ... -
NodeJS MySQL Library and npmjs
2020-02-07 06:21 288NodeJS MySQL Library and npmjs ... -
Python Library 2019(1)requests and aiohttp
2019-12-18 01:12 261Python Library 2019(1)requests ... -
NodeJS Installation 2019
2019-10-20 02:57 573NodeJS Installation 2019 Insta ... -
Monitor Tool 2019(2)Monit on Multiple Instances and Email Alerts
2019-10-18 10:57 265Monitor Tool 2019(2)Monit on Mu ... -
Sqlite Database 2019(1)Sqlite3 Installation and Docker phpsqliteadmin
2019-09-05 11:24 368Sqlite Database 2019(1)Sqlite3 ... -
Supervisor 2019(2)Ubuntu and Multiple Services
2019-08-19 10:53 370Supervisor 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删除
《精通Scala的Play框架》是一本专为Scala开发者设计的深度学习指南,旨在帮助读者全面理解和熟练运用Play框架。Play框架是构建Web应用程序的一个强大工具,尤其在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.
Play Framework 是一个基于Java和Scala的高性能Web应用框架,它提供了快速开发、可测试和敏捷迭代的能力。在Play Framework中,安全模块是一个重要的组件,它帮助开发者实现基本的认证(Authentication)和授权...
Play Framework是一種用Scala編寫的Web應用框架,其遵循模型-視圖-控制器建築模式。Play Framework使用Scala編寫,並可以被編譯成Java虛擬機器位元組碼中的其他編程語言使用;例如Java語言。
本范例是一个Scala工程,结合Java组件实现了对spark产品分析的结果json文件进行解析,将其内部的几何对象转换为记录集写入数据集里,由于Scala读写文件的效率比较高,故采用Scala与Java组件实现。
标题“scala-json”指的是这个特定的库,可能是社区广泛使用的开源项目,比如“play-json”或“circe”。描述中的“源码 scala json master”表明这是一个项目的主分支源代码,通常可以从GitHub等版本控制系统中获取...
Play Framework 是一个开源的Web应用框架,主要针对Java和Scala开发者设计,它的核心理念是简化开发流程,提高开发效率,并且特别强调了RESTful架构风格。这个“playframework中文教程.zip”压缩包很可能是为了帮助...
- **框架简介**:Play Framework 是一个开源的 Web 开发框架,基于 Java 和 Scala 编程语言。它采用轻量级、非阻塞的服务端架构,特别适合开发高性能、可扩展的应用程序。Play Framework 通过其独特的设计理念简化了...
9. **隐式转换**:Scala的隐式转换允许在特定上下文中将一个类型转换为另一个类型,这可以简化API的使用,但需谨慎使用,以免引入不必要的复杂性。 10. **元编程**:Scala的反射和类型系统支持元编程,即在运行时...
Play Framework 是一个开源的Web应用框架,用于构建现代、高性能的Java和Scala应用程序。它采用模型-视图-控制器(MVC)架构模式,并且强调简洁的代码和开发的即时反馈。Play Framework API 是开发者使用该框架进行...
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 ...
Play Framework DDD示例Play框架的DDD示例播放框架:2.6.x Scala(Scala):2.12.6用例文章:创建并显示文章详细信息帐户:创建帐户并登录draw.io上的设计域:/ designs 给我一颗星星 :glowing_star: 如果你喜欢他们...
【play2+scala+mongodb demo示例】是一个用于学习如何集成和使用Play Framework 2、Scala编程语言以及MongoDB数据库的实战项目。这个项目旨在帮助初学者理解这三者之间的协同工作,通过创建一个基本的CRUD(创建、...