繁体   English   中英

播放框架,从请求解析json数组

[英]Play framework, parse json array from request

我怎样才能将一个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应该在某处使用。

您的控制器不需要担心验证和映射特定的类字段,这是模型的工作。 假设您似乎正在使用Example案例类,您可以使用Play提供的Json.reads宏轻松创建Reads[Example] 隐式Reads应放在相应类的伴随对象中,因此隐式Reads可以从任何地方获取。 如果需要,您还可以通过阅读文档来创建更多自定义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.successful(...)包含在Future.successful(...)以避免将简单的工作分发给Future.successful(...) ,而不是使用Future { ... }来包装基本上不会阻止任何内容的常量值Future.successful(...) ExecutionContext

借用Michael的答案,我们可以通过使用在其类型中参数化parse.json版本来进一步简化控制器代码。

假设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

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

我正在建立一个gregghz回答的答案。 所以......你肯定需要像他一样制作案例类和伴侣对象:

import play.api.libs.json._

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

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

但是你的控制器方法可以更简单,特别是如果你不想乱搞Async。 这对我有用,因为我从客户端发送一个HTML form ,接收每个input并仅发送回该方法。 这种方式可能存在缺点,我很感激在评论中听到它们,但你要做的就是:

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")
    }
  }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM