【问题标题】:Play framework, parse json array from request播放框架,从请求中解析 json 数组
【发布时间】:2017-08-27 00:12:06
【问题描述】:

如何将 json 对象数组解析为 scala ListArray

现在我有一个解析单个对象的代码:

{"id":1,"name":"example1"}

这是代码:

def exampleAction = Action.async(parse.json) { implicit request =>
    for {
        id <- (request.body \ "id").asOpt[Int]
        name <- (request.body \ "name").asOpt[String]
    } yield {
        (exampleService.create(Example(id, name)) map { n => Created("Id of Object Added : " + n) }).recoverWith {
            case e => Future {
                InternalServerError("There was an error at the server")
            }
        }
    }.getOrElse(Future { BadRequest("Wrong json format") })
}

但是我应该如何改变它来解析这样的 json 请求:

{[{"id":1,"name":"example1"},{"id":2,"name":"example2"}]}

我猜函数map应该在某处使用。

【问题讨论】:

  • 最后一行不是有效的 JSON,但没有大括号 {},它是。我假设这就是你的意思。

标签: arrays json scala playframework


【解决方案1】:

您的控制器不必担心验证和映射特定的类字段,这是模型的工作。假设您似乎正在使用 Example 案例类,您可以使用 Play 提供的 Json.reads 宏轻松创建 Reads[Example]。隐含的Reads 应该放在相应类的伴生对象中,这样就可以从任何地方获取隐含的。如果需要,您还可以通过阅读 documentation 创建更多自定义 Reads,但现在我们将坚持基础知识。

import play.api.libs.json._

case class Example(id: Int, name: String)

object Example {
  implicit val reads: Reads[Example] = Json.reads[Example]
}

然后,在您的控制器中,您可以使用JsValue#validate[A] 尝试一次反序列化整个模型。这样做会返回一个JsResult[A],它可以是保存反序列化模型的JsSuccess[A],也可以是JsError。我们可以fold结果来处理这两种情况。

def exampleAction = Action.async(parse.json) { implicit request =>
  request.body.validate[Example].fold(
    error => Future.successful(InternalServerError("JSON did not validate.")),
    example => {
      // Do something with the case class
      exampleService.create(example).map { 
        // ...
      } recoverWith {
        // ...
      }
    }
  )
}

现在,您可以通过更改轻松更改上述控制器以处理数组而不是单个模型:

request.body.validate[List[Example]]

fold 方法的第二部分,您将获得一个可以使用的List[Example]


请注意,在您的错误情况下,不要使用Future { ... } 来包装基本上不会阻塞任何内容的常量值,而是可以将它们包装在Future.successful(...) 中以避免将琐碎的工作分派给ExecutionContext

【讨论】:

  • 这在 2.6 中是否已被弃用,或者在执行此方法的控制器中是否需要导入语句?在这一行request.body.validate[Example].fold(IntelliJ 下划线validate 部分,表示无法解决。
  • @NateH06 请参阅 playframework.com/documentation/2.6.x/… 了解在 play 2.6 中围绕这些内容所做的更改。
  • 有什么“简单”的方法而不必创建额外的类?也许只是把结果放在 List[Map[String, String]] 中?
【解决方案2】:

借用 Michael 的回答,我们可以通过使用 parse.json that is parameterized in its type 的版本进一步简化控制器代码。

假设Reads 存在:

import play.api.libs.json._

case class Example(id: Int, name: String)

object Example {
  implicit val reads: Reads[Example] = Json.reads[Example]
}

要处理 Example 对象的 json 数组,您可以简单地使用 parse.json[List[Example]] 作为正文解析器,然后 request.body 将成为 List[Example]

def exampleAction = Action.async(parse.json[List[Example]]) { implicit request =>
  val examples: List[Example] = request.body

  // ...
}

如果发布到此端点的正文不是示例对象的有效 json 数组,Play 将自动返回 400 Bad Request

【讨论】:

  • 当我这样做时,IntelliJ 抱怨 request.body 部分,说“AnyContent 类型的表达式不符合预期的 Listminimal reproducible example 类型”
  • 你离开了 parse.json 部分。 Action.async(parse.json[List[Example]])。 Play 中的默认正文解析将为您提供 AnyContent。
  • 另外,尝试在 intellij 之外编译(直接使用 sbt)。众所周知,Intellij 有时会出错。
  • 不,没有忘记它,肯定会复制并粘贴您的代码,将Example 替换为我的案例类。我尝试自己使用 SBT 进行编译,但它给出了一个没有消息的编译错误。我也尝试在浏览器中编译,它给了我更多:type mismatch; found : play.api.mvc.AnyContent required: List[models.jsonmodels.Example]
  • “它给出了一个没有消息的编译错误” 这看起来很奇怪。您是否可能缺少案例课程的阅读内容?
【解决方案3】:

我尝试按照接受的答案和 greggz' 来写信,但无法让它们编译。

不过,我正在根据 gregghz 的答案构建一个答案。所以......你肯定需要像他一样制作案例类和伴随对象:

import play.api.libs.json._

case class Example(id: Int, name: String)

object Example {
  implicit val reads: Reads[Example] = Json.reads[Example]
}

但是你的控制器方法可以更简单,特别是如果你不想搞乱异步。这对我有用,因为我从客户端发送 HTML form,获取每个 input 并仅将其发送回此方法。这种方式可能存在缺陷,我很高兴在 cmets 中听到它们,但您所要做的就是:

def exampleAction = Action {
    implicit request: Request[AnyContent] => {
      val jsonBody = request.body.asJson
      val myContent : List[Example] = jsonBody.get.as[List[Example]]
      // ... do rest of work here
      Ok("Json parsed")
    }
  }

【讨论】:

  • 如果正文不是 json 或与 Example 的 Jon 模式不匹配,这将返回 500 内部服务器错误。
  • 我想手动解析数组的原因是因为我想以各种方式返回200,只是相应地返回不同的内容。所有的答案都没有帮助,在 play framework scala 中解析 Json Array 有那么难吗?我是 scala 的新手,这似乎很困难,因为在谷歌搜索 5 分钟后我找不到任何解决这个简单问题的方法
猜你喜欢
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多