首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Play框架从一组组合类中创建JSON输出

如何使用Play框架从一组组合类中创建JSON输出
EN

Stack Overflow用户
提问于 2017-02-08 05:17:57
回答 1查看 88关注 0票数 2

我是一个Scala新手,扩展了别人的代码。代码使用Play框架的JSON库。我正在访问Future[Option[A]]Future[Option[List[B]]类的对象。类AB都有自己的JSON writes方法,因此每个类都可以将JSON作为对web请求的响应返回。我正在尝试将这些组合到一个JSON响应中,我可以将其作为HTTP响应返回。

我认为创建一个将AB组成单个类的类可以让我做到这一点,大致是这样的:

代码语言:javascript
复制
case class AAndB(a: Future[Option[A]], b: Future[Option[List[B]]])
object AAndB {
    implicit val implicitAAndBWrites = Json.writes[AAndB]
}

但这在所有地方都是失败的。A和B的结构都是这样的:

代码语言:javascript
复制
sealed trait A extends SuperClass {
    val a1: String = "identifier"
}

case class SubA(a2: ClassA2) extends A {
    override val a1: String = "sub identifier"
}

object SubA {
    val writes = Writes[SubA] { aa =>
        Json.obj(
            "a1" -> aa.a1
            "a2" -> aa.a2
        )
    }
}

由于B是以列表的形式访问的,因此预期的输出将如下所示:

代码语言:javascript
复制
{  
   "a":{  
      "a1":"val1",
      "a2":"val2"
   },
   "b":[  
      {  
         "b1":"val 3",
         "b2":"val 4"
      },
      {  
         "b1":"val 5",
         "b2":"val 6"
      },
      {  
         "b1":"val 7",
         "b2":"val 8"
      }
   ]
}

非常感谢您的帮助。

EN

回答 1

Stack Overflow用户

发布于 2017-02-08 07:07:10

正如@cchantep在你的问题的评论中提到的,将Futures作为case class声明的一部分是非常不寻常的-- Future[T]类非常适合封装不可变域对象(也就是不随时间变化的域对象),但是一旦你涉及到case,你可能会有多个结果:

  • Future

yet

  • Future failed
  • Future successfully,并包含T实例

您不希望将这些时态内容与转换为JSON的操作混为一谈。出于这个原因,您应该对包装器类进行建模,并删除Future

代码语言:javascript
复制
case class AAndB(a: Option[A], b: Option[List[B]])
object AAndB {
  implicit val implicitAAndBWrites = Json.writes[AAndB]
}

取而代之的是在你的Controller类中使用Scala/Play对它们的非常简洁的处理来访问它们的内容。在下面的示例中,假设存在如下注入的服务类:

代码语言:javascript
复制
class AService {
  def findA(id:Int):Future[Option[A]] = ...
}

class BListService {
  def findBs(id:Int):Option[Future[List[B]]] = ...
}

下面是我们的控制器方法可能的样子:

代码语言:javascript
复制
def showCombinedJson(id:Int) = Action.async {

  val fMaybeA = aService.findA(id)
  val fMaybeBs = bService.findBs(id)

  for {
    maybeA <- fMaybeA
    maybeBs <- fMaybeBs
  } yield {
    Ok(Json.toJson(AAndB(maybeA, maybeBs)))
  }
}

因此,我们在这里并行启动A查询和B查询(我们必须在for-comprehension之外执行此操作才能实现这种并行性)。只有当两个-comprehension都成功完成时,才会执行forFutureFuture块-此时可以安全地访问其中的内容。然后,只需构建包装器类的一个实例,转换为JSON并返回Ok结果即可播放。

请注意,yield块的结果本身将在一个Future中(在本例中是一个Future[Result]),所以我们使用Play的Action.async操作构建器来处理这一点-让Play处理所有实际等待发生的事情。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42100180

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档