尝试解析Future响应时出现了什么问题?

3

我有一个函数,它将通过ajax请求获取Token。只要Token有效,它就会返回目录列表响应。

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => checkToken(form.token).map(token => {
      val directories = Directories.all.map(directory => {
        Json.toJson(directory)
      })
      Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
    })
  )
}

当我运行上述代码时,它显示错误信息[ ^ 符号表示错误发现的位置]。
No Json serializer found for type scala.concurrent.Future[play.api.libs.json.JsValue]. Try to implement an implicit Writes or Format for this type.
Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
                                                                                                                                            ^

这个可能会有帮助:https://dev59.com/vV0Z5IYBdhLWcg3wtSPr - Yuval Itzchakov
2
if (<condition>) true else false 你是认真的吗?:D - Łukasz
1个回答

5
这是我想出来的内容。
def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => for {
      (token, directories) <- checkToken(form.token) zip Directories.all
    } yield {
      val isTokenValid = token.isDefined
      val responseBody = Json.obj(
        "status" -> isTokenValid, 
        "message" -> {
          if (isTokenValid)
            Json.toJson(directories)
          else
            "Invalid token"
        }
      )
      Ok(responseBody)
    }
  )
}

假设checkTokenDirectories.all都返回Future
您的函数需要返回Future[Result]。在折叠时,第一个分支是正确的。
formWithErrors => Future.successful(BadRequest(formWithErrors.toString))

然而,在第二个分支中,你似乎通过调用 Directories.all 开始了一个新的 Future,并希望将其序列化并作为 json 返回。由于这没有意义,因此不存在 Future[JsValue] 的序列化程序,它必须阻塞以获取结果。你需要以某种方式获取 checkToken(form.token)Directories.all 两者的值。
你可以像上面那样做,或者例如像这样做:
form => {
  val futureToken = checkToken(form.token)
  val futureDirectories = Directories.all

  for {
    token <- futureToken
    directories <- futureDirectories
  } yield {
     // same code as above
  }
}

请注意,如果您将futureTokenfutureDirectories内联,则它们将按顺序执行。
还要注意,您将目录列表转换为json两次。
这里是第一次。
val directories = Directories.all.map(directory => {
  Json.toJson(directory)
})

假设 Directories.all 返回 Future[List[Directory]],那么当您使用 map 时,传递的函数将在 List[Directory] 上运行,因此变量应该命名为 directories 而不是 directory。它会起作用,play可以轻松地将任何可转换为json的列表进行转换,无需手动操作。
第二次您在这里做到了。
Json.toJson(directories)

是的,你说得对... checkTokenDirectories.all 都返回 Future - testuser
感谢分享你的想法...它对我有用...@Lukasz - testuser
我在条件语句val isTokenValid = token.get.id.getOrElse(0) >= 1中犯了一个错误。正确应该是使用token.isDefined而不是token.get.id.getOrElse(0) >= 1。当我使用token.get.id.getOrElse(0) >= 1时,代码会抛出异常。 - testuser
1
您可能意思是 token.map(_.id).getOrElse(0) >= 1 - Łukasz
2
你可能也可以这样做:token.exists(_.id > 0) - Peter Neyens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接