JSON 基础

    JSON是一种轻量级的数据交换格式,请看下面一个例子:

    如果想了解跟多关于JSON的知识,请访问

    play.api.libs.json包中包含表示JSON数据的数据结构和用于将这些数据结构与其他数据格式互相转换的实用工具。

    这是一个特质(trait),可以表示任何JSON值。JSON库中通过一系列对JsVlaue进行扩展的case类来表示各种有效的JSON类型。

    • JsString
    • JsNumber
    • JsBoolean
    • JsObject
    • JsArray
    • JsNull

    你可以利用这些多种多样的JsValue类型来构造任何JSON结构。

    Json

    Json对象提供一些工具,这些工具用于将数据格式转换为JsValue结构或者逆向转换。

    JsPath

    JsPath用于表示JsValue内部结构的路径,类似于XPath对XML的意义。可以利用JsPath析取JsValue结构,或者对隐式转换进行模式匹配。

    字符串解析

    1. import play.api.libs.json._
    2. val json: JsValue = Json.parse("""
    3. {
    4. "name" : "Watership Down",
    5. "location" : {
    6. "lat" : 51.235685,
    7. "long" : -1.309197
    8. },
    9. "residents" : [ {
    10. "name" : "Fiver",
    11. "age" : 4,
    12. "role" : null
    13. }, {
    14. "name" : "Bigwig",
    15. "age" : 6,
    16. "role" : "Owsla"
    17. } ]
    18. }
    19. """)
    1. import play.api.libs.json._
    2. val json: JsValue = JsObject(Seq(
    3. "name" -> JsString("Watership Down"),
    4. "location" -> JsObject(Seq("lat" -> JsNumber(51.235685), "long" -> JsNumber(-1.309197))),
    5. "residents" -> JsArray(Seq(
    6. JsObject(Seq(
    7. "name" -> JsString("Fiver"),
    8. "age" -> JsNumber(4),
    9. "role" -> JsNull
    10. )),
    11. JsObject(Seq(
    12. "name" -> JsString("Bigwig"),
    13. "age" -> JsNumber(6),
    14. "role" -> JsString("Owsla")
    15. ))
    16. ))
    1. import play.api.libs.json.{JsNull,Json,JsString,JsValue}
    2. val json: JsValue = Json.obj(
    3. "name" -> "Watership Down",
    4. "location" -> Json.obj("lat" -> 51.235685, "long" -> -1.309197),
    5. "residents" -> Json.arr(
    6. Json.obj(
    7. "name" -> "Fiver",
    8. "age" -> 4,
    9. "role" -> JsNull
    10. ),
    11. Json.obj(
    12. "name" -> "Bigwig",
    13. "age" -> 6,
    14. "role" -> "Owsla"
    15. )
    16. )
    17. )

    Writers转换器

    Scala中通过工具方法Json.toJson[T](T)(implicit writes:Writes[T])。这个功能通过类型转换器将T类型的数据转换为JsValue。

    Play框架的JSON库API接口提供了大部分基础类型的隐式Writes,例如IntDoubleStringBoolean。当然,该JSON库也有针对包含上述基本类型元素的集合的Writes转换器。

    1. import play.api.libs.json._
    2. // basic types
    3. val jsonString = Json.toJson("Fiver")
    4. val jsonNumber = Json.toJson(4)
    5. val jsonBoolean = Json.toJson(false)
    6. // collections of basic types
    7. val jsonArrayOfInts = Json.toJson(Seq(1, 2, 3, 4))
    8. val jsonArrayOfStrings = Json.toJson(List("Fiver", "Bigwig"))

    如果想把自己定义的模型转换成JsValues,你需要定义隐式的Writes转换器,并将它们引入执行环境。

    作为备选,你可以通过配合模式(combinator pattern)来定义自己的Writes转换器。

    注意:关于配合模式(combinator pattern)在JSON Reads/Writes/Formats 选择器一节中有详细介绍。

    1. import play.api.libs.json._
    2. import play.api.libs.functional.syntax._
    3. implicit val locationWrites: Writes[Location] = (
    4. (JsPath \ "lat").write[Double] and
    5. (JsPath \ "long").write[Double]
    6. )(unlift(Location.unapply))
    7. implicit val residentWrites: Writes[Resident] = (
    8. (JsPath \ "name").write[String] and
    9. (JsPath \ "age").write[Int] and
    10. (JsPath \ "role").writeNullable[String]
    11. )(unlift(Resident.unapply))
    12. implicit val placeWrites: Writes[Place] = (
    13. (JsPath \ "name").write[String] and
    14. (JsPath \ "location").write[Location] and
    15. (JsPath \ "residents").write[Seq[Resident]]
    16. )(unlift(Place.unapply))

    你可以析取JsValue结构并读取特定的值。语法和功能类似于Scala处理XML的方法。

    1. 注意:下面的例子应用在前面创建的JsValue结构上

    Simple path\

    \操作符应用于一个JsValue可以返回跟相关域对应的属性。下面假设有一个JsObject:

    1. val lat = json \ "location" \ "lat"
    2. // 返回JsNumber(51.235685)

    Recursive path\\

    1. val names = json \\ "name"
    2. // returns Seq(JsString("Watership Down"), JsString("Fiver"), JsString("Bigwig"))

    可以通过索引值从JsArray中获取值。

    字符串工具

    • 微型
    1. val minifiedString: String = Json.stringify(json)
    2. {"name":"Watership Down","location":{"lat":51.235685,"long":-1.309197},"residents":[{"name":"Fiver","age":4,"role":nul
    • 可读的
    1. {
    2. "name" : "Watership Down",
    3. "location" : {
    4. "lat" : 51.235685,
    5. "long" : -1.309197
    6. },
    7. "residents" : [ {
    8. "name" : "Fiver",
    9. "age" : 4,
    10. "role" : null
    11. "name" : "Bigwig",
    12. "age" : 6,
    13. "role" : "Owsla"
    14. } ]
    15. }

    JsValue.as或者Jsvalue.asOpt

    将JsValue对象转换成其他类型的最简单的方法是使用JsValue.as[T](implicit fjs:Reads[T]):T 需要自定义一个类型转换器Reads[T]来讲JsValue转换成T类型的数据(和Writes[T]相反)。 跟Writes一样,JSON库提供了Reads转换器需要的基本类型。

    1. val name = (json \ "name").as[String]
    2. // "Watership Down"
    3. val names = (json \\ "name").map(_.as[String])
    4. // Seq("Watership Down", "Fiver", "Bigwig")

    如果路径(path)不存在或者转换失败,as方法会抛出JsResultException异常。更安全的方法是使用JsValue.asOpt[T](implicit fjs:Reads[T]):Option[T]

    1. val nameOption = (json \ "name").asOpt[String]
    2. // Some("Watership Down")
    3. val bogusOption = (json \ "bogus").asOpt[String]
    4. // None

    尽管asOpt方法更安全,但是如果有错误也不能捕捉到。

    使用有效性(validation)

    推荐使用validate方法将JsValue转换为其他类型(这个方法含有一个Read类型的参数)。这个方法同时执行有效性验证和类型转换操作,返回的结果类型是JsResultJsResult通过两个类实现:

    • JsSuccess——表示验证/转换成功并封装结果。
    • JsError——表示验证/转换不成功,并包含有错误列表。

    可以使用多种模式来处理验证结果:

    如果要将JsValue转换为模型,你要定义隐式Reads[T]转换器,其中T是模型的类型。

    1. case class Location(lat: Double, long: Double)
    2. case class Resident(name: String, age: Int, role: Option[String])
    3. case class Place(name: String, location: Location, residents: Seq[Resident])
    4. import play.api.libs.json._
    5. import play.api.libs.functional.syntax._
    6. implicit val locationReads: Reads[Location] = (
    7. (JsPath \ "lat").read[Double] and
    8. (JsPath \ "long").read[Double]
    9. )(Location.apply _)
    10. implicit val residentReads: Reads[Resident] = (
    11. (JsPath \ "name").read[String] and
    12. (JsPath \ "age").read[Int] and
    13. (JsPath \ "role").readNullable[String]
    14. )(Resident.apply _)
    15. implicit val placeReads: Reads[Place] = (
    16. (JsPath \ "name").read[String] and
    17. (JsPath \ "location").read[Location] and
    18. (JsPath \ "residents").read[Seq[Resident]]
    19. )(Place.apply _)
    20. val json = { ... }
    21. val placeResult: JsResult[Place] = json.validate[Place]
    22. // JsSuccess(Place(...),)
    23. val residentResult: JsResult[Resident] = (json \ "residents")(1).validate[Resident]

    下一节: