概述
使用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 ), ) ), 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 ), ) ), 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" } |