【问题标题】:How to handle Future[Option[BSONDocument] in Play action如何在 Play 操作中处理 Future[Option[BSONDocument]
【发布时间】:2017-07-18 18:53:26
【问题描述】:

我正在创建一个用户注册模块。提交时(使用 JSON),我想检查 JSON 是否正确解析。如果 JSON 有问题,我想返回错误。如果 JSON 正确,我想检查用户是否已经存在(查看名字)。数据在 MongoDB 中。我正在使用 ReactiveMongoPlugin 0.10。我将使用返回 Future[Option[BSONDocument]] 的“一个”方法。如何在 Action 完成之前等待这个 Future 完成?

方法 1 - 使用 Action 并尝试自己处理 Future 的结果。代码无法编译,不知道如何等待 Future 完成

  def registrationRequest = Action(parse.json) { request => {
    Logger.debug("received message:" + request)
    Logger.debug("received message:" + request.body)
    val jr:JsResult[User2] = request.body.validate[User2]
    Logger.debug( "jr is "+jr)

    jr match {
      case s:JsSuccess[User2] => {

        val user = s.get
        Logger.debug("opening database connection")

        val driver = new MongoDriver()
        val connection = driver.connection(List("localhost"))
        val db = connection.db("website-db")
        val collection = db.collection[BSONCollection]("users")

        // the data from client is a JSON of type {user:{firstname:"name"}}. I have created code to parse the JSON
        val query = BSONDocument("user"-> BSONDocument("firstname"->user.firstname))
        Logger.debug("query is:"+query)


        val result = collection.find(query).one

我现在想等待结果并返回 Ok(Json.toJson(ack)) 或 BadRequest(Json.toJson(ack))。我怎么做?我已经编写了以下代码,但我被困在两点 (a) 代码是否会等待未来完成 (b) onComplete 返回 Unit 但 Play 的 Action 需要 play.api.mvc.Result。我该怎么做?

//I guess data would be Success or Failure
result onComplete ( data =>
        data match {
          //If Success, value would be Some or None
          case Success(value) => {
            value match {
              case None => { //no record. Can add
                Logger.debug("No record from mongo: Can add")
                val ack = Acknowledgment (1, "Welcome " + user.firstName + " " + user.lastName)
                Logger.debug ("success ack Json:" + Json.toJson (ack) )
                Ok (Json.toJson (ack) )

              }
              case Some(x) => { //duplicae record
                Logger.debug("error from Mongo. Duplicate:"+x)
                val ack = Acknowledgment(0,"duplicate: "+x.toString())
                Logger.debug("fail ack:"+Json.toJson(ack))
                BadRequest(Json.toJson(ack))
              }

            }
          }
          case Failure (e)=> {
            Logger.debug("error from Mongo."+e)
            val ack = Acknowledgment(0,"MongoDB Error: "+e.toString())
            Logger.debug("fail ack:"+Json.toJson(ack))
            BadRequest(Json.toJson(ack))
          }
        }) //onComplete returns Unit. Action needs play.api.mvc.Result
  case f:JsError => {
    Logger.debug("error: "+JsError.toFlatJson(f))
    val ack = Acknowledgment(0,JsError.toFlatJson(f).toString())
    Logger.debug("fail ack:"+Json.toJson(ack))
    BadRequest(Json.toJson(ack))
  }
}

}

方法 2 - 我读到我应该使用 Action.async 但我无法将这些部分组合在一起。我遵循的第二种方法是使用 Action.Async 但代码没有编译,因为它需要 Future[SimpleResult]

def registrationRequest = Action.async(parse.json) { request => {
    Logger.debug("received message:" + request)
    Logger.debug("received message:" + request.body)
    val jr:JsResult[User2] = request.body.validate[User2]
    Logger.debug( "jr is "+jr)

    jr match {
      case s:JsSuccess[User2] => {

        val user = s.get
        Logger.debug("opening database connection")
        val driver = new MongoDriver()
        val connection = driver.connection(List("localhost"))
        val db = connection.db("website-db")
        val collection = db.collection[BSONCollection]("users")

        val query = BSONDocument("user"-> BSONDocument("firstname"->user.firstName))
        Logger.debug("query is:"+query)

        //result is of type Future[Option[BSONDocument]]
        val result = collection.find(query).one

        result.map(option => option match {
          case None => {
            //no record. Can add
            Logger.debug("No record from mongo: Can add")
            val ack = Acknowledgment(1, "Welcome " + user.firstName + " " + user.lastName)
            Logger.debug("success ack Json:" + Json.toJson(ack))
            Ok(Json.toJson(ack))
          }
          case Some(x) => {
            //duplicae record
            Logger.debug("error from Mongo. Duplicate:" + x)
            val ack = Acknowledgment(0, "duplicate: " + x.toString())
            Logger.debug("fail ack:" + Json.toJson(ack))
            BadRequest(Json.toJson(ack))
          }
        }
        )
      }
      case f:JsError => {
        Logger.debug("error: "+JsError.toFlatJson(f))
        val ack = Acknowledgment(0,JsError.toFlatJson(f).toString())
        Logger.debug("fail ack:"+Json.toJson(ack))
        BadRequest(Json.toJson(ack)) //Action.async expect scala.concurrent.Future[play.api.mvc.SimpleResult]
  }
}


  }

【问题讨论】:

    标签: scala playframework


    【解决方案1】:

    解决方案是使用返回 Future[SimpleResult] 的 Action.async。在代码内部使用 map 和 flatMap on Future 返回 Future[SimpleResult]。

    【讨论】:

    • 永远不要等待(测试中的除外)而是撰写Future
    猜你喜欢
    • 1970-01-01
    • 2020-12-13
    • 2015-11-03
    • 2021-12-13
    • 2020-05-18
    • 2020-03-16
    • 2016-11-08
    • 2014-11-19
    • 2021-06-20
    相关资源
    最近更新 更多