我有两个课程,User&地址。
case class User(
id: Pk[Long] = NotAssigned,
name: String = "",
email: String = "",
addresses: Seq[Address])
case class Address(
id: Pk[Long] = NotAssigned,
userId: Long,
city: String)
在我的控制器中,我要发送所有用户及其地址,例如Map[User, List[Address]]
。我能够使用anorm(mysql)提取它们,但后来我需要将它们作为json发送。你能帮忙解决一下如何实现写入&读取以上Map[User, List[Address]]
,谢谢。
答案 0 :(得分:5)
那应该有帮助
import anorm._
import play.api.libs.json._
import play.api.libs.functional.syntax._
case class User(
id: Pk[Long] = NotAssigned,
name: String = "",
email: String = "",
addresses: Seq[Address])
case class Address(
id: Pk[Long] = NotAssigned,
userId: Long,
city: String)
// Play does not provide Format[Pk[A]], so you need to define it
implicit def pkReads[A](implicit r: Reads[Option[A]]): Reads[Pk[A]] = r.map { _.map(Id(_)).getOrElse(NotAssigned) }
implicit def pkWrites[A](implicit w: Writes[Option[A]]): Writes[Pk[A]] = Writes(id => w.writes(id.toOption))
implicit val addrFormat = Json.format[Address]
implicit val userFormat = Json.format[User]
现在您可以轻松地序列化用户:
val as = Seq(Address(Id(2), 1, "biim"))
val u = User(Id(1), "jto", "jto@foo.bar", as)
scala> Json.toJson(u)
res6: play.api.libs.json.JsValue = {"id":1,"name":"jto","email":"jto@foo.bar","addresses":[{"id":2,"userId":1,"city":"biim"}]}
正如朱利安所说,你不能只序列化Map[User, Seq[Address]]
。它只是没有意义,因为User不能成为Json对象中的键。
答案 1 :(得分:4)
您可以通过将Map[User, List[Address]]
转换为List[User]
来解决此问题,并且JsonWriter将变得易于编写。
类似的东西:
list.map {
case (user, address) => user.copy(addresses = address.toSeq)
}
答案 2 :(得分:2)
User中的“地址”包含地址,因此您不需要将Map [User,List [Address]]发送回客户端。 Json将是一系列序列化用户对象,地址就是其中的一部分。如果你确实想要发回Map,那么类型Map [String,List [Address]]在Json序列化上下文中更有意义。这是为List [User]生成Json的代码。输出看起来像这样
[
{
"id": 1,
"name": "John Doe",
"email": "john@email.com",
"addresses": [
{
"id": 1001,
"userId": 1,
"city": "Chicago"
},
{
"id": 1002,
"userId": 1,
"city": "New York"
}
]
},
{
"id": 2,
"name": "Jane Doe",
"email": "jane@email.com",
"addresses": [
{
"id": 1012,
"userId": 1,
"city": "Dallas"
}
]
}
以下是您控制器中的代码。它具有Json.toJson使用的隐式Json格式化程序。
implicit object PkWrites extends Writes[Pk[Long]] {
def writes(key: Pk[Long]) = Json.toJson(key.toOption)
}
implicit object PkReads extends Reads[Pk[Long]] {
def reads(json: JsValue) = json match {
case l: JsNumber => JsSuccess(Id(l.value.toLong))
case _ => JsSuccess(NotAssigned)
}
}
implicit val AddressWrites: Writes[Address] = (
(JsPath \ "id").write[Pk[Long]] and
(JsPath \ "userId").write[Long] and
(JsPath \ "city").write[String]
)(unlift(Address.unapply))
implicit val AddressReads: Reads[Address] = (
(JsPath \ "id").read[Pk[Long]] and
(JsPath \ "userId").read[Long] and
(JsPath \ "city").read[String]
)(Address.apply _)
implicit val UserWrites: Writes[User] = (
(JsPath \ "id").write[Pk[Long]] and
(JsPath \ "name").write[String] and
(JsPath \ "email").write[String] and
(JsPath \ "addresses").write[List[Address]]
)(unlift(User.unapply))
def makeJson() = Action {
val johnAddr1 = Address(Id(1001), 1, "Chicago")
val johnAddr2 = Address(Id(1002), 1, "New York")
val janeAddr1 = Address(Id(1012), 1, "Dallas")
val john = User(Id(1), "John Doe", "john@email.com", List(johnAddr1, johnAddr2))
val jane = User(Id(2), "Jane Doe", "jane@email.com", List(janeAddr1))
Ok(Json.toJson(List(john, jane)))
// Ok(Json.toJson(map))
}