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