概述
使用JSON的推荐方式是使用 Play 的基于类的JSON库,位于play.api.libs.json下.
该库构建于Jerkson之上,它是一个Scala包装者,基于一个超快的基于Java的JSON库,Jackson.
这种方式的好处是,Java和Scala可以共享同样的库(Jackson),而Scala用户可以享受额外类型安全的好处。play.api.libs.json包中,包含了7个JSON数据类型:
JsObject
JsNull
JsUndefined
JsBoolean
JsNumber
JsArray
JsString
它们都继承自JsValue。
解析JSON字符串
你可以將任何的JSON字符串解析成JsValue。
1
|
val
json
:
JsValue
=
Json.parse(jsonString)
|
遍历JSON树
只要你拥有一个JsValue,你就可以遍历该树。该API看起来很像Scala提供的使用NodeSeq遍历XML文档的方式.
1
2
3
4
|
val
json
=
Json.parse(jsonString)
val
maybeName
=
(json \
"user"
\ name).asOpt[String]
val
emails
=
(json \
"user"
\\
"emails"
).map(
_
.as[String])
|
注意使用 \ 遍历不会导致失败.你必须在末尾使用 asOpt[T]自行处理出错误情形,它將返回 None 如果值缺失的话.否则,你可以使用 as[T],以抛异常的方式处理失败,如果值丢失的话.
Scala值转成Json
As soon as you have a type class able to transform the Scala type to Json, it is pretty easy to
generate any Scala value to Json. For example letʼs create a simple Json object:
只要你有一个type class 你就能將Scala类型转成Json,很容易將任何的Scala值转成Json.例如让我们创建一个简单的Json对象:
1
|
val
jsonNumber
=
Json.toJson(
4
)
|
或者创建Json数组
1
|
val
jsonArray
=
Json.toJson(Seq(
1
,
2
,
3
,
4
))
|
1
|
val
jsonArray
=
Json.toJson(Seq(
1
,
"Bob"
,
3
,
4
))
|
简单的选择是將它们做为Seq[JsValue]处理:
1
2
3
|
val
jsonArray
=
Json.toJson(Seq(
toJson(
1
), toJson(
"Bob"
), toJson(
3
), toJson(
4
)
))
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
val
jsonObject
=
Json.toJson(
Map(
"users"
-> Seq(
toJson(
Map(
"name"
-> toJson(
"Bob"
),
"age"
-> toJson(
31
),
"email"
-> toJson(
"bob@gmail.com"
)
)
),
toJson(
Map(
"name"
-> toJson(
"Kiki"
),
"age"
-> toJson(
25
),
"email"
-> JsNull
)
)
)
)
)
|
它將产生如下Json结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
val
jsonObject
=
Json.toJson(
Map(
"users"
-> Seq(
toJson(
Map(
"name"
-> toJson(
"Bob"
),
"age"
-> toJson(
31
),
"email"
-> toJson(
"bob@gmail.com"
)
)
),
toJson(
Map(
"name"
-> toJson(
"Kiki"
),
"age"
-> toJson(
25
),
"email"
-> JsNull
)
)
)
)
)
|
Json序列化
將JsValue转成Json字符串形式很容易:
1
|
val
jsonString
:
String
=
Json.stringify(jsValue)
|
其它选择
上面讨论的基于类型的选择是推荐的形式,当然也不会限制你使用其它JSON库。例如,下面是一小段演示怎样將纯Scala对象转成JSON 对象,通过绑定的,基于反射的Jerkson。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
com.codahale.jerkson.Json.
_
val
json
=
generate(
Map(
"url"
->
"http://nytimes.com"
,
"attributes"
-> Map(
"name"
->
"nytimes"
,
"country"
->
"US"
,
"id"
->
25
),
"links"
-> List(
"http://link1"
,
"http://link2"
)
)
)
|
处理Json请求
处理Json请求
一个 JSON 请求是一个使用 request body 搭载经验证的JSON内容的 HTTP 请求.它必须指定 Content-Type 为text/json或application/json mime类型。
默认Action使用any content body parser,让你以JSON取值得request body 值(实际上是JsValue):
1
2
3
4
5
6
7
8
9
10
11
|
def
sayHello
=
Action { request
=
>
request.body.asJson.map { json
=
>
(json \
"name"
).asOpt[String].map { name
=
>
Ok(
"Hello "
+ name)
}.getOrElse {
BadRequest(
"Missing parameter [name]"
)
}
}.getOrElse {
BadRequest(
"Expecting Json data"
)
}
}
|
更好的方法是自定义BodyParser,请求Play直接將body解析为JSON:
1
2
3
4
5
6
7
|
def
sayHello
=
Action(parse.json) { request
=
>
(request.body \
"name"
).asOpt[String].map { name
=
>
Ok(
"Hello "
+ name)
}.getOrElse {
BadRequest(
"Missing parameter [name]"
)
}
}
|
注意:当使用JSON body parser的时候,request.body的值直接做为一个经验证的JsValue值。
你可以通过在命令行中用curl测试:
1
2
3
4
5
|
curl
--header "Content-type: application/json"
--request POST
--data '{"name": "Guillaume"}'
http://localhost:9000/sayHello
|
返回:
1
2
3
4
5
|
HTTP/
1.1
200
OK
Content-Type
:
text/plain; charset
=
utf-
8
Content-Length
:
15
Hello Guillaume
|
返回JSON响应
前面的一些例子,我们接收JSON请求,但我们返回的是text/plain响应。
让我们更改为一个有效的HTTP响应:
1
2
3
4
5
6
7
8
9
10
11
|
def
sayHello
=
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]"
)
))
}
}
|
现在它返回:
1
2
3
4
5
|
HTTP/
1.1
200
OK
Content-Type
:
application/json; charset
=
utf-
8
Content-Length
:
43
{
"status"
:
"OK"
,
"message"
:
"Hello Guillaume"
}
|