PlayFramework:WS获取JSON并将其保留在Action中

时间:2014-09-15 13:14:47

标签: scala playframework

我正致力于持久性Action。在其中我需要调用WS,通过邮政代码确定位置:

http://uk-postcodes.com/api

我从请求中收到的邮政编码,我使用的处理:

def futureLocationForPostCode(postcode: String): Option[Location] = {
    val postcodeWithoutSpace = postcode.replaceAll(" ", "");
    val url = "http://uk-postcodes.com/postcode/"+postcodeWithoutSpace+".json"
    val holder: WSRequestHolder = WS.url(url)

    val futureResponse: Future[WSResponse] = holder.get()

    val result = futureResponse match {
      case response: WSResponse => response.status match {
        case 200 => {
          val lat = (response.json \ "geo" \ "lat").as[Double]
          val lon = (response.json \ "geo" \ "lng").as[Double]
          val location: Location = Location(lat, lon)
          location
        }
        case _ => None
      }
    }
    result
  }

这是Location的模型:

case class Location(lat: Double, lon: Double)

object Location {

  implicit val locationReads: Format[Location] = (
    (JsPath \ "lat").format[Double](min(-90.0) keepAnd max(90.0)) and
    (JsPath \ "lon").format[Double](min(-180.0) keepAnd max(180.0))
  )(Location.apply, unlift(Location.unapply))

}

如果Action中没有“无”,我就不知道如何保存位置:

def createAccount = Action.async {
    implicit request => {
      createAccountForm.bindFromRequest fold (
        formWithErrors => {
          Logger.info("Validation errors")
          Future.successful(BadRequest(createAccountForm.errorsAsJson))
        },
        accountInfo => {
          AccountService.findByEmail(accountInfo.email) map {
            case accountOpt: Option[Account] => accountOpt match {
              case Some(acc) => BadRequest(Json.toJson(Json.obj("message" -> "Email is already in use")))
              case None => {
                Logger.info("Created account")
                val account = Account.createAccount(accountInfo)

                //TODO: Add location to account if it is not None
                val futureLocation = Account.futureLocationForPostCode(accountInfo.postCode)

                Created(Json.toJson(AccountService.add(account)))
              }
            }
            case _ => {
              Logger.info("DB connection error")
              InternalServerError(Json.toJson(Json.obj("message" -> "DB connection error")))
            }
          }
        })
    }
  }

1 个答案:

答案 0 :(得分:1)

您为futureLocationForPostCode方法假定了错误的返回类型。以下应该有效:

def futureLocationForPostCode(postcode: String): Future[Option[Location]] = {
    val postcodeWithoutSpace = postcode.replaceAll(" ", "");
    val url = "http://uk-postcodes.com/postcode/"+postcodeWithoutSpace+".json"
    val holder: WSRequestHolder = WS.url(url)

    val futureResponse: Future[WSResponse] = holder.get()

    val result = futureResponse map { response =>
        response.status match {
            case 200 => {
                val lat = (response.json \ "geo" \ "lat").as[Double]
                val lon = (response.json \ "geo" \ "lng").as[Double]
                val location: Location = Location(lat, lon)
                Some(location)
             }
             case _ => None
        }   
    }
    result
}

然后

 val futureLocation = Account.futureLocationForPostCode(accountInfo.postCode)

 // Action.async requires a result of Future[SimpleResult] so map the future accordingly
 futureLocation map { locationOption =>
     val json = locationOption match {
         case Some(location) => {
             // here you can add location to account before return
             Json.toJson(AccountService.add(account))
         }
         case None => {
             Json.toJson(AccountService.add(account))
         }
     }

     Created(json)
 }